HTTPS 적용기

공병주(Chris)·2022년 7월 31일
5
post-thumbnail

우아한테크코스 Level3 팀 프로젝트의 스프린트 3의 요구 사항 중에, HTTPS를 적용해야 하는 요구 사항이 있었습니다. HTTPS를 적용한 방법에 대해 알아보겠습니다.

Nginx

여러 방법 중 Nginx를 통해 Https를 구현한 이유

먼저, Nginx를 통해서 Https를 구현했는데요. 아래와 같은 이유때문에 Nginx를 선택했습니다.

  1. Nginx가 SSL 설정이 간단하다.
  2. 추후에, Nginx가 Load Balancing, html css등의 정적 리소스 서빙 등의 역할을 해줄 수 있다.
    사실, Nginx를 위한 EC2를 따로 구축하지 않아서 당장 로드밸런싱의 효과를 볼 수 없지만, 추후에 Nginx를 통해서 Load Balancing을 진행할 예정이니, Nginx을 써보자.
  3. 레퍼런스가 많다.

도메인 준비

도메인 구입

먼저, 저희 팀은 가비아에서 도메인을 구입했습니다.

sokdaksokdak.com

도메인과 Web Server 연결

구매한 도메인에 프론트 서버가 있는 ec2의 public ip를 연결해줘야 합니다.

가비아 > 서비스 관리 > DNS 관리툴 에서 연결할 도메인을 체크하고 DNS 설정을 클릭하면 위의 창이 보입니다.

호스트에 www(www.sokdaksokdak.com)와 @(sokdaksokdak.com)를 추가해주고
값/위치에 프론트 서버가 있는 ec2의 Public IP를 지정해주었습니다.
이제 sokdaksokdak.com으로 접속했을 시에, 프론트 서버로 요청이 전송됩니다.

Ngnix 설치

$ sudo apt install nginx # nginx 설치
$ sudo service nginx start # nginx 실행
$ sudo service nginx status # nginx가 잘 실행중인지 확인

먼저, 위의 명령어를 통해 Ngnix를 프론트 서버가 존재하는 ec2에 설치하고 실행시킵니다.

인증서 발급(Let’s Ecrypt)

Let’s Ecrypt

Let’s Ecrypt는 이메일과 도메인만으로, 빠르게 인증서를 발급할 수 있는 무료 서비스입니다.

인증서는 Certbot을 통해서 받을 수 있습니다.

먼저 아래의 명령어로 Certbot을 설치해줍니다. apt를 통해서 설치하셔도 무방합니다.

$ sudo snap install certbot --classic

Nginx에 SSL 적용하기

$ sudo certbot --nginx -d {도메인}

ex)
$ sudo certbot --nginx -d sokdaksokdak.com

위의 명령어를 통해 인증서를 발급하면서 nginx에 인증서 관련 설정을 자동 으로 할 수 있습니다.

위의 명령어를 작성하면 Successfullu received certificate. 라는 안내와 함께 인증서 정보를 출력줍니다.

$ cd /etc/nginx/sites-available
$ vi default

위의 경로에 가보시면 default라는 파일이 있습니다. 해당 파일을 열어보면 CertBot이 nginx의 사이트에 인증서 관련 설정을 보실 수 있습니다.

저는 default 파일을 삭제하고, 아래와 같이 .conf 파일을 따로 작성해주었습니다. 파일의 이름은 제한이 없습니다. 하지만 위치는 반드시 /etc/nginx/sites-available 이어야 합니다.

#프론트 서버의 nginx 관련 설정

