# Claude AI IP Filter for Tailscale Funnel # # Routes MCP transport to Claude AI IPs only, while allowing # OAuth/auth endpoints from any IP (needed for user login flow). # # Pattern: homelab-argocd/atlantis/templates/nginx-webhook-config.yaml worker_processes auto; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; sendfile on; keepalive_timeout 65; # Map Claude AI outbound IPs (must be at http level) geo $remote_addr $is_claude_ai { default 0; # Anthropic Claude AI Outbound IP Range # Source: https://docs.claude.com/en/api/ip-addresses # Last updated: 2026-03-29 # IPv4 range 160.79.104.0/21 1; # Claude AI } server { listen 8080; server_name _; # Trust Tailscale proxy for real IP extraction real_ip_header X-Forwarded-For; set_real_ip_from 100.64.0.0/10; # Tailscale CGNAT range set_real_ip_from 10.0.0.0/8; # Docker internal networks set_real_ip_from 172.16.0.0/12; # Docker bridge networks real_ip_recursive on; # OAuth/auth endpoints + favicon - allow ALL IPs (user browser needs access for login flow) location ~ ^/(oauth|\.well-known|app|favicon\.ico)(/|$) { proxy_pass http://mcp-login-flow:8004; 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 https; } # MCP transport endpoint - Claude AI IPs ONLY # login-flow uses streamable-http transport (no /sse needed) location /mcp { if ($is_claude_ai = 0) { return 403 '{"error": "Access denied - IP not in Claude AI range", "source_ip": "$remote_addr"}\n'; } proxy_pass http://mcp-login-flow:8004; 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 https; # Streamable HTTP support (long-lived connections) proxy_buffering off; proxy_cache off; proxy_read_timeout 86400s; proxy_send_timeout 86400s; proxy_http_version 1.1; proxy_set_header Connection ''; } # Default - deny everything else location / { return 404 '{"error": "Not found"}\n'; } } }