이번에는 Spring Boot프로젝트를 Nginx 웹서버와 함께 HTTPS 설정까지 완료하는 과정입니다.
Java 8 설치
저의 경우 프로젝트는 Java 8버전으로 실행되고 있습니다. 각 프로젝트에 맞는 버전의 Java를 설치합니다.
sudo apt -y install {Spring Boot 개발 환경에 맞는 버전의 JDK or JRE 패키지}
sudo apt install openjdk-11-jre-headless
Maven 설치
EC2 인스턴스에 로그인을 한 후 spring Boot를 배포하기 위해서 Java8과 Maven을 설치가 안되여 있으면 설치합니다.
wget maven 다운 링크를 다음의 명령어로 실행합니다.
wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
다운이 잘 되었으면 다음의 명령어로 파일을 풀어줍니다.
tar xvfs apache-maven-3.6.3-bin.tar.gz
파일을 푼 후 환경변수를 설정하기 이전에 maven 파일들을 maven이라는 폴더를 마들고 그 폴더에 옮긴 후 시작하겠습니다.
mkdir ./maven
mv ./apache-maven-3.6.3 ./maven
mv ./apache-maven-3.6.3-bin.tar.gz ./maven
환경변수를 설정하기 위해 계정의 home으로 오고 .bash_profile
을 오픈합니다.
cd ~
vi .bash_profile
그 후에 다음과 같이 입력합니다.
MAVEN_HOME=/home/ec2-user/maven/apache-maven-3.6.3
PATH=$PATH:$MAVEN_HOME/bin
export MAVEN_HOME
이제 변경한 .bash_progile
파일을 반영하고 잘 작동하는지 다음의 명령어로 확인합니다.
sudo apt-get install maven
라는 명령어를 통해서도 설치할 수 있습니다. 단 E: unable to locate package maven
에러가 발생할 수도 있는데 다음의 명령어를 입력해 update를 한 후 install을 합니다.
sudo apt-get install software-properties-common
sudo apt-add-repository universe
sudo apt-get update
sudo apt-get install maven
우분투 서버로 접속한 다음 Git Clone을 통해 프로젝트 코드를 가져오도록 합니다.
만약 application.yml
또는 application.yml
이 없을 경우 새로 파일을 만들어서 설정을 넣어줍니다.
이제 준비는 다 되었고, Maven을 패키지해서 배포하면 됩니다.
pom.xml
이 있는 폴더로 와서 다음의 명령어를 실행합니다.
테스트가 없을 때
mvn package
테스트가 있을 때
mvn package -Dmaven.test.skip=true
gradle build -x test
그러면 아래의 사진과 같이 target
이라는 폴더가 하나 생성된 것을 확인할 수 있습니다.
그리고 target이라는 폴더를 들어가면 ~~.jar
이라는 형식의 파일을 하나 볼 수 있습니다.
Gradle : ~프로젝트 경로/build/libs
이제 jar를 파일을 실행해보겠습니다. 개발환경 파트에서 포트번호가 8088이라고 보안그룹에서 8088 포트를 인바운드 규칙에 추가하였습니다.
다음의 명령어를 입력해 배포파일을 실행해봅니다.
java -jar ~~~.jar
그리고 퍼블릭 IPv4주소에 8088 포트번호 주소를 입력하면 프로젝트가 잘 실행되는 것을 볼 수 있습니다.
기본 Nginx 설정 파일을 보면 Forward(순방향) Proxy임을 확인할 수 있습니다. Forward Proxy는 경로로 들어오는 경우, root에 지정된 경로에 따라 일치하는 파일로 이동하여 웹에서 내용을 보여줍니다. 하지만 Nginx 서버에서 Reverse Proxy
기능도 제공합니다.
Reverse Proxy
는 Forward Proxy
와는 다르게 외부에서 내부 서버가 제공하는 서비스를 접근할 때, proxy 서버를 먼저 거쳐 내부 서버로 들어오는 방식입니다. 그리고 외부 클라이언트는 실제 내부 서버의 존재를 모릅니다.
그리고 모든 접속은 Reverse Proxy
서버에게 들어오며, Reverse Proxy 서버는 요청에 맵핑되는 서버의 정보에게 요청을 넘깁니다. 이로써 내부 서버의 정보를 외부로부터 감추루 수 있기 떄문에 보안이 높아집니다. 또 proxy 서버가 내부 서버의 정보를 알고 있으므로 로드밸런싱을 통해 부하 여부에 따라 요청을 분배할 수 있습니다. Proxy 서버를 사용하여 캐싱 기능과 트래칙 분산 기능을 결합시켜 전반적인 서버 성능의 향상 또한 기대할 수 있습니다. 참고로 Nginx는 서버가 부팅될 때 자동으로 시작됩니다.
Apache
는 프로세스를 fork하거나 쓰레드를 사용하지만,
Nginx
는 CPU와 관계없이 IO들을 전부 Event Listener로 미루기 때문에 흐름이 끊기지 않고 응답이 빠른 작업이 가능합니다.
추가적으로 Nginx
는 Apache
와 달리 동시접속자 수가 많아져도 추가적인 생성비용이 들지 않고, 메모리적인 측면에서 Nginx
가 System Resource를 적게 처리한다는 장점이 있습니다.
nginx -t
nginx 설정 파일의 문법이 올바른지 확인
sudo service nginx status
nginx 상태 확인
sudo service nginx start
nginx 실행
sudo service nginx restart
중지 후 재실행
sudo servcie nginx reload
수정된 파일 적용하여 연결을 끊지 않고 재실행
sudo service nginx stop
nginx 중지
sudo service disable nginx
자동 시작 비활성화
sudo service enable nginx
자동 시작 활성화
Nginx를 설치하기 위해 다음의 명령어를 입력합니다.
sudo apt-get update
sudo apt install nginx -y
nginx -v
: Nginx 버전 확인
sudo service nginx status
: Nginx 상태 확인
만약 active상태가 아니라면 sudo service nginx start
커맨드를 입력해 서버를 실행합니다.
퍼블릭 IP주소를 입력하면 아래의 이미지처럼 Nginx 기본 페이지가 출력됩니다.
그리고 개발자 도구에서 Network 요청을 보면 원격 주소의 포트가 80
임을 알 수 있습니다.
이제 Nginx를 통해 HTTP 80번 포트를 접속했을 때 8088번 포트로 리다이렉트를 할 수 있도록 하겠습니다.
Nginx 웹 서버를 사용할 때 서버블록을 사용해 구성 세부 정보를 캡슐화하고 단일 서버에서 둘 이상의 도메인을 호스팅할 수 있습니다. 단일 사이트를 호스팅하는 경우 기본적으로 활성화된 서버 블록인 /var/www/html
을 활용하면 되지만, 여러 사이트를 호스팅할 경우 /var/www/{domain}/html
과 같은 방식으로 디렉토리 구조를 수정해 적용할 수 있습니다.
Nginx 파일 및 디렉토리
/var/www/html
: 기본적으로 기본 Nginx 페이지가 있습니다. Nginx 구성 파일을 변경 수 있습니다.
/etc/nginx/nginx.conf
기본 Nginx 구성 파일입니다. Nginx 전역 구성을 변경하도록 수정할 수 있습니다.
/etc/nginx/sites-available/
사이트별로 서버 블록을 저장할 수 있는 디렉토리입니다. Nginx는 sites-enabled
디렉토리에 연결되지 않은 경우 이 디렉토리의 구성 파일을 사용하지 않습니다. 일반적으로 sites-available
디렉토리에서 서버 블록이 구성된 후에 다른 디렉토리에 연결되어 사용할 수 있게 됩니다.
/etc/nginx/sites-enabled
활성화된 사이트별 서버 블록이 저장되는 디렉토리입니다. 일반적으로 sites-available
디렉토리에 있는 구성파일에 연결해 생성됩니다.
/var/log/nginx/access.log
별도로 구성되지 않는 한 웹 서버에 대한 모든 요청이 기록됩니다.
/var/log/nginx/error.log
모든 Nignx 오류가 기록됩니다.
sudo mkdir /var/log/nginx/proxy/ # log, error 파일이 들어갈 디렉토리 생성
sudo vi /etc/nginx/proxy_params
포트번호가 80인 http에서 요청이 오면, Spring Boot 프로젝트에서 8088번 포트를 바라볼 수 있도록 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;
다음으로 서버 블록을 생성하기 위해선 도메인이 필요한데, 가비아, 또는 freenom 사이트에서 도메인을 구매합니다. freenom으로 도메인을 등록하는 경우는 이 블로그를 참고하면 되겠습니다.
저의 경우 가비아를 이용해 도메인을 결제했는데요, 정상적으로 결제 하시면 우측 상단에 My가비아에 들어가시면 아래와 같이 잘 추가된 것을 볼 수 있습니다.
이제 도메인 준비는 끝났고 적용할 차례입니다.
다음은 구매한 도메인을 Route 53을 통해 만든 EC2 인스턴스와 연결해 주어야 합니다. 먼저 EC2 콘솔에 들어가셔서 등록하고자 하는 인스턴스의 IPv4 퍼블릭 주소가 필요합니다.
Route 53에 들어가줍니다. 그리고 좌측 메뉴에 좌측 메뉴에서 호스팅 영역으로 들어가 준 뒤, 호스팅 영역 생성을 선택하면 우측에 창이 뜨는데요, 아래의 사진처럼 도메인 이름에 구매한 도메인 이름을 입력해줍니다.
도메인 이름은 구매한 도메인을 넣으시고 설명은 자유롭게 작성하고 유형은 퍼블릭 호스팅 영역으로 생성합니다. 생성된 호스팅 영역을 클릭하면 레코드를 생성할 수 있는데, 레코드 생성 버튼을 눌러줍니다.
이름에는 연결하고 싶은 주소를 입력해주시면 되는데, 비운다면 예)yourdomain.com 주소로 연결이 되고 www를 붙여 연결하고 싶으시면 이름에 www를 입력하시면 됩니다. 그리고 아래 값 부분에 아까 기록해둔 EC2 인스턴스의 퍼블릭 IPv4 주소를 입력합니다. 이로써 이름의 주소에 그 인스턴스를 연결이 완료되었습니다.
그러면 다음과 같이 레코드 세트가 총 3개가 됩니다.
이제 네임 서버를 변경해주어야 합니다. 유형이 NS인 레코드를 선택하시면 총 4개의 값/트래픽 라우팅 대상이 들어가 있는 것을 확인할 수가 있는데요, 아래와 같이 네임서버들을 가비아에 있는 여러분이 구매한 도메인의 네임서버로 바꿔주시면 됩니다.
이로써 도메인 추가가 완료되었습니다. 해당 도메인을 연결해서 사용할 수 있습니다.
현재 가지고 있는 도메인과 jar 파일을 이용하기 위해서 기본 구성 파일을 수정해 서버 블록을 생성해주겠습니다.
명령어 sudo vi /etc/nginx/sites-available/{domain}
를 입력 후, 아래 코드를 복사해 붙여넣어줍니다. (저의 경우 sudo vi /etc/nginx/sites-available/springworld.site
로 입력하였습니다.)
server { # server 블록
listen 80;
server_name {domain} www.{domain};
access_log /var/log/nginx/proxy/access.log;
error_log /var/log/nginx/proxy/error.log;
location / { # location 블록
include /etc/nginx/proxy_params;
proxy_pass http://{퍼블릭IP주소}:8088; # reverse proxy의 기능
}
}
이 코드를 추가하면서 location 블록의 proxy_pass
를 통해 8088번 포트를 통해 접속해야 볼 수 있는 화면(Spring Boot 프로젝트 화면)을 80번(HTTP) 포트에 접속했을 때 확인할 수 있도록 설정, 즉 Reverse proxy
의 기능을 하게 할 수 있습니다.
Nginx는 이제 listen 지시문에 의해 포트 번호 80으로 들어오는 요청들에 대해 server_name 값과 정확하게 일치하는 서버 블록을 찾으려고 시도합니다. 만약 server_name을 추가할 때 해시 버킷 메모리 문제가 발생할 수 있기에 /etc/nginx/nginx.conf
파일에서 옵션을 조정하였습니다.
http { ...
server_names hash_bucke_size 64; # 주석 처리를 제거
...
}
서버블록까지 생성하였으니 새로 생성한 파일을 활성화해보도록 하겠습니다.
sites-available
디렉토리로부터 site-enabled 디렉토리에 대한 링크를 생성해 파일을 활성화합니다.
sudo ln -s /etc/nginx/sites-available/{domain} /etc/nginx/sites-enabled/
기본 구성 파일 삭제
sites-available 디렉토리와 sites-enabled 디렉토리에서 명령어 ls -al
을 실행해보면 원래 nginx 서버를 연결하던 default 파일이 새로 생성한 파일과 함께 보입니다.
이대로 연결하면 연결이 되지 않기 때문에 Default 파일을 삭제합니다.
sudo rm /etc/nginx/sites-available/default
sudo rm /etc/nginx/sites-enabled/default
Nginx에 대해 구문 오류가 없는지 테스트하고, Spring Boot 프로젝트와 함께 재시작해보겠습니다.
sudo nginx -t
sudo service nginx reload
java -jar {jar 파일명}.jar
그리고 도메인 주소(http://springworld.site)로 들어가면 정상 작동됨을 확인할 수 있습니다.
무중단 배포(백그라운드 실행)
nohup + &
명령어로 우분투 터미널의 세션 연결이 종료됐을 때도 jar 파일을 멈추지 않고 실행할 수 있습니다.
nohup java -jar {jar 파일명}.jar &
AWS Certificate Manager를 이용해 SSL 인증서를 발급하고 nginx에 적용하여 HTTPS 주소로 웹 페이지를 운영할 수 있도록 해보겠습니다. (아래의 과정으로 과금이 발생할 수도 있습니다!)
인증서 발급기관은 유료인증기관, letsencrypt 등 다양한 기관에서 발급받을 수 있지만 AWS Certificate Manager에선 무료로 발급받을 수 있고, 웹사이트 접속에 문제가 없다는 가정하에 인증서가 자동 갱신되고 유지보수가 수월하다는 장점이 있습니다(letsencrypt의 경우 3개월마다 갱신). 단 로드밸런서에 ACM을 넣게 되는데 로드밸런서를 이용하면서 트래픽에 따른 과금이 발생합니다.
인증서는 웹서버(Nginx)에 설치되지 않고 ALB(AWS LoadBalancer)에 연결되기 때문에,
사용자가 도메인을 요청하면 바로 EC2(웹서버)로 넘어가지 않고 ALB로 이동되며 ALB를 통해 EC2로 향하게 됩니다. 따라서 443 포트를 연결해 포워딩을 하지 않아도 됩니다!
먼저, AWS에서 Certificate Manager 서비스로 들어갑니다. 그리고 인증서 요청 버튼을 누릅니다.
발급받았던 도메인을 입력하고 DNS 검증을 선택하고 태그는 선택적으로 추가하시면 됩니다. 그리고 입력한 내용들에 틀린 부분은 없는지 확인하고 확인 및 요청을 누릅니다.
그러면 아래와 같이 검증을 시작하고 승인을 받으려면 추가적인 작업이 필요합니다. 아래 사진처럼 Route 53에서 레코드 생성을 눌러주세요.
그 뒤 Route 53에 자신의 도메인을 클릭하면 아래와 같이 레코드 세트가 추가된 것을 볼 수 있습니다. 그리고 최대 30분 정도 승인요청이 소요될 수 있습니다.
다음은 EC2 로드 밸런서 설정을 해야합니다. EC2 서비스에 들어가서 좌측 메뉴에서 로드 밸런서를 들어가주세요. 그리고 로드 밸런서 생성을 클릭합니다.
왼쪽 상단의 로드밸런서 생성을 선택합니다.
Application Load Balancer
으로 생성해도 되지만 영문과 복잡한 구조로 되어있기 때문에, Classic Load Balance
으로 생성합니다. Classic으로 생성한 후 마법사를 돌리면 Application Load Balancer
과 같은 결과를 가져다 줍니다.
Load Balancer 이름 작성 후 HTTPS(보안 HTTP)를 선택해 아래 사진과 같도록 합니다.
그다음 EC2 인스턴스의 보안그룹을 선택해 주시고 다음을 누릅니다.
그리고 ACM에서 인증서 선택창을 누르고 이전에 발급받았던 인증서를 선택합니다.
그리고 상태 검사를 구성으로 넘어오게 되는데, 변경할 것은 없습니다.
그리고 프로젝트가 있는 EC2 인스턴스를 적용할 인스턴스로 추가해주세요.
마지막으로 태그를 추가할 것이 있다면 추가하고 검토 및 생성합니다.
클래식 로드밸런서로 생성했는데, 차세대 로드밸런서로 선택하기 위해 사진에서 보이는 것처럼 지금 마이그레이션을 선택하면 차세대 로드밸런서로 사용할 수 있습니다.(마이그레이션 후 기존의 클래식 로드밸런서는 삭제!)
Route 53 설정
다시 Route 53 서비스의 등록한 도메인 호스팅 영역에서 유형 A의 레코드 세트를 선택하고, 별칭을 예로 선택하신 뒤, 별칭 대상에서 만든 로드 밸런서를 선택하여 줍니다. 그리고 저장해주세요.
그리고 마지막으로 프로젝트가 있는 EC2 인스턴스의 보안그룹에서 HTTPS 포트를 열어줍니다.
이제 거의 다 되었습니다./etc/nginx/sites-available/springworld.site
에서 HTTP 요청을 HTTPS 로 받아 처리할 수 있도록 코드만 추가하면 됩니다. 사진과 같이 아래의 코드(if문)를 추가해주세요!
sudo vi /etc/nginx/sites-available/springworld.site`
위의 명령어를 입력하고 if문을 추가합니다.
if ($http_x_forwarded_proto = 'http'){
return 301 https://$host$request_uri;
}
그리고 설정값이 변경되었으니 아래의 명령어를 입력해줍니다.
$ sudo ln -sf /etc/nginx/sites-available/{domain} /etc/nginx/sites-enabled/
nginx도 한번 껐다 켜줍시다.
$ sudo systemctl daemon-reload && sudo systemctl restart nginx
그리고 https://도메인.주소
로 들어가보시면 잘 적용이 된 것을 볼 수가 있습니다!!
끝!