[Nginx] Let's Encrypt를 통해 Nginx에서 무료로 https 설정하기

업데이트(2020.07.19): Ubuntu 지원 버전에 따른 설치 방법 업데이트

업데이트(2018.03.03): 기존에 webroot plugin 방식에서 python-certbot-nginx을 사용하는 방식을 추가하였습니다. python-certbot-nginx를 통해서 설치하는게 훨씬 간단합니다.

무료 인증서 서비스를 제공하는 Let’s Encrypt를 통해서 서비스에 ssl 설정을 추가하자


환경

  • Ubuntu 20.04 (LTS)
  • Ubuntu 18.04 (LTS)
  • Ubuntu 16.04 (LTS)
  • Ubuntu 14.04 (LTS)
  • Nginx (version: 1.4.6)(apt-get을 통한 설치)
  • 도메인


사전 준비사항

  • Nginx에 대한 간단한 사용법
  • HTTPS와 인증서에 대한 개념
  • 도메인도 하나 필요합니다. 여기에서는 example.com이라는 도메인이 있다고 가정하고 진행하겠습니다.


소개

이 글은 How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04를 간단하게 요약 정리한 글이며 SSL과 인증서에 대한 소개는 다음 포스팅에서 하도록 하겠습니다.

Let’s Encrypt는 Certificate Authority (CA). 즉, 인증기관으로 보다 쉬운 방법과 무료로 TLS/SSL 인증서를 발급해서 HTTPS 통신을 가능하게 해주는 서비스 기관입니다.

Let’s Encrypt는 certbot 이라는 소프트웨어를 통해서 이를 쉽게 자동화하도록 만들어져 있습니다.


1. certbot 설치

Ubuntu 16.04 (LTS), Ubuntu 18.04 (LTS) 저장소 세팅

저장소 설정 및 업데이트 진행

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository universe
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update

Ubuntu 20.04 (LTS) 저장소 세팅

저장소를 설정 및 업데이트 진행

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository universe
$ sudo apt-get update

공통

certbot 설치

$ sudo apt-get install certbot python3-certbot-nginx


2. Nginx 세팅

Certbot이 자동으로 SSL을 세팅해주기 때문에 server blockserver_name을 설정해주면 됩니다.

$ sudo vim /etc/nginx/sites-available/[your server block]

아래는 제 예시입니다. undang_backend_nginx.conf에 블록들이 있기 때문에 아래처럼 되었습니다.

$ sudo vim /etc/nginx/sites-available/undang_backend_nginx.conf

이제 서버 블록 파일 안에 server_name을 설정하고자 하는 도메인 이름으로 변경해주시면 됩니다. 저는 아래와 같습니다.

...
# configuration of the server
server {

    listen      80;
    listen [::]:80;
    # Put your domain next to server_name
    server_name undang.twpower.me;
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

...

}

설정이 완료 되었다면 저장하고 아래 명령어를 통해서 재시작합니다.

$ sudo nginx -t
$ sudo service nginx reload


3. SSL 인증 획득하기

다음 아래 명령어를 사용하면 nginx plugin을 통해서 가능합니다. 도메인을 추가적으로 더 하고 싶다면(위에 server_name에도 물론 설정이 되어있어야겠죠?) -d 옵션을 주고 더 주가하면 됩니다.

$ sudo certbot --nginx -d example.com -d www.example.com

제 예시는 아래와 같습니다.

$ sudo certbot --nginx -d undang.twpower.me

그러면 아래와 같이 1과 2를 선택하는 화면이 나오는데 저와 같은 경우는 모든 경우를 https로 하고 싶어서 redirect를 허용하는 2번을 하였습니다.

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2

번호를 선택해주면 아래처럼 진행되며 key들도 자동으로 생성해줍니다. success


4. 인증서 자동갱신 설정 확인

설정한 certbot은 90일 동안만 유효하기 때문에 갱신을 해줘야합니다. 매번 해주기 귀찮으나 설치한 certbot은 자동으로 갱신을 이틀 단위로 해줍니다.

해당하는 갱신이 제대로 되는지는 아래 명령어를 통해서 확인 가능하며 에러가 나타나지 않으면 renewal이 정상적으로 작동 할겁니다.

$ sudo certbot renew --dry-run

