Post

백엔드/프론트 통합 환경에서 HTTPS 적용하기

프론트와 백엔드가 하나의 모듈에서 관리되는 환경에서 Nginx 웹서버를 통해 HTTPS를 적용하는 방법에 대해서 살펴봅니다.

React + Spring Boot 환경에서 http 프로토콜로 서비스를 제공하고 있었다. 주소창의 안전하지 않은 사이트 라는 표시가 이전에도 거슬리긴했지만 그래도 굳이 회원의 정보를 서버로 전달하는 기능은 없었기 때문에 필요성을 느끼지 못하고 있었는데 구글 애드센스를 사용하기 위해서는 https 프로토콜로 서비스를 제공해야한다는 것을 알고 도메인을 https로 제공하기로 마음먹었다.

구글링을 통해서 ssh 키를 업체로부터 발급받고, nginx설정을 하는 부분을 찾아보았는데 대부분 프론트 서버와 백엔드 서버가 분리되어있어 443 포트로 요청이 오면 백엔드 서버로 연결시키는 경우가 많았다. 하지만 나의 경우에는 백엔드와 프론트 환경이 같은 인스턴스내에 존재했기 때문에 http(80)요청이 들어왔을 때 https(443)으로 리다이렉션하고 프론트의 정적 페이지 index.html을 보여주고, 또 같은 도메인 주소로 백엔드에 접근해야하므로 특정 경로의 요청에 대해서는 localhost:8080으로 리다이렉션 시켜주어야 했다.

이런 상황에서 https를 적용하는 방법과 내가 겪었던 문제점에 대해서 정리해보고자 한다.

HTTPS로 전환하기

HTTPS가 필요한 이유

HTTP 프로토콜을 사용하면 웹 서버와 브라우저간에 암호화 되지 않은 상태로 데이터가 전송되기 때문에 누군가 중간에 패킷을 낚아채 훔쳐볼 수 있는 위험이 있다. 그래서 아이디, 패스워드, 주민등록번호같은 중요한 정보를 전송해야한다면 꼭 암호화해 데이터를 전송하는 HTTPS 프로토콜을 사용해야한다.

인증서를 발급받아 HTTPS로 접속하기

HTTPS 는 HTTPS에 SSL(Secured Socket Layer)기능을 더한것인데, HTTPS를 적용하기 위해서는 SSL 인증서가 필요하다. SSL 인증서를 업체로부터 발급받아서 엔진엑스(Nginx)에 적용해야한다. 그러면 클라이언트 측에서는 업체로부터 받은 도메인의 공개키로 암호화해서 서버로 전송하고 서버는 클라이언트가 전송한 내용을 개인키로 복호화해서 통신한다.

SSL 인증서는 인증기관으로부터 발급받아야하는데, 여러 인증기관이 있지만 무료로 SSL인증서를 발급해주는 Let’s Encrypt 서비스를 사용해보자. 유료 인증서와는 보안사고 발생 시 인증서에 따라 배상금을 지급하지 않는 차이가 있다.

  1. 터미널에서 certbotpython3-certbot-nginx를 설치한다.
1
2
  sudo apt install certbot
  sudo apt install python3-certbot-nginx

certbot은 SSL 인증서를 생성, 발급, 갱신, 관리하는데 사용하고, python3-certbot-nginx는 엔진엑스 서버와 함께 사용하기 위해서 필요하다.

  1. nginx 에서 사용할 Let’s Encrypt 인증서를 발급한다.
    1
    
     sudo certbot certonly --nginx
    

    중간에 인증서를 발급할 도메인을 물어보는데 잘 입력해주면 된다. 순서대로 잘 입력하면 다음과같은 경로에 인증서가 생성된다. ``` /etc/letsencrypt/live/(입력한 도메인)/fullchain.pem /etc/letsencrypt/live/(입력한 도메인)/privkey.pem

```

  1. nginx 설정파일을 수정한다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
      server {
          listen 80;
          server_name gongnomok.site;
    
          location / {
            return 301 https://gongnomok.site$request_uri;
          }
    
            location /api {
                proxy_pass http://localhost:8080;
          }
      }
    
      server {
          listen 443 ssl;
          server_name gongnomok.site;
    
          ssl_certificate /etc/letsencrypt/live/gongnomok.site/fullchain.pem; # managed by Certbot
          ssl_certificate_key /etc/letsencrypt/live/gongnomok.site/privkey.pem; # managed by Certbot
          include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    
          location / {
              root   /usr/project/gongnomok-simulator/frontend/dist;
              index  index.html index.htm;
              try_files $uri $uri/ /index.html;
          }
    
            location /api {
                  proxy_pass http://localhost:8080;
          }
      }
    
    

    HTTP 80번 포트로 요청이왔을 때 HTTPS 443 포트로 리다이렉트 해주었다. 또 SSL인증서를 적용하기 위해서 SSL 관련 설정을 적용했다. 중간의 도메인 이름은 본인것을 써야한다는 점에 주의하자 나는 백엔드로의 요청을 /api로 구분하였기 때문에 /api로 온 요청은 http://locahost:8080 으로 프록시 패스해주었다.

  • GCP나 AWS EC2를 사용하는 경우 HTTPS(443)포트의 방화벽을 해제해주어야한다는 점도 주의하자.
  • 이제 브라우저에서 http대신 https로 접속할 수 있게 된다.

8080포트로 백엔드 요청을 보낸 실수

단순히 8080포트로 백엔드 요청을 보내면 되겠지? 생각하여 https://(도메인):8080/api/... 로 요청을 보냈으나 응답을 정상적으로 받을 수 없는 문제가 발생했다. SSL을 설정하면서 이제 허용된 포트이외에는 직접 접근할 수 없게 되었기 때문이다. /api로 된 경로는 자동으로 http://localhost:8080로 프록시를 설정했기 때문에 이제는 https://(도메인)/api/...로 요청을 보내주면 된다.

This post is licensed under CC BY 4.0 by the author.