๋ฆฌ๋ฒ์ค ํ๋ก์ (Reverse Proxy)
๊ฐ์
๋ฆฌ๋ฒ์ค ํ๋ก์๋ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ๋ฐ์ ๋ค์ ์๋ ๋ฐฑ์๋ ์๋ฒ(Spring Boot, Node.js ๋ฑ)์ ๋์ ์ ๋ฌํ๊ณ , ๋ฐฑ์๋์ ์๋ต์ ํด๋ผ์ด์ธํธ์๊ฒ ๋๋ ค์ฃผ๋ ์ค๊ฐ ์ญํ ์ ํ๋ ๊ฒ์ด๋ค.
"ํ๋ก์"๋ผ๋ ๋ง์ด ์ข ๋ฏ์ค ์ ์๋๋ฐ, ์ฝ๊ฒ ๋งํด "๋์ ์ผํด์ฃผ๋ ๋๋ฆฌ์ธ"์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ์.
โข
*์ผ๋ฐ ํ๋ก์(Forward Proxy)๋ ํด๋ผ์ด์ธํธ๋ฅผ ๋์ ํด์.
์๋ฅผ ๋ค์ด, ํ์ฌ ๋ด๋ถ ์ง์์ด ๊ฐ์ธ์ ๋ณด ๋ณดํธ๋ฅผ ์ํด ํ์ฌ ํ๋ก์๋ฅผ ๊ฑฐ์ณ ์ธํฐ๋ท์ ์ ์ํ๋ ๊ฑฐ์ฃ . ํด๋ผ์ด์ธํธ ์
์ฅ์์ ์์ฒญ์ ๋ณด๋ด๋ ๊ฑฐ์์.
โข
*๋ฆฌ๋ฒ์ค ํ๋ก์(Reverse Proxy)๋ ์๋ฒ๋ฅผ ๋์ ํด์.
ํด๋ผ์ด์ธํธ๊ฐ ์ง์ ๋ฐฑ์๋ ์๋ฒ(Spring Boot)์ ์ ์ํ๋ ๊ฒ ์๋๋ผ, ์์ ์๋ Nginx(๋ฆฌ๋ฒ์ค ํ๋ก์)๋ฅผ ๊ฑฐ์ณ์ ์ ์ํด์. ํด๋ผ์ด์ธํธ๋ Nginx๋ง ๋ณด์ด๊ณ , ๋ค์ ๋ญ๊ฐ ์๋์ง๋ ๋ชฐ๋ผ์!
Forward Proxy vs Reverse Proxy
graph LR
A["๐ค ํด๋ผ์ด์ธํธ"] -->|"์์ฒญ"| B["๐ถ๏ธ Forward Proxy<br/>(ํด๋ผ์ด์ธํธ ํ๋ก์)"]
B -->|"๋์ ์์ฒญ"| C["๐ ์ธํฐ๋ท<br/>์ธ๋ถ ์๋ฒ"]
C -->|์๋ต| B
B -->|์๋ต| A
D["๐ค ํด๋ผ์ด์ธํธ"] -->|"์์ฒญ"| E["๐ Reverse Proxy<br/>(์๋ฒ ํ๋ก์)"]
E -->|"๋์ ์์ "| F["๐ฅ๏ธ ๋ฐฑ์๋ ์๋ฒ<br/>Spring Boot<br/>Node.js"]
F -->|์๋ต| E
E -->|์๋ต| D
style B fill:#FFB366
style E fill:#90EE90Mermaid
๋ณต์ฌ
๊ตฌ๋ถ | Forward Proxy | Reverse Proxy |
๋ชฉ์ | ํด๋ผ์ด์ธํธ ๋ณดํธ | ์๋ฒ ๋ณดํธ |
์์น | ํด๋ผ์ด์ธํธ ์ | ์๋ฒ ์ |
์ญํ | ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋์ ๋ณด๋ | ์๋ฒ ์์ฒญ์ ๋์ ๋ฐ์ |
๋ํ ์ฌ์ฉ | VPN, ํ์ฌ ๋ฐฉํ๋ฒฝ | ์น ์๋ฒ ๋ก๋ ๋ฐธ๋ฐ์ฑ |
Nginx ์์น | - | |
ํด๋ผ์ด์ธํธ๊ฐ ์๋ ๊ฒ | Proxy ์ฃผ์ | Proxy ์ฃผ์๋ง (๋ฐฑ์๋ ๋ชจ๋ฆ) |
Nginx ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ํคํ
์ฒ
graph TD
A["๐ค ํด๋ผ์ด์ธํธ<br/>IP: 203.0.113.50"] -->|"1. HTTP ์์ฒญ<br/>example.com:80"| B["๐ฅ๏ธ Nginx<br/>๋ฆฌ๋ฒ์ค ํ๋ก์<br/>๊ณต๊ฐ IP: 203.0.113.10"]
B -->|"2. ์์ฒญ ์ ๋ฌ<br/>X-Real-IP ํค๋ ์ถ๊ฐ"| C["๐ Spring Boot<br/>๋ฐฑ์๋ ์๋ฒ<br/>๋ด๋ถ IP: 10.0.0.50:8080"]
C -->|"3. ์๋ต"| B
B -->|"4. ์๋ต ๋ฐํ"| A
style B fill:#FFD700
style C fill:#87CEEBMermaid
๋ณต์ฌ
์์ฒญ ํ๋ฆ ์์ธ
sequenceDiagram
participant ์ฌ์ฉ์ as ๐ค ์ฌ์ฉ์<br/>203.0.113.50
participant Nginx as ๐ฅ๏ธ Nginx<br/>203.0.113.10
participant Spring as ๐ Spring Boot<br/>10.0.0.50:8080
์ฌ์ฉ์->>Nginx: GET /api/users (203.0.113.50)
Note over Nginx: ์์ฒญ ์ฒ๋ฆฌ<br/>1. ๊ฒฝ๋ก ํ์ธ (/api/*)<br/>2. ํ๋กํ ์ฝ ๊ฒฐ์ (http)<br/>3. ํค๋ ์ถ๊ฐ (X-Real-IP ๋ฑ)
Nginx->>Spring: GET /api/users<br/>Host: example.com<br/>X-Real-IP: 203.0.113.50<br/>X-Forwarded-For: 203.0.113.50
Note over Spring: ์์ฒญ ์ฒ๋ฆฌ<br/>1. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ<br/>2. ๋น์ฆ๋์ค ๋ก์ง ์คํ
Spring-->>Nginx: HTTP 200<br/>{ "users": [...] }
Note over Nginx: ์๋ต ์ฒ๋ฆฌ<br/>1. ์ํ ์ฝ๋ ํ์ธ<br/>2. ํ์์ ํค๋ ์ถ๊ฐ
Nginx-->>์ฌ์ฉ์: HTTP 200<br/>{ "users": [...] }Mermaid
๋ณต์ฌ
๊ธฐ๋ณธ ๋ฆฌ๋ฒ์ค ํ๋ก์ ์ค์
server {
listen 80;
server_name example.com;
# ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฆฌ๋ฒ์ค ํ๋ก์
location /api/ {
proxy_pass <http://localhost:8080>;
}
}
Plain Text
๋ณต์ฌ
์ด ํ ์ค๋ก๋ ๊ธฐ๋ณธ ๋ฆฌ๋ฒ์ค ํ๋ก์๊ฐ ์๋ํด์! ํ์ง๋ง ์ค๋ฌด์์๋ ๋ ๋ง์ ์ค์ ์ด ํ์ํฉ๋๋ค.
ํ์ ํ๋ก์ ํค๋ ์ค์
server {
listen 80;
server_name example.com;
location /api/ {
# ๋ฐฑ์๋ ์๋ฒ ์ง์
proxy_pass <http://localhost:8080>;
# ============================================
# ํ์ ํค๋ โ ๋ฐฑ์๋๊ฐ ์ ๋ณด๋ฅผ ์์์ผ ํจ
# ============================================
# ์๋ ์์ฒญ๋ ๋๋ฉ์ธ ์ด๋ฆ
proxy_set_header Host $host;
# ์ค์ ํด๋ผ์ด์ธํธ IP (๊ฐ์ฅ ์ค์!)
proxy_set_header X-Real-IP $remote_addr;
# ํ๋ก์ ์ฒด์ธ์ ๊ฑฐ์น ๋ชจ๋ IP ๋ชฉ๋ก
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# ์๋ ํ๋กํ ์ฝ (http or https)
proxy_set_header X-Forwarded-Proto $scheme;
# ์๋ ํฌํธ๋ฒํธ
proxy_set_header X-Forwarded-Port $server_port;
# Host ํค๋ ๋ณ๊ฒฝ ๊ธ์ง
proxy_set_header X-Forwarded-Host $server_name;
}
}
Plain Text
๋ณต์ฌ
๊ฐ ํค๋์ ์ญํ
ํค๋ | ๊ฐ ์์ | ์ฉ๋ |
Host | example.com | ๋ฐฑ์๋๊ฐ ์ด๋ ๋๋ฉ์ธ์ธ์ง ์๊ธฐ |
X-Real-IP | 203.0.113.50 | ์ค์ ์ฌ์ฉ์ IP (๋ก๊น
, ๋ณด์) |
X-Forwarded-For | 203.0.113.50 | ํ๋ก์ ์ฒด์ธ ์ถ์ |
X-Forwarded-Proto | https | HTTPS ์ฌ๋ถ (๋ฆฌ๋ค์ด๋ ํธ ํ๋จ) |
X-Forwarded-Port | 443 | ์๋ ์ ๊ทผ ํฌํธ |
๊ณ ๊ธ ํ๋ก์ ์ค์
# ์
์คํธ๋ฆผ ์ ์ (๋ก๋ ๋ฐธ๋ฐ์ฑ ๋๋น)
upstream backend {
server localhost:8080 weight=1;
server localhost:8081 weight=1;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass <http://backend>;
# ํ์ ํค๋
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# ============================================
# ๋ฒํผ ๊ด๋ฆฌ
# ============================================
proxy_buffering on; # ์๋ต ๋ฒํผ๋ง ํ์ฑํ
proxy_buffers 8 4k; # ๋ฒํผ ๊ฐ์ ๋ฐ ํฌ๊ธฐ
proxy_buffer_size 4k; # ํค๋ ๋ฒํผ ํฌ๊ธฐ
# ============================================
# ํ์์์ (๊ธฐ๋ณธ๊ฐ์ 60์ด๋ก ๋ณดํต ์ถฉ๋ถ)
# ============================================
proxy_connect_timeout 60s; # ์ฐ๊ฒฐ ํ์์์
proxy_send_timeout 60s; # ์์ฒญ ์ ์ก ํ์์์
proxy_read_timeout 60s; # ์๋ต ์์ ํ์์์
# ============================================
# ์ฌ์๋ ์ค์
# ============================================
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_tries 2;
# ============================================
# ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ (HTTP Keep-Alive)
# ============================================
proxy_http_version 1.1;
proxy_set_header Connection "";
# ============================================
# ํฐ ํ์ผ ์
๋ก๋ ํ์ฉ
# ============================================
client_max_body_size 10M;
}
}
Plain Text
๋ณต์ฌ
URL ๊ฒฝ๋ก๋ณ ๋ค์ค ๋ฆฌ๋ฒ์ค ํ๋ก์
graph TD
A["๐ค ํด๋ผ์ด์ธํธ"] -->|"์์ฒญ"| B["๐ฅ๏ธ Nginx<br/>๋ผ์ฐํฐ ์ญํ "]
B -->|"/api/" ๊ฒฝ๋ก| C["๐ Spring Boot<br/>API ์๋ฒ<br/>:8080"]
B -->|"/static/" ๊ฒฝ๋ก| D["๐ ์ ์ ํ์ผ<br/>๋๋ ํ ๋ฆฌ"]
B -->|"/ws/" ๊ฒฝ๋ก| E["๐ WebSocket<br/>์๋ฒ<br/>:8081"]
B -->|"/" ๊ฒฝ๋ก| F["โ๏ธ React<br/>ํ๋ก ํธ์๋<br/>๋น๋ ๊ฒฐ๊ณผ"]Mermaid
๋ณต์ฌ
server {
listen 80;
server_name example.com;
# ============================================
# 1. ์ ์ ํ์ผ ์๋น (React ๋น๋)
# ============================================
root /var/www/frontend;
location / {
try_files $uri $uri/ /index.html; # SPA ๋์
}
# ============================================
# 2. ์ ์ ์์
์บ์ฑ
# ============================================
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# ============================================
# 3. REST API (Spring Boot)
# ============================================
location /api/ {
proxy_pass <http://localhost: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;
proxy_set_header X-Forwarded-Proto $scheme;
}
# ============================================
# 4. WebSocket (์ค์๊ฐ ํต์ )
# ============================================
location /ws/ {
proxy_pass <http://localhost:8081>;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
# ============================================
# 5. Admin ํ์ด์ง (IP ์ ํ)
# ============================================
location /admin/ {
allow 203.0.113.0/24; # ํ์ฌ IP๋ง
deny all;
proxy_pass <http://localhost:8080>;
}
}
Plain Text
๋ณต์ฌ
WebSocket ๋ฆฌ๋ฒ์ค ํ๋ก์
WebSocket์ ์ผ๋ฐ HTTP์ ๋ค๋ฅด๊ฒ ์ฐ๊ฒฐ์ ์ ์งํด์ผ ํด์!
location /ws/ {
proxy_pass <http://localhost:8081>;
# HTTP/1.1 ํ์ (WebSocket ํ๋กํ ์ฝ)
proxy_http_version 1.1;
# ์ฐ๊ฒฐ ์
๊ทธ๋ ์ด๋ ํค๋
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# ๊ธฐ๋ณธ ํค๋
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# WebSocket์ ์ค๋ ์ ์ง๋๋ฏ๋ก ํ์์์ ๊ธธ๊ฒ
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
Plain Text
๋ณต์ฌ
๋ก๋ ๋ฐธ๋ฐ์ฑ (์ฌ๋ฌ ๋ฐฑ์๋ ์๋ฒ)
graph LR
A["๐ค ํด๋ผ์ด์ธํธ"] -->|์์ฒญ| B["๐ฅ๏ธ Nginx<br/>๋ก๋ ๋ฐธ๋ฐ์"]
B -->|์์ฒญ 1| C["๐ Spring Boot 1<br/>:8080"]
B -->|์์ฒญ 2| D["๐ Spring Boot 2<br/>:8081"]
B -->|์์ฒญ 3| E["๐ Spring Boot 3<br/>:8082"]
C --> F["๊ฒฐ๊ณผ ์ง๊ณ<br/>๋น ๋ฅธ ์๋ต"]
D --> F
E --> F
style B fill:#FFD700Mermaid
๋ณต์ฌ
# ์
์คํธ๋ฆผ ์ ์ โ ์ฌ๋ฌ ๋ฐฑ์๋ ์๋ฒ
upstream backend_servers {
# ๋ผ์ด๋ ๋ก๋น (๊ธฐ๋ณธ)
server localhost:8080;
server localhost:8081;
server localhost:8082;
}
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Plain Text
๋ณต์ฌ
๋ก๋ ๋ฐธ๋ฐ์ฑ ์๊ณ ๋ฆฌ์ฆ
์๊ณ ๋ฆฌ์ฆ | ์ค์ | ํน์ง |
๋ผ์ด๋ ๋ก๋น | (๊ธฐ๋ณธ) | ์์๋๋ก ๋์๊ฐ๋ฉฐ ๋ถ๋ฐฐ |
Least Conn | least_conn; | ์ฐ๊ฒฐ์ด ์ ์ ์๋ฒ ์ฐ์ |
IP Hash | ip_hash; | ํด๋ผ์ด์ธํธ IP ๊ธฐ์ค ์ผ๊ด๋ ๋ถ๋ฐฐ |
Weighted | weight=3; | ์๋ฒ ์ฑ๋ฅ์ ๋ฐ๋ผ ๋น์จ ์กฐ์ |
upstream backend {
least_conn; # ์ฐ๊ฒฐ์ด ์ ์ ์๋ฒ๋ก ๋ถ๋ฐฐ
server localhost:8080 weight=3; # ์ฑ๋ฅ ์ข์, ๋ง์ด ๋ถ๋ฐฐ
server localhost:8081 weight=1; # ์ฑ๋ฅ ์ฝํจ, ์ ๊ฒ ๋ถ๋ฐฐ
}
Plain Text
๋ณต์ฌ
ํต์ฌ ์ ๋ฆฌ
๋ฆฌ๋ฒ์ค ํ๋ก์ = ํด๋ผ์ด์ธํธ ๋์ ๋ฐฑ์๋ ์๋ฒ๋ฅผ ๋ณดํธํ๊ณ ์ค๊ฐ
๊ธฐ๋ณธ ์ค์ : proxy_pass http://localhost:8080
ํ์ ํค๋: X-Real-IP, X-Forwarded-For, X-Forwarded-Proto (๋ฐฑ์๋ ์ ๋ณด ์ ๋ฌ)
WebSocket: Upgrade ํค๋ + proxy_http_version 1.1 ํ์
๋ก๋ ๋ฐธ๋ฐ์ฑ: upstream์ผ๋ก ์ฌ๋ฌ ๋ฐฑ์๋ ์๋ฒ ๋ถ๋ฐฐ
ํ์์์: API๋ 60์ด, WebSocket์ 86400์ด(1์ผ) ๋ฑ์ผ๋ก ์ํฉ์ ๋ง๊ฒ



