Nginx 리버스 프록시 설정과 Let’s Encrypt 무료 SSL 적용 방법 (Certbot 자동 갱신까지)
서버에 띄운 애플리케이션을 도메인과 HTTPS로 서비스할 때 가장 많이 쓰는 방법이 바로 Nginx 리버스 프록시 구성이다. 애플리케이션을 띄우면 보통 http://서버IP:8080 같은 주소로 접속하게 되는데, 개발할 때는 상관없지만 실제로 서비스를 운영하려면 도메인으로 접속되어야 하고, 요즘은 HTTPS가 사실상 필수다. 브라우저는 HTTP 사이트에 “주의 요함” 경고를 띄우고, 검색 엔진도 HTTPS 사이트를 더 신뢰한다.
그래서 많이 쓰는 조합이 Nginx 리버스 프록시 + Let’s Encrypt 무료 SSL이다. 앞단의 Nginx가 80, 443 포트로 요청을 받고, 뒤쪽의 애플리케이션(Spring Boot, Node.js 등)으로 전달하는 구조다. 인증서는 Let’s Encrypt에서 무료로 발급받고, Certbot으로 자동 갱신까지 걸어 두면 한 번 설정으로 계속 쓸 수 있다.
이번 글에서는 Nginx 설치부터 리버스 프록시 설정, Let’s Encrypt SSL 적용, 자동 갱신 확인, 그리고 자주 만나는 오류 해결 방법까지 순서대로 정리해 보도록 하겠다.
Nginx 리버스 프록시란 무엇인가
리버스 프록시(Reverse Proxy)는 클라이언트의 요청을 대신 받아서 내부 서버로 전달해 주는 서버를 말한다. 사용자는 Nginx와만 통신하고, 실제 애플리케이션은 외부에 직접 노출되지 않는다.
사용자(브라우저) ──HTTPS(443)──▶ Nginx ──HTTP(8080)──▶ 애플리케이션(Spring Boot, Node.js 등)이렇게 구성하면 다음과 같은 장점이 있다.
- 포트 숨기기 : 8080, 3000 같은 포트를 외부에 열지 않고 80, 443만 열면 된다.
- SSL 처리 일원화 : 인증서는 Nginx에만 적용하면 되고, 애플리케이션은 HTTP로 동작해도 된다.
- 여러 서비스 운영 : 도메인이나 경로별로 서로 다른 애플리케이션에 연결할 수 있다.
- 정적 파일·캐시·압축 : Nginx가 정적 파일 서빙, gzip 압축 등을 대신 처리해 준다.
Nginx 리버스 프록시 구성 전 준비 사항
시작하기 전에 아래 항목이 준비되어 있어야 한다. 특히 도메인 연결과 포트 개방이 안 되어 있으면 인증서 발급 단계에서 실패하니 먼저 확인하자.
- 리눅스 서버 (이 글은 Ubuntu 기준, Rocky Linux 등 RHEL 계열 명령어도 함께 표기)
- 도메인 1개, DNS의 A 레코드가 서버 공인 IP를 가리키도록 설정
- 방화벽에서 80, 443 포트 허용
- 서버 내부에서 실행 중인 애플리케이션 (이 글에서는
127.0.0.1:8080으로 가정)
도메인이 서버 IP로 잘 연결되었는지는 다음 명령어로 확인할 수 있다.
dig +short example.com방화벽 포트는 ufw 기준으로 다음과 같이 열어 준다. 방화벽 설정이 처음이라면 리눅스 방화벽 설정 방법 (ufw / firewalld 사용법) 글을 먼저 참고하자.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw statusNginx 설치
Ubuntu / Debian
sudo apt update
sudo apt install nginxRocky Linux / RHEL 계열
sudo dnf install nginx서비스 시작 및 자동 실행 등록
sudo systemctl enable --now nginx
sudo systemctl status nginx설치가 끝났다면 브라우저에서 http://도메인으로 접속해 보자. “Welcome to nginx!” 페이지가 보이면 정상이다.
Nginx 리버스 프록시 설정
설정 파일 만들기
Ubuntu는 /etc/nginx/sites-available에 설정 파일을 만들고 sites-enabled에 링크를 거는 방식을 쓴다. RHEL 계열은 /etc/nginx/conf.d/도메인.conf 파일을 만들면 된다.
sudo vi /etc/nginx/sites-available/example.com아래 내용을 입력한다. example.com은 본인 도메인으로, 8080은 애플리케이션 포트로 바꿔 주면 된다.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
}
}각 설정의 의미는 다음과 같다. 전체 옵션은 Nginx 공식 문서(ngx_http_proxy_module)에서 확인할 수 있다.
server_name: 이 설정이 적용될 도메인이다. 뒤에서 Certbot이 이 값을 보고 인증서를 적용한다.proxy_pass: 요청을 전달할 내부 애플리케이션 주소다.Host: 원래 요청한 도메인 정보를 애플리케이션에 그대로 넘긴다.X-Real-IP,X-Forwarded-For: 실제 사용자 IP를 전달한다. 설정하지 않으면 애플리케이션 로그에 모든 접속이 127.0.0.1로 찍힌다.X-Forwarded-Proto: 사용자가 http로 왔는지 https로 왔는지 전달한다. 로그인 후 리다이렉트 주소가 http로 바뀌는 문제를 막아 준다.
설정 활성화
Ubuntu라면 심볼릭 링크를 만들어 설정을 활성화하고, 기본 사이트 설정은 비활성화한다.
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default설정 검증 후 적용
설정을 바꾼 뒤에는 반드시 문법 검사를 먼저 하는 습관을 들이자. 오류가 있는 상태로 재시작하면 Nginx가 아예 뜨지 않을 수 있다.
sudo nginx -t
sudo systemctl reload nginxsyntax is ok, test is successful가 나오면 정상이다. 이제 http://example.com으로 접속했을 때 8080 포트의 애플리케이션 화면이 보이면 리버스 프록시 설정이 끝난 것이다.
Nginx 리버스 프록시에서 WebSocket 사용하기
채팅, 실시간 알림처럼 WebSocket을 쓰는 애플리케이션이라면 업그레이드 헤더를 추가로 전달해야 한다. 이 설정이 없으면 WebSocket 연결만 계속 실패한다.
# http 블록 안 (예: /etc/nginx/conf.d/websocket.conf)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# location 블록 안
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;Nginx 리버스 프록시에 Let’s Encrypt 무료 SSL 적용하기
Let’s Encrypt는 무료로 SSL/TLS 인증서를 발급해 주는 인증 기관이다. 발급과 갱신은 Certbot이라는 도구로 처리하는데, Nginx 플러그인을 쓰면 인증서 발급부터 Nginx 리버스 프록시 설정 파일 수정까지 자동으로 해 준다.
Certbot 설치
Certbot 공식 문서에서는 snap 설치를 권장한다.
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotsnap을 쓰지 않는다면 패키지 매니저로 설치해도 된다.
# Ubuntu / Debian
sudo apt install certbot python3-certbot-nginx
# Rocky Linux / RHEL 계열 (EPEL 필요)
sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx인증서 발급
-d 옵션에 인증서를 적용할 도메인을 모두 적어 준다. www를 함께 쓴다면 둘 다 넣어야 한다.
sudo certbot --nginx -d example.com -d www.example.com처음 실행하면 이메일 입력, 약관 동의 등을 묻는다. 진행이 끝나면 Certbot이 인증서를 발급하고 Nginx 설정 파일에 SSL 설정과 HTTP → HTTPS 리다이렉트를 자동으로 추가해 준다.
변경된 설정 확인
Certbot이 수정한 Nginx 리버스 프록시 설정 파일을 열어 보면 다음과 같이 바뀌어 있다. # managed by Certbot 주석이 붙은 부분이 자동으로 추가된 내용이다.
server {
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
# ... proxy_set_header 설정 동일 ...
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example.com www.example.com;
return 404; # managed by Certbot
}이제 https://example.com으로 접속해 주소창에 자물쇠 아이콘이 보이는지 확인하자. http://로 접속해도 자동으로 https로 넘어가면 성공이다.
인증서 자동 갱신 확인
Let’s Encrypt 인증서의 유효 기간은 90일로 짧은 편이고, 앞으로 더 짧아질 예정이다. 또 Let’s Encrypt는 2025년부터 만료 안내 이메일 발송을 중단했기 때문에 자동 갱신이 제대로 동작하는지 확인하는 것이 무엇보다 중요하다. 인증서가 만료되면 Nginx 리버스 프록시 뒤의 모든 서비스가 브라우저 경고와 함께 접속 불가 상태가 된다.
Certbot은 설치 시 systemd 타이머(또는 cron)를 함께 등록한다. 등록 여부는 다음과 같이 확인한다.
systemctl list-timers | grep certbot실제로 갱신이 되는지는 테스트 모드로 점검할 수 있다. 실제 인증서는 바뀌지 않으니 부담 없이 실행해도 된다.
sudo certbot renew --dry-runCongratulations, all simulated renewals succeeded 메시지가 나오면 자동 갱신 준비는 끝났다. 현재 발급된 인증서 목록과 만료일은 아래 명령어로 볼 수 있다.
sudo certbot certificatesNginx 리버스 프록시 적용 시 자주 발생하는 문제
502 Bad Gateway
Nginx 리버스 프록시가 뒤쪽 애플리케이션에 연결하지 못했다는 뜻이다. 대부분 아래 셋 중 하나다.
- 애플리케이션이 실행 중이 아니거나 포트가 다르다 →
ss -tlnp | grep 8080으로 확인 proxy_pass주소 오타- RHEL 계열에서 SELinux가 Nginx의 외부 연결을 막는 경우 →
sudo setsebool -P httpd_can_network_connect 1
원인은 Nginx 에러 로그에서 바로 확인할 수 있다. 로그 위치가 헷갈린다면 리눅스 로그 파일 위치 정리 글을 참고하자.
sudo tail -f /var/log/nginx/error.logCertbot 인증서 발급 실패
Let’s Encrypt는 80 포트로 접속해 도메인 소유를 확인한다. 따라서 다음을 점검해야 한다.
- DNS A 레코드가 현재 서버 IP를 가리키는지 (변경 직후라면 전파까지 시간이 걸릴 수 있다)
- 방화벽과 클라우드 보안 그룹에서 80 포트가 열려 있는지
- Nginx 설정의
server_name과-d에 넣은 도메인이 일치하는지
짧은 시간에 발급을 여러 번 실패하면 일정 시간 요청이 제한(rate limit)되므로, 원인을 먼저 고친 뒤 --dry-run으로 테스트해 보는 것이 좋다.
무한 리다이렉트 (ERR_TOO_MANY_REDIRECTS)
Cloudflare 같은 CDN을 앞에 두고 SSL 모드를 “Flexible”로 설정한 경우 자주 발생한다. CDN은 서버에 HTTP로 요청하고, Nginx는 다시 HTTPS로 돌려보내는 것이 반복되는 것이다. Cloudflare SSL 모드를 “Full (strict)”로 바꾸면 해결된다.
로그인 후 http 주소로 이동하는 문제
애플리케이션이 자신이 HTTPS 뒤에 있다는 사실을 모르기 때문에 생긴다. Nginx에서 X-Forwarded-Proto 헤더를 넘기고, 애플리케이션이 이 헤더를 인식하도록 설정해야 한다. Spring Boot라면 application.yml에 다음을 추가한다.
server:
forward-headers-strategy: framework413 Request Entity Too Large
파일 업로드 시 이 오류가 난다면 Nginx의 기본 업로드 제한(1MB)에 걸린 것이다. server 블록에 허용 크기를 늘려 준다.
client_max_body_size 20M;Nginx 리버스 프록시 설정 정리
정리하면 Nginx 리버스 프록시와 Let’s Encrypt SSL 적용은 다음 순서로 진행하면 된다.
- 도메인 A 레코드 연결, 80·443 포트 개방
- Nginx 설치 후
proxy_pass로 리버스 프록시 설정 nginx -t로 검증 후 reload- Certbot으로 인증서 발급 (
certbot --nginx) certbot renew --dry-run으로 자동 갱신 확인
Nginx 리버스 프록시를 한 번 구성해 두면 새 서비스를 추가할 때도 설정 파일 하나와 Certbot 명령어 한 줄이면 HTTPS 적용이 끝난다. 애플리케이션 포트를 외부에 직접 열어 두고 있었다면 이번 기회에 Nginx 뒤로 옮겨 보자. 보안과 관리 편의성 모두 훨씬 좋아진다.
첫 댓글을 남겨보세요