Ubuntu의 경우 /etc/cron.d/에 보면 certbot이 생성되어있습니다.


5. SSL 적용 확인 및 평가

본인의 서버에 SSL이 적용이 잘 되었는지 평가할 수 있는 여러 사이트가 있는데 들어가서 본인의 서버 도메인을 입력하면 됩니다.

https://www.ssllabs.com/ssltest/

ssl-test


참고자료






아래는 webroot plugin 방식을 통해 설정하는 방법입니다.

1. certbot 설치

apt-get에 certbot저장소를 추가해줍니다.

$ sudo add-apt-repository ppa:certbot/certbot

패키치 목록을 업데이트해주고 certbot을 설치합니다.

$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx

간혹 업데이트와 업그레이드가 되지 않는 경우가 있는데 그러면 직접 아래처럼 업그레이드를 해줍니다. 업데이트가 자주 바뀌며 지원되는게 달라지기 때문에 certbot 최신 버전을 설치하시길 추천드립니다.

$ sudo add-apt-repository ppa:certbot/certbot


2. 인증서 발급받기

Let’s Encrypt는 다양한 plugin들을 통해서 SSL 인증서를 제공합니다. 아파치를 제외한 대부분의 설치 플러그인들은 발급만 해주고 나머지 설정을 들을 직접 해주어야합니다.

본문에서는 webroot plugin을 통해서 인증서를 발급해 보겠습니다.


Webroot Plugin 사용하기

Webroot Plugin은 /.well-known이라는 폴더에 파일을 추가해서 Let’s Encrypt 서버가 접속할 수 있도록 합니다.

우선, /etc/nginx/sites-available/에 있는 conf 파일들 중에서 추가하고자 하는 파일을 열어줍니다. 여기서는 default conf 파일을 통해 설정해보도록 하겠습니다.

$ sudo vim /etc/nginx/sites-available/default


이제 해당 파일의 server 블럭 안에 다음을 추가합니다.

server {
        . . .

        location ~ /.well-known {
                allow all;
        }

        . . .
}


nginx의 설정 파일이 문법이 제대로 되었는지 확인하고 재시작합니다.

$ sudo nginx -t
$ sudo service nginx restart


이제 server block에서 root설정이 어디인지 알아보고 인증서를 발급해보겠습니다. 인증서를 발급하기 위해서는 webroot-path라는 부분에 server blockroot 경로를 지정해줘야 발급이 가능하다고 합니다.

다음 명령어를 통해서 설정파일에 들어갑니다. 이번에도 역시 /etc/nginx/sites-available/에 있는 default를 이용하겠습니다.

$ vim /etc/nginx/sites-available/default


문서의 server block을 보시면 아래처럼 나와있는 root에 설정된 경로를 기억해주시면됩니다. 다른 설정을 하지 않았다면 기본으로 /usr/share/nginx/html으로 나와있습니다.

server {
        . . .
        root /usr/share/nginx/html; # 이 경로를 기억해야합니다.
        . . .
}


이제 인증서를 발급해봅시다. --webroot-path에 위에 있던 root로 설정된 폴더 경로를(여기서는 /usr/share/nginx/html), -d 옵션을 통해서 지정하고자 하는 도메인명을 넣어줍니다. 여러 도메인을 적용하고 싶다면 최상위 도메인부터 앞에서부터 적어주어야 합니다. 만약 본문처럼 example.comdev.example.com 둘다 하고 싶다면 아래처럼 적용하면 됩니다.

$ sudo certbot certonly --webroot --webroot-path=/usr/share/nginx/html -d example.com -d dev.example.com


처음 적용하는거라면 Email과 Terms of Service에 동의해야 합니다. 입력하고 동의를 하고 나면 다음처럼 성공적으로 완료되었다는 창이 나오며 인증서들과 키가 어떤 경로에 위치한다는 정보와 만기일이 나옵니다. 다음 아래 내용은 How To Secure Nginx with Let’s Encrypt on Ubuntu 14.04에 있는 결과를 가져왔습니다.

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem. Your cert
   will expire on 2017-07-26. 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 lose your account credentials, you can recover through
   e-mails sent to sammy@example.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - 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


Certificate 파일

