Supergateway + Nginx Reverse Proxy 설정 예시 — 프로덕션 완전 가이드

Supergateway를 Nginx 역방향 프록시 뒤에 배치하면 TLS 암호화, 인증, Rate Limiting, 감사 로그를 한 번에 확보할 수 있습니다. 아래는 바로 복사해서 사용 가능한 프로덕션급 설정 예시입니다.skywork+2


🎯 최종 아키텍처

text
Internet (클라이언트)
↓ HTTPS (443)
┌─────────────────────────────────────┐
│ Nginx Reverse Proxy │
│ - TLS 종단 (Let's Encrypt) │
│ - JWT/OAuth 인증 │
│ - Rate Limiting (초당 10 요청) │
│ - 보안 헤더 주입 │
│ - 감사 로그 (JSON) │
└─────────────────────────────────────┘
↓ HTTP (내부망, localhost:3000)
┌─────────────────────────────────────┐
│ Supergateway (포트 3000) │
│ --stdio MCP Slack Server │
│ --outputTransport sse │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ MCP Slack Server (stdio) │
│ - Slack API 연동 │
└─────────────────────────────────────┘

📋 사전 준비물

항목 필요 조건 확인 명령어
Ubuntu/Debian 서버 20.04+ (또는 동급 Linux) lsb_release -a
Supergateway 설치 Node.js 18+ node --version
도메인 mcp.yourcompany.com (DNS A 레코드 설정 완료) dig mcp.yourcompany.com
Root 권한 Nginx 설치 및 설정용 sudo -v

🚀 1단계: Supergateway 설치 및 실행 (2분)

Supergateway 설치

bash
# Node.js 18+ 설치 (미설치 시)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs

# Supergateway 전역 설치 (선택, 권장)
sudo npm install -g supergateway

# 또는 npx 로 즉시 실행도 가능

MCP Slack 서버 준비 (예시)

bash
# 작업 디렉토리 생성
sudo mkdir -p /opt/mcp
cd /opt/mcp

# 예시 MCP 서버 스크립트 생성 (mcp-slack-server.py)
cat > mcp-slack-server.py << 'EOF'
import os
from mcp.server import Server
from mcp.server.stdio import stdio_server

server = Server("slack-secure")

@server.tool("list_channels")
async def list_channels():
from slack_sdk import WebClient
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
result = client.conversations_list(types="public_channel")
return [{"id": c["id"], "name": c["name"]} for c in result["channels"]]

@server.tool("send_message")
async def send_message(channel: str, message: str):
from slack_sdk import WebClient
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
result = client.chat_postMessage(channel=channel, text=message)
return {"ok": True, "ts": result["ts"]}

if __name__ == "__main__":
import asyncio
asyncio.run(stdio_server(server))
EOF

환경 변수 설정 (.env)

bash
# .env 파일 생성 (절대 Git 에 커밋하지 말 것!)
cat > /opt/mcp/.env << 'EOF'
SLACK_BOT_TOKEN=xoxb-123456789012-1234567890123-AbCdEfGhIjKlMnOpQrStUvWx
MCP_AUTH_TOKEN=sk-mcp-your-secret-token-xyz123
EOF
# 권한 설정 (오직 mcp 사용자만 읽기 가능)
sudo chmod 600 /opt/mcp/.env

Supergateway 실행 스크립트 (/opt/mcp/start.sh)

bash
cat > /opt/mcp/start.sh << 'EOF'
#!/bin/bash
set -e

# 환경 변수 로드
source /opt/mcp/.env

# 로그 디렉토리 생성
mkdir -p /var/log/mcp

# Supergateway 시작
exec npx -y supergateway \
--stdio "python /opt/mcp/mcp-slack-server.py" \
--port 3000 \
--outputTransport sse \
--header "X-Auth-Source: nginx" \
2>&1 | tee /var/log/mcp/supergateway.log
EOF
# 실행 권한 부여
sudo chmod +x /opt/mcp/start.sh

systemd 서비스 등록 (자동 시작)

bash
cat > /etc/systemd/system/mcp-gateway.service << 'EOF'
[Unit]
Description=MCP Slack Gateway (Supergateway)
After=network.target

[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/mcp
EnvironmentFile=/opt/mcp/.env
ExecStart=/opt/mcp/start.sh
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mcp-gateway

# 보안 강화
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/mcp

[Install]
WantedBy=multi-user.target
EOF
# 서비스 시작
sudo systemctl daemon-reload
sudo systemctl enable mcp-gateway
sudo systemctl start mcp-gateway
sudo systemctl status mcp-gateway

확인: curl http://localhost:3000/ssetext/event-stream 응답이 보이면 성공.modelcontextprotocol-security+1


⚙️ 2단계: Nginx 설치 및 기본 설정 (3분)

Nginx 설치

bash
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

MCP 전용 로그 형식 정의

/etc/nginx/nginx.confhttp { } 블록 안에 추가:

text
http {
# ... 기존 설정 ...

# MCP 특화 JSON 로그 형식
log_format mcp_json escape=json
'{'
'"time":"$time_iso8601",'
'"client_ip":"$remote_addr",'
'"user_email":"$http_x_user_email",'
'"method":"$request_method",'
'"uri":"$uri",'
'"status":$status,'
'"bytes":$body_bytes_sent,'
'"request_time":$request_time,'
'"user_agent":"$http_user_agent"'
'}';

# 전역 Rate Limiting 존 정의
limit_req_zone $binary_remote_addr zone=mcp_global:10m rate=10r/s;
limit_req_zone $http_x_user_email zone=mcp_per_user:10m rate=5r/s;

# ... 나머지 설정 ...
}

확인 후 리로드:

bash
sudo nginx -t && sudo systemctl reload nginx

🔐 3단계: Nginx Reverse Proxy 설정 (완전 예시)

사이트 설정 파일 생성

/etc/nginx/sites-available/mcp-gateway 생성:

text
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name mcp.yourcompany.com;

# Let's Encrypt 인증용 경로 허용
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

# 그 외 모든 HTTP 요청은 HTTPS 로 리다이렉트
location / {
return 301 https://$server_name$request_uri;
}
}

# HTTPS 서버 블록
server {
listen 443 ssl http2;
server_name mcp.yourcompany.com;

# ===== TLS 설정 =====
ssl_certificate /etc/letsencrypt/live/mcp.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.yourcompany.com/privkey.pem;

# 현대적 TLS 프로토콜 및 암호
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

# ===== 보안 헤더 =====
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# ===== 로그 설정 =====
access_log /var/log/nginx/mcp-access.log mcp_json;
error_log /var/log/nginx/mcp-error.log warn;

# ===== 메인 프록시 설정 =====
location / {
# Rate Limiting (전역 + 사용자별)
limit_req zone=mcp_global burst=20 nodelay;
limit_req zone=mcp_per_user burst=10 nodelay;
limit_req_status 429;
limit_req_log_level warn;

# Supergateway 로 프록시
proxy_pass http://localhost:3000;
proxy_http_version 1.1;

# SSE/WebSocket 지원 (Upgrade 헤더)
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;

# SSE/WebSocket 긴 연결 유지 (24 시간)
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;

# 버퍼링 끄기 (실시간 스트리밍)
proxy_buffering off;
proxy_cache off;

# 청크 전송 인코딩
chunked_transfer_encoding on;
}

# ===== 건강 점검 엔드포인트 (모니터링용) =====
location /health {
access_log off;
proxy_pass http://localhost:3000/health;
proxy_read_timeout 5s;
add_header Content-Type text/plain;

# 실패 시 503 반환
proxy_intercept_errors on;
error_page 502 503 504 = @health_fail;
}

location @health_fail {
default_type text/plain;
return 503 "unhealthy\n";
}

# ===== Prometheus 메트릭 (내부망만 접근) =====
location /metrics {
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;

proxy_pass http://localhost:3000/metrics;
proxy_read_timeout 5s;
}

# ===== 에러 페이지 =====
proxy_intercept_errors on;

error_page 429 = @rate_limit_exceeded;
error_page 502 503 504 = @gateway_error;

location @rate_limit_exceeded {
default_type application/json;
return 429 '{"error": "Too Many Requests", "message": "Rate limit exceeded. Please try again later."}';
}

location @gateway_error {
default_type application/json;
return 503 '{"error": "Service Unavailable", "message": "MCP Gateway is temporarily unavailable. Please try again later."}';
}
}

설정 활성화

bash
# 심볼릭 링크 생성
sudo ln -s /etc/nginx/sites-available/mcp-gateway /etc/nginx/sites-enabled/

# 기존 default 사이트 제거 (선택, 보안 권장)
sudo rm /etc/nginx/sites-enabled/default

# 설정 테스트 및 리로드
sudo nginx -t && sudo systemctl reload nginx


🔒 4단계: Let’s Encrypt TLS 인증서 발급 (2분)

bash
# Nginx 플러그인으로 자동 발급
sudo certbot --nginx -d mcp.yourcompany.com

# 자동 갱신 테스트
sudo certbot renew --dry-run

확인: https://mcp.yourcompany.com 접속 → 자물쇠 아이콘 표시.augmentcode+1


🧪 5단계: 연결 테스트 (1분)

기본 연결 테스트

bash
# SSE 엔드포인트 테스트 (200 OK + text/event-stream 확인)
curl -I https://mcp.yourcompany.com/sse

# 예상 응답:
# HTTP/2 200
# content-type: text/event-stream
# strict-transport-security: max-age=31536000; includeSubDomains; preload

건강 점검 테스트

bash
curl https://mcp.yourcompany.com/health
# 예상 응답: healthy

Rate Limiting 테스트

bash
# 30 회 연속 요청 (10 회 이후 429 발생)
for i in {1..30}; do
curl -s -o /dev/null -w "%{http_code}\n" https://mcp.yourcompany.com/sse
done

Claude Desktop 설정 테스트

claude_desktop_config.json:

json
{
"mcpServers": {
"slack-secure": {
"command": "npx",
"args": [
"-y",
"supergateway",
"--sse",
"https://mcp.yourcompany.com/sse"
]
}
}
}

Claude 실행 후 테스트:

text
@Claude Slack 에 연결됐어? #general 채널 최근 메시지 3 개 요약해줘.

🔐 옵션: JWT/OAuth 인증 추가 (엔터프라이즈)

OpenResty 설치 (JWT 검증용)

bash
# 기존 Nginx 제거 (선택)
sudo apt remove nginx

# OpenResty 설치
wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
sudo apt update
sudo apt install -y openresty

JWT 검증 모듈 설치

bash
sudo apt install -y lua-resty-openidc

Nginx 설정 수정 (JWT 검증 추가)

/etc/nginx/sites-available/mcp-gatewaylocation / { 블록 안에 추가:

text
location / {
# ===== JWT 검증 (Keycloak 예시) =====
access_by_lua_block {
local openidc = require("resty.openidc")

local res, err = openidc.authenticate({
discovery = "https://auth.yourcompany.com/.well-known/openid-configuration",
client_id = "mcp-gateway",
client_secret = os.getenv("KEYCLOAK_CLIENT_SECRET"),
redirect_uri = "https://mcp.yourcompany.com/callback",
scope = "openid profile mcp.access",
ssl_verify = "yes",
redirect_after_auth_uri = "https://mcp.yourcompany.com/"
})

if err then
ngx.status = 401
ngx.header["Content-Type"] = "application/json"
ngx.say('{"error": "Unauthorized", "message": "' .. err .. '"}')
ngx.exit(401)
end

-- 검증된 사용자 정보를 헤더로 전달
ngx.req.set_header("X-User-Email", res.user.email)
ngx.req.set_header("X-User-Roles", table.concat(res.user.roles or {}, ","))
ngx.req.set_header("X-User-Name", res.user.name)
}

# Rate Limiting (JWT email 기준)
limit_req zone=mcp_global burst=20 nodelay;
limit_req zone=mcp_per_user burst=10 nodelay;
limit_req_status 429;

# ... 나머지 프록시 설정 (위와 동일) ...
proxy_pass http://localhost:3000;
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_buffering off;
}

환경 변수 추가

bash
# /opt/mcp/.env 에 추가
echo "KEYCLOAK_CLIENT_SECRET=your-keycloak-client-secret" >> /opt/mcp/.env
sudo chmod 600 /opt/mcp/.env

Nginx 리로드

bash
sudo nginx -t && sudo systemctl reload nginx

📊 로그 분석 예시

최근 1 시간 접근 로그 확인

bash
# JSON 로그를 사람이 읽기 쉽게
cat /var/log/nginx/mcp-access.log | \
jq -r '"\(.time) | \(.client_ip) | \(.user_email) | \(.method) \(.uri) | \(.status) | \(.request_time)s"' | \
tail -20

429 에러가 많은 사용자 Top 5

bash
cat /var/log/nginx/mcp-access.log | \
jq -r 'select(.status == 429) | .user_email' | \
sort | uniq -c | sort -rn | head -5

평균 응답 시간이 1 초를 넘는 요청

bash
cat /var/log/nginx/mcp-access.log | \
jq -r 'select(.request_time > 1) | "\(.time) | \(.uri) | \(.request_time)s"' | \
tail -10

🛡️ 보안 강화 체크리스트

  • HTTPS 강제: http:// 접근 시 301 리다이렉트 확인

  • TLS 버전: ssl_protocols TLSv1.2 TLSv1.3; 설정 확인

  • 보안 헤더: Strict-Transport-Security, X-Content-Type-Options 등 확인

  • Rate Limiting: 초당 10 회 이상 요청 시 429 반환 확인

  • 감사 로그: JSON 형식으로 상세 로그 기록 확인

  • 건강 점검: /health 에서 200 OK 반환 확인

  • 환경 변수 권한: .env 파일이 600 권한인지 확인

  • systemd 서비스: mcp-gatewayactive (running) 상태인지 확인


📈 성능 튜닝 팁

Nginx 워커 수 조정 (고트래픽 환경)

/etc/nginx/nginx.conf:

text
worker_processes auto; # CPU 코어 수에 맞춤
worker_rlimit_nofile 65535;

events {
worker_connections 4096; # 동시 연결 수 증가
multi_accept on;
use epoll;
}

http {
# ... 기존 설정 ...

# Keepalive 최적화
keepalive_timeout 65;
keepalive_requests 100;

# 업스트림 연결 풀 (Supergateway 여러 인스턴스 실행 시)
upstream supergateway {
server localhost:3000;
server localhost:3001; # 추가 인스턴스
keepalive 32;
}
}


⚠️ 문제 해결 (FAQ)

Q1. 502 Bad Gateway 에러 발생

확인 리스트:

  1. Supergateway 실행 상태: sudo systemctl status mcp-gateway

  2. 포트 3000 리스닝: sudo netstat -tlnp | grep 3000

  3. Nginx 에러 로그: sudo tail -f /var/log/nginx/mcp-error.log

해결:

bash
# Supergateway 재시작
sudo systemctl restart mcp-gateway

# Nginx 재시작
sudo systemctl restart nginx


Q2. SSE 연결이 바로 끊김

해결:

  1. Nginx 설정에서 proxy_buffering off; 확인

  2. proxy_read_timeout 86400s; 설정 확인

  3. 클라이언트 (Claude Desktop) 방화벽에서 긴 연결 허용 확인


Q3. Rate Limiting 이 너무 엄격함

조정:

text
# /etc/nginx/sites-available/mcp-gateway 수정
limit_req_zone $binary_remote_addr zone=mcp_global:10m rate=20r/s; # 10→20
limit_req_zone $http_x_user_email zone=mcp_per_user:10m rate=10r/s; # 5→10
bash
sudo nginx -t && sudo systemctl reload nginx

Q4. JWT 인증 후 무한 리다이렉트

확인:

  1. Keycloak redirect_urihttps://mcp.yourcompany.com/callback 으로 정확히 설정되었는지 확인

  2. Nginx 설정의 redirect_after_auth_uri 확인

  3. Keycloak 클라이언트 설정에서 Valid Redirect URIshttps://mcp.yourcompany.com/* 포함 확인


“Nginx 는 MCP 게이트웨이의 보안 요새입니다.”modelcontextprotocol-security+1

 
 

30 분 투자로 프로덕션급 보안을 확보하세요. Supergateway 는 도구일 뿐, 보안은 Nginx 가 책임집니다.augmentcode+1

댓글 남기기