사전 학습
해당 포스팅은 프록시 서버에 대해 이해하기, Forward Proxy 구축하기와 이어지기에 해당 내용을 보고 오는 것을 추천합니다!
Reverse Proxy
Reverse Proxy는 서버 쪽에 위치하여 클라이언트 요청을 받아 실제 서버로 전달하고, 서버의 응답을 클라이언트에게 반환하는 역할을 한다.
그림에서의 Target Server(A,B)
는 내부 네트워크에 위치한 서버를 의미하며,
프록시 서버는 내부 혹은 DMZ에 위치한다.
이는 내부 서버를 보호하고, 로드 밸런싱, SSL 암호화, 캐싱 등의 기능을 제공하기 위함이다.
1. Nginx Reverse Proxy
이번 실습에서는 Nginx Reverse Proxy 를 사용할 예정이다.
Nginx reverse proxy는 위에 설명한 일반적인 reverse proxy의 클라이언트와 웹 서버 간 중개자 역할을 한다.
이러한 일반적인 기능 이외에 웹 서버로 향하는 요청에 대한 부하를 분산시키는 로드 밸런싱이나,
내부 서버의 IP가 노출되지 않도록 보호하는 등의 다양한 기능을 수행할 수 있다.
주요 특징은 다음과 같다.
트래픽 분산 (Tarffic Distribution)
- 로드 밸런싱
- Nginx는 여러 백엔드 서버 사이에서 트래픽을 분산하여 로드를 균등하게 나누어 처리한다.
- 이를 통해 서버의 성능을 향상하고 응답 시간을 줄일 수 있다.
- 서버 상태 모니터링
- Nginx는 백엔드 서버의 상태를 모니터링하여, 응답이 느리거나 실패한 서버로의 요청을 자동으로 조정한다.
컨텐츠 캐싱 (Content Caching)
- 정적 및 동적 컨텐츠 캐싱
- Nginx는 정적 파일 및 동적 컨텐츠의 캐싱을 지원한다.
- 자주 요청되는 컨텐츠를 캐싱하고, 서버의 부하를 줄여 사용자의 요청에 대한 응답 속도를 향상한다.
고가용성
- Nginx는 고가용성 아키텍처를 지원하여 시스템 안정성을 보다 더 높일 수 있다.
- 여러 Nginx 인스턴스를 클러스터링하여 장애 발생 시 서비스가 계속 유지되도록 설정할 수 있다.
정적 컨텐츠 제공 (Static Content Serving)
- Nginx는 정적 파일(이미지, CSS, Javascript 등)을 매우 효율적으로 제공할 수 있다.
- 정적 컨텐츠 제공을 위해 백엔드 서버에 가해지는 부하를 줄일 수 있다.
모니터링 및 로깅
- Nginx는 상세한 access 로그와 error 로그를 기록하여 모니터링과 문제 해결에 도움을 준다.
2. 구성도
위 그림과 같이 클라이언트가 인터넷을 통해 대상 서버인 Server A
, Server B
에 요청을 할 때,
Nginx reverse proxy를 통해 전달될 수 있도록 구성하였으며, 응답도 마찬가지로 해당 proxy 서버를 통해 전달된다.
이 과정에서 대상 서버인 Server A
, Server B
의 정보(IP 등) 노출 없이 진행된다.
- 여기서 내부 네트워크 라고 함은 "인증 및 인가되지 않은 접근은 불가능하며, 외부 통신은 제한"라는 가정이 전제된다.
- reverse proxy 서버는 DMZ 구간에 배포된 서버이며, 내/외부 경계에 위치하여 제약 사항이 존재한다.
3. Nginx rever proxy 구축
3-1. nginx 설치
nginx reverse proxy는 결국 nginx가 역방향 프록시 기능과 역할을 수행할 수 있음을 의미한다.
따라서, 기존에 nginx를 설치하던 과정과 크게 다르지 않다.
다만, 다른점은 설치한 이후에 역방향 프록시 기능과 역할을 수행할 수 있도록 따로 설정해줘야 한다는 것이다.
sudo apt-get install -y nginx
정상적으로 설치 되었는지 서비스 구동 상태를 확인하고, curl
명령어를 날려서 기본 웹 페이지가 정상 동작하는지 확인하자.
# 구동 상태 확인
sudo systemctl status nginx
# 페이지 정상동작 확인
curl -X GET http://localhost
3-2. 대상 서버 구조
이번 실습은 nginx의 reverse proxy에 중점을 두었으므로, 대상 서버에 대해 자세하게 기록하지는 않는다.
대상 서버의 역할은 다음과 같다.
Server A
: 웹 서버, FastAPI 기반Server B
: 로그 서버
3-3. reverse proxy 구성
nginx의 전역 설정 파일은 /etc/nginx/nginx.conf
이다.
이는 서버 전체의 기본 설정을 정의하는 파일로 워커 프로세스 수, 기본 사용자 및 그룹, 타임아웃 등 성능과 보안 관련 전역 옵션이 포함된다.
또한, 전역적으로 사용할 HTTP 프로토콜 관련 설정을 정의한다.
여기서 정의된 값들은 모든 서버 블록에 적용될 수 있으며, 서버별로 별도로 설정한 값이 없다면 기본 값이 사용된다.
해당 HTTP 블록에서 포함(include
)시키는 부분인 /etc/nginx/sites-enalbed/*
을 통해 개별 서버 설정 파일을 포함하는데,
이는 해당 디렉터리 내의 파일들은 서버별 세부 설정을 관리한다.
여기에는 각 도메인에 대한 포트, SSL 인증서, 리버스 프록시 설정 등 이 포함된다.
즉, 사이트별 설정은 sites-available
디렉토리에 위치한 개별 설정 파일에서 관리되는 구조이며,
해당 설정(/etc/nginx/sites-enables/*
)에서 이번에 구성하고자 하는 reverse proxy 설정 및 관리 가 이루어진다.
더보기
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
해당 구성은 HTTP 요청에 대해 일반적으로 80 포트를 기반으로 클라이언트의 요청을 처리하는 방법을 정의하고 있다.
여기서 추가 및 수정하고자 하는 부분은 다음과 같다.
HTTPS(443)
설정 및 리다이렉션- 대상 서버인 API 서버(
192.168.219.166
)에 대한 reverse proxy 설정 -> location 설정
위 항목에 대해 구성 파일별로 정의해보겠다.
하지만, 구성 전에 nginx에서 제공하는 모듈에 대해 간략하게 알아볼 필요가 있다.
3-4. nginx modules
HTTP 모듈
구분 | 모듈 | 내용 |
---|---|---|
역할 | HTTP | HTTP 및 HTTPS 프로토콜을 처리하는 모듈 |
위치 | HTTP | http {} 블록 안에서 정의됨 |
기능 | HTTP | 웹 트래픽, 로그 설정, 압축, 캐싱 등 다양한 기능 지원 |
구조 | HTTP | 여러 개의 server {} 블록 포함할 수 있음 |
Server 모듈
구분 | 모듈 | 내용 |
---|---|---|
역할 | Server | 하나의 포트와 도메인에 대한 특정 설정 정의 |
위치 | Server | http {} 또는 stream {} 블록 안에서 정의됨 |
기능 | Server | 각 도메인 또는 IP에 대한 트래픽을 처리함. 포트, SSL 설정 등 포함 |
구조 | Server | 각 server {} 블록은 하나의 포트와 도메인을 담당함 |
3-5. /etc/nginx/sites-enabled/*
해당 경로의 파일은 앞서 설명한 것처럼 HTTP(S)
관련 사이트 설정이 포함된 디렉토리로,
HTTP 모듈과 관련된 설정만 포함된다.
즉, /etc/nginx/sites-enabled/*
디렉토리에서 사용하는 설정 파일들은 HTTP/HTTPS 트래픽을 처리하는 HTTP 모듈을 기반으로 동작한다.
nginx의 HTTP 모듈은 기본적으로 웹 트래픽(HTTP, HTTPS)을 처리하도록 설계되어 있으며, 이를 통해 TCP/UDP 기반 트래픽을 직접 처리할 수는 없다.
웹 서비스와 같은 HTTP 기반 트래픽을 처리하며, 일반적으로는 server {}
블록을 사용해 HTTP 요청을 다룬다.
물론, 정적 파일 제공이나 리버스 프록시 설정도 수행한다.
각 프로토콜에 대한 서버 블록을 정의하여, listen
지시어를 사용해 해당 서버가 어떤 포트를 통해 요청을 수신할지 결정한다.
HTTP와 Stream 모듈에서 Server 블록은 각각의 프로토콜에 맞게 설정된다.
즉, 각 server {}
블록은 하나의 도메인이나 서비스에 대한 설정을 정의한다.
주로 특정 포트와 도메인에 대한 트래픽 을 처리한다고 보면 된다.
이를 다음과 같이 구성할 수 있다.
server {
listen 80;
listen [::]:80;
location /static/ {
root /path/to/your/static/files;
}
location / {
proxy_pass http://192.168.219.166:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
위 설정을 정리하면 다음과 같다.
listen 80;
: 80번 포트로 들어오는 HTTP 요청을 수신한다.location /
: 모든 경로에 대해 아래의 설정을 적용한다.proxy_pass
: 요청을 내부 FastAPI 서버(192.168.219.166:8080
)로 전달한다.proxy_set_header
: 원본 클라이언트의 정보를 유지하기 위해 헤더를 설정한다.
이렇게 대상 서버 중계를 위한 프록시 서버의 설정을 마무리하였다.
위 변경사항을 정리하고 nginx가 올바르게 작동하는지 확인 후, 재시작하자.
sudo nginx -t
sudo systemctl restart nginx
3-6. 프록시 테스트
reverse proxy를 구성한 이유는 뭐였는지 기억이 나는가?
대상 서버를 노출시키지 않고, 클라이언트에 대한 요청을 프록시 서버가 중계하여 응답을 반환하는 통신을 하기 위함이다.
따라서, 인터넷을 통한 클라이언트의 요청을 nginx reverse proxy에게 전달한다.
그럼 이제 /etc/nginx/sites-enables/default
파일에서 server {}
블록에서 정의한,
URL 경로 구성에 따라서 API 서버에 요청이 정상적으로 넘어가는지 확인해보자.
메시지(GET) - /api/
정상적으로 리버스 프록시된 것을 볼 수 있다.
이번에는 nginx reverse proxy 서버의 로그를 살펴보자.
$ tail -n 5 /var/log/nginx/access.log
192.168.219.169 - - [12/Nov/2024:10:07:25 +0000] "GET / HTTP/1.1" 500 21 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
192.168.219.169 - - [12/Nov/2024:10:07:25 +0000] "GET / HTTP/1.1" 500 21 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
192.168.219.169 - - [12/Nov/2024:10:09:03 +0000] "GET / HTTP/1.1" 200 24 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
192.168.219.169 - - [12/Nov/2024:10:09:07 +0000] "GET / HTTP/1.1" 200 24 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
192.168.219.169 - - [12/Nov/2024:10:09:10 +0000] "GET /api HTTP/1.1" 200 23 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
클라이언트의 정보와 함께 정의된 경로로 요청한 정보, 그리고 HTTP 상태 코드(200)가 확인된다.
API 서버가 중계된 요청에 대한 응답(데이터)을 반환하며 proxy 역할을 잘 수행함을 로그 결과를 보며 확실하게 알 수 있다.