NGINX SSL 설정
기본 환경
-
Oracle Cloud Free-tier
-
Ubuntu 22.04
-
Podman 3.4.4
Docker 대신 Cockpit 서버매니저에서 관리도구를 제공하는 Podman을 사용합니다.
-
웹서버 도메인
웹서버는 공식 NGINX 이미지를 도커 컨테이너로 사용하여 서비스한다고 가정합니다.
http 프로토콜을 사용하여 접속하는 웹서버의 도메인 이름. 본인이 사용하는 명칭을 적용합니다.
my-domain.co.krWarningiptime.org 또는 duckdns.org 같은 DDNS 서비스를 사용하는 경우 전체 도메인 이름을 사용하여야 합니다.
예)
my-server.iptime.org,my-server.duckdns.org -
Web 컨텐츠 디렉토리
/opt/web/_site: 웹서버의 index.html 파일이 저장되어 있는 루트 폴더
Oracle Cloud에서 80 포트 열기
-
Cloud의 VM 인스턴스 VNet 설정에서 80 포트를 열어 줍니다. 이때 반드시 Source는 ‘All’로 두어야 합니다.
[여기]를 참조하여 포트 설정을 진행합니다.
-
80 포트로 웹접속이 되는지를 확인합니다. 만약 연결이 안될 경우 서버에 ssh로 접속하여 아래의 3 ~ 5 절차를 수행합니다.
-
iptables를 사용하여 80, 443 포트를 열어 줍니다.$ sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT $ sudo iptables -I INPUT 7 -m state --state NEW -p tcp --dport 443 -j ACCEPT -
설정값을 저장합니다.
$ sudo netfilter-persistent save아래와 같은 메시지를 표시하며 저장됩니다.
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save -
iptables서비스를 재시작 합니다.$ sudo systemctl restart iptables $ sudo service iptables restart
Let's Encrypt 인증서 발급
정상적으로 웹서버가 80 포트에서 동작하여야 진행 할 수 있습니다.
certbot 설치
-
Ubuntu 패키지로 설치
$ sudo apt update $ sudo apt install certbot -
Snap 패키지 관리자로 설치
Ubuntu 패키지로 설치할 경우 의존 패키지가 많이 설치되므로 그런것을 피할려면 Snap 패키지 관리자를 사용하면 됩니다.
$ sudo snap install core $ sudo snap refresh core $ sudo snap install --classic certbotNote만약 snap이 설치되지 않은 경우 아래의 명령으로 설치하면 됩니다.
$ sudo apt update $ sudo apt install snapd살치된
snapd서비스를 활성화 해주어야 합니다.$ sudo systemctl enable --now snapd.socket
certbot으로 인증서 발급받기
다음의 명령을 실행합니다.
$ sudo certbot certonly --webroot -w /opt/web/_site
명령이 표시되는 부분에 발급자의 이메일 주소를 입력하고, 뉴스레터 수신여부(Y/N) 입력하면 인증서가 발급이 됩니다.
발급되는 파일은 다음과 같습니다.
/etc/letsencrypt/live/good-ghost.duckdns.org/fullchain.pem/etc/letsencrypt/live/good-ghost.duckdns.org/privkey.pem
만약 오류가 발생하는 경우, 대부분의 경우에는 80 포트로 접속이 안되는 경우입니다.
curl localhost:80 명령으로 웹서버가 정상 동작하는지를 확인하고, 정상 동작하는 경우 curl http://my-domain.co.kr:80 명령으로 인터넷으로 웹서버가 정상동작하는지를 확인해봅니다.
NGINX 웹서버에 SSL 적용하기
-
NGINX 도커를 기본값으로 사용중이라면 먼저 컨테이너의 config 파일을 복사를 해야합니다. config를 저장하는 폴더는
/opt/docker/nginx라고 가정하겠습니다.$ sudo docker cp nginx:/etc/nginx/conf.d/default.conf /opt/docker/nginx/nginx.conf에디터로
/opt/docker/nginx/nginx.conf파일을 열고 아래의 내용을 추가합니다. 기본적으로 이 파일에는 80 포트에 대한 설정값만을 포함하고 있습니다.# ... 80번 포트 설정 server{ listen 443 ssl http2; server_name my-domain.co.kr; # SSL Certificate ssl_certificate /etc/nginx/cert/fullchain.pem; ssl_certificate_key /etc/nginx/cert/privkey.pem; location / { try_files $uri $uri/ =404; 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; proxy_set_header X-Forwarded-Proto $scheme; } }Danger443포트를 사용하는server설정에서location / {}에proxy_pass localhost:80;을 절대 사용하지 않습니다.대신
try_files $uri $uri/ =404;를 사용하도록 합니다.80포트 리다이렉트를 지정하였는데,443포트의 설정이proxy_pass localhost:80;를 사용할 경우 리다이렉트 무한루프를 돌게 됩니다. -
다음의 명령으로 NGINX 도커 컨테이너를 제거합니다.
NGINX 컨테이너 이름이
myweb라고 가정합니다.$ sudo docker rm myweb -
아래의 명령으로 NGINX 컨테이너를 시작합니다.
$ sudo docker run -itd \ --name myweb \ -p 80:80 -p 443:443 \ -v /opt/docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro \ -v /opt/web/_site:/usr/share/nginx/html:ro \ -v /etc/letsencrypt/live/my-domain.co.kr/fullchain.pem:/etc/nginx/cert/fullchain.pem \ -v /etc/letsencrypt/live/my-domain.co.kr/privkey.pem:/etc/nginx/cert/privkey.pem \ nginx -
https://my-domain.co.kr주소로 접속이 정상적으로 이루어지는지 확인을 합니다. -
만일 80 포트로 접속하는것을 허용하지 않으려면, 80 포트로 접속하는 모든 요청을 443 보안 포트로 리다이렉트하면 됩니다.
/opt/docker/nginx/nginx.conf파일의 80 포트 설정 부분을 아래와 같이 수정을 합니다.server { listen 80; server_name my-domain.co.kr; return 301 https://my-domain.co.kr$request_uri; }NGINX 도커 컨테이너를 재시작하고
http://my-domain.co.kr주소로 접속하여 https:// 주소로 리다이렉트 되는지를 확인합니다.
인증서 갱신하기
기본적으로 Let's Encrypt의 인증서는 90일간 유효합니다. 아래의 절차로 인증서를 갱신할 수 있습니다.
-
인증서 확인
$ sudo certbot certificatesResultSaving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Found the following certs: Certificate Name: my-domain.co.kr Serial Number: ******************************** Key Type: RSA Domains: my-domain.co.kr Expiry Date: yyyy-MM-dd hh:mm:ss+00:00 (VALID: nn days) Certificate Path: /etc/letsencrypt/live/my-domain.co.kr/fullchain.pem Private Key Path: /etc/letsencrypt/live/my-domain.co.kr/privkey.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
인증서 갱신
인증서를 갱신할 경우엔 80 포트를 443 포트로 리다이렉트 하고 있으면 오류가 발생을 합니다. nginx.conf에서 80 포트 설정을 원상 복구하고 아래 명령을 실행을 하여야 합니다.
$ sudo certbot renew --dry-runResultSaving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/my-domain.co.kr.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Simulating renewal of an existing certificate for my-domain.co.kr - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/my-domain.co.kr/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
인증서 삭제
$ sudo certbot delete --cert-name my-domain.co.kr -
인증서 자동 갱신
Ubuntu에 설치된 인증서는
systemd데몬에 의해 기본적으로 하루에 두번 갱신하도록 설정이 되어있습니다.아래의 명령으로 관련 파일을 찾아봅니다.
$ sudo dpkg -L certbot | grep systemd아래와 같이 표시됩니다.
Result/lib/systemd /lib/systemd/system /lib/systemd/system/certbot.service /lib/systemd/system/certbot.timer내용을 한번 보면…
-
certbot.service
[Unit] Description=Certbot Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html Documentation=https://certbot.eff.org/docs [Service] Type=oneshot ExecStart=/usr/bin/certbot -q renew PrivateTmp=true -
certbot.timer
[Unit] Description=Run certbot twice daily [Timer] OnCalendar=*-*-* 00,12:00:00 RandomizedDelaySec=43200 Persistent=true [Install] WantedBy=timers.target
위의 설정대로라면 매일 자정 및 정오에
/usr/bin/certbot -q renew을 실행하여 인증서를 갱신하도록 하고 있습니다.인증서가 90일동안 유효하니, 갱신주기를 한달에 한번으로 바꾸어 보겠습니다.
certbot.timer파일의OnCalendar부분을 다음과 같이 수정하고 저장을 합니다.OnCalendar=*-*-01 01:00:00위와 같이 변경을 하면 매달 1일 새벽 1시에 갱신을 실행할 것입니다.
-
80 포트를 443 포트로 리다이렉트 하고 있는 경우 자동 갱신하기
80 포트 리다이렉트를 하더라도 웹 서비스가 정상적일 경우에만 아래 사항을 적용합니다.
80 포트 리다이렉트를 하고 있을 경우 아래와 같은 systemd 설정만으로는 자동 갱신이 실패하게 됩니다.
ExecStart=/usr/bin/certbot -q renew
NGINX의 80 포트가 리다이렉트하지 않도록 변경을 하고 certbot 갱신을 실행하도록 하여야 합니다.
먼저 /opt/docker/nginx/nginx/conf를 사용하여 redirect.conf 파일과 normal.conf 파일을 생성합니다.
-
redirect.conf- 80 포트를 443 포트로 리다이렉트하는 config 파일 -
normal.conf- 80 포트를 리다이렉트하지 않는 config 파일
$ sudo nano /usr/bin/renew-certbot.sh 명령으로 텍스트 파일을 생성을 하고 아래의 내용을 저장을 합니다.
#! /bin/bash
docker stop nginx
sleep 1
cp /opt/docker/nginx/normal.conf /opt/docker/nginx/nginx.conf
sleep 1
docker start nginx
sleep 1
/usr/bin/certbot -q renew
sleep 1
docker stop nginx
sleep 1
cp /opt/docks/nginx/redirect.conf /opt/docks/nginx/nginx.conf
sleep 1
docker start nginx
각 명령어 마다 1초식 지연되도록 sleep 명령어를 추가했습니다.
파일을 저장합니다.
아래의 명령으로 쉘 스크립트를 실행가능한 형식으로 변경합니다.
$ sudo chmod +x /usr/bin/renew-certbot.sh
다음으로 certbot.service 파일의 ExecStart 부분을 아래와 같이 수정하고 저장을 합니다.
ExecStart=/usr/bin/renew-certbot.sh
80 포트를 443 포트로 리다이렉트 하고 있는 경우 갱신하기 부분은 아직 직접 검증하지 않았습니다.