[Nginx] Nginx HTTPS 및 Let’s Encryt SSL 인증서 적용



Nginx에서 SSL 인증서를 적용하고 암호화 통신 프로토콜로 웹서비스를 제공하기 위한 HTTPS 설정 내용을 정리합니다.


테스트 환경

Nginx를 설치된 환경에서 진행을 하고 위 링크의 포스트가 선행되어야 하겠습니다.


Let’s Encrypt SSL 인증서

Let’s Encrypt는 무료이며 자동화된 개방형 인증 기간이라고 사이트에서 소개하고 있습니다.

Let’s Encrypt에서는 HTTPS 프로토콜에 사용하는 SSL(TLS) 인증서를 무료로 발급해 주는 기관입니다.

루트 도메인, 서브 도메인, 와일드카드 서브 도메인 인증서 등 다양하게 무료로 발급이 가능합니다.

발급된 인증서는 유효기간이 90일이며 만료 30일 전부터 갱신할 수 있고 갱신 가능 횟수는 무제한이라고 합니다.


인증서 발급 방식

ㅇ standalone

  • certbot에 내장된 셋팅을 사용해서 도메인만으로 인증서를 발급하는 방식입니다.
  • *.example.com 형태의 와일드카드 서브 도메인 인증서는 발급할 수 없습니다.

ㅇ webroot

  • 웹 서버에서 작동중인 웹사이트를 이용해서 인증서를 발급하는 방식입니다.
  • *.example.com 형태의 와일드카드 서브 도메인 인증서는 발급할 수 없습니다.

ㅇ dns

  • 도메인이 연결된 DNS에 TXT 레코드를 생생해서 인증서를 발급하는 방식입니다.
  • 인증서 발급 과정에 웹서버(Nginx 등)가 필요 없습니다.
  • *.example.com 형태의 와일드 카드 서브 도메인 인증서도 발급할 수 있습니다.
  • 매번 인증서를 갱신할 때마다 DNS에 TXT 레코드를 새로 생성하고 인증서를 수동으로 갱신해야 합니다.
  • 다만 외부에서 TXT 레코드를 입력할 수 있도록 DNS가 API 등을 제공하면 자동으로 갱신되도록 구현은 할 수 있습니다.
  • dns 방식에 대해서는 아래 포트스에서 이미 정리한 바 있습니다.

Certbot 설치

[root@jackerlab ~]# dnf install epel-release
[root@jackerlab ~]# dnf install epel-release
...
설치됨:
  epel-release-8-8.el8.noarch                                                                                                                        

완료되었습니다!
[root@jackerlab ~]# dnf install certbot
Extra Packages for Enterprise Linux Modular 8 - x86_64                                                               0.0  B/s |   0  B     00:30    
Failed to download metadata for repo 'epel-modular'
오류: Failed to download metadata for repo 'epel-modular'

[root@jackerlab ~]# yum install certbot
...
완료되었습니다!
[root@jackerlab ~]# 

Let’s Encrypt 인증서 발급 (Standalone 방식)

[root@jackerlab ~]# certbot certonly --standalone -d [도메인]

인증서 발급을 진행하기 전에 Nginx 서비스는 중지되어 있어야 합니다.

ㅇ Nginx 서비스가 중지 안되었을 때 에러

[root@jackerlab ~]# certbot certonly --standalone -d apps.jackerlab.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for apps.jackerlab.com
Cleaning up challenges
Problem binding to port 80: Could not bind to IPv4 or IPv6.
[root@jackerlab ~]#

ㅇ Nginx 서비스 중지 및 확인

