HTTPS설정(proxy_pass와 포트번호)

고동현·2024년 9월 18일
0

"더 깊이, 더 넓게"

목록 보기
6/12

HTTPS로 변환하는이유

스프링에서 Local로 서버를 띄우던, EC2를 이용해 인스턴스를 빌려서 띄우던
해당 서버를 통한 웹사이트 접근을 하면 항상 http://어쩌구~로 시작하는것을 볼 수 있다.

나는 현재 prove프로젝트에서 백엔드로 서버를 띄웠고 react를 사용하여 프론트 작업을 수행중인 친구가 http://3.39.xxx.xx 해당 엔드포인트로 요청을 보내면되었다.

그런데?

이런식으로
This request has been blocked; the content must be served over HTTPS라고 react단에서 해당 http://3.39.xx.xx로 요청시 이런 오류가 뜬다.

엇? 그런데 HTTP는 뭐고 HTTPS는 뭐길래 HTTPS로 요청을 보내라는걸까?

HTTP와 HTTPS의 차이

HTTP는 Hypertext Transfer Protocol의 약자이다.
서로 다른 시스템들 사이에서 통신을 주고받게 하는 기초적인 프로토콜이다.
웹서핑을 할때 서버에서 브라우저로 데이터를 전송해주는 용도로 가장 많이 사용된다.

그런데 문제는 서버에서 브라우저로 전송되는 정보가 암호화되지 않는다는것이다.

이말은, 데이터가 쉽게 도난 당할 수 있다는 것이다.

HTTPS 프로토콜은 SSL(보안 소켓 계층)을 사용하므로서 해당 문제를 해결하였다.
HTTP와 HTTPS의 차이는 바로 SSL인증서이다. HTTP에다가 보안기능을 추가한게 HTTPS인데,

SSL인증서에서는 사용자가 사이트에게 제공하는 정보를 암호화한다. 만약 내가 id와 비밀번호를 로그인할때 입력해서 서버로 전송할때, 암호화하지 않으면 전송된 데이터를 중간에 누가 탈취하면 그대로 id와 비번이 털리게 된다.

그러나 암호화해서 전달하면, 해당 데이터를 탈취하더라도 해독할수가 없다.

예를들어 내가 만든 Prove프로젝트 기업 사장 DH는 HTTPS를 적용하기 위해서 개인키와 공개키를 만든다. 당연히 개인키와 공개키는 서로 다르다.

  1. DH가 신뢰할수있는 CA를 선택해 공개키를 관리해달라고 계약한다.
  2. CA기업은 CA기업만의 공개키와, 개인키를 가지고있다. CA기업이 CA기업 이름, prove의 공개키, 공개키의 암호화 방법등의 정보를 담은 인증서를 발급하고, 발급한 인증서를 CA기업의 개인키로 암호화해서 DH에 전달한다.
  3. DH기업에 클라이언트가 암호화된 HTTPS요청이 아닌 요청이 들어오면 암호화된 인증서를 전송한다.
  4. CA기업의 공개키는 브라우저가 이미 알고 있기 때문에, 클라이언트는 CA기업의 공개키로 서버로 부터 전달받은 인증서를 복호화하고, 이를통해 A기업의 공개키를 얻을 수 있다.
  5. 그뒤로는 클라이언트가 DH기업의 서버와 통신할때는 id와 비번을 A기업의 공개키로 암호화해서 request를 날릴 수 있다.

여기까지가 일반적인 HTTP,HTTPS의 내용이고 이제 문제 상황에 대해서 설명하도록 하겠다.

문제

일단 현재 상황을 설명해보자면,

  1. Route 53에서 do-prove.com이라는 도메인을 구입한 상태이다.
  2. 3.39.xx.x라는 ec2인스턴스를 빌린상태이다.
  3. route 53에서 recode를 추가하여 인스턴스의 ipv4와 do-prove.com이라는 도메인을 연동시킨 상태이다.

고로 현재상태는

http://3.39.xxx.xx:8080/으로 접속시 정상접속
http://do-prove.com:8080/으로 접속시 정상접속이 완료된 상태이다.

