EC2 인스턴스에서 Nginx 컨테이너를 사용하여 SSL(HTTPS)을 적용하는 방법을 설명합니다. Let’s Encrypt 및 Certbot을 활용한 인증서 발급 및 자동 갱신 설정을 컨테이너 환경에 맞춰 구성합니다.
SSL 인증서 발급 및 HTTPS 활성화를 위해 EC2의 보안 그룹(Security Group) 에서 다음 포트를 허용해야 합니다.
| 포트 | 프로토콜 | 설명 |
|---|---|---|
| 22 | TCP | SSH 접속 (필요 시만 오픈) |
| 80 | TCP | HTTP (Certbot이 인증서 발급 시 필요) |
| 443 | TCP | HTTPS (SSL 활성화 후 사용) |
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: 자동 모드 실행Let’s Encrypt 인증서는 90일마다 갱신이 필요하므로, 자동 갱신을 설정해야 합니다.
docker run --rm -it \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot/certbot renew --quiet
아래 명령어를 실행하여 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
0 3 * * *)--quiet: 실행 로그를 출력하지 않음docker restart proxy: 인증서 갱신 후 Nginx 컨테이너를 재시작하여 적용Crontab을 저장한 후, 정상적으로 등록되었는지 확인합니다.
sudo crontab -l
UFW를 사용하는 경우, SSL 트래픽을 허용해야 합니다.
sudo ufw allow 'Nginx Full'
sudo ufw reload
적용된 방화벽 규칙을 확인합니다.
sudo ufw status
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;
}
}
}
이 nginx.conf 파일은 백엔드 API 및 웹소켓 프록시 역할을 담당하는 Nginx 설정을 제공합니다. 또한, SSL 인증 및 HTTP 요청을 HTTPS로 강제 리디렉션하는 기능을 포함합니다.
worker_processes auto;
auto를 사용하면 Nginx가 시스템의 CPU 코어 수를 기반으로 워커 프로세스를 자동으로 결정하여 성능을 최적화합니다.events {
worker_connections 1024;
}
worker_connections: 각 워커 프로세스당 최대 1024개의 연결을 허용합니다. 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;
/var/log/nginx/access.log에 저장됩니다. 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_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;
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;
}
frontend 컨테이너의 Nginx로 요청을 전달합니다. 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/health, /actuator/info, /actuator/prometheus 요청을 백엔드로 전달하여 모니터링 시스템과 연동할 수 있도록 설정합니다. 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/ 경로로 들어오는 요청을 백엔드 서버(backend:8080)로 전달합니다.Upgrade 및 Connection 헤더를 추가하여 웹소켓 연결을 유지할 수 있도록 설정합니다. 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 서버로 전달하여 실시간 채팅 기능을 지원합니다.Upgrade 및 Connection 헤더 설정을 추가하여 웹소켓 연결이 정상적으로 유지될 수 있도록 합니다. 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
이 docker-compose.yml 파일의 proxy 서비스는 Nginx를 이용한 프록시 서버 역할을 수행합니다. 이를 통해 HTTPS 지원, API 프록시, 정적 파일 서빙 등의 기능을 제공합니다.
proxy:
image: nginx:1.26-alpine
container_name: proxy
nginx:1.26-alpine을 사용하여 가벼운 Alpine 기반의 Nginx를 실행합니다.proxy라는 이름을 지정하여 컨테이너를 관리하기 쉽게 만듭니다. ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- /etc/letsencrypt:/etc/letsencrypt:ro
./nginx.conf 파일을 컨테이너 내부의 /etc/nginx/nginx.conf 경로에 연결하여, 로컬 설정을 적용할 수 있도록 합니다./etc/letsencrypt를 읽기 전용(ro)으로 마운트하여 Let’s Encrypt 인증서를 사용할 수 있도록 합니다. depends_on:
- backend
backend 서비스가 먼저 실행된 후 proxy 서비스가 실행되도록 보장합니다. networks:
- moonggeul-network
moonggeul-network에 연결하여 프론트엔드 및 백엔드 서비스와 원활한 통신을 가능하게 합니다.