Nginx 는 대표적인 리버스 프록시 역할을 수행하는 웹 서버에 해당한다.
( 리버스 프록시는 크게 보면, 오리진 서버를 숨기기 위한 기술을 의미한다. 따라서 오리진 서버로 들어오는 요청에 대해 관리할 수 있고, 여러 보안과 관련된 처리(e.g. IP 제한 등)도 할 수 있게 된다. )
일반적으로 웹은 CS(Client-Server) 구조로 동작한다. 즉, 여러 클라이언트가 서버에 요청을 보내고 그에 대한 응답을 받는 구조를 가진다. 그런데 여기서, 클라이언트의 요청이 오리진 서버에 직접 닿게되면 보안상 취약할 수 있고, 서비스의 확장성이나 효율의 측면에서 봤을 때도 적절하지 않다.
그래서 일반적으로는 클라이언트의 트래픽을 오리진 서버가 직접 받는게 아니라, 앞에 프록시 서버를 구성하고, 해당 서버로부터 대신해서 요청을 받도록 하여, 보안적인 측면과 가용성 면에서도 더 용이하도록 구성한다. 뿐만 아니라 이를 통해 로드 밸런싱, 캐싱, SSL 등도 적용할 수 있다.
지금까지 필자는 현업에서 주로 Apache 를 사용했었지만, 직접 구성을 해보거나 설정을 해본 경험이 많지 않아, 이번 기회에 기본적인 학습을 진행해보려고 한다.
그리고 실무에서는 Apache 보다 성능상 더 뛰어난 Nginx 를 더 많이 사용하는 것 같아, Nginx 로 학습을 진행해보기로 결정했다.
처음 학습해보는 것이기에, 자주 사용하는 Nginx 의 문법과 기본적인 파일 구조, Nginx 활용 기술 위주로 알아보겠다.
sudo apt updatehttps://nginx.org/en/linux_packages.html#Ubuntu ) 를 참고하자.sudo apt updatesudo apt install nginxsudo systemctl start nginxsudo systemctl status nginxhttp://{EC2 IP 주소} 로 접속해보자.
Nginx 가 잘 실행되는 것을 확인할 수 있다.Nginx 는 클라이언트의 요청 시, 위 페이지(기본 페이지)를 띄우는데 필요한 기본적인 HTML, CSS, JS 파일들을 (다운받을 수 있도록) 제공한다. -> 물론 설정 파일 수정을 통해 변경할 수 있다.Nginx 로그 확인Nginx 의 로그 파일 위치는 /var/log/nginx/ 이다.access.logerror.logNginx 는 대표적으로 웹 서버(Web Server)로서 역할을 수행한다.
( 웹 서버(Web Server)는 일반적으로 사용자의 요청에 대한 HTML, CSS, JS, 이미지와 같은 정적 파일들을 제공하는 서버를 의미한다. )
다시말해, Nginx는 웹 서버로서, 사용자의 요청이 들어올 때마다 파일(HTML, CSS, JS, 이미지 등)을 제공할 수 있는 기능을 가지고 있다.
( 그리고 브라우저는 이렇게 다운받은 파일의 코드를 해석해서 웹 사이트를 화면에 띄우게 된다. )
Nginx 기본 설정/문법
/etc/nginx/nginx.conf/etc/nginx/conf.d/default.conf/etc/nginx/conf.d/default.conf 파일을 분석해보자.
localhost:80 가 아닌, http://{EC2의 IP 주소} 로 접속했는데도 불구하고, 위 설정이 적용됐다.server_name 이 일치하는 server 블럭이 없는 경우, 첫 번째 정의되어 있는 server{..} 블럭을 기반으로 처리한다.;)을 빠트려서 에러가 뜨는 경우가 많으니 주의하자. server{..} 블록에서 여러 코드의 순서가 섞여있더라도, 일반적으로 Nginx 는 listen, server_name 을 가장 먼저 확인한다.sudo nginx -t : Nginx 설정 파일 중 문법 에러가 있는 지 체크sudo nginx -s reload : Nginx 설정 파일을 변경한 경우, 해당 명령을 통해 변경된 설정 파일을 반영할 수 있다.1) (HTML, CSS, JS) 로 개발한 프로젝트 배포
github 에 머지된 소스코드를 clonecd /usr/share/nginxsudo git clone https://git주소nginx-frontend-html 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.cd /etc/nginx/conf.dsudo vi default.conf
sudo nginx -tsudo nginx -s reloadhttp://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.
2) (React + Vite)를 활용해서 개발한 프로젝트 배포
github 에 머지된 소스코드를 clonecd /usr/share/nginxsudo git clone https://git주소nginx-frontend-react 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.node -vcd /usr/share/nginx/nginx-frontend-reactsudo npm inode_modules 가 생성되고 그 내부에 설치된 패키지가 저장된다.sudo npm run builddist 라는 디렉토리가 생성되고, 그 내부에 빌드된 파일이 저장된다. ( 이제 이 파일들이 Nginx 웹 서버에 의해 제공되도록 해보자. )
cd /etc/nginx/conf.dsudo vi default.conf 를 다음과 같이 변경
/usr/share/nginx/nginx-frontend-react/dist ) sudo nginx -tsudo nginx -s reloadhttp://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.
3) (Next.js) 로 개발한 프로젝트 배포
github 에 머지된 소스코드를 clonecd /usr/share/nginxsudo git clone https://git주소nginx-frontend-next 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.cd nginx-frontend-nextsudo npm isudo npm run buildout 라는 디렉토리가 생성되고, 그 내부에 빌드된 파일이 저장된다. ( 이제 이 파일들이 Nginx 웹 서버에 의해 제공되도록 해보자. )
next.config.mjs )
cd /etc/nginx/conf.dsudo vi default.conf 를 다음과 같이 변경
/usr/share/nginx/nginx-frontend-next/out )sudo nginx -tsudo nginx -s reloadhttp://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.Nginx는 어떤 도메인 주소로 요청이 들어오냐에 따라서, 그에 맞는 웹 사이트로 응답할 수 있는 기능을 가지고 있다. ( Nginx의 입장에서는 shop.kr로 요청이 들어온 거랑 admin.shop.kr로 요청이 들어온 거랑 구별해서 웹 사이트를 보여줄 수 있어야 한다. )

