WEB_WAS/Nginx

Nginx로 HTTPS(SSL) 구축하기 (Reverse Proxy + Let’s Encrypt)

코딩금융치료 2026. 3. 20. 11:17

예전에는 HTTPS를 붙인다고 하면 꽤 부담스러운 작업처럼 느껴졌다.

인증서 발급, CSR 생성, 인증서 파일 적용, 웹서버 설정, 갱신 관리까지 손이 많이 갔고, 작은 서비스 하나 올리는데도 진입장벽이 있었다.

그런데 Nginx + Let’s Encrypt + Certbot 조합으로 구성해보니 생각보다 훨씬 간단했다.

특히 개인 서버나 소규모 서비스에서는 “도메인 연결 + Nginx reverse proxy + certbot 실행” 정도만으로도 HTTPS 서비스를 빠르게 올릴 수 있다.

이번 글에서는 Nginx를 이용해 SSL(HTTPS)을 붙이는 전체 흐름을 실제 적용 순서대로 정리한다.


1. 구성 목표

이번에 목표로 한 형태는 다음과 같다.

  • 도메인: example.com (본인 도메인으로 변경)
  • 웹서버: nginx
  • 내부 서비스: 웹 애플리케이션 (예: 127.0.0.1:3000)
  • 외부 접속: https://example.com
  • 방식: Nginx가 80/443 포트를 받고, 내부 서비스로 reverse proxy

구조는 아래와 같다.

사용자 브라우저
    ↓
<https://example.com>
    ↓
Nginx (80/443)
    ↓
내부 서비스 (예: 127.0.0.1:3000)

이 구조의 장점은 명확하다.

  • 외부에는 80/443만 공개
  • 내부 서비스는 로컬 포트로만 유지 가능
  • SSL 처리는 Nginx에서 일괄 담당
  • 서비스가 늘어나도 도메인만 추가해 확장 가능

2. 먼저 도메인 연결부터

HTTPS를 붙이기 전에 가장 먼저 해야 할 일은 도메인이 서버를 정확히 가리키도록 DNS를 설정하는 것이다.

예를 들어 example.com를 쓰려면 DNS에서 A 레코드를 등록한다.

  • 호스트: @ 또는 서브도메인(예: app)
  • 타입: A
  • 값: 서버 공인 IP

TTL은 처음에는 짧게 두면 변경 반영 여부를 확인하기 편하다.


3. Nginx reverse proxy 먼저 구성 (HTTP)

SSL을 붙이기 전에 먼저 HTTP로 서비스가 정상 연결되는지 확인하는 것이 좋다.

처음부터 HTTPS까지 한 번에 보려고 하면 DNS 문제인지, Nginx 문제인지, 애플리케이션 문제인지 구분이 어렵다.

아래는 가장 단순한 reverse proxy 예시다.

server {
    listen 80;
    listen [::]:80;

    server_name example.com;

    location / {
        proxy_pass <http://127.0.0.1:3000>;
        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;

        # WebSocket 등 업그레이드가 필요한 서비스라면 아래 헤더가 필요할 수 있음
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_buffering off;
        proxy_read_timeout 3600;
        proxy_send_timeout 3600;
    }
}

설정 후에는 아래처럼 테스트한다.

sudo nginx -t
sudo systemctl reload nginx

그리고 브라우저에서 접속해본다.

<http://example.com>

여기서 서비스가 정상적으로 뜨면, 그 다음이 HTTPS 단계다.


. 중간에 만난 문제: 정적 파일 404

처음에는 reverse proxy만 걸면 끝날 줄 알았는데, 실제로는 하위 리소스(정적 파일)들이 404가 나는 문제가 있었다.

예를 들면 아래 같은 요청이 계속 실패했다.

<http://example.com/static/loader.js>

원인을 확인해보니 Nginx 설정에 남아 있던 정적 웹서버 설정(root 등)이 요청을 가로채고 있었다.

예를 들어 server 블록에 아래 설정이 남아 있으면:

root /var/www/html;

Nginx는 /static/loader.js 요청을 upstream으로 넘기지 않고 로컬 파일 경로에서 먼저 찾는다.

  • 기대했던 동작: /static/loader.js → upstream(내부 서비스)로 전달
  • 실제 동작: /static/loader.js → Nginx 로컬 경로에서 파일 검색 → 404

그래서 reverse proxy 전용 server 블록에서는 root, index, try_files 같은 정적 웹서버 설정을 빼고,

요청을 전부 proxy_pass로 넘기는 구조가 더 깔끔했다.


5. Certbot으로 HTTPS 적용

HTTP가 정상이라면 이제 SSL 인증서를 붙이면 된다.

지금은 Certbot이 발급과 Nginx 설정 변경까지 대부분을 자동화해준다.

(1) 설치 (Ubuntu 예시)

배포판/환경에 따라 설치 방식이 다를 수 있으니, 공식 문서를 함께 확인하는 것을 권장한다.

sudo apt update
sudo apt install -y snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

(2) 인증서 발급 및 Nginx 설정 자동 반영

sudo certbot --nginx -d example.com

실행 중 이메일, 약관 동의, HTTP→HTTPS 리다이렉트 여부 등을 묻는다.

리다이렉트를 선택하면 Certbot이 Nginx 설정까지 자동으로 수정해준다.


6. 최종 구성 형태 (HTTPS + 리다이렉트)

최종적으로는 아래와 같은 형태가 된다.

인증서 경로는 Certbot이 발급한 도메인 기준으로 자동 생성되며, 환경에 따라 다를 수 있다.

server {
    listen 80;
    listen [::]:80;

    server_name example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass <http://127.0.0.1:3000>;
        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;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_buffering off;
        proxy_read_timeout 3600;
        proxy_send_timeout 3600;
    }
}

이제 사용자는 https://example.com로 접속하고,

Nginx가 SSL을 종료한 뒤 내부 서비스로 안전하게 전달한다.


7. 자동 갱신 확인

SSL 구축이 쉬워진 가장 큰 이유는 갱신 관리까지 자동화가 가능하다는 점이다.

아래처럼 dry-run으로 갱신 테스트를 해볼 수 있다.

sudo certbot renew --dry-run

이게 성공하면 운영 중 인증서 만료로 인한 사고 가능성이 크게 줄어든다.


8. 여러 서비스로 확장하기

이 구조는 한 서비스에서 끝나지 않고, 서비스가 늘어나도 쉽게 확장할 수 있다.

  • app.example.com → 웹 서비스
  • api.example.com → API 서버
  • admin.example.com → 관리자 페이지

즉 Nginx를 진입점으로 두고, 뒤쪽 서비스들을 reverse proxy로 나누면 된다.

소규모 환경에서는 호스트에 Nginx를 설치해 SSL과 라우팅을 담당하게 하는 방식이 특히 실용적이다.


마무리

정리하면 흐름은 단순하다.

  1. 도메인을 서버 IP에 연결
  2. Nginx reverse proxy로 내부 서비스 연결
  3. HTTP로 정상 동작 확인
  4. Certbot으로 SSL 적용
  5. HTTPS 리다이렉트 및 자동 갱신 확인

예전에는 SSL이 어렵게 느껴졌지만,

지금은 오히려 기본 인프라 작업 중 가장 빠르게 끝나는 편에 가까워졌다.