docker container nginx 설정, https 적용
by yuyeol3, 2025-02-28
현재 사용하고 있는 계정의 aws free-tier가 거의 끝나기도 했고 기존 wigit 서버와 youtube-shortener 서버를 계속 돌리고 있어 요금이 많이 나오기도 했다. 따라서 대안을 찾던 중 youtube-shortener 서버를 Google Cloud Platform을 옮기기로 했다.
1. nginx, certbot 설정하기
# docker-compose.yml services: database: # Dockerfile이 있는 위치 build: ./database image: yuyeol3/youtube-shortener-database # 내부에서 개방할 포트 : 외부에서 접근할 포트 ports: - "4000:3306" volumes: - ./database/mysql_data:/var/lib/mysql env_file: - ./database/.env backend: build: ./youtube_shortener image: yuyeol3/youtube-shortener-backend ports: - "3000:3000" environment: - DBHOST=database ############################ # NGINX - Reverse Proxy ############################ nginx: image: nginx:alpine container_name: nginx-reverse-proxy depends_on: - backend ports: - "80:80" - "443:443" volumes: # Mount your custom NGINX configuration - ./nginx/conf.d:/etc/nginx/conf.d # Mount the certificates generated by certbot - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot # You can also use environment variables or a custom default.conf # so that NGINX points to your backend container(s). # recert를 위한 command # command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" ############################ # CERTBOT - Let's Encrypt ############################ certbot: image: certbot/certbot container_name: certbot depends_on: - nginx volumes: - ./certbot/conf:/etc/letsencrypt - ./certbot/www:/var/www/certbot # We will run Certbot commands manually (or via a script) to obtain certificates # recert를 위한 command # entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" # volumes:
docker-compose.yml에서 nginx와 certbot을 추가한다. ./certbot 에 conf 폴더와 www 폴더를 만든다. ./nginx/conf.d/에 default.conf를 만들고 다음과 같이 설정하자.
# ./nginx/conf.d/default.conf server { listen 80; listen [::]:80; server_name youtube-shortener.duckdns.org; # # 정적 파일이 위치한 폴더 # root /home/ubuntu/youtube_shortener/backend/public; # index index.html; # location /assets/ { # try_files $uri $uri/ @app; # } # 요청 URL이 파일이나 디렉터리로 존재하면 정적 서빙, # 없으면 @app 위치 블록(Express 서버)로 요청을 넘김 location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { try_files $uri $uri/ @app; } # 동적 처리가 필요한 경우 Express 서버로 프록시 location @app { proxy_pass http://backend:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # # SSL 설정 (Certbot에서 관리) # ssl_certificate /etc/letsencrypt/live/youtube-shortener.duckdns.org/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/youtube-shortener.duckdns.org/privkey.pem; # include /etc/letsencrypt/options-ssl-nginx.conf; # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } # server { # listen 80; # listen [::]:80; # server_name youtube-shortener.duckdns.org; # # HTTP 요청은 HTTPS로 리다이렉트 # return 301 https://$host$request_uri; # }
아직 https 인증을 받지 못했으므로 인증서 파일이 없다. 따라서 일단 ssl 설정 등은 주석 처리를 통해 비활성화해야 오류가 나지 않는다.
$ sudo docker compose pull $ sudo docker compose up -d $ sudo docker ps
backend와 nginx가 살아있는지 확인한다.
2. 인증 스크립트를 통해 https 인증받기
$ curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > $ init-letsencrypt.sh $ chmod +x init-letsencrypt.sh $ nano init-letsencrypt.sh # 도메인, 이메일, 디렉토리 수정 $ sudo ./init-letsencrypt.sh # 인증서 발급
# ./init-letsencrypt.sh #!/bin/bash if ! [ -x "$(command -v docker-compose)" ]; then echo 'Error: docker-compose is not installed.' >&2 exit 1 fi domains=(domain1 domain2) rsa_key_size=4096 data_path="./certbot" email="(email)" staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits if [ -d "$data_path" ]; then read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then exit fi fi if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then echo "### Downloading recommended TLS parameters ..." mkdir -p "$data_path/conf" curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf" curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem" echo fi echo "### Creating dummy certificate for $domains ..." path="/etc/letsencrypt/live/$domains" mkdir -p "$data_path/conf/live/$domains" docker compose run --rm --entrypoint "\ openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\ -keyout '$path/privkey.pem' \ -out '$path/fullchain.pem' \ -subj '/CN=localhost'" certbot echo echo "### Starting nginx ..." docker compose up --force-recreate -d nginx echo echo "### Deleting dummy certificate for $domains ..." docker compose run --rm --entrypoint "\ rm -Rf /etc/letsencrypt/live/$domains && \ rm -Rf /etc/letsencrypt/archive/$domains && \ rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot echo echo "### Requesting Let's Encrypt certificate for $domains ..." #Join $domains to -d args domain_args="" for domain in "${domains[@]}"; do domain_args="$domain_args -d $domain" done # Select appropriate email arg case "$email" in "") email_arg="--register-unsafely-without-email" ;; *) email_arg="--email $email" ;; esac # Enable staging mode if needed if [ $staging != "0" ]; then staging_arg="--staging"; fi docker compose run --rm --entrypoint "\ certbot certonly --webroot -w /var/www/certbot \ $staging_arg \ $email_arg \ $domain_args \ --rsa-key-size $rsa_key_size \ --agree-tos \ --force-renewal" certbot echo echo "### Reloading nginx ..." docker compose exec nginx nginx -s reload
필자의 경우 docker-compose 명령어가 작동하지 않아서 docker compose로 전부 바꾸어 주었다.
3. 인증 후 nginx, docker-compose.yml 수정하기
# ./nginx/conf.d/default.conf server { listen 443 ssl; listen [::]:443 ssl; server_name youtube-shortener.duckdns.org; # 정적 파일이 위치한 폴더 root /home/ubuntu/youtube_shortener/backend/public; index index.html; location /assets/ { try_files $uri $uri/ @app; } # 요청 URL이 파일이나 디렉터리로 존재하면 정적 서빙, # 없으면 @app 위치 블록(Express 서버)로 요청을 넘김 location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { try_files $uri $uri/ @app; } # 동적 처리가 필요한 경우 Express 서버로 프록시 location @app { proxy_pass http://backend:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # SSL 설정 (Certbot에서 관리) ssl_certificate /etc/letsencrypt/live/youtube-shortener.duckdns.org/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/youtube-shortener.duckdns.org/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { listen 80; listen [::]:80; server_name youtube-shortener.duckdns.org; # HTTP 요청은 HTTPS로 리다이렉트 return 301 https://$host$request_uri; }
# docker-compose.yml services: database: # Dockerfile이 있는 위치 build: ./database image: yuyeol3/youtube-shortener-database # 내부에서 개방할 포트 : 외부에서 접근할 포트 ports: - "4000:3306" volumes: - ./database/mysql_data:/var/lib/mysql env_file: - ./database/.env backend: build: ./youtube_shortener image: yuyeol3/youtube-shortener-backend ports: - "3000:3000" environment: - DBHOST=database ############################ # NGINX - Reverse Proxy ############################ nginx: image: nginx:alpine container_name: nginx-reverse-proxy depends_on: - backend ports: - "80:80" - "443:443" volumes: # Mount your custom NGINX configuration - ./nginx/conf.d:/etc/nginx/conf.d # Mount the certificates generated by certbot - ./data/certbot/conf:/etc/letsencrypt - ./data/certbot/www:/var/www/certbot # You can also use environment variables or a custom default.conf # so that NGINX points to your backend container(s). # recert를 위한 command command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" ############################ # CERTBOT - Let's Encrypt ############################ certbot: image: certbot/certbot container_name: certbot depends_on: - nginx volumes: - ./certbot/conf:/etc/letsencrypt - ./certbot/www:/var/www/certbot # We will run Certbot commands manually (or via a script) to obtain certificates # recert를 위한 command entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" # volumes:
4. service 등록하기
[Unit] Description=Youtube Shortener After=network.target docker.service [Service] User=(user name) Group=(user group) WorkingDirectory=/home/zerom50/server ExecStart=/usr/bin/docker compose up --detach Restart=always RestartSec=5 Environment="DOCKER_HOST=unix:///var/run/docker.sock" [Install] WantedBy=multi-user.target
user에게 docker 권한이 없을 수 있으므로 다음과 같이 설정한다.
groups zerom50 # 현재 그룹 확인
sudo usermod -aG docker zerom50 # docker 그룹 추가가
$ sudo systemctl daemon-reload $ sudo systemctl enable server $ sudo systemctl start server $ sudo systemctl status server
댓글 불러오는 중...