Nginx Proxy

임승환·2024년 4월 4일

CS

목록 보기
3/5
post-thumbnail

프록시란?

  • 빠른 엑세스나 안전한 통신 등을 확보하기 위한 중계서버로 대신 통신을 받아 주는 서버이다.
  • 프록시가 없다면, 사용자가 갑자기 많아지는 경우나 웹서버가 그대로 노출되어 있기 때문에 보안성의 위험성이 있다. nginx를 사용하면 로드 밸런싱으로 부하를 줄여줄 수 있고, 분산 처리 또한 가능하고, SSL인증도 적용할 수 있다.

포워드 프록시와 리버스 프록시

https://engineer-mole.tistory.com/288#google_vignette
해당 블로그 참고했다.

포워드 프록시

클라이언트 대신 프록시 서버가 목적 서버에 통신해주는 구성

  • 프록시를 사용하지 않은 경우
    포워드 프록시 이미지 1

  • 프록시를 사용한 경우
    포워드 프록시 이미지 2

포워드 프록시의 경우 프록시 서버가 외부 Web 서버와 통신을 한다. 따라서 클라이언트는 프록시 서버만을 통해 정보를 얻게된다.

포위드 프록시의 경우 어던 프록시 서버를 경유하도록 할 것인가는 클라이언트가 설정할 수 있다.
윈도우 10의 경우 [Windows 메뉴] > [설정] > [네트워크와 인터넷] > [프록시]

포워드 프록시의 장점

캐시 저장(액세스 고속화)

프록시 서버에 캐시를 저장할 수 있다. 동일한 페이지를 리퀘스트 했을 때에는 캐시에 남아 있는 정보를 클라이언트에게 준다.
포워드 프록시 이미지 3

URL 필터링

외부의 액세스는 프록시 서버를 경유하므로 사용자 전원의 웹 사이트로의 액세스를 필터링 할 수 있다.
포워드 프록시 이미지 4

리버스 프록시

Web 서버 쪽에 위치하여 클라이언트의 접근을 최초로 받아 리퀘스트에 해당하는 Web 서버에 배분해주는 역할을 한다.
리버스 프록시 이미지1

클라이언트에서 엑세스를 프록시 서버에 집약해서 URL에 따라 리퀘스트를 받을 Web 서버가 바뀌도록 설정하고 있다.

플록시 서버가 Web 서버와 같은 동작을 하므로 Web서버가 여러 개 존재하는 것을 은폐할 수 있는 것도 리버스 프록시의 특징이다.

리버스 프록시의 장점

로드 밸런싱

설정으로 정적 콘텐츠와 동적 콘텐츠의 보는 곳을 나눔으로써 메모리 사용량의 효율화를 할 수 있다. 로드 밸런스와 병용하면 더욱 부담을 분산할 수 있다.

캐시의 저장

Nginx를 역방향 프록시로 사용하면 미리 렌더링된 버전의 페이지를 캐시하여 페이지 로드 시간을 단축할 수 있다.
프록시 서버의 응답에서 수신한 콘텐츠를 캐싱하고 이 콘텐츠를 사용하여 매번 동일한 콘텐츠를 프록시 서버에 연결할 필요 없이 클라이언트에 응답하는 방식으로 작동한다.

SSL 터미네이션

Nginx는 클라이언트와의 연결에 대한 SSL 끝점 역할을 할 수 있습니다. 수신 SSL 연결을 처리 및 해독하고 프록시 서버의 응답을 암호화한다.

압축

프록시 서버가 압축된 응답을 보내지 않는 경우 클라이언트로 보내기 전에 응답을 압축하도록 Nginx를 구성할 수 있다.

세큐리티 대책, 바이러스 대책

통신시 프록시 서버에 집약되므로 프록시 서버 내에 세큐리티 대책, 바이러스 대책을 구현하여 Web 서버로의 부정 엑세스, 사용 등을 방지할 수 있다.

Nginx를 이용한 리버스 프록시 형태

Nginx.conf

user nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

	# 백엔드 upstream 설정
    # upstream myweb-api {
    #     server api:8080;
    # }

	# 프론트엔드 upstream 설정
    upstream next-server {
        server 172.17.0.1:3000; # docker를 사용하지 않는다면 localhost:3000(웹서버주소)
    }

    server {
        listen 80;

		# /api 경로로 오는 요청을 백엔드 upstream 의 /api 경로로 포워딩
        # location /api {
        #     proxy_pass         http://myweb-api/api;
        # }

		# / 경로로 오는 요청을 프론트엔드 upstream 의 / 경로로 포워딩
        location / {
            proxy_pass         http://next-server/;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;
    # include /etc/nginx/conf.d/*.conf;
}

upstream 블럭과 server 블럭을 주의깊게 봐야한다.

  1. 사용자가 nginx 서버 요청합니다(localhost:80). 기본적으로 http는 80포트를 사용하기 때문에 nginx에서는 listen 80 포트로 구성합니다.

  2. nginx 서버는 location 블럭에서 proxy_pass 로 지정된 주소로 요청을 전달해준다.

  3. 만약 운영중인 서버가 localhost:8080, 혹은 localhost:3000이면 upstream 블럭에 localhost:8080, localhost:3000으로 적어준다.

  4. 웹 서버 (port 3000)를 시작하고, nginx도 시작해준다.

  5. nginx 서버 주소로 요청하면 (localhost:80), proxy_pass 로 지정된 웹 서버로 요청이 전달된다.

docker-compose 사용시

docker-compose.yml

version: "3.8"

networks:
  corp:
    driver: bridge

services:
  nginx_proxy:
    image: nginx:1.21.5-alpine
    container_name: nginx_proxy    
    ports:
      - 80:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf

  next-client:
    container_name: next-client
    build:
      context: ./
      dockerfile: ./Dockerfile
    ports:
      - 3000:3000
  • docker-compose.yml 폴더 위치에 nginx 폴더를 생성하고 nignx.conf 파일을 생성해준다.
    nginx_proxy 블럭의 내용은 고정이다.
    밑의 next-client는 docker로 띄울 웹 서버의 정보이다.
    위 설정은 Next.js로 웹 서버를 만들었고, Dockerfile로 빌드하도록 설정되어 있다.

nginx:proxy_pass의 마지막 슬래시 여부에 따른 처리

proxy_pass에 URI를 생략하는 경우, 요청으로 들어온 전체 Path가 프록시 서버로 전달된다.
proxy_pass에 URI를 정의하는 경우(/포함), location 블럭에서 매칭된 나머지 주소만 프록시 주소에 정의된 URI에 붙어 전달된다.


요청 URL이 아래와 같다고 가정하면,

http://example.com/foo/bar/baz

각 룰 케이스 별로 프록시로 전달되는 path는 아래와 같다.

location과 proxy_pass에 / 가 없는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000;
}

-> 프록시 서버로 전달되는 path: /foo/bar/baz

location 에 /가 있고, proxy_pass에 /가 없는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000;
}

-> 프록시 서버로 전달되는 path: /foo/bar/baz

location에 /가 없고, proxy_pass에 /가 있는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000/;
}

-> 프록시로 서버로 전달되는 path: //bar/baz
	location 블럭에서 매칭된 나머지 주소 (/baz/baz)가 프록시 주소의 마지막에 붙어 전달된다.

location에 /가 있고, proxy_pass 에 /가 있는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000/;
}

-> 프록시로 서버로 전달되는 path: //bar/baz
	location 블럭에서 매칭된 나머지 주소(/bar/baz)가 프록시 주소의 마지막에 붙어 전달된다.

location에 /가 있고, proxy_pass에도 / 가 있는 경우

location ^~ /foo/ {
    proxy_pass http://localhost:3000/foo;
}
-> 프록시로 서버로 전달되는 path: /foobar/baz
	변경 없이, location 블럭에서 매칭된 나머지 주소(bar/baz)가 프록시 주소의 마지막에 붙어 전달된다.

location에 /가 없고, proxy_pass에 URI가 있는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000/foo;
}
-> 프록시로 서버로 전달되는 path: /foo/bar/baz
    마찬가지로, location 블럭에서 매칭된 나머지 주소(/bar/baz)가 
    프록시 주소의 마지막에 붙어 전달된다.

location에 /가 없고, proxy_pass에 URI와 매칭되지 않는 패턴이 존재하는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000/xxx;
}
-> 프록시로 서버로 전달되는 path: /xxx/bar/baz
	마찬가지로, location 블럭에서 매칭된 나머지 주소 (/bar/baz)가 프록시 주소의 마지막에 붙어 전달된다.
    proxy_pass URI가 요청 URI와 동일한 패턴인지 여부는 관계 없다.

location 에 /가 없고, proxy_pass 에 URI가 있고 마지막에 /가 있는 경우

location ^~ /foo {
	proxy_pass http://localhost:3000/foo/;
}
-> 프록시로 서버에 전달되는 path: /foo//bar/baz

참고 블로그
https://narup.tistory.com/238
https://ohgyun.com/621

profile
주니어 개발자

0개의 댓글