[root@jackerlab ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1430/sshd           
tcp        4      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      29208/node          
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      2715/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      2715/nginx: master  
tcp6       0      0 :::22                   :::*                    LISTEN      1430/sshd           
tcp6       0      0 :::80                   :::*                    LISTEN      2715/nginx: master  
[root@jackerlab ~]# systemctl stop nginx
[root@jackerlab ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1430/sshd           
tcp        4      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      29208/node          
tcp6       0      0 :::22                   :::*                    LISTEN      1430/sshd           
[root@jackerlab ~]#

ㅇ Nginx 중지 후 재 진행

[root@jackerlab ~]# certbot certonly --standalone -d apps.jackerlab.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for apps.jackerlab.com
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/apps.jackerlab.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/apps.jackerlab.com/privkey.pem
   Your cert will expire on 2020-08-03. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

[root@jackerlab ~]#

정상적으로 SSL 인증서가 발급되고 발급된 경로를 안내해 주고 있습니다.

ㅇ SSL 인증서 파일 확인

[root@jackerlab ~]# ll /etc/letsencrypt/live/apps.jackerlab.com/
total 4
lrwxrwxrwx. 1 root root  42 May  5 15:22 cert.pem -> ../../archive/apps.jackerlab.com/cert1.pem
lrwxrwxrwx. 1 root root  43 May  5 15:22 chain.pem -> ../../archive/apps.jackerlab.com/chain1.pem
lrwxrwxrwx. 1 root root  47 May  5 15:22 fullchain.pem -> ../../archive/apps.jackerlab.com/fullchain1.pem
lrwxrwxrwx. 1 root root  45 May  5 15:22 privkey.pem -> ../../archive/apps.jackerlab.com/privkey1.pem
-rw-r--r--. 1 root root 692 May  5 15:22 README
[root@jackerlab ~]#

Nginx HTTPS 설정 및 인증서 적용

Nginx에서 HTTPS 적용은 /etc/nginx/nginx.conf 파일에서 설정하고 서비스를 구동하면 됩니다.

nginx.conf 설정 파일에서 TLS 부분을 모두 주석을 해제하고 인증서 정보를 적용해 주면 되겠습니다.

[root@jackerlab ~]# vim /etc/nginx/nginx.conf
... (앞 부분 생략)
# 아래 설정 주석 풀고 설정함
# Settings for a TLS enabled server.
    server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        #server_name    _;
        server_name  apps.jackerlab.com; # 도메인 주소 적용
        root         /usr/share/nginx/html;
        charser utf-8;
        
        ssl_certificate /etc/letsencrypt/live/apps.jackerlab.com/fullchain.pem; # 인증서 경로 추가
        ssl_certificate_key     /etc/letsencrypt/live/apps.jackerlab.com/privkey.pem; # 인증서 경로 추가
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}
... (뒷부분 생략)
[root@jackerlab ~]#

설정 내용을 저장하고 서비스를 구동하면 정상적으로 HTTPS(443) 서비스 및 인증서가 적용된 것을 확인할 수 있습니다.

[root@jackerlab ~]# systemctl start nginx
[root@jackerlab ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1430/sshd                  
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      3279/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      3279/nginx: master  
tcp6       0      0 :::22                   :::*                    LISTEN      1430/sshd           
tcp6       0      0 :::443                  :::*                    LISTEN      3279/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      3279/nginx: master  
[root@jackerlab ~]# 

Let’s Encrypt 인증서 자동 갱신(renew) 적용

ㅇ 인증서 renewal 설정 적용

[root@jackerlab apps.jackerlab.com]# cat /etc/letsencrypt/renewal/apps.jackerlab.com.conf

위 경로에 Let’s Encrypt 인증서 갱신하는 설정 파일이 존재합니다.

인증서를 갱신할 때 해당 설정을 참조하여 진행이 되고 인증서 발급(Standalone)할 때 Nginx가 중지되어 있어야 하기 때문에 아래와 같이 몇가지 설정을 추가해 주어야 합니다.

# renewal 설정
[root@jackerlab apps.jackerlab.com]# cat /etc/letsencrypt/renewal/apps.jackerlab.com.conf 
# renew_before_expiry = 30 days
version = 1.4.0
archive_dir = /etc/letsencrypt/archive/apps.jackerlab.com
cert = /etc/letsencrypt/live/apps.jackerlab.com/cert.pem
privkey = /etc/letsencrypt/live/apps.jackerlab.com/privkey.pem
chain = /etc/letsencrypt/live/apps.jackerlab.com/chain.pem
fullchain = /etc/letsencrypt/live/apps.jackerlab.com/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = 4505136a740ba8154ebe1c52fa80596b
authenticator = standalone
server = https://acme-v02.api.letsencrypt.org/directory
pre_hook = systemctl stop nginx    # 추가
post_hook = systemctl start nginx    # 추가
[root@jackerlab apps.jackerlab.com]# 

ㅇ 인증서 renewal 테스트

[root@jackerlab apps.jackerlab.com]# certbot renew --dry-run
# renewal 테스트
[root@jackerlab apps.jackerlab.com]# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/apps.jackerlab.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator standalone, Installer None
Running pre-hook command: systemctl stop nginx
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for apps.jackerlab.com
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/apps.jackerlab.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/apps.jackerlab.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: systemctl start nginx
[root@jackerlab apps.jackerlab.com]#

SSL 인증서 renewal 테스트 결과 정상적으로 nginx가 중지 된 후, 갱신 처리가 진행되는 것을 확인할 수 있고 인증서 renewal이 완료 된 후, 자동적으로 nginx가 구동되는 것을 확인할 수 있습니다.

ㅇ Crontab 적용

Crontab에 스케쥴 잡으로 적용한 후, 자동적으로 인증서 renewal 처리가 실행되도록 하면 되겠습니다.

# crontab 적용
[root@jackerlab apps.jackerlab.com]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@jackerlab apps.jackerlab.com]# crontab -l
0 0 1 * * certbot renew
[root@jackerlab apps.jackerlab.com]# 

레퍼런스

ㅇ Let’s Encrypt 내용 참고 : https://namu.wiki/w/Let’s%20Encrypt

ㅇ Let’s Encrypt 사이트 : https://letsencrypt.org/ko/



1 thought on “[Nginx] Nginx HTTPS 및 Let’s Encryt SSL 인증서 적용”

Leave a Comment