박재성 - Nginx 입문/실전

김수호·2025년 3월 4일
0
post-thumbnail

Nginx 는 대표적인 리버스 프록시 역할을 수행하는 웹 서버에 해당한다.
( 리버스 프록시는 크게 보면, 오리진 서버를 숨기기 위한 기술을 의미한다. 따라서 오리진 서버로 들어오는 요청에 대해 관리할 수 있고, 여러 보안과 관련된 처리(e.g. IP 제한 등)도 할 수 있게 된다. )

일반적으로 웹은 CS(Client-Server) 구조로 동작한다. 즉, 여러 클라이언트가 서버에 요청을 보내고 그에 대한 응답을 받는 구조를 가진다. 그런데 여기서, 클라이언트의 요청이 오리진 서버에 직접 닿게되면 보안상 취약할 수 있고, 서비스의 확장성이나 효율의 측면에서 봤을 때도 적절하지 않다.

그래서 일반적으로는 클라이언트의 트래픽을 오리진 서버가 직접 받는게 아니라, 앞에 프록시 서버를 구성하고, 해당 서버로부터 대신해서 요청을 받도록 하여, 보안적인 측면과 가용성 면에서도 더 용이하도록 구성한다. 뿐만 아니라 이를 통해 로드 밸런싱, 캐싱, SSL 등도 적용할 수 있다.

지금까지 필자는 현업에서 주로 Apache 를 사용했었지만, 직접 구성을 해보거나 설정을 해본 경험이 많지 않아, 이번 기회에 기본적인 학습을 진행해보려고 한다.

그리고 실무에서는 Apache 보다 성능상 더 뛰어난 Nginx 를 더 많이 사용하는 것 같아, Nginx 로 학습을 진행해보기로 결정했다.

처음 학습해보는 것이기에, 자주 사용하는 Nginx 의 문법과 기본적인 파일 구조, Nginx 활용 기술 위주로 알아보겠다.


Nginx 설치 및 실행

  • 참고) AWS EC2 인스턴스를 생성하여 실습을 진행한다.
  • ( Ubuntu 환경 ) Nginx 설치
    • 패키지 목록을 최신 상태로 업데이트
      • sudo apt update
    • nginx 설치에 필요한 라이브러리 설치
      • ( https://nginx.org/en/linux_packages.html#Ubuntu ) 를 참고하자.
    • nginx 설치
      • sudo apt update
      • sudo apt install nginx
  • Nginx 실행
    • sudo systemctl start nginx
  • Nginx 상태 확인 ( Nginx가 정상적으로 실행되고 있는 지 체크 )
    • sudo systemctl status nginx
  • http://{EC2 IP 주소} 로 접속해보자.
    • Nginx 가 잘 실행되는 것을 확인할 수 있다.
    • 참고) Nginx 는 클라이언트의 요청 시, 위 페이지(기본 페이지)를 띄우는데 필요한 기본적인 HTML, CSS, JS 파일들을 (다운받을 수 있도록) 제공한다. -> 물론 설정 파일 수정을 통해 변경할 수 있다.
  • 참고) Nginx 로그 확인
    • Nginx 의 로그 파일 위치는 /var/log/nginx/ 이다.
      • 해당 디렉터리에는 크게 2개의 파일이 있다.
      • ① Nginx 서버로 접근한 클라이언트 요청에 대한 정보: access.log
      • ② Nginx 서버에서 발생한 에러에 대한 정보: error.log

Nginx 설정

Nginx 는 대표적으로 웹 서버(Web Server)로서 역할을 수행한다.
( 웹 서버(Web Server)는 일반적으로 사용자의 요청에 대한 HTML, CSS, JS, 이미지와 같은 정적 파일들을 제공하는 서버를 의미한다. )

다시말해, Nginx는 웹 서버로서, 사용자의 요청이 들어올 때마다 파일(HTML, CSS, JS, 이미지 등)을 제공할 수 있는 기능을 가지고 있다.
( 그리고 브라우저는 이렇게 다운받은 파일의 코드를 해석해서 웹 사이트를 화면에 띄우게 된다. )

