[웹서버로 콘텐츠 구분해서 서빙하기] NGINX의 대표적인 기능들

Hyunjun Kim·2025년 5월 16일
0

Data_Engineering

목록 보기
74/153

3 NGINX의 대표적인 기능들

3.1 경로별 Reverse Proxy 설정

3.1.1 Reverse Proxy


image source : https://zoidsec.medium.com/breaking-parse-logic-gain-access-to-nginx-api-read-write-upstreams-1cb062aa44ca

Reverse proxy는 네트워크의 inbound traffic에 대해서 proxy 역할을 하는 것이다. 다음과 같은 경우에 사용한다.

  • 외부에 노출한 서비스는 Proxy 서버의 IP만으로 접근하고, 연결되는 실제 서비스의 IP를 감추고 싶다.
  • 외부에 노출한 서비스의 요청은 한 곳에서 받아주고, 실제 서비스의 운영 상의 유연성을 높이고 싶다.
    • Health Check, LoadBalacing 기능
  • 외부에 노출한 서비스의 요청에 대해 공통처리를 Proxy 서버에서 처리하고, 실제 서비스의 부담을 줄여준다.
    • SSL offloading

SSL offloading
SSL Offloading(SSL 오프로딩)은 클라이언트와 서버 간의 HTTPS(SSL/TLS) 통신에서 발생하는 암·복호화 연산을 웹서버(또는 로드밸런서)에서 처리하고, 그 뒤에 있는 애플리케이션 서버와는 평문(HTTP)으로 통신하는 방식

3.1.2 server 설정 위치

http {
	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;
	
    server {
		server_name="server1";
	}

	server {
		server_name="server2";
		access_log /var/log/nginx/server2.log;
	}
}

server 블록( server { } )은 구체적인 proxy의 대상과 규칙을 정하는 블록이다. server 블록 이전에 어떤 프로토콜인지 먼저 블록이 정해져있어야 한다. HTTP는 http { } , TCP는 stream { } 을 사용한다. server 블록은 프로토콜 블록 안에 들어와야 한다.

로그 파일의 위치와 같은 공통 설정은 프로토콜 블록에 올 수 도, server 블록에 올 수도 있다. 상위레벨에만 선언한 공통 설정은 상속된다. 같은 옵션이 여러 블록에 선언되어 있다면 자신의 블록의 설정으로 override 된다.

  • Q: 위의 설정에서 server1, server2 의 access log와 error log 는 각각 어느 경로에 기록되는가?

3.1.3 server 의 설정 내용

$name 형식은 값이 달라지는 파라미터를 의미한다.

  • server_name : 서버의 논리적 이름을 정한다. 이름을 정해야 validation 에서 실패했을 때 위치를 빠르게 찾을 수 있다. 논리적 이름은 겹치면 안된다.
  • listen $port $protocol : 어떤 port로 listen 할지 설정한다. protocol은 선택이다. SSL등을 지정할 때 쓴다.
  • location $PATH { } : 어떤 URI 경로에 대한 설정을 할 수 있다. $PATH에는 URI경로의 규칙을 지정한다. 블록 안에는 상세 설정을 할 수 있다.
  • proxy_pass ${URL:port or upstream name} : proxy로 연결할 대상을 지정한다. URL로 지정할 수도 있고, upstream 으로 지정한 논리적인 대상을 지정할 수도 있다.

3.1.4 location 으로 path별 proxy 설정하기

location 블록은 URI의 PATH에 따라서 규칙을 할 수 있다. location 블록 내에 proxy_pass 로 해당 경로로 들어온 요청을 어디로 전달해줄 지 설정한다.

sudo vi proxy-path.conf
server {
	server_name "server1";
	listen 8081;

	location /user {
		proxy_pass http://$server1:9000;
	}

	location /customer {
		proxy_pass http://$server2:9000;
	}
}
sudo nginx -s reload

