image source : https://zoidsec.medium.com/breaking-parse-logic-gain-access-to-nginx-api-read-write-upstreams-1cb062aa44ca
Reverse proxy는 네트워크의 inbound traffic에 대해서 proxy 역할을 하는 것이다. 다음과 같은 경우에 사용한다.
SSL offloading
SSL Offloading(SSL 오프로딩)은 클라이언트와 서버 간의 HTTPS(SSL/TLS) 통신에서 발생하는 암·복호화 연산을 웹서버(또는 로드밸런서)에서 처리하고, 그 뒤에 있는 애플리케이션 서버와는 평문(HTTP)으로 통신하는 방식
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 된다.
$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 으로 지정한 논리적인 대상을 지정할 수도 있다.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 정적 파일 서빙하기
를 참고.
server {
server_name staticserver;
listen 8082;
root /www/data;
location / {
}
location /images/ {
}
location ~ \.(mp3|mp4) {
root /www/media;
}
}
location /
기본으로 URI의 PATH에 해당하는 파일을 /www/data 디렉토리에서 찾아서 응답한다.location /images/
라는 URI로 요청이 온다면, /www/data/images 디렉토리에서 이후 경로의 이름에 해당하는 파일을 찾아서 응답한다.location ~ \.(mp3|mp4)
.mp3 또는 .mp4 확장자에 해당하는 파일을 /www/media 디렉토리를 root로 해서 찾아서 응답한다. ~ 는 case-sensitive matching을 의미.디렉토리를 만든다.
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
웹브라우저에서 다음 URL을 확인한다.
http://$server:8082/notebook.jpg
http://$server:8082/apple.jpg
http://$server:8082/images/load.jpg
http://$server:8082/earth.mp4
upstream $name { }
블록으로 논리적인 서버의 묶음을 설정할 수 있다. 여기서 설정한 name은 server 블록에서 proxy_pass 의 파라미터에 지정할 수 있다.
upstream 블록 내에 server ${address:port};
로 대상 서버를 추가할 수 있다.
upstream block 내의 첫번째 줄에 규칙을 지정할 수 있다. 규칙 이름과 ;
를 쓰면된다. 아무 설정이 없으면 RR(round-robin)이다.
server $target $option;
형식으로 규칙에 따라서 server 들에 추가 옵션을 지정할 수 있다. 추가 설정은 server 설정 줄의 마지막에 온다.
아래는 무료버전에서 설정 가능한 리스트. 각 설정 설명의 알파벳 들여쓰기가 추가옵션.
1. default : round robin
least_conn;
ip_hash;
hash ${user_defined_key} consistent(선택);
least_time $option;
header
– Time to receive the first byte from the serverlast_byte
– Time to receive the full response from the serverlast_byte inflight
– Time to receive the full response from the server, taking into account incomplete requestsrandom
각 loadbalancer 설정에 대한 자세한 설명은 LoadBalancer 강의에서 다루었으므로 여기선 생략한다.
LoadBalancer 에 대한 더 상세한 설정 방법과 설명은 공식문서를 참고
기본 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;
}
}
health_check 설정으로, 기준을 충족하지 못하는 서버는 자동으로 upstream에서 제외할 수 있다.
upstream {
server $server1 max_fails=3 fail_timeout=30s;
server $server2 max_fails=3 fail_timeout=30s;
}
위 방법은 passive 설정.
active 설정은 유료버전에서만 이용가능.
HTTPS 등 SSL 인증 요청이 들어왔을때, nginx 에서 인증서로 인증을 하고, proxy 하는 서버로는 ssl이 없는 요청을(http) 전달할 수 있다.
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를 생성한다.
생성시 묻는 정보는 임의의 정보를 입력한다.
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 설정을 한다.ssl_certificate
에 cert 파일 경로 세팅ssl_certificate_key
에 private key 파일 경로 세팅❗ 실습에서 사용한 crt 는 임의로 생성한 것이고 공임 CA에서 받은 인증서가 아니기 때문에, 브라우저에서는 unsafe 하다는 경고가 뜬다. detail 로 들어가서 내가 cert 를 생성할때 입력한 정보가 나온다면, nginx상에서 ssl 정보는 잘 세팅해준 것으로 이해하면 된다.
NGINX에서 header의 내용을 해석할 수 있다. proxy 에게 header 정보를 변경하거나 그대로 보낼 수도, client에게 response로 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.1
에서 실습한 header.conf 의 server
블록에 add_header
로 원하는 헤더정보를 추가한다.
server {
add_header X-MYHEADER JOEY;
}
curl -v -XGET http://$nginxserver:8086/user
image source : https://knnx.medium.com/demystifying-forward-and-reverse-proxies-e52eea330e85
Forward Proxy는 네트워크상의 outbound traffic에 대해서 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;
}
}
NGINX 설정을 리로드한다.
nginx -t
nginx -s reload
다음 명령어로 결과를 확인
curl -v -L http://example.com --proxy http://localhost:8889
curl -L http://example.com --proxy http://localhost:8889/ >> example.com.html
단, 현재 nginx forward proxy의 다양한 기능을 쓰기 위해서는 유료버전 모듈을 쓰거나, compile 단계에서 다른 모듈을 포함해서 빌드를 한 바이너리를 써야하는 단점이 있다. nginx의 빌드는 C언어로 이루어지기 때문에 하드웨어와 운영체제에 종속적이다.