Nginx 기본 설정/문법

  • Nginx 는 크게 2가지 설정 파일이 존재한다.
    • /etc/nginx/nginx.conf
      • Nginx에서 가장 근본이 되는 설정 파일(루트 설정 파일)
      • 전역적으로 설정되어야 하는 내용(워커 프로세스 개수, 로그 저장 위치 등)이 포함되어 있다.
    • /etc/nginx/conf.d/default.conf
      • 기본 웹 서버(Web Server) 설정 파일
  • /etc/nginx/conf.d/default.conf 파일을 분석해보자.
    • 참고) 그런데 위에서 필자는 localhost:80 가 아닌, http://{EC2의 IP 주소} 로 접속했는데도 불구하고, 위 설정이 적용됐다.
      • NGINX 기본 작동 원리 : 위 주석에서도 작성된 것 처럼, NGINX 는 server_name 이 일치하는 server 블럭이 없는 경우, 첫 번째 정의되어 있는 server{..} 블럭을 기반으로 처리한다.
    • 참고) 설정 파일을 작성할 때 세미 콜론(;)을 빠트려서 에러가 뜨는 경우가 많으니 주의하자.
    • 참고) server{..} 블록에서 여러 코드의 순서가 섞여있더라도, 일반적으로 Nginx 는 listen, server_name 을 가장 먼저 확인한다.
  • 참고) 기본 명령
    • sudo nginx -t : Nginx 설정 파일 중 문법 에러가 있는 지 체크
    • sudo nginx -s reload : Nginx 설정 파일을 변경한 경우, 해당 명령을 통해 변경된 설정 파일을 반영할 수 있다.

Nginx 웹 서버를 활용하여 프론트엔드 배포하기

1) (HTML, CSS, JS) 로 개발한 프로젝트 배포

  • 프로젝트를 EC2에 가져오기: github 에 머지된 소스코드를 clone
    • cd /usr/share/nginx
    • sudo git clone https://git주소
    • 참고) 받아온 디렉터리를 nginx-frontend-html 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.
  • Nginx 설정 파일 수정하기: Nginx 에 내장되어 있는 웹 서버 기능으로 나의 정적 파일이 제공(서빙)되도록 설정 파일 수정
    • cd /etc/nginx/conf.d
    • sudo vi default.conf
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • 결과 확인
    • http://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.

 

2) (React + Vite)를 활용해서 개발한 프로젝트 배포

  • 프로젝트를 EC2에 가져오기: github 에 머지된 소스코드를 clone
    • cd /usr/share/nginx
    • sudo git clone https://git주소
    • 참고) 받아온 디렉터리를 nginx-frontend-react 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.
  • 그런데 React 프로젝트는 빌드를 해야한다. 그리고 빌드를 위해서는 node.js 가 필요하다. 따라서 먼저 node.js를 설치하자.
    • node.js 설치
      • 설치 과정은 강의를 참고하자.
      • 참고) node.js 설치 확인: node -v
        • 참고) 버전 정보가 나오면 정상적으로 설치된 것이다.
    • React 프로젝트 빌드하기
      • cd /usr/share/nginx/nginx-frontend-react
      • 의존성 설치
        • sudo npm i
        • 참고) 수행하면 현재 디렉토리 내부에 node_modules 가 생성되고 그 내부에 설치된 패키지가 저장된다.
      • 빌드
        • sudo npm run build
        • 참고) 빌드가 완료되었다면 dist 라는 디렉토리가 생성되고, 그 내부에 빌드된 파일이 저장된다. ( 이제 이 파일들이 Nginx 웹 서버에 의해 제공되도록 해보자. )
  • 웹 서버 설정 파일 변경
    • cd /etc/nginx/conf.d
    • sudo vi default.conf 를 다음과 같이 변경
      • 빌드된 파일 경로로 변경한다. ( /usr/share/nginx/nginx-frontend-react/dist )
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • 결과 확인
    • http://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.

 

3) (Next.js) 로 개발한 프로젝트 배포

  • 프로젝트를 EC2에 가져오기: github 에 머지된 소스코드를 clone
    • cd /usr/share/nginx
    • sudo git clone https://git주소
    • 참고) 받아온 디렉터리를 nginx-frontend-next 라 가정하고, 클라이언트가 루트 경로로 요청시 해당 디렉토리 내부의 index.html 를 제공하도록 하자.
  • 그런데 Next.js 프로젝트는 빌드를 해야한다. 그리고 빌드를 위해서는 node.js 가 필요하다. 따라서 먼저 node.js를 설치하자.
    • node.js 설치
      • 위에서 이미 설치했다.
    • Next.js 프로젝트 빌드하기
      • cd nginx-frontend-next
      • 의존성 설치
        • sudo npm i
        • 참고) 수행하면 현재 디렉토리 내부에 node_modules 가 생성되고 그 내부에 설치된 패키지가 저장된다.
      • 빌드
        • sudo npm run build
        • 참고) 빌드가 완료되었다면 out 라는 디렉토리가 생성되고, 그 내부에 빌드된 파일이 저장된다. ( 이제 이 파일들이 Nginx 웹 서버에 의해 제공되도록 해보자. )
        • 참고) 빌드한 결과물이 정상적으로 생성되려면 아래와 같이 설정해야 한다. ( next.config.mjs )
  • 웹 서버 설정 파일 변경
    • cd /etc/nginx/conf.d
    • sudo vi default.conf 를 다음과 같이 변경
      • 빌드된 파일 경로로 변경한다. ( /usr/share/nginx/nginx-frontend-next/out )
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • 결과 확인
    • http://{EC2 IP 주소} 로 접속해보자. -> 내가 개발한 화면이 노출되면 정상이다.

