CentOS 7환경에서 Nginx에 SSL을 적용하는 방법에 대해 알아보겠습니다.

( SSL에 대한 개념은 여기를 참고해주세요 ! )


원래 SSL 인증서는 인증된 기관( CA )으로부터 발급 받아야 하는데, Let's Encrypt을 이용하면 무료로 인증서를 발급 받을 수 있습니다.

단, 90일 동안만 인증서가 유효하므로 서버에서 cron을 이용하여 주기적으로 인증서를 갱신해야 합니다.


Let's Encrypt로 부터 인증서를 발급 받으려면 유효한 도메인인지 확인하는 작업이 필요합니다.

도메인이 있으시다면 문제될 것이 없지만, 여기서는 도메인이 없어도 적용 할 수 있도록 ngrok을 사용할 것입니다.


ngrok은 localhost를 공공IP로 포워딩 해주는 툴인데, 세션이 8시간 동안 유효하므로 테스트용으로 적합합니다.

( ngrok에 대한 정보는 여기를 참고해주세요 ! )




이제 Nginx에 SSL을 적용해보도록 하겠습니다.

그러기 위해서 우선, Nginx를 먼저 설치할 것입니다.


1. Nginx 설치 및 테스트

지난 글( 링크 )에서 Nginx를 컴파일 설치하는 방법에 대해 알아보았기 때문에, 이번에는 yum으로 설치해볼 것입니다.

Nginx를 yum으로 설치하기 위해서는 그 전에 repo를 등록해야 합니다.

/etc/yum.repos.d 경로에 nginx.repo 파일을 생성하여 아래와 같이 작성합니다.

# vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1


다음으로 Nginx을 yum으로 설치한 후, 서비스를 등록합니다.

# yum install -y nginx

# systemctl start nginx
# systemctl enable nginx


Nginx가 잘 설치되었는지 확인하기 위해 기본 페이지에 접근해보겠습니다.

ipconfig로 IP를 확인한 후, 브라우저에 접속합니다. ( 저같은 경우는 http://192.168.245.132 ) 

 

 

참고로 yum으로 설치했을 때 html 파일은 /usr/share/nginx/html/ 경로에 있습니다.




2. Let's Encrypt로 인증서 ( .pem 파일 ) 발급 받기

우선 톰캣에 SSL을 적용하기 위해서는 공인된 인증서가 필요합니다.

원래는 CA로부터 인증서를 발급받아야 하는데, 돈이 들기 때문에 무료로 인증서를 발급 받을 수 있는 Let's Encrypt를 사용할 것입니다.


1) Let's Encrypt 인증서 발급

Let‘s encrypt를 github에서 가져오도록 합니다.

# yum install -y git

# git clone https://github.com/letsencrypt/letsencrypt # cd letsencrypt


Github으로부터 letsencrypt을 clone한 후, 인증서를 발급 받는 명령어를 작성합니다.

명령어 형식은 다음과 같으며, Let's encrypt를 사용하기 위한 의존 라이브러리들을 자동으로 설치합니다.


./letsencrypt-auto certonly --manual --email [이메일 주소] -d [사용할 도메인주소]


우선은 이메일 주소와, 도메인 주소를 아무렇게나 작성해보겠습니다.

# ./letsencrypt-auto certonly --manual --email foo@example.ocm -d test-001.com


이어서 이메일 주소를 작성하고, Agree -> N -> Y 를 순서대로 입력합니다.

그러면 마지막에 다음과 같은 메시지가 출력됩니다.



위에서 작성한 도메인이 유효한 도메인인지 확인하기 위해, 두 번째 네모 박스인 파일 경로에 첫 번째 네모 박스의 내용이 작성되어 있는지 확인합니다.

이 과정이 완료되면 인증서( .pem 파일 )를 발급 받을 수 있습니다.


도메인이 있으시다면, 6단계로 넘어가서 바로 인증서를 발급 받으시면 됩니다.

2 ~ 5 단계는 도메인이 없는 경우를 위해 필요한 단계입니다.


저는 공공 IP가 없으므로, 공공 IP를 생성하여 localhost로 포워딩 해주는 툴인 ngrok을 사용할 것입니다.

우선은 엔터를 누르고 Let's Encrypt 발급을 중지합니다.




2) ngork

ngrok 사용법은 매우 간단하기 때문에 부담 갖지 않으셔도 됩니다.

먼저 ngrok을 다운 받으신 후( 링크 ), ngrok http test-001.com:9090 명령어를 입력해주세요.


이 프로그램은 브라우저에서 http://a52cc5ea.ngrok.io으로 요청하면, test-001.com:80으로 포워딩 해줍니다.

