스프링 + 리액트 : https, nginx, Mixed Content
문제 상황
첫 프로젝트, 첫 배포였다. 개발 과정은 api를 만들고 ec2 서버에 올려 프론트가 서버에 올려둔 api를 호출해서 테스트하는 방식으로 개발했으며, ec2 서버 내에 Spring과 React를 각각 3000번 포트와 8080번 포트로 실행했다. 하지만 배포 과정은 쉽지 않았다.
서버로 들어오는 http 요청을 https로 바꿔주기 위해 서버에 nginx와 letsencrypt를 설치하고, 프록시 서버를 둬서 React로 들어오는 요청에 https를 적용시켜 주었다. 그리고 웹 페이지로 들어가서 요청을 해본 결과
Mixed Content 에러가 떴다.
Mixed Content ?
최초 HTML이 안전한 HTTPS 연결을 통해 로드될 때 혼합 콘텐츠가 발생하지만 다른 리소스(예: 이미지, 동영상, 스타일시트, 스크립트)는 안전하지 않은 HTTP 연결을 통해 로드 됩니다. 이는 HTTP 콘텐츠와 HTTPS 콘텐츠가 함께 로드되어 동일한 페이지를 표시하므로 혼합 콘텐츠라고 하는데, 최초의 요청은 HTTPS 연결을 통해 보안 처리되었습니다. 최신 브라우저는 이 유형의 콘텐츠에 대한 경고를 표시하여 해당 페이지에 보안되지 않은 리소스가 포함되어 있음을 사용자에게 알려 줍니다.
쉽게 말해서 https 웹 사이트에서 http 요청을 보낼 수 없다는 것이다.
처음 생각한 것은
' 아, 그러면 api 서버용 도메인을 하나 더 구입해서 각각 https를 적용시켜야 하는건가 ? '
라고 고민했는데, 나랑 같은 생각을 한 사람이 있었다. https://xetown.com/questions/780401 < 참고 사이트
해결 방법
프론트엔드와 백엔드를 각각 https를 적용시키지 않고 요청 분기에 따라서 요청을 처리하는 것이다.
예를 들어서 example.com/~ 으로 들어오면 3000번 포트 리액트로 요청을 보내고,
exaple.com/api/~ 으로 들어오면 8080번 포트 스프링 부트로 요청을 보내는 것이다.
이렇게 하면, 도메인으로 들어오는 모든 요청이 https가 적용되어서 Mixed Content 에러를 해결할 수 있다.
리버스 프록시를 사용하는 것인데, 서버의 가장 앞에 설치되어서 서버가 요청을 받을 때 중간다리 역할을 하고 내부 서버로 요청을 전달해준다.
장점으로는
- 클라이언트는 프록시 서버를 호출해서, 서버를 감출 수 있게 된다. (보안)
- 트래픽을 분산시켜서 로드밸런싱 할 수 있다.
리버스 프록시 적용시키기
ec2 배포 환경에 https를 적용시키기 위해서 서버에 nginx를 두고, letsencrypt로 https 인증서를 발급받았다.
ec2에서 install 해야하는 것들은 설명하지 않는다.
1. letsencrypt를 사용하기 위해서 먼저 가비아에서 도메인을 사야한다.
2. 호스팅 영역을 생성하고, 구매한 도메인을 등록한다.
3. 가비아 해당 도메인 관리 - 도메인 정보 변경- 네임서버 설정으로 들어가서, route 53의 네임서버로 모두 바꿔준다.
(네임 서버 변경하는데 시간이 걸릴 수 있다. 나는 새벽에 해서 자고 일어나니까 적용되어 있었음)
4. ec2에 접속해서
sudo vi /etc/nginx/proxy_params
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;
proxy_set_header X-NginX-Proxy true;
client_max_body_size 256M;
client_body_buffer_size 1m;
proxy_buffering on;
proxy_buffers 256 16k;
proxy_buffer_size 128k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_max_temp_file_size 1024m;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_intercept_errors on;
저장한다.
5. /etc/nginx의 폴더에 sites-available, sites-enabled 폴더가 없으면 만든다. sites-available 폴더에 도메인 명 파일을 만든다. ex) vi example.com
server {
server_name example.com www.example.com;
location / {
include /etc/nginx/proxy_params;
proxy_pass http:000.000.000.000:port; # ip:port 프론트엔드 포트
}
location /api {
include /etc/nginx/proxy_params;
proxy_pass http://000.000.000.000:port: #ip:port 백엔드 포트
}
}
저장한다.
6.
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
example.com 자신의 도메인 주소로 바꿔서 입력.
7.
sudo certbot --nginx -d example.com -d www.example.com
자신의 도메인 주소로 바꿔서 입력.
8.
sudo service nginx reload
sudo service nginx restart
nginx를 재시작 해준다.
결론
배포 과정은 로컬에서 개발하는 환경과 매우 다르며, 네트워크 지식과 여러 브라우저 정책 또한 알고 있어야한다.
또한 nginx를 사용하면 리버스 프록시를 사용해서 Mixed Content 문제를 해결할 수 있으며, 프록시 서버를 노출하기 때문에 보안에도 좀 더 안전하다.
더 나아가서 로드 밸런싱도 적용해보도록 하자, , , ,