SSL 인증서 발급 및 자동 갱신 - [HTTPS, Let's Encrypt, Certbot]

aqualung·2024년 7월 26일

무료로 SSL인증 해주는 Let's Encrypt와 이를 자동으로 갱신해주는 Certbot을 프로젝트에 적용하고 싶었다.

인증서 발급과 Certbot 간편하게 할 수 있는 스크립트가 있어 이를 참고하였다.


AWS EC2 ubuntu에서, Nginx를 리버스프록시로 사용하는 환경에서 적용하였다.


1. docker-compose 파일 수정

파일에 아래와 같은 내용을 추가/수정해주면 된다.

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;'"

기존 프로젝트에 certbot 컨테이너가 추가되고, nginxcertbot 컨테이너 모두 호스트 파일 시스템에서 인증서를 발급받을 경로로 바인드해주면 된다.

nginxcommand는 매 6시간마다 nginx를 재설정해준다.
relaodrestart와 다르게 서버를 내렸다 다시 올리지 않는다고 한다. 서버는 계속 살아있고 설정만 새로 적용한다. (새로운 설정에 오류가 있을 경우 기존에 있던 설정이 사용된다고 한다.)

cerbot은 매 12시간마다 갱신을 시도한다. 너무 자주 갱신을 시도하는 것이 아닌가 걱정했지만 만료기간이 30일 이하로 남지 않으면 갱신하지 않는다고 한다.

wait $${!}가 아니라 wait $$를 써야할 거 같아서 리눅스쉘에서 여러가지 테스트를 해봤지만 역시 wait $${!}는 올바르게 작동하지 않는다. 하지만 왜인지 docker-compose명령어로 작성하면 문제없이 작동한다...


2. 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; # 80포트에서 443포트로 수정
    server_name example.org;
    server_tokens off;

	# SSL인증서에 대한 설정
    # 잊지말고 자신의 도메인으로 수정해주자
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
    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;
    }
}
  1. 기존 nginx.conf에서 80포트로 사용하던 것들을 443포트로 바꾸어주고, SSL에 대한 설정을 추가해준다.

  2. 80포트에 대한 서버 설정에서 ACME 프로토콜을 사용하기 위한 설정을 추가하고, 80포트에 대한 요청을 https 443 포트로 리디렉션해준다.

ACME는 인증서 발급을 위한 프로토콜인데 아래와 같은 발급과정을 거친다고 한다.

  1. 인증서발급을 요청
  2. ACME서버는 도메인소유자가 맞는지 확인하기 위해 토큰을 발급해주고, /.well-known/acme-challenge에 받은 토큰을 업로드하라고 지시한다.
  3. 도메인소유자가 토큰을 업로드
  4. ACME서버가 경로에 있는 토큰을 확인하면 인증서를 발급

위 과정에서 도메인소유자가 인증서를 발급하고 토큰을 업로드하는 과정은 Certbot의 도움을 받아서 진행된다.


3. 도커 컨테이너 실행

docker compose up등의 명령어로 프로젝트를 실행하자.

아마 nginx컨테이너가 제대로 실행되지 않을 것이다. 하지만 걱정하지 않아도 된다.

nginx.conf에는 인증서에 대한 설정을 했지만 우리는 아직 인증서가 없다. 그래서 우선 더미 인증서를 생성하는 내용이 스크립트에 포함되어 있다.


4. 인증서 발급

링크init-letsencrypt.sh을 받아 수정해준다.

domains=(example.org www.example.org)
rsa_key_size=4096
data_path="./data/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
  • domains : 자신의 도메인 작성
  • data_path : nginxcertbot에서 바인드마운트 해주었던 인증서경로
  • email : 본인 이메일

!! docker-compose 명령어가 아니라 docker compose를 쓴다면 해당 부분도 모두 수정해주자.

sudo ./init-letsencrypt.sh

스크립트를 실행하면 인증서 발급을 완료된다.


5. 도커 재실행

이제 도커를 다시 실행해 모두 정상적으로 작동하는지 확인하자.

0개의 댓글