하나의 EC2 서버에서, 다른 도메인을 가진 여러 웹 사이트 배포하기 (멀티 도메인)

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 관련 사이트를 제공하도록 할 것이다.
      • 즉, 도메인 주소에 따라서 각각 다른 웹 페이지가 제공되도록 만들 것이다.
    • 참고) 필자는 무료 도메인을 사용했지만, 실제 운영되는 서비스에 무료 도메인을 사용하기에는 안정성의 측면에서 적절하지 않다.
      • AWS Route53, 가비아 등 도메인을 발급하고 관리해주는 DNS(Domain Name System) 서비스가 있으니 참고하자.
  • Nginx 설정 수정
    • cd /etc/nginx/conf.d
    • sudo vi default.conf 를 다음과 같이 변경
      • 80번 포트의 soehapdlsgksrnr.p-e.kr 경로로 요청된 경우, nginx-frontend-react/dist 에서 제공.
      • 80번 포트의 admin.soehapdlsgksrnr.p-e.kr 경로로 요청된 경우, nginx-frontend-next/out 에서 제공.
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • 결과 확인
    • http://soehapdlsgksrnr.p-e.kr / http://admin.soehapdlsgksrnr.p-e.kr 로 접속해보자.
  • 전체 구조 정리

Nginx, Certbot 을 활용한 HTTPS 적용

Certbot 이라는 툴을 활용하면, HTTPS 를 쉽게 적용할 수 있다.
( Certbot은 Let’s Encrypt에서 무료 SSL/TLS 인증서를 발급하고 자동 갱신까지 도와주는 오픈소스 툴이다. 보통 HTTPS 인증서를 수동으로 발급하려면 꽤 복잡한 과정을 거쳐야 하는데, Certbot을 사용하면 명령어 몇 줄로 간단하게 인증서를 발급하고 적용할 수 있다. )

  • Certbot 설치
    • sudo snap install --classic certbot
    • sudo ln -s /snap/bin/certbot /usr/bin/certbot
  • HTTPS 인증서 발급받기
    • sudo certbot --nginx -d <도메인 주소>
      • ex) sudo certbot --nginx -d soehapdlsgksrnr.p-e.kr
      • ex) sudo certbot --nginx -d admin.soehapdlsgksrnr.p-e.kr
    • 이렇게 하면 해당 도메인에 대한 HTTPS 적용은 끝난다. 수동으로 하면 복잡한 과정을 거치지만, Certbot 은 이러한 많은 과정을 자동화해준다.
    • 참고) IP 주소에는 HTTPS 적용을 할 수 없다. 도메인 주소가 있어야만 HTTPS 적용을 할 수 있다. 그리고 각 도메인마다 인증서는 따로 발급받아야 한다.
  • 잘 적용되었는지 확인해보자.
    • https://soehapdlsgksrnr.p-e.kr/
    • https://admin.soehapdlsgksrnr.p-e.kr/
    • 정상적으로 접속된 것을 확인할 수 있다.
  • 참고) http://soehapdlsgksrnr.p-e.kr/ 로 접근해보자. 그러면 https://soehapdlsgksrnr.p-e.kr/redirect 된다.
    • 그 이유는 다음과 같다.
      • HTTPS 인증서를 발급받으면, 그 과정에서 Certbot이 설정파일(/etc/nginx/conf.d/default.conf)에 여러 내용을 추가한다.
      • 그 내용 중에서는, 80포트 로 온 요청에 대해서, https 로 리다이렉트 하는 내용이 포함되어 있다.
  • 참고) (soehapdlsgksrnr.p-e.kr 또는 admin.soehapdlsgksrnr.p-e.kr 와 같이) http://https:// 를 명시하지 않고 요청하면, 브라우저는 자동으로 http 로 요청한다.
    • 그러면 Nginx 설정에 따라, http 요청은 https 로 리다이렉트 된다.
    • 참고로 크롬, 파이어폭스 등 최신 브라우저는 HTTPS 우선 모드를 사용 ( HTTPS 를 먼저 시도 )

Nginx의 리버스 프록시(Reverse Proxy) 기능을 활용해 백엔드 서버 배포