webroot plugin을 통해 잘 발급을 받았다면 아래와 같은 4개의 파일들이 생성됩니다.

  • cert.pem: 도메인의 인증서
  • chain.pem: Let’s Encrypt chain 인증서
  • fullchain.pem: cert.pem + chain.pem
  • privkey.pem: 인증서의 개인키


위의 파일들은 /etc/letsencrypt/archive에 위치하며 /etc/letsencrypt/live/[your_domain_name]에서 가장 최근의 인증서들에 대해 symbolic link를 가지고 있습니다. 이 위치에서 가장 최신의 인증서를 가지고 있기 때문에 인증서와 키들을 참조할 때 /etc/letsencrypt/live/[your_domain_name] 폴더를 이용해야 합니다.

다음 아래의 명령어를 통해 해당 4개의 파일들이 존재하는지 확인할 수 있습니다.

$ sudo ls -l /etc/letsencrypt/live/your_domain_name


디프-헬만 그룹 추가하기

보안을 위해서 디프-헬만 그룹을 추가해야한다고 합니다. 아래의 명령어를 통해 실행해줍니다. 화면에 여러 점들이 찍히면서 진행이되며 시간이 다소 몇분 소요됩니다

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

다 생성이 되면 /etc/ssl/certs/에서 dhparam.pem 파일을 확인 할 수 있습니다.


3. TLS/SSL 설정하기

이제 Nginx의 server block들을 처리해서 TLS/SSL 설정을 하도록 하겠습니다. nginx에서 default 파일을 수정합시다.

$ sudo vim /etc/nginx/sites-available/default


server block에서 80포트에 대한 기본정보가 아래처럼 나와 있을텐데 지워줍니다.

server{
    ...
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    ...
}    


이제 SSL 관련 설정 세팅을 시작해봅시다. server block안에 다음 내용들을 추가합니다. 여기서 [domain]은 등록하신 도메인을 입력해야합니다!

server{
    ...
    listen 443 ssl;

    server_name [domain] [another_domain];

    ssl_certificate /etc/letsencrypt/live/[domain]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[domain]/privkey.pem;
    ...
}


위의 작업이 끝났다면 아래의 내용도 그대로 server block에 추가합니다.

server{
    ...
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;
    ...
}


마지막으로 아래에 다음과 같은 새로운 server block을 추가합니다.

해당 block은 해당 도메인에 대한 http의 요청을 https로 redirect 해주는 block입니다.

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}


자, 이제 설정이 다 끝났습니다. 다음처럼 문법을 확인하고 재시작해줍시다. 아래와 같은 스크린샷이 나오면 정상적으로 작동하는겁니다.

$ sudo nginx -t
$ sudo service nginx restart
or
$ sudo /etc/init.d/nginx restart
# sudo service nginx restart가 실행되지 않으면 위의 명령어로도 실행 가능합니다.

Nginx Restart


추가로! 다음 아래 사이트에서 마지막 d=에 설정하신 도메인을 넣어주시면 ssl 설정이 완료되었는지 등급이 어느정도인지 알 수 있습니다. 제대로 따라오셨다면 A+가 나와야합니다.

https://www.ssllabs.com/ssltest/analyze.html?d=[domain]


4. 갱신 자동화하기

Let’s Encrypt는 3개월간 유효하며 이를 자동적으로 갱신을 해야하는데 crontab을 통해서 그 일을 자동화시켜 보겠습니다.

다음 명령어를 통해서 crontab을 엽니다.

$ sudo crontab -e


텍스트 에디터로 열리면 아래의 명령어를 파일의 끝에 추가해줍니다.

. . .
15 3 * * * /usr/bin/certbot renew --quiet --renew-hook "/usr/sbin/service nginx reload"

간단히 설명을 하면

  • 15 3 * * *: 매일 3:15 AM에 실행하겠다는 의미입니다.
  • /usr/bin/certbot: 실행하는 파일이며
  • renew: 자동으로 certbot이 인증서들을 보고 갱신이 필요하면 갱신을 진행해줍니다.
  • –quiet: 사용자에게 output을 전달하지 않고 실행합니다.(백그라운드)
  • –renew-hook “/usr/sbin/service nginx reload”: 파일이 새로 갱신되었다면 Nginx를 reload해줍니다.


참고자료