본문 바로가기
DevOps

Next.js + Docker + Nginx SSL 인증서 발급하기 (Let's encrypt , certbot, nip.io)

by 태균맨 2025. 4. 24.

SEO 테스트를 위해 SSL인증서를 발급받았습니다.

 

사용한 기술 스택

Linux (ubuntu 22.04)
Next.js 14
Docker (Docker-compose)
Nginx
Let's encrypt (무료로 SSL 인증서를 발급해 주는 서비스)
certbot (Let’s Encrypt에서 인증서를 발급받고 자동 갱신할 수 있게 도와주는 CLI 도구)
nip.io (무료 와일드카드 도메인 서비스 https://123.456.789.123.nip.io)

 

1. SSL 인증서 발급

 

https://github.com/wmnnd/nginx-certbot/blob/master/init-letsencrypt.sh

 

nginx-certbot/init-letsencrypt.sh at master · wmnnd/nginx-certbot

Boilerplate configuration for nginx and certbot with docker-compose - wmnnd/nginx-certbot

github.com

위 git링크에서 쉘스크립트를 받아오고 몇 가지 수정해 줍니다.

 

domains=(12.345.678.90.nip.io www.12.345.678.90.nip.io) # 도메인 주소 (nip.io 이용하는 예시를 써놨음) 
rsa_key_size=4096
data_path="./certbot" # Certbot 관련 파일이 저장될 경로. 저는 ./certbot으로 수정했음
email="" # 메일 주소 입력인데 이메일은 오진 않는 것 같다..
staging=0 # 0은 실제 발급모드, 1은 테스트 모드(실제 인증서 아님)
# 여러번 시도하면 블록된다하니 테스트할 땐 1로

 

스크립트는 다음과 같은 기능을 합니다.

 

- Docker Compose 설치 여부 확인

- 기존 인증서 데이터 유무 확인 및 덮어쓰기 확인

- Certbot용 TLS 보안 설정 파일 다운로드

- 더미 SSL 인증서 생성

- Nginx 시작

- 더미 인증서 삭제

- Let's Encrypt 실제 인증서 요청 (Certbot 사용)

- Nginx 재시작

 

 

그리고 nginx.conf 도 수정해야 합니다.

server {
    listen 80;
    server_name 아이피~.nip.io www.아이피~.nip.io;
    
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
        allow all;
    }
    
    location / {
        proxy_pass http://nextjs:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# HTTPS는 인증서가 발급된 후에 주석 해제
#server {
#    listen 443 ssl;
#    server_name 아이피~.nip.io www.아이피~.nip.io;
#    
#    # 인증서 경로 수정 - archive 디렉토리 사용
#    ssl_certificate /etc/letsencrypt/archive/아이피~.nip.io/fullchain1.pem;
#    ssl_certificate_key /etc/letsencrypt/archive/아이피~.nip.io/privkey1.pem;
#    
#    location / {
#        proxy_pass http://nextjs:3000;
#        proxy_set_header Host $host;
#        proxy_set_header X-Real-IP $remote_addr;
#    }
#}

저는 주석을 안 하면 certbot에서 접근 에러가 나서 미리 주석을 해줬습니다.

 

또한 경로는 archive에 있는 pem을 직접 연동했습니다.

 

bash ./docker-compose.sh

 

서버에 두고 정상적으로 발급되었으면 아래와 같이 생깁니다.

 

./certbot

 

./certbot/conf/archive/도메인/

 

저는 certbot/conf/archive/도메인에 있는 pem을 직접 연동했기 때문에 잘 있나 확인해 줬습니다.

 

2. docker-compose로 서버 열기

이제 nginx.conf 주석을 해제해준 후 docker-compose.yml을 작성해 줍시다.

 

version: "3"

services:
  nextjs:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: nextjs
    restart: always
    env_file:
      - .env
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./certbot/conf:/etc/letsencrypt:ro
      - ./certbot/www:/var/www/certbot
    depends_on:
      - nextjs
    networks:
      - app-network
    command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"'''

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    networks:
      - app-network
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

networks:
  app-network:
    driver: bridge

 

요약해 보면

 

Next.js는 Dockerfile에 따라 빌드 후 시작

-----

nginix.conf 에서 설정 파일 마운트

command에서 6시간마다 nginx 자동 리로드

-----

certbot이 12시간마다 인증서 갱신을 시도해서 볼륨에 공유

 

 

성공~