본문 바로가기

AWS

[M1 Mac] Nginx 이용해 프론트, 백엔드(Spring Boot 프로젝트) HTTPS 적용

클라이언트, 서버측(Srping Boot) 각각 서버를 배포하는데 성공했지만 보안을 위해 https를 적용하기로 했다.

보안적인 측면 뿐만 아니고 로딩 속도가 30%나 빨라진다는 이점도 있다고 한다!

무조건 적용해야지.............

그런데 이번에도 역시.... 뜻대로 잘 되지 않았다 

그래서 미래의 나를 위해 기록해 두려고 한다

 

 

나는 EC2 인스턴스를 2개 생성해서, 하나는 프론트 서버로 하나는 백엔드 서버로 사용 중이다. 

그리고 Ubuntu 환경에서 진행했다. 

 

 

 

1.  도메인  준비 

 

SSL을 적용하기 위해서 도메인이 필요하다.

나의 경우 Route 53 에서 도메인을 구입했다.

 

나는 가장 저렴한 도메인을 구매했다 

(여기서 꿀팁은 OOO.click 의 도메인이 3달러로 굉장히 저렴하다! 어디 블로그 글에서 봤었는지 기억이 안난다 ㅠ 정말 감사합니닷)

 

https://us-east-1.console.aws.amazon.com/route53/v2/home?region=ap-northeast-2#Home

 

https://us-east-1.console.aws.amazon.com/route53/v2/home?region=ap-northeast-2#Home

 

us-east-1.console.aws.amazon.com

 

 

2. 레코드 등록 

 

 

레코드 이름은 비워 두어도 되고, www 등과 같이 입력해 주어도 된다. 

레코드 유형은 A로 지정하고,

에는 퍼블릭 IP 주소를 입력해주면 된다.

 

나의 경우 하나의 도메인을 사서 프론트와 백엔드 둘 모두에게 지정해 주었다.

 

프론트는 레코드 이름을 비웠고 ex) garu.com 

백엔드의 경우 레코드 이름을 넣었다. ex) back.garu.com

 

 

 

3.  HTTPS 포트 열어주기

 

EC2 인스턴스의 보안그룹에서 443 포트를 열어주자 

 

 

 

4. Nginx 설치 및 실행

 

인증서를 발급 받기 전에, 각각의 서버가 존재하는 EC2에 Ngnix를 설치하고 실행해주자.

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

 

 

 

5. Nginx 서버 연동

 

Proxy 설정

(이 설정은 백엔드 서버가 존재하는 EC2에서만 설정해 주었다.)

 

sudo mkdir /var/log/nginx/proxy/	# log, error 파일이 들어갈 디렉토리 생성
sudo vi /etc/nginx/proxy_params   	# proxy_params 파일 열기

 

 

참고한 블로그에 따르면, 포트번호가 80인 http에서 요청이 오면 스프링 부트 프로젝트에서 8080번 포트(프로젝트에서 각자가 설정해 둔 포트 번호, 나의 경우 8090)를 바라볼 수 있도록 proxy 설정을 해주는 것이라고 한다. 

 

proxy_params에 아래의 코드를 붙여 넣어 준다.

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;
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;

 

 

각각의 설정이 무엇을 의미하는 것인지 몰라 ChatGPT의 도움을 받아 보았다.

X-Real-IP 및 X-Forwarded-For 설정: 이 설정은 원격 사용자의 IP 주소를 식별하기 위해 사용됩니다. 프록시를 통과하는 경우, 사용자의 원래 IP 주소가 프록시 서버의 IP 주소로 바뀝니다. 이를 해결하기 위해, 원격 사용자의 실제 IP 주소를 HTTP 헤더로 전달합니다.
Host 및 X-Forwarded-Proto 설정: 이 설정은 호스트 헤더와 프로토콜을 설정하여 웹 서버에 전달합니다. 이 정보는 원격 서버에서 요청을 처리하는 데 사용됩니다.
client_max_body_size 및 client_body_buffer_size 설정: 이 설정은 클라이언트로부터의 요청 본문 크기 및 버퍼 크기를 설정합니다. 큰 파일 업로드와 같은 작업을 처리할 때 유용합니다.
proxy_buffering 및 proxy_buffers 설정: 이 설정은 프록시 버퍼링을 활성화하고 버퍼의 크기를 설정합니다. 이를 통해 백엔드 서버로의 요청을 버퍼링하여 더 효율적으로 처리할 수 있습니다.
proxy_temp_file_write_size 및 proxy_max_temp_file_size 설정: 이 설정은 프록시가 임시 파일을 작성하는 경우 파일 크기 제한을 설정합니다. 이를 통해 디스크 공간을 효율적으로 관리할 수 있습니다.
proxy_connect_timeout, proxy_send_timeout, proxy_read_timeout 설정: 이 설정은 프록시 서버와 백엔드 서버 간의 연결 및 읽기/쓰기 시간 제한을 설정합니다. 이를 통해 네트워크 지연이나 문제로 인한 타임아웃을 관리할 수 있습니다.
proxy_intercept_errors 설정: 이 설정은 프록시 서버가 오류를 감지하고 처리하는 방법을 제어합니다. 일반적으로 오류 페이지를 사용자에게 반환하기 전에 프록시 서버가 오류를 확인하고 처리합니다.

 

 

 

