escape-room

[Ubuntu] Nginx, Let's Encrypt를 사용하여 HTTPS 설정하기 (+에러 해결)

기매_ 2023. 5. 19. 19:22

HTTP로 연결하였을 때 위와 같은 경고 문구를 확인할 수 있다.

 

HTTP 프로토콜은 Header, Body 등의 평문 데이터가 서버로 전송될 때 모두 노출되므로 보안에 취약하다는 문제가 있다. 그래서 일반적으로는 보안이 강화된 HTTPS 프로토콜을 사용한다.

이를 적용하기 위해 SSL 인증서를 발급 받고, 웹 서버에서 SSL 프로토콜을 적용해보자 !

(HTTPS는 SSL 프로토콜로 암호화한 HTTP 프로토콜이다.)


0. 기본 정보

  • Nginx : 웹 서버 중, 하나로 톰캣과 같은 WAS 앞단에 위치하여 리버스 프록시 서버 역할을 할 수 있다. 대표적으로 로드밸런싱, 포트 포워딩, SSL 설정 등이 있다. 이번 프로젝트에서는 Reverse Proxy Server로 활용해서 이 서버에 SSL 인증서를 발급해두어 HTTPS를 적용한다.
  • Let’s Encrypt : SSL 인증서를 무료로 발급해주는 CA
  • Certbot : ACME 프로토콜을 준수하는 프로그램으로 Certbot 프로그램을 사용하여 인증서를 발급 받는다.

1. Nginx 설치하기

1) Nginx 설치하기

// 패키지 버전 업데이트 & 업그레이드
sudo apt-get update
sudo apt-get upgrade

// nginx 설치
sudo apt install nginx

설치 중에 Do you want to continue? [Y/n] 같은 것이 뜨면 y 를 입력하여 설치를 마친다.

 

2) Nginx 실행

// nginx 실행
sudo service nginx
// nginx 실행 확인
sudo service nginx status

+) 혹시

sudo service nginx status 를 입력했을 때

lines 1-16/16 (END) 라는 문구가 뜬다면,

wq 를 입력하여 빠져나올 수 있다 !

 

3) default 파일 수정

// 디렉토리 이동
cd /etc/nginx/sites-available
// default 파일 수정
sudo vi default

 

server_name 에 가비아에서 구매한 도메인을 입력한다. ( server_name www.openthedoor.site; )

 

4) Nginx 재시작

sudo service nginx restart

 

+

cd ~ : 홈 디렉토리로 이동

cd .. : 상위 디렉토리로 이동

pwd : 현재 위치 확인


2. Certbot 설치 및 인증서 발급

// certbot 설치
sudo apt-get install python3-certbot-nginx
// 인증서 발급
sudo certbot --nginx -d [도메인 주소]

예시) sudo certbot --nginx -d www.openthedoor.site

 

메일, 약관 동의 여부 등에 대해 물어보는데 읽어보고 동의한다고 하면 인증서 발급이 완료된다 ! ㅎㅎ

 

인증서 발급이 성공하면 위와 같은 메시지가 출력된다

`/etc/letsencrypt/live/도메인/` 의 경로에 pem키 발급이 되었다는 메세지를 확인할 수 있다 !


3. 인증서 추출하기

1) 디렉토리 이동하기

// 디렉토리 이동
cd /etc/letsencrypt
// 권한 변경 (live 디렉토리 권한 주기)
sudo chmod 755 live/
// 디렉토리 이동
cd /etc/letsencrypt/live/[도메인 주소]

 

/etc/letsencrypt/live/www.openthedoor.site

이 위치로 이동해야 하는데, live 디렉토리의 권한이 없으므로 한번에 이동하지 못한다.

 

따라서 cd /etc/letsencrypt 를 통해 /etc/letsencrypt 디렉토리로 이동 후,

sudo chmod 755 live/ 를 통해 live 디렉토리의 권한을 부여한다.

그 후 cd /etc/letsencrypt/live/[도메인 주소] 를 통해 이동하면 된다 !

 

2) SSL 인증서를 PKCS12 형식으로 변환

현재 pem 파일로 저장되어 있는데, Spring Boot 에서는 pem키를 인식할 수 없기 때문에 pkcs12 형태로 변환해야 한다.

 

// pem 파일을 p12 형식으로 변환
sudo openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat -CAfile chain.pem -caname root
// keystore.p12 파일 권한 변경
sudo chmod 755 keystore.p12

sudo openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat -CAfile chain.pem -caname root

명령어를 입력하고 나면, 비밀번호를 입력하라는 메세지가 뜬다

이때 비밀번호를 입력(설정)하면 된다 !

위 사진과 같이 비밀번호를 키보드로 입력해도 눈으로 보이지는 않는다

따라서 그냥 비밀번호를 입력하고 나서 엔터를 누르면 된다 .. !

Verifying - 메세지는 비밀번호 확인 메세지이다.

방금 입력했던 비밀번호를 똑같이 입력해주면 p12 파일로 변환이 완료된다.

ls 명령어를 통해 keystore.p12 파일이 있는 것을 확인할 수 있다.

 

3) Ubuntu에서 발급한 keystore.p12 파일을 scp 통신을 사용하여 서버에서 로컬 폴더로 이동

먼저 exit 명령어를 통해 Ubuntu를 종료하고 cmd로 돌아온다.

 

cmd 에서 아래 명령어를 입력

scp -i [비밀키] ubuntu@[탄력적 IP]:/etc/letsencrypt/live/[도메인]/keystore.p12 [로컬의 폴더 위치]

예시 )

scp -i aws-key.pem ubuntu@43.786.453.186:/etc/letsencrypt/live/www.openthedoor.site/keystore.p12 C:\Users\hahaha\Desktop\AWS

 

=> 내가 입력한 위치로 keystore.p12 파일이 잘 이동된 것을 확인할 수 있다 !!

 


4. Spring Boot 프로젝트에 적용하기

resources 폴더에 keystore.p12 파일을 복붙하여 넣고, application.yml 에 다음과 같이 입력한다.

 

 

application.yml

# SSL 설정 (HTTPS)
server:
  ssl:
    key-store: classpath:keystore.p12
    key-store-type: PKCS12
    key-store-password: [pkcs12 파일 발급 당시 지정한 비밀번호]
    key-alias: tomcat
    
# 만약 스프링 시큐리티를 사용중이라면 아래 설정도 포함 (아니면 제외)
security:
  require-ssl: true

만약 application.properties 라면

server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=[pkcs12 파일 발급 당시 지정한 비밀번호]
server.ssl.key-alias=tomcat

# 만약 스프링 시큐리티를 사용중이라면 아래 설정도 포함
# security.require-ssl=true

 


keystore.p12 와 민감정보(비밀번호)가 담긴 application.yml 파일은 .gitignore 에 추가하는 것이 좋다.

나의 경우 application.yml과 application-profile.yml으로 나누어 민감 정보는 application-profile.yml에서 따로 관리하고 있다.


5. 프로젝트를 재빌드 한 후 다시 배포하여 HTTPS 설정이 완료되었는지 확인하기!

빌드 및 배포하는 방법은 아래 글을 참고 ..

https://maemae22.tistory.com/103

 

[AWS] EC2 배포 관련 명령어

SSH 클라이언트로 인스턴스 연결하는 방법 (SSH 접속) 인스턴스 - 연결 클릭 cmd에서 pem 파일 (프라이빗 키 파일)이 위치한 경로로 이동(cd) 후 위의 사진에서 ssh- 로 시작하는 것을 입력하면 인스턴

maemae22.tistory.com


https://www.openthedoor.site:8080/cafe/all

로 들어가보면

데이터가 잘 출력되는 것을 확인할 수 있다 !

( 주의 : 포트 포워딩 설정 전이라면 http 가 아닌 https로 들어가야한다. )

 

 

 

HTTPS .. 드디어 성공 ...


번외. 마주한 에러들

5번에서 프로젝트 재빌드 및 재배포 한 후 바로 HTTPS 접속에 성공한 것이 아니라, 수많은 에러를 마주하였다 ...

일단 접속이 정상적으로 되지 않으면

$ tail -f nohup.out

이 명령어로 실시간 로그를 보며 에러 메세지를 확인해보자 .. 

 


1) at java.base/sun.net. www.protocol.file.FileURLConnection.connect(FileURLConnection.java:86) 에러

ubuntu@ip-:~$ tail -f nohup.out
        at java.base/sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:86) ~[na:na]
        at java.base/sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:184) ~[na:na]
        at org.apache.catalina.startup.CatalinaBaseConfigurationSource.getResource(CatalinaBaseConfigurationSource.java:118) ~[tomcat-embed-core-9.0.74.jar!/:na]
        at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:200) ~[tomcat-embed-core-9.0.74.jar!/:na]
        at org.apache.tomcat.util.net.SSLHostConfigCertificate.getCertificateKeystore(SSLHostConfigCertificate.java:207) ~[tomcat-embed-core-9.0.74.jar!/:na]
        at org.apache.tomcat.util.net.SSLUtilBase.getKeyManagers(SSLUtilBase.java:282) ~[tomcat-embed-core-9.0.74.jar!/:na]
        at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:246) ~[tomcat-embed-core-9.0.74.jar!/:na]
        at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:105) ~[tomcat-embed-core-9.0.74.jar!/:na]
        ... 34 common frames omitted

 