동적 콘텐츠를 서빙하는 경우, proxy_pass 로 대상을 지정한다.
정적 파일을 서빙하는 경우는 root 키워드로 콘텐츠의 root 디렉토리를 지정하면, 그 하위에서 파일을 찾아서 응답한다. 자세한 내용은 아래 2.2 정적 파일 서빙하기를 참고.

3.2 정적 파일 서빙하기

3.2.1 root 파일 디렉토리 설정

server {
	server_name staticserver;
	listen 8082;

	root /www/data;

	location / {
	}

	location /images/ {
	}

	location ~ \.(mp3|mp4) {
		root /www/media;
	}
}
  • root 로 해당 server 블록에서 사용할 file system의 기본 디렉토리 위치를 설정한다.
  • location / 기본으로 URI의 PATH에 해당하는 파일을 /www/data 디렉토리에서 찾아서 응답한다.
  • location /images/ 라는 URI로 요청이 온다면, /www/data/images 디렉토리에서 이후 경로의 이름에 해당하는 파일을 찾아서 응답한다.
  • location ~ \.(mp3|mp4) .mp3 또는 .mp4 확장자에 해당하는 파일을 /www/media 디렉토리를 root로 해서 찾아서 응답한다. ~ 는 case-sensitive matching을 의미.

3.2.2 실습 파일 다운로드

디렉토리를 만든다.

sudo mkdir /www
sudo mkdir /www/data
sudo mkdir /www/data/images
sudo mkdir /www/media
$ tree www
www
├── data
│ └── images
└── media

파일을 다운로드 받는다.

sudo curl -o /www/data/notebook.jpg https://images.unsplash.com/photo-1664575196412-ed801e8333a1
sudo curl -o /www/data/apple.jpg https://images.unsplash.com/photo-1570913149827-d2ac84ab3f9a
sudo curl -o /www/data/images/load.jpg https://images.unsplash.com/photo-1580637261961-2ee5a4d3537d
sudo curl -o /www/media/earth.mp4 https://file-examples.com/storage/fe19e1a6e563854389e633c/2017/04/file_example_MP4_480_1_5MG.mp4
$ tree www
www
├── data
│ ├── apple.jpg
│ ├── images
│ │ └── load.jpg
│ └── notebook.jpg
└── media
└── earth.mp4

3.2.3 static 파일 서빙 확인

웹브라우저에서 다음 URL을 확인한다.

  • http://$server:8082/notebook.jpg
  • http://$server:8082/apple.jpg
  • http://$server:8082/images/load.jpg
  • http://$server:8082/earth.mp4

3.3 Load Balancing 규칙 정하기

3.3.1 upstream 으로 논리적인 서버 그룹 설정하기

upstream $name { } 블록으로 논리적인 서버의 묶음을 설정할 수 있다. 여기서 설정한 name은 server 블록에서 proxy_pass 의 파라미터에 지정할 수 있다.

3.3.2 upstream 에 서버 추가하기

upstream 블록 내에 server ${address:port}; 로 대상 서버를 추가할 수 있다.

3.3.3 loadbalancing 규칙 지정하기

upstream block 내의 첫번째 줄에 규칙을 지정할 수 있다. 규칙 이름과 ; 를 쓰면된다. 아무 설정이 없으면 RR(round-robin)이다.

server $target $option; 형식으로 규칙에 따라서 server 들에 추가 옵션을 지정할 수 있다. 추가 설정은 server 설정 줄의 마지막에 온다.

아래는 무료버전에서 설정 가능한 리스트. 각 설정 설명의 알파벳 들여쓰기가 추가옵션.
1. default : round robin

  • a. weight
  1. least_conn;
    • a. weight
  2. ip_hash;
    • a. down
  3. hash ${user_defined_key} consistent(선택);
    • a. consistent 를 설정한 경우 ketama consistent hashing이 적용된다.
    • b. hash를 쓴다면 consistent를 사용하기를 추천. Rehashing 에 대한 부담을 줄일 수 있다.
  4. least_time $option;
    • a. 옵션 리스트
      • header – Time to receive the first byte from the server
      • last_byte – Time to receive the full response from the server
      • last_byte inflight – Time to receive the full response from the server, taking into account incomplete requests
  5. random