이렇게 도메인 연결이 끝났으면 이제 https로만 바꾸면 되겠지? 라고 생각한 나였지만,,,

도저히 https로 변경이 안됐다.

이때 https로 변경하기위해서 AWS의 로드벨런서를 사용하여서 대상그룹을 설정하였는데



로드밸런스, 대상그룹 설정, 상태까지 전부 정상으로 뜨는데도 도저히 되지 않았다..


도저히 혼자 해결을 하지 못해 개발자 커뮤니티에 올리고 이랬는데, AWS 로드벨런스는 과금이 심하고 certbot을 활용해서 인증서발급과 nginx를 통한 https변경이 좋다는 내용과
네트워크 지식이 부족하다는 쓴소리까지 댓글에 달리는 뻘쭘함까지 ㅠㅠ(근데 나 컴퓨터 네트워크 분반1등이었는데..ㅠ)

그래서 결국 로드벨런스는 서버가 여러대일때 쓰는건데 일단 난 서버가 1대라서 굳이 사용하지 않아도 되고, 과금때문에 nginx를 사용하기로 결정했다.

https://seungpnag.tistory.com/11

nginx와 ssl발급같은건 그냥 구글링 하면 똑같이 할 수 있는거고, 나는 해당 과정을 거치면서 내가 겪은 문제에 대해서 설명하겠다.

http://do-prove.com:8080

http://3.39.xxx.x:8080

http로 접속시 주의요함으로 뜨면서 정상적으로 접속되는것을 확인 할 수 있다.

그다음 내가 nginx설정을 끝내고 시도한것이 바로
https://do-prove.com:8080 이거다

아니 당연히 http에서 https로 바꿨으니까 https로만 바꾸면 되는거 아닌가?
싶었는데 되지 않았고

나는 해당 블로그가 잘못된줄알고, 다른 블로그를 찾고, 이것저것 수정하면서 3주의 시간을 보냈다.

그래서 도대체 내가 설정한 파일들과 도메인의 포트 8080에대해서 생각해보았다.

왜 도대체 8080인걸까?

애초에 질문이 있다.
ec2서버에 해당 spring 프로젝트의 jar파일을 올려서 내 프로젝트를 서버에서 구동중이었다.

근데 왜 하필 8080이냐?
ec2에서 실행시키지 않고 로컬에서 실행시켜도
http://localhost:8080/어쩌구저쩌구
이렇게 되는데 왜? 포트번호를 8080으로 설정해놓냐는거다.

조금만 네트워크 지식이 있으면 HTTP 기본 포트가 80번인것을 알 수 있다. 그러나 포트 번호 80은 특권 포트로 분류되어 관리자 권한이 필요하다.
또한 개발 및 테스트환경에서 여러대의 서버나 애플리케이션이 실행될 수 있는데 기본적으로 HTTP가 80포트를 사용하므로 서버 충돌을 방지하기 위해서 8080같은 다른 포트가 사용되는것이다.

고로, 현재 Spring Boot 애플리케이션은 8080으로 듣고있다.
즉, 이말은 http://localhost:80/ http://localhost:443/ 같은 다른 포트번호가 아닌 8080포트번호로 정확이 요청이 들어와야지 애플리케이션으로 요청을 처리할 수 있다는것이다.

참고
application.properties에서 server.port=9090으로 바꿀 수 있다.

이제 내가 nginx에서 작성한 파일을 보자
/etc/nginx/conf.d/default.conf

해당파일은 do-prove.com 도메인에 대해 HTTPS(포트 443)과 HTTP(포트 80)요청을 처리하도록 구성되어있다.

server {
    listen 443 ssl;
    server_name do-prove.com;

포트 443에서는 ssl을 사용하여 HTTPS요청을 수신한다.

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }

