Nginx 사용하기 (Reverse Proxy, SSL/TLS 인증)

김재혁·2025년 2월 12일

공통 프로젝트

목록 보기
9/12

AWS EC2에서 Nginx 컨테이너를 통한 SSL 설정 (Let's Encrypt + Certbot)

1. 개요

EC2 인스턴스에서 Nginx 컨테이너를 사용하여 SSL(HTTPS)을 적용하는 방법을 설명합니다. Let’s Encrypt 및 Certbot을 활용한 인증서 발급 및 자동 갱신 설정을 컨테이너 환경에 맞춰 구성합니다.


2. 사전 준비 사항

✅ EC2 보안 그룹 설정

SSL 인증서 발급 및 HTTPS 활성화를 위해 EC2의 보안 그룹(Security Group) 에서 다음 포트를 허용해야 합니다.

포트프로토콜설명
22TCPSSH 접속 (필요 시만 오픈)
80TCPHTTP (Certbot이 인증서 발급 시 필요)
443TCPHTTPS (SSL 활성화 후 사용)

3. Certbot을 활용한 SSL 인증서 발급

(1) Certbot 컨테이너 실행 및 인증서 발급

Certbot 컨테이너를 사용하여 Let’s Encrypt SSL 인증서를 발급받습니다.

docker run --rm -it \
	-p 80:80 \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -v /var/lib/letsencrypt:/var/lib/letsencrypt \
    -v /var/www/html:/var/www/html \
    certbot/certbot certonly --standalone \
    -d i12b206.p.ssafy.io --non-interactive --agree-tos \
    -m your-email@example.com
  • --standalone: Nginx 없이 단독으로 웹서버를 실행하여 인증서를 발급
  • -d i12b206.p.ssafy.io: 인증서를 발급받을 도메인 (사용자 도메인으로 변경 필요)
  • -m your-email@example.com: 이메일 주소 입력 (갱신 알림 용도)
  • --agree-tos: Let’s Encrypt 서비스 약관 자동 동의
  • --non-interactive: 자동 모드 실행

4. SSL 인증서 자동 갱신 설정

Let’s Encrypt 인증서는 90일마다 갱신이 필요하므로, 자동 갱신을 설정해야 합니다.

(1) Certbot 갱신 명령어 실행

docker run --rm -it \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -v /var/lib/letsencrypt:/var/lib/letsencrypt \
    certbot/certbot renew --quiet

(2) Crontab을 이용한 자동 갱신 등록

아래 명령어를 실행하여 cron 작업을 추가합니다.

sudo crontab -e

파일 맨 아래에 다음 줄을 추가합니다.

0 3 * * * docker run --rm -v /etc/letsencrypt:/etc/letsencrypt -v /var/lib/letsencrypt:/var/lib/letsencrypt certbot/certbot renew --quiet && docker restart proxy
  • 매일 새벽 3시에 인증서를 갱신 (0 3 * * *)
  • --quiet: 실행 로그를 출력하지 않음
  • docker restart proxy: 인증서 갱신 후 Nginx 컨테이너를 재시작하여 적용

Crontab을 저장한 후, 정상적으로 등록되었는지 확인합니다.

sudo crontab -l

5. 방화벽 설정 (선택 사항)

UFW를 사용하는 경우, SSL 트래픽을 허용해야 합니다.

sudo ufw allow 'Nginx Full'
sudo ufw reload

적용된 방화벽 규칙을 확인합니다.

sudo ufw status

Nginx 설정 파일 (nginx.conf) 작성

0. 전체 코드

(1)

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    # ✅ 백엔드 서버 정보 로깅
    log_format backend_info '$remote_addr - [$time_local] '
                            '"$request" $status '
                            'upstream: $upstream_addr ($upstream_status) '
                            'response_time: $upstream_response_time';

    access_log /var/log/nginx/access.log backend_info;

    # ✅ HTTP 요청을 HTTPS로 강제 리디렉션
    server {
        listen 80;
        server_name i12b206.p.ssafy.io;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name i12b206.p.ssafy.io;

        # ✅ SSL 인증서 설정
        ssl_certificate /etc/letsencrypt/live/i12b206.p.ssafy.io/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/i12b206.p.ssafy.io/privkey.pem;

        # ✅ HSTS 설정 (HTTPS 강제)
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        # ✅ 프론트엔드 정적 파일 요청 처리
        location / {
            proxy_pass http://frontend:80;
            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;
        }

        # ✅ Actuator API 프록시 (health, info, prometheus)
        location ~* ^/actuator/(health|info|prometheus)$ {
            proxy_pass http://backend: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;
        }

        # ✅ API 요청 프록시
        location /api/ {
            proxy_pass http://backend:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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;
        }

        # ✅ 웹소켓 프록시 설정 추가
        location /stomp/chat {
            proxy_pass http://backend:8080;  # Spring Boot STOMP 서버로 전달
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            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;
        }
    }
}

1. 개요

nginx.conf 파일은 백엔드 API 및 웹소켓 프록시 역할을 담당하는 Nginx 설정을 제공합니다. 또한, SSL 인증 및 HTTP 요청을 HTTPS로 강제 리디렉션하는 기능을 포함합니다.


2. 기본 설정

(1) 워커 프로세스 자동 설정

worker_processes auto;
  • 자동 설정: auto를 사용하면 Nginx가 시스템의 CPU 코어 수를 기반으로 워커 프로세스를 자동으로 결정하여 성능을 최적화합니다.

(2) 이벤트 설정