각 loadbalancer 설정에 대한 자세한 설명은 LoadBalancer 강의에서 다루었으므로 여기선 생략한다.
LoadBalancer 에 대한 더 상세한 설정 방법과 설명은 공식문서를 참고

3.3.4 실습

기본 Round Robin

upstream backend {
    server $server1:9000;
    server $server2:9000;
}

server {
    server_name loadbalancing;
    listen 8083;

    location / {
        proxy_pass http://backend;
    }
}

weight - 비율로 분배

upstream backend {
	server $server1:9000 weight=8;
	server $server2:9000 weight=2;
}

server {
	server_name loadbalancing;
	listen 8083;

	location / {
		proxy_pass http://backend;
	}
}

backup 설정 - 모두 이용불가 되었을 때 투입

upstream backend {
	server $server1:9000;
	server $server2:9000 backup;
}

server {
	server_name loadbalancing;
	listen 8083;

	location / {
		proxy_pass http://backend;
	}
}
  • 일반 요청
  • server1번을 kill 한 뒤에 요청

3.4 HealthCheck 로 자동으로 서비스에서 제외하기

health_check 설정으로, 기준을 충족하지 못하는 서버는 자동으로 upstream에서 제외할 수 있다.

upstream {
	server $server1 max_fails=3 fail_timeout=30s;
	server $server2 max_fails=3 fail_timeout=30s;
}
  • 30초동안 3번 실패하면, 이용불가로 판단.

위 방법은 passive 설정.
active 설정은 유료버전에서만 이용가능.

  • 별도의 포트, path, status_code 등 다양한 옵션을 줄 수 있다.

3.5 SSL 인증서 인증하기(offloading)

HTTPS 등 SSL 인증 요청이 들어왔을때, nginx 에서 인증서로 인증을 하고, proxy 하는 서버로는 ssl이 없는 요청을(http) 전달할 수 있다.

3.5.1 실습준비 - key, crt 생성

sudo mkdir /etc/nginx/ssl
sudo openssl req -x509 -days 30 -nodes -newkey rsa:2048 \
-keyout /etc/nginx/ssl/nginx-ssl.key \
-out /etc/nginx/ssl/nginx-ssl.crt

위 명령어로 certificate file 과 private key를 생성한다.
생성시 묻는 정보는 임의의 정보를 입력한다.

3.5.2 NGINX ssl 설정

server {
	listen 443 ssl;
	server_name $yourdomain;

	ssl_certificate /etc/nginx/ssl/nginx-ssl.crt;
	ssl_certificate_key /etc/nginx/ssl/nginx-ssl.key;
}
  • listen $port ssl 로 ssl 설정을 한다.
  • server_name 은 사용할 도메인 네임과 같아야 한다. 실습에서는 AWS ec2 public domain name을 사용한다.
  • ssl_certificate 에 cert 파일 경로 세팅
  • ssl_certificate_key 에 private key 파일 경로 세팅

❗ 실습에서 사용한 crt 는 임의로 생성한 것이고 공임 CA에서 받은 인증서가 아니기 때문에, 브라우저에서는 unsafe 하다는 경고가 뜬다. detail 로 들어가서 내가 cert 를 생성할때 입력한 정보가 나온다면, nginx상에서 ssl 정보는 잘 세팅해준 것으로 이해하면 된다.

3.6 Header 변경하기

NGINX에서 header의 내용을 해석할 수 있다. proxy 에게 header 정보를 변경하거나 그대로 보낼 수도, client에게 response로 header를 추가할 수 있다.

3.6.1 실습 - proxy로 header 전달하기

