Supergateway를 Nginx 역방향 프록시 뒤에 배치하면 TLS 암호화, 인증, Rate Limiting, 감사 로그를 한 번에 확보할 수 있습니다. 아래는 바로 복사해서 사용 가능한 프로덕션급 설정 예시입니다.skywork+2
🎯 최종 아키텍처
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 연동 │
└─────────────────────────────────────┘📋 사전 준비물
🚀 1단계: Supergateway 설치 및 실행 (2분)
Supergateway 설치
# 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 서버 준비 (예시)
# 작업 디렉토리 생성
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)
# .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/.envSupergateway 실행 스크립트 (/opt/mcp/start.sh)
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.shsystemd 서비스 등록 (자동 시작)
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/sse → text/event-stream 응답이 보이면 성공.modelcontextprotocol-security+1
⚙️ 2단계: Nginx 설치 및 기본 설정 (3분)
Nginx 설치
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginxMCP 전용 로그 형식 정의
/etc/nginx/nginx.conf 의 http { } 블록 안에 추가:
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;
# ... 나머지 설정 ...
}
확인 후 리로드:
sudo nginx -t && sudo systemctl reload nginx🔐 3단계: Nginx Reverse Proxy 설정 (완전 예시)
사이트 설정 파일 생성
/etc/nginx/sites-available/mcp-gateway 생성:
# 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."}';
}
}
설정 활성화
# 심볼릭 링크 생성
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분)
# Nginx 플러그인으로 자동 발급
sudo certbot --nginx -d mcp.yourcompany.com
# 자동 갱신 테스트
sudo certbot renew --dry-run
확인: https://mcp.yourcompany.com 접속 → 자물쇠 아이콘 표시.augmentcode+1
🧪 5단계: 연결 테스트 (1분)
기본 연결 테스트
# 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
건강 점검 테스트
curl https://mcp.yourcompany.com/health
# 예상 응답: healthyRate Limiting 테스트
# 30 회 연속 요청 (10 회 이후 429 발생)
for i in {1..30}; do
curl -s -o /dev/null -w "%{http_code}\n" https://mcp.yourcompany.com/sse
doneClaude Desktop 설정 테스트
claude_desktop_config.json:
{
"mcpServers": {
"slack-secure": {
"command": "npx",
"args": [
"-y",
"supergateway",
"--sse",
"https://mcp.yourcompany.com/sse"
]
}
}
}Claude 실행 후 테스트:
@Claude Slack 에 연결됐어? #general 채널 최근 메시지 3 개 요약해줘.🔐 옵션: JWT/OAuth 인증 추가 (엔터프라이즈)
OpenResty 설치 (JWT 검증용)
# 기존 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 검증 모듈 설치
sudo apt install -y lua-resty-openidcNginx 설정 수정 (JWT 검증 추가)
/etc/nginx/sites-available/mcp-gateway 의 location / { 블록 안에 추가:
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;
}
환경 변수 추가
# /opt/mcp/.env 에 추가
echo "KEYCLOAK_CLIENT_SECRET=your-keycloak-client-secret" >> /opt/mcp/.env
sudo chmod 600 /opt/mcp/.envNginx 리로드
sudo nginx -t && sudo systemctl reload nginx📊 로그 분석 예시
최근 1 시간 접근 로그 확인
# JSON 로그를 사람이 읽기 쉽게
cat /var/log/nginx/mcp-access.log | \
jq -r '"\(.time) | \(.client_ip) | \(.user_email) | \(.method) \(.uri) | \(.status) | \(.request_time)s"' | \
tail -20429 에러가 많은 사용자 Top 5
cat /var/log/nginx/mcp-access.log | \
jq -r 'select(.status == 429) | .user_email' | \
sort | uniq -c | sort -rn | head -5평균 응답 시간이 1 초를 넘는 요청
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-gateway가active (running)상태인지 확인
📈 성능 튜닝 팁
Nginx 워커 수 조정 (고트래픽 환경)
/etc/nginx/nginx.conf:
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 에러 발생
확인 리스트:
-
Supergateway 실행 상태:
sudo systemctl status mcp-gateway -
포트 3000 리스닝:
sudo netstat -tlnp | grep 3000 -
Nginx 에러 로그:
sudo tail -f /var/log/nginx/mcp-error.log
해결:
# Supergateway 재시작
sudo systemctl restart mcp-gateway
# Nginx 재시작
sudo systemctl restart nginx
Q2. SSE 연결이 바로 끊김
해결:
-
Nginx 설정에서
proxy_buffering off;확인 -
proxy_read_timeout 86400s;설정 확인 -
클라이언트 (Claude Desktop) 방화벽에서 긴 연결 허용 확인
Q3. Rate Limiting 이 너무 엄격함
조정:
# /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→10sudo nginx -t && sudo systemctl reload nginxQ4. JWT 인증 후 무한 리다이렉트
확인:
-
Keycloak
redirect_uri가https://mcp.yourcompany.com/callback으로 정확히 설정되었는지 확인 -
Nginx 설정의
redirect_after_auth_uri확인 -
Keycloak 클라이언트 설정에서
Valid Redirect URIs에https://mcp.yourcompany.com/*포함 확인
“Nginx 는 MCP 게이트웨이의 보안 요새입니다.”modelcontextprotocol-security+1
30 분 투자로 프로덕션급 보안을 확보하세요. Supergateway 는 도구일 뿐, 보안은 Nginx 가 책임집니다.augmentcode+1