Search

๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ

๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ (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:#90EE90
Mermaid
๋ณต์‚ฌ
๊ตฌ๋ถ„
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:#87CEEB
Mermaid
๋ณต์‚ฌ

์š”์ฒญ ํ๋ฆ„ ์ƒ์„ธ

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
์›๋ž˜ ์ ‘๊ทผ ํฌํŠธ
์ด ํ—ค๋”๋“ค์ด ์—†์œผ๋ฉด: Spring Boot๋Š” ๋ชจ๋“  ์š”์ฒญ์ด 127.0.0.1์—์„œ ์˜จ ๊ฒƒ์œผ๋กœ ์ธ์‹ํ•ด์š”! ์‚ฌ์šฉ์ž์˜ ์ง„์งœ IP๋ฅผ ์•Œ ์ˆ˜ ์—†๊ฒŒ ๋˜๋Š” ๊ฑฐ์ฃ .

๊ณ ๊ธ‰ ํ”„๋ก์‹œ ์„ค์ •

# ์—…์ŠคํŠธ๋ฆผ ์ •์˜ (๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ ๋Œ€๋น„) 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:#FFD700
Mermaid
๋ณต์‚ฌ
# ์—…์ŠคํŠธ๋ฆผ ์ •์˜ โ€” ์—ฌ๋Ÿฌ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ 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์ผ) ๋“ฑ์œผ๋กœ ์ƒํ™ฉ์— ๋งž๊ฒŒ