server1에 있는 server.js. 파일에 다음 로깅을 API마다 추가하고 재기동한다.

console.log(JSON.stringify(req.headers));

header.conf 파일을 conf.d에 추가한다.

server {
	listen 8086;
	server_name headerserver;

	location /user {
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_pass http://13.125.255.35:9000;
	}

	location /customer {
		proxy_set_header X-CUSTOM custom;
		proxy_pass http://13.209.4.45:9000;
	}
}

웹사이트 에서 자신의 public IP를 확인하고 header에 남는 정보가 맞는지 확인한다.

3.6.2 실습 - Client 로 header 전달하기

3.6.1에서 실습한 header.conf 의 server 블록에 add_header 로 원하는 헤더정보를 추가한다.

server {
	add_header X-MYHEADER JOEY;
}
curl -v -XGET http://$nginxserver:8086/user
  • 상세로그에서 X-MYHEADER 값을 확인

3.7 Forward Proxy

3.7.1 Forward Proxy 가 필요한 이유


image source : https://knnx.medium.com/demystifying-forward-and-reverse-proxies-e52eea330e85

Forward Proxy는 네트워크상의 outbound traffic에 대해서 proxy를 해주는 것을 말한다. 다음과 같은 경우에 사용한다.

  • 외부망에서 사전에 허가된 IP만 access를 허용하는 경우
    • 예: B2B 제품을 이용할 때, IP ACL을 위해서 Proxy Server 의 public IP를 상대 회사에 알려주고, 내부에서는 proxy server를 통해서 연동한다.
  • 내부망에서 외부망으로 나가는 요청에 대해서 Proxy에서 추가 로직이 필요한 경우
    • 예: B2B 제품을 이용할 때, 인증을 위해서 Header에 회사에 할당된 토큰정보를 입력한다. 내부에서는 proxy server를 통해서 연동한다.
  • 내부망에서 외부망으로 요청하지만, 외부망으로부터 내부망의 Client ip를 감추거나, 교체하고 싶은 경우
    • 예: Docker registry는 client IP 별로 access limit을 두고, 라이센스 구매자만 제한없이 리소스를 다운받을 수 있다. 회사에서 Docker에 접속하는 proxy 서버를 두고, license 에 대한 권한을 proxy 서버에서 처리한다.

3.7.2 NGINX Forward Proxy 설정

다음 예제는 google.com 에 접속하는 proxy 서버이다.
forward-proxy.conf 를 conf.d 디렉토리에 추가한다.

server {
	listen 8889;
	access_log /var/log/nginx/forward-proxy.log;
	error_log /var/log/nginx/forward-proxy.error.log;
	
    location / {
		resolver 8.8.8.8;
		proxy_pass http://$http_host$uri$is_args$args;
	}
}
  • Proxy server용 listen port 설정
  • resolver 는 도메인을 찾아줄 name server
  • client 에서 요청한 http_host, uri(path), argument 정보를 위의 예약 변수(httphosthttp_hosturiisargsis_argsargs)로 받아온다.

NGINX 설정을 리로드한다.

nginx -t
nginx -s reload

3.7.3 Client 에서 요청하기

다음 명령어로 결과를 확인

curl -v -L http://example.com --proxy http://localhost:8889
curl -L http://example.com --proxy http://localhost:8889/ >> example.com.html

3.7.4 주의사항

단, 현재 nginx forward proxy의 다양한 기능을 쓰기 위해서는 유료버전 모듈을 쓰거나, compile 단계에서 다른 모듈을 포함해서 빌드를 한 바이너리를 써야하는 단점이 있다. nginx의 빌드는 C언어로 이루어지기 때문에 하드웨어와 운영체제에 종속적이다.

  • Forward Proxy 설정을 기본 모듈보다 편하게 해주는 모듈이 있다. 링크
    • 하지만, 이것도 역시 컴파일하면서 설치를 해야한다.
profile
Data Analytics Engineer 가 되

0개의 댓글