server {
        listen 443 ssl; # 443 포트의 요청을 받음
        server_name sokdaksokdak.com; # 도메인 지정

        location / { 
               root /home/ubuntu/2022-sokdak/frontend/dist; # 빌드된 프론트의 파일 위치
               index index.html; # 렌더링 해줄 html 파일 이름 
               try_files $uri $uri/ /index.html; # 사용자가 존재하는 않는 uri로 요청을 보내도, index.html을 보여줌
        }

        ssl_certificate /etc/letsencrypt/live/sokdaksokdak.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sokdaksokdak.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

server {
        listen 80; # 80 포트의 요청을 받음
        server_name sokdaksokdak.com;
        return 301 https://sokdaksokdak.com$request_uri; # 동일한 uri를 https로 리다이렉트
}

위는 프론트 서버에 nginx를 구축할 때의 설정입니다.

Server 블럭

위의 server 블럭은 sokdaksokdak.com으로 443(https) 요청이 왔을 때, index.html을 띄워주는 것입니다.

아래의 server 블럭은 sokdaksokdak.com으로 80(http) 요청이 왔을 때, 443으로 리다이렉션 해주는 설정입니다.

SSL 관련 설정

  • ssl_certificate
    conf 파일에서 ssl_certificate 에는 certbot이 발급해준 fullchain.pem의 경로를 지정하면 됩니다.
    기억이 안나신다면, /etc/letsencrypt/{위에서 인증서 발급받은 도메인}/fullchain.pem 을 작성하면 됩니다.
  • ssl_certificate_key
    ssl_certificate_key 에는 certbot이 발급해준 privkey.pem의 경로를 지정해주면 됩니다.
    파일이 위치하는 디렉토리는 위와 같습니다./etc/letsencrypt/{위에서 인증서 발급받은 도메인}/privkey.pem
  • options-ssl-nginx.conf와 ssl_dhparam
    options-ssl-nginx.conf을 include 하는 것과 ssl_dhparam을 지정해주는 것은 certbot이 자동으로 해줬던 것입니다.
    options-ssl-nginx.conf에는 ssl의 session_cache, session_timeout, ssl_protocols 등의 설정이 있습니다.

설정 확인

.conf 파일 설정 후, 아래의 명령어로 nginx 문법에 틀린 것이 있는지 체크해줍니다. 오타나 문제가 있을 수 있으니, 한번씩 체크하시는걸 추천합니다!

$ sudo nginx -t

sites-avaliable과 sites-enable 심볼릭링크 설정

$ sudo ln /etc/nginx/sites-available/2022-sokdak.conf /etc/nginx/sites-enabled/

다음으로, 위의 명령어를 통해 방금 .conf를 수정했던 /etc/nginx/sites-available 디렉토리와 /etc/nginx/sites-enable 디렉토리에 심볼릭링크를 걸어주어야합니다. 또한, sites-enable에 존재하는 default 파일은 삭제하였습니다.

sites-available은 nginx에 대한 .conf 파일을 설정하는 곳이고, sites-enabled에 있는 설정은 실제로 nginx가 실행될 때 적용되는 nginx 설정을 읽는 디렉토리입니다. sites-available에서는 nginx에 대한 .conf 파일을 설정하고, sites-enable과 심볼릭링크하여 nginx에 설정을 적용하는 방식입니다.

$ sudo nginx -s reload
# 혹은
$ sudo service nginx restart

그 후에, 위의 명령어를 통해 nginx를 재시작하면

프론트엔드는 HTTPS 성공!!!!!!

백엔드 Https

백엔드 https를 위한 nginx 따로 구축

백엔드는 Spring이 돌아가고 있는 EC2에 Nginx를 설치하지 않고, Nginx를 위한 EC2를 별개로 구축했습니다. 아래와 같은 이유를 고려하지 않으시면, 프론트의 https처럼 하나의 EC2에 Nginx를 설치해도 됩니다.

이유는 아래와 같습니다.

  1. 하나의 Nginx와 Spring이 함께 Nginx가 존재하면, EC2의 리소스를 나누어 사용한다.
    현재 EC2가 t4 micro로 낮은 사양이기 때문에, Nginx와 Spring을 분리시키는 것이 운영에 안정적이겠다.
  2. 추후에 Nginx로 로드밸런싱을 할 예정이니, Nginx를 따로 구축해두자.
  3. 모든 요청은 Nginx가 받기 때문에, 외부로부터 서버를 숨길 수 있습니다.

백엔드 https 적용 방법

위에서 프론트엔드 방법과 동일하게 하시면 됩니다.

다른 점은 listen하고 있는 server_name이 다른 도메인이라는 것입니다.

server {
        listen 443 ssl; # 443 포트의 요청을 받음
        server_name was.sokdaksokdak.com; # 도메인 지정

        location / {
								proxy_pass http://{백엔드서버 IP}:8080; //Spring과 nginx가 같은 ec2에 있기 때문에, localhost로 요청 위임
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header Host $http_host;
				}
        ssl_certificate  /etc/letsencrypt/live/was.sokdaksokdak.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/was.sokdaksokdak.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

server {
        listen 80; # 80 포트의 요청을 받음
        server_name was.sokdaksokdak.com;
        return 404; # http로 요청하면 404 응답
}

location

또한, 프론트엔드의 location과는 설정이 다릅니다.

proxy_pass

Nginx는 서버에 대한 요청을 처리할 수 없기 때문에, Spring에게 요청을 위임해야합니다. 따라서, proxy_pass에는 Spring이 동작하고 있는 주소를 지정해줍니다.

header 설정

.conf에서 proxy_set_header를 위와 같이 설정해주면, Spring으로 들어오는 요청에 대한 로깅은 아래와 같습니다.

###### HTTP Request ######
GET /boards/contents HTTP/1.0
x-forwarded-for: 218.39.176.142 # $proxy_add_x_forwarded_for 로 설정
x-forwarded-proto: https # $scheme 로 설정
x-real-ip: 218.39.176.142 # $remote_addr로 설정
host: was.sokdaksokdak.com # $http_host 로 설정
connection: close
  • x-forwarded-for : client의 원 IP 주소를 식별하는 표준 헤더로, $proxy_add_x_forwarded_for 로 설정해주었습니다. $proxy_add_x_forwarded_for 로 설정하면, 원 client의 IP를 x-forwarded-for 헤더에 append 해줍니다.
  • x-forwarded-proto : 클라이언트가 프록시(nginx)로 요청을 보낼 때의 프로토콜로, $scheme 로 설정해줍니다.
  • x-real-ip : 바로 직전의 client IP를 나타냅니다. 현재 client-nginx-tomcat으로 요청이 들어가기 때문에, 단순하게 $remote_addr(원 클라이언트의 IP) 로 설정해주었습니다.

위와 같이 설정하면 아래와 같은 통신 구조가 구축됩니다!

끗!

참고자료

https://velog.io/@pinot/Ubuntu-Nginx-환경에서-CertBot을-사용하여-https-사용하기

https://gist.github.com/woorim960/dda0bc85599f61a025bb8ac471dfaf7a

https://maximorlov.com/tips/sites-available-vs-sites-enabled-in-nginx/

도움주신분

우아한테코크스 4기 BE 릭

0개의 댓글