Docker와 Nginx를 이용해 Let's Encrypt로 SSL 인증서 적용하기
Docker Compose, Certbot을 활용한 HTTPS 설정 자동화 방법
들어가기 전에
Docker와 Nginx 환경에서 Let's Encrypt를 활용해 SSL/TLS 인증서를 적용한 경험을 기록하고자 해요. 최근 진행한 프로젝트에서 HTTPS 적용이 필요했고, 이를 Docker 환경에서 구성한 방법이에요.
프로젝트에 HTTPS가 필요했던 이유?
다음 3가지 이유가 컸는데요.
현대 브라우저들은 HTTPS가 적용되지 않은 사이트에 '안전하지 않음' 경고를 표시하고 있어요.
푸시 알림(웹 API) HTTPS에서만 작동(https://developer.mozilla.org/ko/docs/Web/API/Notifications_API/Using_the_Notifications_API)
검색 엔진이 HTTPS 사이트를 우선적으로 색인(SEO)
기존 환경 소개(Docker, Nginx)
Docker를 사용해 각 서비스를 독립적인 컨테이너로 운영
Nginx 서버가 각 서비스로 리버스 프록시 역할
Docker Compose로 컨테이너와 네트워크 구성

왜 Let`s Encrypt?
SSL 인증서 비교
3가지 옵션을 두고 선정을 했고 주요 특징과 목적에 따라 고려해보았어요.
외부 CA(ex. AWS)
갱신 주기 1년, EV 인증서
유료
Cloud Platform 종속, 확장가능한 서비스
Let`s Encrypt
갱신 주기 90일
무료
개인 서버
자체 서명(openssl)
인증서 사용해도 브라우저 경고
무료
개발
https를 쓰는 이유와 부합하고 특별히 AWS와 같은 Platform에 종속되어있지 않아 저의 경우엔 Let`s Encrypt를 사용했는데요. 사용 목적에 따라 선정하시면 좋을 것 같아요.
적용 순서
1. Nginx 기본 구성
nginx.conf 파일 구성
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name [DOMAIN]; // 등록한 도메인
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
}
}
2. Docker Compose 구성
docker-compose.yml 파일 구성
volumes에 들어가는 경로는 저의 서버 폴더 경로로 임의로 지정했습니다(nginx/*)
version: '3'
services:
nginx:
container_name: nginx
image: nginx
restart: always
ports:
- '80:80' # HTTP
- '443:443' # HTTPS
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/letsencrypt:/etc/letsencrypt
- ./nginx/www:/var/www/certbot
environment:
- TZ=Asia/Seoul
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./nginx/letsencrypt:/etc/letsencrypt
- ./nginx/www:/var/www/certbot
depends_on:
- nginx
3. certbot을 활용한 인증서 발급
https://github.com/wmnnd/nginx-certbot/blob/master/init-letsencrypt.sh 를 활용해서 인증서를 발급받았습니다.
curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh
chmod +x init-letsencrypt.sh
vi init-letsencrypt.sh // 도메인, 이메일, 파일 디렉토리 수정
sudo ./init-letsencrypt.sh // 인증서 발급
아래 수정할 init-letsencrtypt.sh의 일부입니다. doamin과 data_path, email을 입력해주시고 script를 사용하였어요
domains=(example.org www.example.org)
rsa_key_size=4096
data_path="./nginx/letsencrypt"
email="jeong9132@gmail.com" # Adding a valid address is strongly recommended
staging=0 # 개발용(1, rate limit를 우회합니다), 운영(0)
최종적으로 {data_path}에 pem 파일들이 생성됩니다.
4. Nginx SSL/TLS 구성
443 port의 server block을 추가하고 ssl pem값을 등록하여 주었어요. 마지막으로 80번으로 들어온 요청에 대해 443으로 리다이렉트(301) 시켜주었습니다.
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 443 ssl;
server_name [DOMAIN] // 등록한 도메인
# https://nginx.org/en/docs/http/configuring_https_servers.html
ssl_certificate /etc/letsencrypt/live/[DOMAIN]/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/[DOMAIN]/privkey.pem;
location / {
proxy_pass http://web;
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;
}
}
server {
listen 80;
server_name [DOMAIN]; // 등록한 도메인
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
}
결과

(추가) certbot 갱신
저는 한국 시간으로 자정으로 매일 실행하고싶어서 아래와 같은 명령어를 등록했어요.
crontab -e
0 15 * * * cd {파일 경로} && docker compose run --rm certbot renew --quiet && docker compose restart nginx
다음 단계.
배운점과 개선점
Docker 환경에서의 SSL 적용
Let's Encrypt의 짧은 갱신 주기(90일)로 인한 자동화 필요성
클라우드 환경(AWS)과 온프레미스 환경에 따른 적절한 SSL 솔루션 선택
트래픽 증가에 따른 SSL 암/복호화 시스템 부하 개선점 고민
참고 자료
Last updated