-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp-apache.conf
More file actions
88 lines (77 loc) · 3.58 KB
/
Copy pathmcp-apache.conf
File metadata and controls
88 lines (77 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# Apache 2.4 vhost for ndcourts-mcp on a dedicated subdomain.
# Use when an existing Apache install is already fronting :80/:443 and you
# want to add an MCP endpoint without disturbing it.
#
# Access model: capability URL (secret path). The opinion data is public
# (CC0), so the unguessable path segment is access control against bots and
# scrapers, not secrecy. No per-user credentials; share the full URL:
#
# https://MCP_HOST/MCP_TOKEN/mcp
#
# Everything outside /MCP_TOKEN/ returns 404 from Apache without touching
# the app. Pair with deploy/fail2ban/ (apache-mcp jails): token-less probes
# get banned on repeated 404s, and real traffic is rate-capped per IP.
#
# Install:
# 1. Generate a token and render the file (the rendered file is what
# Apache reads — the token lives ONLY on the server, never in git):
# TOKEN=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 28)
# sudo sed -e "s/MCP_HOST/mcp.example.com/g" -e "s/MCP_TOKEN/$TOKEN/g" \
# deploy/mcp-apache.conf | sudo tee /etc/apache2/sites-available/mcp.example.com.conf
# 2. Enable required modules (idempotent):
# sudo a2enmod proxy proxy_http headers ssl rewrite
# 3. Enable the site and reload Apache (the :443 block is guarded by
# <IfFile>, so Apache starts cleanly before the cert exists):
# sudo a2ensite mcp.example.com
# sudo systemctl reload apache2
# 4. Issue the TLS cert. --apache uses HTTP-01 over the :80 vhost below:
# sudo certbot certonly --apache -d mcp.example.com
# sudo systemctl reload apache2
# 5. Install the fail2ban jails (see deploy/fail2ban/jail.d/apache-mcp.conf).
#
# Rotate access: change the token in the rendered conf, reload Apache, and
# re-share the URL. Cert renewal: certbot's systemd timer handles it.
<VirtualHost *:80>
ServerName MCP_HOST
# Keep /.well-known/acme-challenge/ reachable for cert renewal; redirect
# everything else to HTTPS.
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
# The :443 block activates only after certbot has populated the cert files.
# This lets `a2ensite` + reload succeed on a fresh install before step 4.
<IfFile "/etc/letsencrypt/live/MCP_HOST/fullchain.pem">
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName MCP_HOST
ErrorLog ${APACHE_LOG_DIR}/MCP_HOST-error.log
CustomLog ${APACHE_LOG_DIR}/MCP_HOST-access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/MCP_HOST/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/MCP_HOST/privkey.pem
# --- Reverse proxy, reachable ONLY under the secret path ---
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 120
# Deny everything by default (403 at Apache; the app never sees it),
# then re-open just the token path. Later <Location> wins on overlap.
<Location />
Require all denied
</Location>
<Location /MCP_TOKEN/>
Require all granted
ProxyPass http://127.0.0.1:8000/ flushpackets=on
ProxyPassReverse http://127.0.0.1:8000/
# MCP can return text/event-stream; defeat buffering & compression
# so SSE chunks reach the client as they're produced.
SetEnv proxy-sendchunked 1
RequestHeader unset Accept-Encoding
Header set X-Accel-Buffering "no"
</Location>
# Cap request bodies — JSON-RPC payloads are tiny.
LimitRequestBody 262144
</VirtualHost>
</IfModule>
</IfFile>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet