SSL(Secure Socket Layer) 또는 TLS(Transport Layer Security)은 전송계층 상에서 클라이언트, 서버에 대한 인증 및 데이터 암호화를 수행한다. 클라이언트와 서버 양단 간 응용계층 및 TCP 전송계층 사이에서 안전한 보안 채널을 형성해주는 역할을 하는 보안용 프로토콜이다. 이 둘은 버전의 차이이며, 보통 SSL이라 통칭한다.
HTTPS(Hypertext Transfer Protocol Over SSL)는 SSL 위에 SSL을 적용한 HTTP로 보안을 강화한 전송 기능이다. 그래서 SSL 인증서 적용이 된 도메인만이 https://
주소를 가질 수 있다.
Let’s Encrypt는 무료로 TLS 인증서를 발급해주는 비영리기관이다. 무료인 대신 만료기한이 90일로 주기적으로 재발급해야 한다. 서비스를 운영한다면 더 보안등급이 높은 유료 인증서를 사용해야 한다.
CertBot은 Let’s Encrypt 인증서를 사용하여 HTTPS를 적용할 수 있게 하는 오픈 소스툴이다.
공식페이지에서는 Snap을 이용한 설치가 권장된다. 우리는 apt-get을 이용하여 다운받았다.
apt 업데이트
$ apt-get update
$ apt-get upgrade
certbot을 설치한다.
$ apt-get install python3-certbot-nginx
설치된 certbot을 이용하여 도메인에 대한 SSL 인증서를 발급받는다.
$ certbot certonly --nginx -d example.com
certonly
: certbot
명령어로 인증서를 다운받고, 설치할 수 있다. 하지만 설치까지 진행하면 설정이 자동으로 된다. 따라서 certonly
옵션으로 인증서 다운만 받고 설정은 추후에 진행할 수 있다.—nginx
: 해당 도메인에 대한 소유주가 자신임을 인증하기 위해 이용할 플러그인이다. nginx에 대한 인증서 취득 및 설치가 자동으로 이루어진다./etc/letsencrypt/live/example.com
경로에 5개의 파일 (4개의 pem, 1개의 README)가 생성되었는지 확인한다.
$ ll /etc/letsencrypt/live/example.com
sites-available
과 sites-enabled
을 이용하던지, conf.d
디렉토리를 이용하여 conf 파일을 작성한다.
nginx 메인 설정파일 확인
$ cd /etc/nginx
$ vi nginx.conf
/etc/nginx/conf.d
아래에 있는 모든 .conf 파일, /etc/nginx/sites-enabled
의 모든 파일들을 include한다.
1) conf.d 디렉토리에 conf 파일은 작성만 하면된다.
2) sites-available 디렉토리에 작성하면, 아래 명령어를 통해 심볼릭 링크를 만들어준다.
$ sudo nginx -t # 문법 확인
$ sudo ln -s /etc/nginx/sites-available/test.conf /etc/nginx/sites-enabled
test.conf
파일 작성
example.com : 본인의 도메인 주소를 넣어준다.
# 1)
server {
listen 80; # 80포트로 받을 때
server_name example.com; # 도메인주소
return 301 https://example.com$request_uri;
}
# 2)
server {
listen 443 ssl http2;
server_name example.com;
# ssl 인증서 적용하기
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / { # location 이후 특정 url을 처리하는 방법을 정의(여기서는 / -> 즉, 모든 request)
proxy_pass https//localhost:9001; # Request에 대해 어디로 리다이렉트하는지 작성. 8443 -> 자신의 springboot app 이사용하는 포트
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;
}
}
# 3)
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example.com;
return 404; # managed by Certbot
}
1) 80포트로 들어오는 요청 즉, http로 들어오는 모든 요청을 https로 리다이렉션을 한다.
2) https://
로 들어오는 요청을 서비스 중인 포트로 연결시켜준다.
proxy_pass
: 프록시 주소, 백엔드 운영 서버 ip를 넣어준다.proxy_set_header Host $http_host
: HTTP Request의 Host 헤더 값, 클라이언트가 요청한 원래 호스트 주소X-Real-IP $remote_addr
: 실제 방문자의 원격 ip 주소X-Forwarded-For $proxy_add_x_forwared_for
: 클라이언트가 프록시 처리한 모든 서버의 IP 주소를 포함하는 목록X-forwarded-Proto $scheme
: HTTP의 구조로 http or https를 의미한다. HTTPS 서버 블록 내에서 사용할 경우 프록시 서버의 HTTP 응답이 HTTPS로 변환된다.3) 도메인 이름이 다르면 404 에러 처리를 한다.
Nginx 재시작
$ sudo service nginx restart
$ certbot certificates
$ certbot renew --dry-run
$ certbot delete --cert-name {인증서 이름}
도메인 적용되는데 시간이 걸리니 20분 정도 기다렸다가 하자.
아래와 같은 에러 로그가 찍히고 화면은 502 Bad GateWay가 떴다.
nginx 에러로그 위치 : /var/log/nginx/error.log
2023/03/15 04:23:08 [error] 75117#75117: *94 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client: 51.89.5.185, server: daengnyang.site, request: "GET /.env HTTP/1.1", upstream: "https://127.0.0.1:9001/.env", host: "13.125.45.96"
2023/03/15 04:23:09 [error] 75117#75117: *96 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client: 51.89.5.185, server: daengnyang.site, request: "POST / HTTP/1.1", upstream: "https://127.0.0.1:9001/", host: "13.125.45.96"
2023/03/15 04:28:58 [error] 75117#75117: *99 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client: 205.169.39.84, server: daengnyang.site, request: "GET / HTTP/1.1", upstream: "https://127.0.0.1:9001/", host: "daengnyang.site"
위의 에러로그를 검색하면 가장 많이 나오는 것이 설정파일 문제라고 한다.
nginx 설정에서 443으로 들어온 요청은 http로 우리 서비스와 연결시켜줬어야 하는데 https로 또 연결을 하고 있었다. 설정파일 수정하고 해결되었다.
참고
https://velog.io/@jihyunhillpark/2.-spring-boot-기반-앱-배포-Cerbot-인증서-발급과-SSL-적용
https://dallog.github.io/deploy-full-course3/