서버 블록 생성

 

프론트 서버의 경우, 이전 글에서 서버 블록을 설정해 두었었다. 

서버 블록을 설정하는 것에 대한 자세한 내용은 아래 포스팅을 참고하면 된다.

https://beanie.tistory.com/231

 

sudo vi /etc/nginx/sites-available/{파일명}  # 서버 블록 구성할 파일 생성

 

 

나의 경우, 프론트엔드 서버의 파일명은 OOO.conf, 백엔드 서버의 파일명은 {도메인명} 으로 지정했다.

 

 

프론트 서버의 경우

server {
  listen 80;
  location / {
        root /home/ubuntu/OOO;    #000엔 git clone 한 프로젝트 명
        try_files $uri $uri/ /index.html;			
  }
}

 

 

백엔드 서버의 경우, 

server {

    listen 443;

    server_name {domain} back.{domain};    #도메인 명 입력

    access_log /var/log/nginx/proxy/access.log;
    error_log /var/log/nginx/proxy/error.log;

    location / {
        include /etc/nginx/proxy_params;
        proxy_pass https://{퍼블릭 IP 주소}:8090;    # reverse proxy의 기능
    }
}

 

Nginx는 이제 listen 지시문에 의해 포트 번호 443으로 들어오는 요청들에 대해 server_name 값과 정확하게 일치하는 서버 블록을 찾으려고 시도한다.

server_name을 추가할 때 해시 버킷 메모리 문제가 발생할 수 있기에 /etc/nginx/nginx.conf파일에서 옵션을 조정해 주자.

 

http { ...
	server_names hash_bucke_size 64;	# 주석 처리를 제거
	...
}

 

 

생성한 파일 활성화

sudo ln -s /etc/nginx/sites-available/{파일명} /etc/nginx/sites-enabled/

 

 

Nginx 재시작 

 

각각의 서버에서 Nginx를 재시작 해서 도메인 주소로 들어가면 정상 작동 되는 것을 확인할 수 있다.

sudo nginx -t	#구문 오류 테스트
sudo service nginx reload	#재시작

java -jar {jar 파일명}.jar	#스프링 부트 프로젝트의 경우 jar 파일 실행

 

 

 

6. HTTPS 적용 

 

인증서 발급 받기 (Let's Ecrypt) 

 

Let's Ecrypt를 사용한 이유는 인증서를 발급 받는 것이 간단하고, 무료 서비스이기 때문이다.

인증서는 Cerbot을 통해서 받을 수 있다.

 

 

Cerbot을 설치

sudo apt update   # 시스템 패키지 목록 최신 업데이트 
sudo apt install certbot --classic  # cerbot 설치

 

 

Nginx에 SSL 적용하기 

sudo certbot --nginx -d {도메인}    # ex) sudo certbot --nginx -d garu.com

 

 

 

위의 명령어를 통해 인증서를 발급하면서 nginx에 인증서 관련 설정이 자동으로 설정된다.

 

 

프론트엔드 측 설정파일을 다시 확인해보면, 이렇게 자동으로 설정이 되어있는 것을 확인할 수 있다.

server {
  server_name {도메인명}
  location / {
        root /home/ubuntu/{git clone한 프로젝트명};
        try_files $uri $uri/ /index.html;
  }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/{도메인명}/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/{도메인명}/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = {도메인명}) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  listen 80;
  server_name {도메인명};
    return 404; # managed by Certbot


}

 

 

백엔드 서버에서도 마찬가지로 인증서를 발급받으면 된다.

단, sudo certbot --nginx -d {도메인} 부분에 {도메인}은 백엔드 서버에서 설정한 도메인을 적어주어야 한다. ex) back.{도메인}

 

 

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

 

설정 파일이 수정 되었기 때문에, sites-avaliable과 sites-enable 심볼릭링크를 재설정 해준다.