80 포트는 Nginx의 기본 포트이며, ngrok은 이렇게 켜놓기만 하면 됩니다. 




3) Nginx 설정 파일 수정

다음으로 Nginx 기본 설정 파일인 default.conf 파일을 열어서 도메인을 추가합니다.

( yum으로 Nginx를 설치하면 /etc/nginx/nginx.conf 설정 파일에서 conf.d/ 디렉터리의 .conf 파일을 include하도록 되어 있습니다. )

Let's Encrypt 인증서를 발급 받기 위해서는 도메인이 필요하기 때문이죠.

# /etc/nginx/conf.d/default.conf

server_name test-001.com;


 

 

4) hosts 파일 수정

다음으로 서버에서 test-001.com URL을 알 수 있도록 hosts 파일을 수정해야 합니다.

IP주소는 ifconfig 명령어로 확인해주세요.

# vi /etc/hosts

192.168.245.132   test-001.com


뿐만 아니라 브라우저를 실행하는 것은 호스트이기 때문에 호스트인 윈도우에서도 hosts 파일을 수정해야 합니다.

C:\Windows\System32\drivers\etc 경로에서 hosts 파일을 열어서 아래의 내용을 추가해주세요.

192.168.245.132   test-001.com




5) 접속 테스트

nginx 재실행하여,

# systemctl stop nginx

# systemctl start nginx

브라우저에서 http://test-001.com으로 접속이 되는지 확인합니다.

그리고 ngrok에서 제공하는 http://a52cc5ea.ngrok.io 으로 요청해도 접속이 잘 되는지 확인해주세요.




6) 인증서 발급받기

이제 유효한 도메인이 생겼으니 인증서를 발급 받아보도록 하겠습니다.


2)번 과정에서 명령했던 내용을 명령하는데, 끝에 -d 이후의 도메인 부분이 ngrok에서 제공하는 도메인으로 바뀌었습니다.

# cd /root/letsencrypt/

# ./letsencrypt-auto certonly --manual --email foo@example.com -d a52cc5ea.ngrok.io

 

아직 엔터를 누르면 안됩니다.

쉘을 하나 더 열어서 위 경로의 파일에서 내용을 작성하고 저장합니다.

# mkdir -p /usr/share/nginx/html/.well-known/acme-challenge

# vi /usr/share/nginx/html/.well-known/acme-challenge/tgyD3dNqsS4Pt-VdyX9iONXHdXuzKH92MgyYhropYhs tgyD3dNqsS4Pt-VdyX9iONXHdXuzKH92MgyYhropYhs.Hgg7b4dUAD58ejqCXKsZnphxYFkAl4Fj9AsmyEz0n_s


원래 쉘로 돌아와서 엔터를 누르면 아래와 같이 pem 파일이 생성되었다고 합니다.

 

이 과정이 끝나면 Let's Encrypt 인증키를 발급 받은 것입니다.