구글링해도 많은 정보가 나오지 않아 정확하게 파악하진 못했지만, SSL 인증서를 가져올 때? 문제가 있었던 것 같다.

원래 처음에 application.yml 설정을 아래와 같이 시작했었는데 이 설정이 잘못되어서 생긴 오류인 것 같다. (특히 key-store 부분 ..)

 

위쪽 '4. Spring Boot 프로젝트에 적용하기'에 적어둔대로 수정한 뒤로 더이상 이 에러를 보지 않을 수 있었다 .. ㅎㅎ

정말 오류를 찾기 위해 20번정도 빌드 & 배포를 반복했던 것 같ㄷ ㅏ ... ㅎ


2) Web server failed to start. Port 8080 was already in use. 에러 문구

ubuntu@ip-:~$ tail -f nohup.out
***************************

Description:

Web server failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

 

이미 8080 포트가 사용중이여서 발생하는 오류다

 

sudo netstat -lntp

이 명령어로 이용중인 포트와 PID를 확인하고,

( 만약 net-tools가 설치되어 있지 않다면, $ sudo apt install net-tools 로 net-tools 설치부터 하기 )

 

$ sudo kill -9 [PID]

이 명령어로 해당 프로세스를 종료시켰다.


3) Bad Request. This combination of host and port requires TLS. 에러

새로운 에러 두두등장 ....

그래도 계속 다른 에러가 등장해주니 뭐라도 되는거 같아 쪼오끔 뿌듯했다 ...

아까 계속 같은 에러만 n번째 보고있을때보다는 행복 .. ^^

 

바로 $ tail -f nohup.out 으로 이번에는 무슨 에러메세지인지 확인 ... 하였으나

ubuntu@ip-:~$ tail -f nohup.out
2023-05-19 14:45:33.154  INFO 43146 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2023-05-19 14:45:33.378  INFO 43146 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-05-19 14:45:34.018  INFO 43146 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-05-19 14:45:34.088  INFO 43146 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
2023-05-19 14:45:35.588  INFO 43146 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-05-19 14:45:35.609  INFO 43146 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-05-19 14:45:37.304  WARN 43146 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-05-19 14:45:38.645  INFO 43146 --- [           main] o.a.t.util.net.NioEndpoint.certificate   : Connector [https-jsse-nio-8080], TLS virtual host [_default_], certificate type [UNDEFINED] configured from [jar:file:/home/ubuntu/escape-room-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/keystore.p12] using alias [tomcat] and with trust store [null]
2023-05-19 14:45:38.685  INFO 43146 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (https) with context path ''
2023-05-19 14:45:38.720  INFO 43146 --- [           main] c.m.escaperoom.EscapeRoomApplication     : Started EscapeRoomApplication in 13.41 seconds (JVM running for 14.596)

? 잘 시작된 것 같았다 ...

근데 왜 안되는거니 ,,,,,,,, 라고 울면서 계속 원인을 찾던 중 ....

 

내가 계속 아래와 같이

http://www.openthedoor.site:8080/cafe/all

http로 요청을 보내고 있었단 걸 알게되었다.

 

설마 하며 아래와 같이

https://www.openthedoor.site:8080/cafe/all 

https로 접속한 순간 ...

.. ^^

해결 완 .....


이전에 한번 야매로? 개인 인증서를 통해 HTTPS 설정을 해본 적이 있었으나,

이렇게 정석대로 해본 건 처음이여서 그런지 정말 많이 헤메었다 .....

 

바로 위 3번 오류처럼 혹시 나처럼 http로 접속을 시도하는 사람이 있을 수 있으니

포트 포워딩을 통해 http로 들어온 요청을 https로 리다이렉트 시켜줘야 한다.

 

또한 발급받은 SSL 인증서는 3개월마다 재발급해야 한다는 번거로운 점이 있다.

따라서 자동 갱신 되도록 설정해두면 편리하고 좋은데

 

포트 포워딩 & 인증서 자동 갱신 설정에 대한 설정을 이 다음 포스팅에서 해보겠다 .. !  아자아자 화이팅 ..