이 글에는 제휴 링크(affiliate link)가 포함되어 있습니다. Vultr·DigitalOcean 가입 링크로 가입하시면 추가 비용 없이 크레딧 혜택을 받으실 수 있으며, 블로그 운영에 도움이 됩니다.
서버 한 대에 여러 서비스를 올리는 프로덕션 운영
서비스가 늘어날 때마다 VPS를 한 대씩 더 사고 계신다면 비용이 서비스 수만큼 배가 됩니다. 거기에 도메인마다 SSL 인증서를 매년 사야 한다면 인증서 비용도 만만치 않습니다. Nginx 리버스 프록시와 Let’s Encrypt 무료 SSL을 쓰면 서버 한 대 위에 모든 서비스를 올리고 인증서는 무료로 발급·갱신할 수 있습니다.

이 튜토리얼에서는 한 대의 VPS에 블로그·API·관리툴을 각각 다른 도메인으로 띄우고, Let’s Encrypt로 자동 갱신되는 SSL까지 붙이는 전체 과정을 다룹니다. 단일 사이트 설정에서 한 단계 더 나아간 프로덕션 다중 서비스 라우팅입니다.
1. 리버스 프록시란?
프록시는 중간에서 대신 전달해 주는 역할입니다. 익숙한 포워드 프록시(회사/학교에서 외부로 나갈 때 거치는 것)와 반대로, 리버스 프록시는 인터넷에서 들어오는 요청을 서버 앞에서 받아 도메인을 보고 알맞은 내부 서비스로 보냅니다. 사용자는 앞에 프록시가 있다는 사실을 모른 채 도메인으로 접속하면 알아서 서비스가 응답합니다. Nginx는 이 분야에서 가장 널리 쓰이는 서버 중 하나입니다 — 가볍고 설정이 단순한 편입니다.
2. server block으로 도메인 분리
Nginx는 들어온 요청의 도메인을 보고 어떤 server block을 쓸지 정합니다. server_name 지시어로 도메인을 매칭합니다. 예를 들어 blog.example.com과 api.example.com을 각각 별도 server block으로 만들면 서로 독립적으로 동작합니다.
# /etc/nginx/sites-available/blog.example.com
server {
listen 80;
server_name blog.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
설정 파일은 /etc/nginx/sites-available/에 도메인별로 만들고 /etc/nginx/sites-enabled/에 심볼릭 링크로 연결합니다. listen 80은 HTTP, 443은 HTTPS입니다 — 처음엔 80번으로 받고 SSL 발급 뒤에 443번으로 바꿉니다.

3. proxy_pass와 헤더 전달
location / 블록 안의 proxy_pass로 백엔드 주소를 적습니다. http://127.0.0.1:8080이면 이 도메인으로 들어온 요청이 8080번 포트의 서비스로 갑니다. API는 3000번, 관리툴은 5050번으로 보내면 각 서비스를 포트만 바꿔 라우팅할 수 있습니다.
주의할 점은 헤더 전달입니다. 프록시가 중간에 있으면 뒤의 서비스는 누가 요청했는지 모릅니다. 그래서 Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto 헤더를 함께 넘겨야 백엔드가 실제 클라이언트 정보를 알 수 있습니다. 이 헤더가 없으면 로그에 실제 사용자 IP가 안 남고 HTTPS가 HTTP로 인식됩니다.
또 proxy_pass 주소 끝에 슬래시를 붙이냐에 따라 경로 처리가 달라집니다. 붙이면 location 경로가 잘리고, 빼면 그대로 전달됩니다 — 이 차이를 헷갈리면 이미지나 API가 깨집니다.
4. Let’s Encrypt 무료 SSL 발급
SSL 인증서를 유료로 사는 시대는 지났습니다. Let’s Encrypt가 무료로 발급해 주고, 도구는 certbot 하나면 됩니다.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx --redirect -d blog.example.com -d api.example.com
--nginx 옵션을 주면 certbot이 Nginx 설정을 읽고 자동으로 인증서를 발급하고 설정 파일까지 고쳐 줍니다. --redirect를 붙이면 HTTP 요청을 HTTPS로 자동 이동시킵니다. 이 과정을 HTTP-01 챌린지라고 부릅니다 — Let’s Encrypt가 특정 주소로 접근해 보고 내 서버가 응답하면 인증서를 줍니다. 그러므로 80번 포트가 열려 있어야 합니다.
처음 설정이 꼬일 때는 --staging 옵션으로 테스트 발급을 받아보세요. 스테이징 환경은 정식 환경보다 발급 한도가 훨씬 높습니다. 정식 발급이 확인되면 다시 정식으로 받으면 됩니다.
5. 자동 갱신 — certbot timer
인증서 유효기간은 현재 90일입니다(Let’s Encrypt는 2027년 2월 10일 64일, 2028년 2월 16일 45일로 줄일 예정 — 공식 블로그). 다행히 certbot을 설치하면 갱신 타이머도 같이 깔립니다.
systemctl status certbot.timer
# 하루에 두 번 갱신 시도, 기간 30일 남았을 때 실제 갱신
갱신 직후에 해야 할 일이 있으면 deploy hook으로 겁니다. 예를 들어 인증서가 바뀌면 Nginx를 다시 불러오도록 등록합니다.
sudo certbot renew --deploy-hook "systemctl reload nginx"
자동이라도 실패할 수 있습니다. Let’s Encrypt는 2025년 6월 4일 만료 알림 메일 발송을 중단했으므로(공식 블로그), sudo certbot renew --dry-run으로 가끔 확인하거나 인증서 만료를 감시하는 모니터링을 두세요.

6. 실전 배치 — 한 VPS에 세 서비스
한 대의 VPS에 세 개의 서비스를 올리는 예시:
- 블로그
blog.example.com→ 8080번 포트의 WordPress - API
api.example.com→ 3000번 포트의 Node.js 앱 - 관리툴
admin.example.com→ 5050번 포트의 pgAdmin
세 서비스가 각각 다른 도메인으로 한 서버에서 돌아갑니다. 비용은 서버 한 대 분량이고 인증서도 세 도메인 모두 무료입니다.
7. 트러블슈팅 — 자주 겪는 문제
설정을 바꿨으면 반드시 sudo nginx -t로 문법을 검사하고 sudo systemctl reload nginx로 다시 불러옵니다. restart가 아니라 reload면 끊김 없이 설정이 적용됩니다.
- 502 Bad Gateway: 뒤의 백엔드 서비스가 죽었을 때. 서비스가 켜져 있는지,
proxy_pass포트와 실제 포트가 같은지 확인. - 도메인이 Nginx에 연결 안 됨: DNS 전파가 끝났는지, 도메인이 서버 IP를 제대로 가리키는지 확인.
- 포트 충돌: 다른 서비스가 80/443번을 이미 쓰고 있을 수 있음.
- 인증서 발급 실패: 80번 포트가 방화벽에 막혀 있으면 HTTP-01 챌린지가 안 됨.
ufw allow 80으로 열어 줄 것.
마무리: 서버 한 대, 무료 인증서
Nginx 리버스 프록시와 Let’s Encrypt로 서버 한 대에 여러 서비스를 안전하게 올렸습니다. 비용은 서버 한 대, 인증서는 무료입니다. 블로그와 API와 관리툴이 각각 다른 도메인으로 돌아갑니다. 다음 글에서는 VPS에 PostgreSQL을 배포하고 백업까지 자동화하는 방법을 다룹니다.
추천 VPS: 이 튜토리얼은 Vultr(서울 리전, 신규 고객 첫 입금 최대 100달러 매칭), DigitalOcean, Hetzner 어디서나 동일하게 적용됩니다.
자주 묻는 질문 (FAQ)
Q1. 리버스 프록시가 정확히 무슨 역할인가요?
인터넷에서 들어오는 요청을 서버 앞에서 먼저 받아, 요청에 담긴 도메인을 보고 알맞은 내부 서비스로 넘겨주는 중계자입니다. 사용자는 프록시의 존재를 모른 채 도메인으로 접속하고, 뒤에서는 포트가 다른 여러 서비스가 각자 응답합니다.
Q2. 502 Bad Gateway가 뜹니다.
뒤에 있는 백엔드 서비스가 죽었거나, proxy_pass에 적은 포트와 실제 서비스 포트가 다를 때 주로 발생합니다. 서비스가 실행 중인지 먼저 확인하고 포트 번호를 대조해 보세요.
Q3. 백엔드 로그에 실제 방문자 IP가 안 남습니다.
프록시가 중간에 있으면 백엔드는 요청자를 알 수 없습니다. proxy_set_header로 Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto를 함께 넘겨야 실제 클라이언트 정보가 전달됩니다. 이 헤더가 빠지면 HTTPS 요청이 HTTP로 인식되기도 합니다.
Q4. SSL 인증서 발급이 실패합니다.
Let’s Encrypt는 HTTP-01 챌린지로 서버에 직접 접근해 확인하므로 80번 포트가 열려 있어야 합니다. 방화벽에 막혀 있다면 sudo ufw allow 80으로 열어 주세요. 설정이 꼬일 때는 –staging으로 테스트 발급을 먼저 받아보면 한도 걱정이 적습니다.



