( ngrok이 제공하는 URL은 이제 더 이상 필요 없습니다. ngrok은 Let's Encrypt 인증서를 발급 받기 위한 역할을 할 뿐입니다. )





3. Nginx에 SSL 설정

Nginx에 SSL 설정을 하기 위해서, Mozila SSL Configuration Generator를 이용할 것입니다. ( 링크 )

여기서 Nginx와 openssl 버전을 입력하면, 설정 내용을 제공해줍니다.

각각의 버전 확인 명령어는 다음과 같습니다.

# nginx -v

# openssl version

 


 

우선 pem 파일이 생성된 경로로 이동해서, SSL 설정에 필요한 dhparam.pem 파일을 생성하겠습니다.

# cd /etc/letsencrypt/live/a52cc5ea.ngrok.io/

# openssl dhparam -out dhparam.pem 2048


다음으로 Nginx 설정 내용인 server{ } 블록을 생성하기 위해 /etc/nginx/conf.d 경로에 test-001.com.conf 파일을 생성하고,

# vi /etc/nginx/conf.d/test-001.com.conf

Mozila SSL Configuration Generator에서 제공하는 설정 내용을 붙여넣기 합니다.




복사한 내용 중 수정해야 할 부분은 다음과 같습니다.


ssl_certificate               => /etc/letsencrypt/live/a52cc5ea.ngrok.io/fullchain.pem;

ssl_certificate_key          => /etc/letsencrypt/live/a52cc5ea.ngrok.io/privkey.pem;

ssl_dhparam                => /etc/letsencrypt/live/a52cc5ea.ngrok.io/dhparam.pem;

ssl_trusted_certificate     => /etc/letsencrypt/live/a52cc5ea.ngrok.io/chain.pem;


그리고 가장 마지막에 있는 resolver 부분은 삭제합니다.



*** 참고 ***

사실 위와 같이 길게 작성할 필요 없이, 아래의 코드만 작성해도 SSL이 적용 됩니다.

server{ 

listen 443 ssl;

ssl_certificate /etc/letsencrypt/live/a52cc5ea.ngrok.io/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/a52cc5ea.ngrok.io/privkey.pem;

}




다시 서버를 재실행하여 브라우저에서 https://test-001.com 경로로 접근해봅니다. ( https 프로토콜임에 유의 )

# systemctl restart nginx

만약 잘 실행이 되지 않는다면 에러 로그를 확인해서 해결하도록 합니다.

# vi /var/log/nginx/error.log


 


 

이 메시지는 let's encrypt로부터 인증 받은 도메인과 test-001.com 도메인과 다르기 때문에 발생한 오류입니다.

( 실제 도메인을 갖고 있다면, 문제가 되지 않은 것으로 확인했습니다. )


하단의 “고급” 버튼을 눌러서 “test-001.com(안전하지 않음)(으)로 이동”을 클릭해서 무시하고 실행합니다.

그러면 Nginx 페이지가 응답되며, 인증서를 확인하기 위해 좌측 상단의 "안전하지 않음" 버튼을 클릭하고 "인증서"를 클릭합니다.




인증서를 확인해보면 let's encrypt로부터 잘 받급된 것을 확인 할 수 있습니다.





4. Cron 설정

Let's Encrpyt의 유효기간은 90일이기 때문에 90일 마다 인증서를 재발급 하도록 cron 작업을 설정해야 합니다.

Let's Encrpyt에서 고맙게도 letsencrypt-auto renew 명령어를 입력하면 간편하게 재발급이 되도록 만들어 놓았기 때문에,

이 명령어를 수행하도록 cron 작업을 설정하면 됩니다.


1) 쉘 스크립트 작성

스크립트에는 인증서를 재발급 하는 위의 명령어를 작성하면 됩니다.

# vi /usr/local/victolee/ssl-renew.sh /root/letsencrypt/letsencrypt-auto renew



2) crontab 설정

# crontab -e # 23일 24시 0분에 3개월 마다(1월,4월,7월.10월) 인증서 재발급 0 23 23 JAN,APR,JUL,OCT * /usr/local/victolee/ssl-renew.sh > /var/log/ssl-renew-cron.log 2>&1

> /var/log/ssl-renew-cron.log 2>&1 의 의미는 " /var/log/ssl-renew-cron.log 파일에 표준 내용과 에러 내용을 기록하라 "는 의미입니다.




이상으로 공공 IP가 없을 때, ngrok을 사용하여 Nginx에서 SSL을 적용하는 방법에 대해 알아보았습니다.

댓글 펼치기 👇
  1. ㅎㅇ 2019.02.04 23:17

    안녕하세요 포스팅 잘보고 갑니다. ^~^ 저번에 답변 달아주셔서 감사합니다.
    궁금한게 있어 이렇게 글 남깁니다.
    SSL 갱신 주기가 어느 정도 되야지 갱신이가능 한건간요?
    마지막 설정이 잘 되는지 궁금해서 갱신 주기를 매 분만 다 실행해서 로그를 찍어 봤습니다. 근데 아래와 같이 갱신이 시도되지 않았다는 문구가 뜨는데 잘 설정되었는지 궁금해서 이렇게 글 남깁니다.

    Saving debug log to /var/log/letsencrypt/letsencrypt.log
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Processing /etc/letsencrypt/renewal/(주소생략).conf
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cert not yet due for renewal
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    The following certs are not due for renewal yet:
    /etc/letsencrypt/live/(주소생략)/fullchain.pem expires on 2019-04-18 (skipped)
    No renewals were attempted.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    • Favicon of https://victorydntmd.tistory.com 우르르응 2019.02.07 21:46 신고

      안녕하세요~

      Let's Encrypt 유효기간이 90일이기 때문에, 유효기간이 만료되어야 갱신이 가능할 것입니다.

      Cert not yet due for renewal
      즉, 아직 갱신할 수 없다는 의미의 메시지 이므로 크론 설정은 잘 된 것 같습니다.

      저도 실제로 90일 지나서 확인해본적이 없지만, 문서보고 참고한 것이라 맞지 않을까 싶네요~

      감사합니다 ^^

  2. ㅇㅇ 2020.06.17 23:52

    와 대박 님덕에 ssl적용 한달 고민한거해결함