location / 는 해당 포트넘버와 경로(servername이 do-prove.com이고 포트넘버가 443이므로 https://do-prove.com임)로 들어오는 모든 요청에 대해서 해당 {,,,}내용을 처리한다.

proxy_pass http://127.0.0.1:8080;은 요청을 수신하면 로컬 서버 127.0.0.1의 포트 8080으로 전달하고 있다.
이경우, Spring Boot애플리케이션이 8080포트에서 동작하므로 8080을 적은 것이다.

나머지는 ssl설정이다.

server {
    listen 80;
    location / {
        return 301 do-prove.com$request_uri;
    }
}

이건 80에서 HTTP요청을 수신한다. 해당 서버 블럭은 HTTP요청을 HTTPS로 리다이렉트 하는 역할을 한다.
ssl이 없으므로 http://do-prove.com:80임을 뜻한다.

여기서 핵심은 proxy_pass이다.
proxy_pass는 Nginx에서 리버스 프록시 역할을 수행한다.
Nginx는 클라이언트의 요청을 받아 내부 또는 외부의 다른 서버로 요청을 전달하고, 그 결과를 클라이언트에게 반환할 수 있다.

즉, Nginx는 중간에 위치한 프록시 서버처럼 작동하며, 클라이언트는 Nginx가 응답을 제공하는 것처럼 보이지만 실제로는 Nginx가 요청을 다른 서버로 전달해 처리되는 결과를 돌려준다.

기본구조

location / {
    proxy_pass <backend_server>;
}

이를통해 우리가 왜 127.0.0.1:8080을 쓴지 알 수 있다.

우리는 Ec2인스턴스를 통해서 3.39.xxx.xx:8080 서버를 실행시키고있는 상태이고,
우리가 Nginx 요청을 보내면 Nginx는 해당 요청을 받아서 127.0.0.1:8080에 있는 벡엔드 서버로 요청을 전달한다.
127.0.0.1은 로컬호스트(현재 서버)를 의미하고 8080포트는 백엔드 애플리케이션이 실행중인 포트이다.(우리는 prove프로젝트(spring)에서 8080포트를 쓰니까 여기다가 8080을 적은거다.)

이제 감이 오는가?

http://do-prove.com:80으로 요청시
-> server {
listen 80;
location / {
return 301 do-prove.com$request_uri;
}
}
해당코드로 인해 80포트에서 요청을 받고 HTTPS로 301 리다이렉트를 한다.

https://do-prove.com으로 접속시 https이므로 443포트에서 ssl을 사용한다.

우리가 server 80+https설정(포트 자동으로 443)으로 설정했기때문에
두가지 경로로 들어오는 요청을 proxy_pass를 통해 백엔드 서버 3.39.xxx.xx로 전달하는것이다.

우리는 https에 대해서 8080포트를 설정한게 아무것도 없으니까 당연히 요청이 받아 들여지지 않는것이다.

그러면 http://do-prove.com:80, 또는 https://do-prove.com으로 접속하면 정상적으로 접속이된다.
http는 80포트로 접속시 리다이렉트 되게 해두어서, proxy_pass로 요청을 응답받을것이고
https는 원래 443포트를 사용하므로, proxy_pass가 적용이 된다.

느낀점

결국 해당 문제는 https-443과 http-80만 설정했기때문에 https 8080으로는 proxy_pass가 동작하지 않았던것이다.
만약 내가 처음에 시도한것처럼, https-8080을 하고싶으면 어떻게 해야할까? 한번 스스로 답을 생각해보자.

정답은

server {
    listen 8080 ssl;
    server_name do-prove.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
    }

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

이런식으로 8080에다가 https요청이니까 ssl을 붙여주면된다.
그리고 해당 경로로 들어오는 모든 요청에 대해 proxy_pass로 내 백엔드 서버로 넘겨주면 된다.

포트넘버와, proxy_pass에 대해서 전혀 생각하지 않고, 그냥 코드만 따라친 결과가 3주를 낭비하게 되었다.
어쨋든 이제는 제대로 알게되어 낭비가 아닌 성장을 하게 되어 기쁘다!

profile
항상 Why?[왜썻는지] What?[이를 통해 무엇을 얻었는지 생각하겠습니다.]

0개의 댓글