기타

[Docker] Docker 환경 Nginx에 SSL 인증서 적용하기(Let’s Encrypt)

tmkimm 2022. 1. 17. 14:28

Nginx에 SSL 인증서를 적용한 내용을 공유합니다.

컨테이너 상의 Nginx에 인증서를 적용하다 보니 방법이 잘 이해가 가지 않아 생각해보다 헤매었네요 😲

Let’s Encrypt 유효성 검사를 완료하려면 Nginx가 필요하지만 인증서가 없으면 nginx가 시작되지 않습니다.

그래서 임시로 https를 사용하지 않는 척 nginx를 실행한 다음 인증서를 발급받고

https를 사용한 nginx에 인증서를 적용하면 됩니다.

준비물

  • docker-compose
  • 도메인 주소
💡 SSL이란?
https를 통한 인터넷 접속은 서버와의 암호화를 통신하고 있는 것을 의미합니다.
이때 사용하는 보안 프로토콜이 SSL(Secure Socket Layer)이며 보안이 향상된 통신을 할 수 있게 됩니다.
- http 뒤에 붙는 s가 secure!
- SSL과 TLS는 같은 의미의 단어(TLS가 후속 버전)
- http는 80번 포트, https는 443번 포트 사용

SSL을 위해 필요한 것이 SSL 인증서입니다.

 

 

👀 https를 적용하지 않고 SSL 인증서 발급받기


docker-compose.yml

nginx.conf 파일은 사용자 환경에 맞게 경로를 잡아주시면 됩니다.

./data 폴더는 수동으로 생성하지 않아도 됩니다.

version: '3'
services:
  nginx:
    image: nginx:latest
    restart: unless-stopped
    volumes:
      - ./conf/nginx.conf:/etc/nginx/nginx.conf
      - ./data/certbot/conf:/etc/letsencrypt 
      - ./data/certbot/www:/var/www/certbot
    ports:
      - 80:80
      - 443:443
  certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt 
      - ./data/certbot/www:/var/www/certbot

 

conf/nginx.conf

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

     server_name domain; // 등록한 도메인으로 변경

     location /.well-known/acme-challenge/ {
             allow all;
             root /var/www/certbot;
     } 
}

docker-compose를 실행합니다.

docker-compose -f docker-compose.yml up -d
docker ps // nginx와 certbot 컨테이너가 살아있는지 확인

 

인증서 발급받는 스크립트를 다운로드하고 도메인, 이메일 주소, 디렉터리를 변경합니다.

인증서 발급에 실패한 경우 실패 시 메시지나 docker log를 통해 원인을 찾을 수 있습니다.

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 // 인증서 발급  

 

 

 

👌 HTTPS 적용하기


이제 인증서를 발급받았으니 HTTPS를 적용할 수 있습니다.

nginx.conf 수정

server {
    listen 80;
    server_name example.org; # 도메인으로 변경
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

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

server {
    listen 443 ssl;
    server_name example.org; # 도메인으로 변경
    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # example.org를 도메인으로 변경
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # example.or를 도메인으로 변경
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass  <http://example.org>;
        proxy_set_header    Host                $http_host;
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
    }
}

 

인증서를 자동으로 갱신하도록 설정하지 않으면 만료될 때마다 다시 발급을 해주어야 합니다.

자동으로 인증서가 갱신되도록 docker-compose.yml 파일을 수정합니다.

version: '3'

services:
  nginx:
    image: nginx:1.15-alpine
    restart: unless-stopped
    volumes:
      - ./data/nginx:/etc/nginx/conf.d
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \\"daemon off;\\"'"
  certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

 

 

마무리


이제 HTTPS이 적용되었습니다!

이 글은 Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes를 참고하여 작성되었으며 예제는 아래 깃헙에서 확인하실 수 있습니다. :)