리버스 프록시를 활용해 Spring Boot 서버 배포하기

  • JDK 17 설치하기
    • sudo apt update && / sudo apt install openjdk-17-jdk -y
    • 참고) 잘 설치됐는 지 확인하기
      • java -version
    • 참고) 설치된 Java를 제거하기
      • sudo apt remove openjdk-17-jdk
  • Github으로부터 Spring Boot 프로젝트 clone 받기
    • cd ~
    • sudo git clone {Github 주소}
      • 프로젝트가 nginx-backend-springboot 라 가정
    • cd nginx-backend-springboot
  • Spring Boot 서버 실행시키기
    • sudo ./gradlew clean build -x test
    • cd build/libs
    • nohup java -jar nginx-backend-springboot-0.0.1-SNAPSHOT.jar &
    • 참고) Spring Boot 서버가 잘 작동하는 지 확인하기
      • lsof -i:8080 ( 8080번 포트에서 실행되고 있는 프로세스 조회 )
  • Nginx 설정 파일 작성
    • cd /etc/nginx/conf.d/websites
    • sudo vi api.backend.conf
    • cd /etc/nginx/conf.d/
    • default.conf 내부에 api.backend.conf include 추가
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • 도메인 설정 변경하기
    • api.soehapdlsgksrnr.p-e.kr 추가
  • 리버스 프록시 설정이 잘 적용됐는 지 확인해보자. ( api.soehapdlsgksrnr.p-e.kr 접근 )
    • 도메인 주소를 통해 백엔드 서버와 통신이 잘 되는 걸 확인했다.
  • (Spring Boot 백엔드 서버에) HTTPS 적용
    • HTTPS 인증서 발급
      • sudo certbot --nginx -d api.soehapdlsgksrnr.p-e.kr
      • 참고) /etc/nginx/conf.d/websites/api.backend.conf 를 보면, Certbot이 HTTPS 인증서를 발급받는 과정에서 설정파일에 여러 내용을 추가한 것을 확인할 수 있다. ( 80포트로 온 요청에 대해서, https 로 리다이렉트 되도록 )
  • (Spring Boot 백엔드 서버에) HTTPS 적용 확인
    • https://api.soehapdlsgksrnr.p-e.kr 로 접근하여 HTTPS 잘 적용된 것을 확인해보자.
    • 참고) (당연한 내용이지만) 도메인을 먼저 등록하고 HTTPS 를 적용해야 한다.
  • 참고) 프록시 서버(Proxy Server)는 다양한 형태로 구성할 수 있다. 따라서 다음과 같이 EC2를 별도로 구성해도 무관하다.

Nginx를 로드 밸런서(Load Balancer)로 사용하기

로드 밸런서(Load Balancer) 란 트래픽을 적절하게 분배해주는 장치를 의미한다.

Nginx로드 밸런서(Load Balancer) 역할을 할 수 있는 기능을 가지고 있다.

  • 참고) 강의에서는 하나의 EC2에 백엔드 서버 2개를 띄워 로드밸런싱하여 학습한다.
  • EC2에 백엔드 서버(Spring Boot) 2개 띄우기
    • 이전에 8080번 포트로 Spring Boot 서버를 실행시켜둔 상태이니, 8081번 포트에 추가적으로 Spring Boot를 띄울 수 있도록 하자.
    • cd ~/nginx-backend-springboot/build/libs
    • nohup java -jar nginx-backend-springboot-0.0.1-SNAPSHOT.jar --server.port=8081 &
    • 참고) 8081번 포트에 Spring Boot 서버가 잘 띄워졌는 지 확인
      • lsof -i:8081
  • Nginx 설정 변경
    • cd /etc/nginx/conf.d/websites
    • sudo vi api.backend.conf
      • 참고) 관련없는 내용은 생략했다.
      • 참고) api.soehapdlsgksrnr.p-e.kr 로 요청이 오면, upstream 에서 정의한 서버로 알아서 분배해준다.
  • Nginx 설정 파일 문법 오류 체크
    • sudo nginx -t
  • Nginx 설정 파일 반영
    • sudo nginx -s reload
  • https://api.soehapdlsgksrnr.p-e.kr/health 로 접근해보자.
    • 새로고침 할 때마다 2개의 서버가 번갈아 응답하는 걸 확인할 수 있다. 즉, 로드 밸런싱이 정상적으로 잘 이루어지고 있음을 알 수 있다.
    • 참고) /health 에 대한 코드는 다음과 같다. ( 각 서버에서 고유한 ID를 출력하도록 )
      • 다른 값을 응답했으니, 다른 서버에서 처리했다고 간주

✔️ 참고

  • 설정 파일 분리
    • 설정 파일의 내용이 길어지면 점차 관리하기 복잡해지고 이에따라 유지보수가 어려워진다.
    • 따라서 관련한 내용들을 별도의 파일들로 분리하고, default.conf 에서 이를 include 할 수 있다. ( include 시 와일드카드 사용 가능 )
  • IP당 요청 수 제한 ( 다음과 같이 Nginx 설정을 통해 IP당 요청 수를 제한할 수 있다. )

강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 JSCODE 박재성 강사님께 있습니다.

profile
현실에서 한 발자국

0개의 댓글