soehapdlsgksrnr.p-e.kr, admin.soehapdlsgksrnr.p-e.kr 로 했고, 두 도메인 모두 같은 EC2 서버와 연결되도록 했다.soehapdlsgksrnr.p-e.kr 요청 시, react.js 관련 사이트를 제공할 것이고, admin.soehapdlsgksrnr.p-e.kr 요청 시, next.js 관련 사이트를 제공하도록 할 것이다.cd /etc/nginx/conf.dsudo vi default.conf 를 다음과 같이 변경
soehapdlsgksrnr.p-e.kr 경로로 요청된 경우, nginx-frontend-react/dist 에서 제공.admin.soehapdlsgksrnr.p-e.kr 경로로 요청된 경우, nginx-frontend-next/out 에서 제공.sudo nginx -tsudo nginx -s reloadhttp://soehapdlsgksrnr.p-e.kr / http://admin.soehapdlsgksrnr.p-e.kr 로 접속해보자.

Certbot 이라는 툴을 활용하면, HTTPS 를 쉽게 적용할 수 있다.
( Certbot은 Let’s Encrypt에서 무료 SSL/TLS 인증서를 발급하고 자동 갱신까지 도와주는 오픈소스 툴이다. 보통 HTTPS 인증서를 수동으로 발급하려면 꽤 복잡한 과정을 거쳐야 하는데, Certbot을 사용하면 명령어 몇 줄로 간단하게 인증서를 발급하고 적용할 수 있다. )
sudo snap install --classic certbotsudo ln -s /snap/bin/certbot /usr/bin/certbotsudo certbot --nginx -d <도메인 주소>sudo certbot --nginx -d soehapdlsgksrnr.p-e.krsudo certbot --nginx -d admin.soehapdlsgksrnr.p-e.krhttps://soehapdlsgksrnr.p-e.kr/https://admin.soehapdlsgksrnr.p-e.kr/http://soehapdlsgksrnr.p-e.kr/ 로 접근해보자. 그러면 https://soehapdlsgksrnr.p-e.kr/ 로 redirect 된다. /etc/nginx/conf.d/default.conf)에 여러 내용을 추가한다.80포트 로 온 요청에 대해서, https 로 리다이렉트 하는 내용이 포함되어 있다.soehapdlsgksrnr.p-e.kr 또는 admin.soehapdlsgksrnr.p-e.kr 와 같이) http:// 나 https:// 를 명시하지 않고 요청하면, 브라우저는 자동으로 http 로 요청한다.http 요청은 https 로 리다이렉트 된다.리버스 프록시를 활용해 Spring Boot 서버 배포하기
sudo apt update && / sudo apt install openjdk-17-jdk -yjava -versionsudo apt remove openjdk-17-jdkcd ~sudo git clone {Github 주소}nginx-backend-springboot 라 가정cd nginx-backend-springbootsudo ./gradlew clean build -x testcd build/libsnohup java -jar nginx-backend-springboot-0.0.1-SNAPSHOT.jar &lsof -i:8080 ( 8080번 포트에서 실행되고 있는 프로세스 조회 )cd /etc/nginx/conf.d/websitessudo vi api.backend.conf
cd /etc/nginx/conf.d/default.conf 내부에 api.backend.conf include 추가sudo nginx -tsudo nginx -s reloadapi.soehapdlsgksrnr.p-e.kr 추가
api.soehapdlsgksrnr.p-e.kr 접근 )

sudo certbot --nginx -d api.soehapdlsgksrnr.p-e.kr/etc/nginx/conf.d/websites/api.backend.conf 를 보면, Certbot이 HTTPS 인증서를 발급받는 과정에서 설정파일에 여러 내용을 추가한 것을 확인할 수 있다. ( 80포트로 온 요청에 대해서, https 로 리다이렉트 되도록 )https://api.soehapdlsgksrnr.p-e.kr 로 접근하여 HTTPS 잘 적용된 것을 확인해보자.
로드 밸런서(Load Balancer) 란 트래픽을 적절하게 분배해주는 장치를 의미한다.
Nginx 는 로드 밸런서(Load Balancer) 역할을 할 수 있는 기능을 가지고 있다.

cd ~/nginx-backend-springboot/build/libsnohup java -jar nginx-backend-springboot-0.0.1-SNAPSHOT.jar --server.port=8081 &lsof -i:8081cd /etc/nginx/conf.d/websitessudo vi api.backend.conf
api.soehapdlsgksrnr.p-e.kr 로 요청이 오면, upstream 에서 정의한 서버로 알아서 분배해준다.sudo nginx -tsudo nginx -s reloadhttps://api.soehapdlsgksrnr.p-e.kr/health 로 접근해보자.
/health 에 대한 코드는 다음과 같다. ( 각 서버에서 고유한 ID를 출력하도록 )
✔️ 참고
default.conf 에서 이를 include 할 수 있다. ( include 시 와일드카드 사용 가능 )
강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 JSCODE 박재성 강사님께 있습니다.