sudo nginx -t	# nginx 문법에 맞는지 체크 
sudo ln /etc/nginx/sites-available/{파일명} /etc/nginx/sites-enabled/   #심볼릭 링크 설정

 

 

nginx 재시작 

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

 

 

설정한 도메인으로 접속해보면, 프론트엔드 측의 HTTPS가 잘 적용된 것을 확인할 수 있다!

 

 

 

백엔드 HTTPS 적용

 

Spring Boot 프로젝트에 HTTPS 연결을 하기 위해선 몇 가지 과정이 더 남았다.

 

pkc12 형태로 변경 

백엔드 측 EC2 서버에 접속해서

/etc/letsencrypt/live/{파일명} 안에 pem 파일 4개를 확인 해보자.  (여기서 {파일명}은 위에서 서버 블록 설정해두었던 파일명이다)

 

sudo su	#현재 사용자를 루트 사용자로 전환
cd /etc/letsencrypt/live/{파일명}	#디렉토리 이동

 

그냥 확인하려니 권한이 없다고 나와서 sudo su 명령을 해주니 디렉토리 이동이 가능했다.

 

cert.pem, chain.pem, fullchain.pem, privatekey.pem 이렇게 4개의 pem 파일이 존재하는 것을 확인할 수 있다.

 

 

하지만 Spring Boot에서는 pem 파일을 지원하지 않는다고 한다. 따라서 다음 명령어를 이용해 pkc12 형태로 변경해야 한다.

 

openssl pkcs12 -export -inkey privkey.pem -in cert.pem -out keystore.p12

 

이 때, 비밀번호를 설정해주어야 한다. 설정하고 싶은 비밀번호를 2번 입력하면 된다.

 

 

 

 

keystore.p2 파일 복사

 

만들어진 keystore.p2 파일을 Spring Boot 디렉토리의 src/main/resources 밑, application.properties 파일과 동일 경로로 복사해 준다.

 

 

mkdir -p {프로젝트 경로}/src/main/resources	#디렉토리 생성
cp keystore.p12 {프로젝트 경로}/src/main/resources	#파일 복사

 

 

Spring Boot의 application.properties(.yml) 파일 설정

 

server.ssl.key-store={프로젝트 경로}/src/main/resources/keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password={pkcs12파일변환시입력한패스워드}
server.ssl.key-alias=1
server.http2.enabled=true

 

 

application.yml 인 경우

server:
  ssl:
    enabled: true
    key-store: {프로젝트 경로}/src/main/resources/keystore.p12
    key-store-password: {pkcs12파일변환시입력한패스워드}
    key-store-type: PKCS12
    key-alias: 1

 

 

이제 이 프로젝트의 jar 파일을 만들어 백엔드 서버에 복사해주자.

SpringBoot 프로젝트를 빌드하고 JAR 파일을 생성해 서버에 전송하는 것에 대한 포스팅은 지난번에 했다.

https://beanie.tistory.com/230

 

sudo nginx -t
sudo service nginx reload
java -jar {jar 파일명}.jar

 

 

브라우저에서 https로 접속이 가능해진다!..

 

참고로, 

nohup java -jar {jar 파일명} &

 

명령어를 이용하면 무중단 배포가 가능하다. (우분투 터미널의 세션이 종료됐을 때도 멈추지 않고 실행이 가능하다.)

 

 

 

 

 

 

 

끝~

 

 

 

 

 

 

 

참고 블로그

 

https://velog.io/@byeongju/HTTPS-%EC%A0%81%EC%9A%A9%EA%B8%B0

 

HTTPS 적용기

Nginx를 통한 HTTPS 적용기

velog.io

 

 

https://martinnoh.tistory.com/m/entry/Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-https-%EC%97%B0%EA%B2%B0%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AC%B4%EB%A3%8C-ssl-%EC%A0%81%EC%9A%A9-%EB%B0%A9%EB%B2%95

 

Spring Boot 프로젝트에 https 연결을 위한 무료 ssl 적용 방법

API 사용을 위한 URL 등록이나 여러 이유로 도메인, https로만 작성을 해야하는 경우가 있다. Spring Boot에서 jar파일로 배포를 하면 http로 접속을 하게 되므로 SSL 인증서 발급과 적용 과정이 필요하다.

martinnoh.tistory.com

 

 

 

https://velog.io/@tritny6516/Spring-Boot-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0-Nginx-HTTPS-%EC%84%A4%EC%A0%95

 

Spring Boot 배포하기 (Nginx, HTTPS 설정)

Spring Boot Deploy with Nginx, Aws Route53, ACM

velog.io

 

 

https://velog.io/@dktlsk6/Spring-boot-Bad-Request-This-combination-of-host-and-port-requires-TLS