events {
    worker_connections 1024;
}
  • worker_connections: 각 워커 프로세스당 최대 1024개의 연결을 허용합니다.
  • 병렬 처리 최적화: 많은 동시 요청을 처리할 수 있도록 설정합니다.

3. HTTP 설정 및 서버 블록

(1) 백엔드 서버 정보 로깅

    log_format backend_info '$remote_addr - [$time_local] '
                            '"$request" $status '
                            'upstream: $upstream_addr ($upstream_status) '
                            'response_time: $upstream_response_time';

    access_log /var/log/nginx/access.log backend_info;
  • 로그 형식 지정: 클라이언트 IP, 요청 시간, 상태 코드, 백엔드 서버 응답 시간 등을 기록하여 트러블슈팅을 용이하게 합니다.
  • 로그 파일 위치: /var/log/nginx/access.log에 저장됩니다.

(2) HTTP 요청을 HTTPS로 강제 리디렉션

    server {
        listen 80;
        server_name i12b206.p.ssafy.io;
        return 301 https://$host$request_uri;
    }
  • 포트 80에서 HTTPS로 리디렉션: HTTP 요청을 자동으로 HTTPS로 변경합니다.

(3) SSL 및 HTTPS 설정

    server {
        listen 443 ssl http2;
        server_name i12b206.p.ssafy.io;

        ssl_certificate /etc/letsencrypt/live/i12b206.p.ssafy.io/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/i12b206.p.ssafy.io/privkey.pem;

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  • SSL 인증서 적용: Let's Encrypt 인증서를 사용하여 HTTPS를 활성화합니다.
  • HSTS 적용: 모든 서브 도메인에서도 HTTPS를 강제하도록 설정합니다.

4. 프록시 설정

(1) 프론트엔드 정적 파일 요청 처리

        location / {
            proxy_pass http://frontend:80;
            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;
        }
  • 프론트엔드(React) 정적 파일 서빙: frontend 컨테이너의 Nginx로 요청을 전달합니다.

(2) Actuator API 프록시 (Health Check, Monitoring)

        location ~* ^/actuator/(health|info|prometheus)$ {
            proxy_pass http://backend: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;
        }
  • 백엔드 Actuator API 프록시: /actuator/health, /actuator/info, /actuator/prometheus 요청을 백엔드로 전달하여 모니터링 시스템과 연동할 수 있도록 설정합니다.

(3) API 요청 프록시 설정

        location /api/ {
            proxy_pass http://backend:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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;
        }
  • 백엔드 API 프록시: /api/ 경로로 들어오는 요청을 백엔드 서버(backend:8080)로 전달합니다.
  • 웹소켓 지원: UpgradeConnection 헤더를 추가하여 웹소켓 연결을 유지할 수 있도록 설정합니다.

(4) 웹소켓 프록시 설정

        location /stomp/chat {
            proxy_pass http://backend:8080;  # Spring Boot STOMP 서버로 전달
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            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;
        }
    }
}
  • 웹소켓 프록시 설정: /stomp/chat 경로로 들어오는 요청을 STOMP 서버로 전달하여 실시간 채팅 기능을 지원합니다.
  • 웹소켓 유지: UpgradeConnection 헤더 설정을 추가하여 웹소켓 연결이 정상적으로 유지될 수 있도록 합니다.

Docker Compose 설정 (proxy 서비스)

0. 전체 코드

  proxy:
    image: nginx:1.26-alpine
    container_name: proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /etc/letsencrypt:/etc/letsencrypt:ro
    depends_on:
      - backend
    networks:
      - moonggeul-network

1. 개요

docker-compose.yml 파일의 proxy 서비스는 Nginx를 이용한 프록시 서버 역할을 수행합니다. 이를 통해 HTTPS 지원, API 프록시, 정적 파일 서빙 등의 기능을 제공합니다.


2. 서비스 정의

(1) Nginx 컨테이너 설정

  proxy:
    image: nginx:1.26-alpine
    container_name: proxy
  • 이미지 지정: nginx:1.26-alpine을 사용하여 가벼운 Alpine 기반의 Nginx를 실행합니다.
  • 컨테이너 이름: proxy라는 이름을 지정하여 컨테이너를 관리하기 쉽게 만듭니다.

(2) 포트 매핑

    ports:
      - "80:80"
      - "443:443"
  • 포트 80(HTTP)와 443(HTTPS) 노출: 외부에서 Nginx로 접근할 수 있도록 설정합니다.
  • SSL 지원: HTTPS 요청을 처리할 수 있도록 443 포트를 열어둡니다.

(3) 볼륨 설정

    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /etc/letsencrypt:/etc/letsencrypt:ro
  • Nginx 설정 파일 매핑: ./nginx.conf 파일을 컨테이너 내부의 /etc/nginx/nginx.conf 경로에 연결하여, 로컬 설정을 적용할 수 있도록 합니다.
  • SSL 인증서 볼륨 마운트: /etc/letsencrypt를 읽기 전용(ro)으로 마운트하여 Let’s Encrypt 인증서를 사용할 수 있도록 합니다.

(4) 의존성 설정

    depends_on:
      - backend
  • 백엔드 서비스 종속성 설정: backend 서비스가 먼저 실행된 후 proxy 서비스가 실행되도록 보장합니다.

(5) 네트워크 설정

    networks:
      - moonggeul-network
  • 컨테이너 간 통신을 위한 네트워크 설정: moonggeul-network에 연결하여 프론트엔드 및 백엔드 서비스와 원활한 통신을 가능하게 합니다.
profile
志鐵心鏡

0개의 댓글