From 196374e70c5f3ab8d79d87a6867df835af91f3c7 Mon Sep 17 00:00:00 2001 From: kaffa Date: Sun, 1 Feb 2026 12:34:47 +0000 Subject: [PATCH] Simplify backend configuration to HTTP only Remove SSL/QUIC backend templates - all backends now use HTTP only with SSL termination at HAProxy frontend. This improves performance (~33% faster than HTTPS backends based on benchmarks). Changes: - server.py: Remove https_port parameter from all functions - haproxy.cfg: Remove ssl/h3 server templates from pool backends - CLAUDE.md: Update docs for HTTP-only backends and acme.sh Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 88 ++++++++------------- conf/haproxy.cfg | 200 ----------------------------------------------- mcp/server.py | 81 +++++++------------ 3 files changed, 60 insertions(+), 309 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 02975ab..598ac90 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -HAProxy Dynamic Load Balancer Management Suite - a system for runtime management of HAProxy without restarts. Provides MCP interface for dynamic domain/server management with HTTP, HTTPS, and HTTP/3 (QUIC) support. +HAProxy Dynamic Load Balancer Management Suite - a system for runtime management of HAProxy without restarts. Provides MCP interface for dynamic domain/server management. Frontend supports HTTP/HTTPS/HTTP3, backends use HTTP only (SSL termination at HAProxy). **Key Feature:** Zero-reload domain management using HAProxy map files and pool backends. @@ -70,32 +70,27 @@ journalctl -u haproxy-mcp -f # Logs ### Adding a Domain -**Default (HTTP/HTTPS/H3):** ```bash haproxy_add_domain("example.com", "10.0.0.1") -# Creates: pool_N_1 (80), pool_N_ssl_1 (443), pool_N_h3_1 (443) -``` +# Creates: pool_N_1 → 10.0.0.1:80 -**Custom port (HTTP only):** -```bash haproxy_add_domain("api.example.com", "10.0.0.1", 8080) -# Creates: pool_N_1 (8080) only +# Creates: pool_N_1 → 10.0.0.1:8080 ``` This will: 1. Find available pool (e.g., `pool_5`) 2. Add to `domains.map`: `example.com pool_5` 3. Update HAProxy runtime map: `add map ... example.com pool_5` -4. Configure server(s) in pool via Runtime API +4. Configure server in pool via Runtime API (HTTP only) 5. Save to `servers.json` for persistence **No HAProxy reload required!** -### Port Logic -| Setting | Servers Created | -|---------|-----------------| -| Default (80/443) | HTTP + HTTPS + HTTP/3 (3 servers) | -| Custom port | HTTP only (1 server) | +### Backend Configuration +- Backends always use HTTP (port 80 or custom) +- SSL/TLS termination happens at HAProxy frontend +- Each pool has 10 server slots (pool_N_1 to pool_N_10) ### Files | File | Purpose | @@ -109,51 +104,35 @@ This will: ### Current Setup | Item | Value | |------|-------| -| ACME Client | certbot + dns-cloudflare | +| ACME Client | acme.sh (Google Trust Services CA) | | Cert Directory | `/opt/haproxy/certs/` (auto-loaded by HAProxy) | -| Deploy Hook | `/etc/letsencrypt/renewal-hooks/deploy/haproxy-deploy.sh` | +| acme.sh Home | `~/.acme.sh/` | ### How It Works 1. HAProxy binds with `crt /etc/haproxy/certs/` (directory, not file) 2. All `.pem` files in directory are auto-loaded 3. SNI selects correct certificate based on domain -4. Certbot deploy hook auto-creates combined PEM on issue/renewal +4. acme.sh deploy hook auto-creates combined PEM on issue/renewal ### Adding New Certificate ```bash -# Issue certificate (Let's Encrypt) -certbot certonly \ - --dns-cloudflare \ - --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \ - -d "newdomain.com" -d "*.newdomain.com" -``` - -Deploy hook automatically: -1. Combines `fullchain.pem + privkey.pem` → `/opt/haproxy/certs/newdomain.com.pem` -2. Restarts HAProxy -3. **No manual cfg modification needed!** - -### Google Trust Services (optional) -```bash -certbot certonly \ - --server https://dv.acme-v02.api.pki.goog/directory \ - --eab-kid "KEY_ID" \ - --eab-hmac-key "HMAC_KEY" \ - --dns-cloudflare \ - --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \ - -d "domain.com" -d "*.domain.com" +# Issue certificate (Google Trust Services) +~/.acme.sh/acme.sh --issue \ + --dns dns_cf \ + -d "newdomain.com" -d "*.newdomain.com" \ + --reloadcmd "cat ~/.acme.sh/newdomain.com_ecc/fullchain.cer ~/.acme.sh/newdomain.com_ecc/newdomain.com.key > /opt/haproxy/certs/newdomain.com.pem && podman exec haproxy kill -USR2 1" ``` ### Certificate Commands ```bash # List certificates -certbot certificates +~/.acme.sh/acme.sh --list -# Renew all (dry run) -certbot renew --dry-run +# Renew all +~/.acme.sh/acme.sh --cron -# Renew all (force) -certbot renew --force-renewal +# Force renew specific domain +~/.acme.sh/acme.sh --renew -d "domain.com" --force # Check loaded certs in HAProxy ls -la /opt/haproxy/certs/ @@ -162,6 +141,7 @@ ls -la /opt/haproxy/certs/ ### Cloudflare Credentials - File: `~/.secrets/cloudflare.ini` - Format: `dns_cloudflare_api_token = TOKEN` +- Also export: `export CF_Token="your_token"` ## HTTP/3 (QUIC) @@ -245,18 +225,17 @@ curl -X POST https://mcp.inouter.com/mcp \ - Each pool has 10 server slots ### Server Naming -Pool backends use this naming: -- `pool_N_1` to `pool_N_10` - HTTP (always created) -- `pool_N_ssl_1` to `pool_N_ssl_10` - HTTPS (default ports only) -- `pool_N_h3_1` to `pool_N_h3_10` - HTTP/3 QUIC (default ports only) +Pool backends use simple naming: `pool_N_1` to `pool_N_10` **Examples:** ``` -example.com (80/443 default): - └─ pool_5_1, pool_5_ssl_1, pool_5_h3_1 +example.com → pool_5 + └─ pool_5_1 (slot 1) + └─ pool_5_2 (slot 2) + └─ ... up to pool_5_10 -api.example.com (custom port 8080): - └─ pool_6_1 only +api.example.com → pool_6 + └─ pool_6_1 (slot 1) ``` ### Persistence @@ -302,10 +281,9 @@ echo "set server pool_1/pool_1_1 state ready" | nc localhost 9999 ├── scripts/ # Utility scripts └── run/ # Runtime socket files -/etc/letsencrypt/ -├── live/ # Certbot certificates -└── renewal-hooks/deploy/ - └── haproxy-deploy.sh # Auto-combine PEM & restart HAProxy +~/.acme.sh/ +├── *_ecc/ # Certificate directories (one per domain) +└── acme.sh # ACME client script /etc/containers/systemd/ └── haproxy.container # Podman Quadlet config @@ -322,7 +300,7 @@ echo "set server pool_1/pool_1_1 state ready" | nc localhost 9999 | `/etc/containers/systemd/haproxy.container` | Podman Quadlet | | `/etc/systemd/system/haproxy-mcp.service` | MCP service | | `/opt/haproxy/conf/mcp-token.env` | MCP auth token | -| `/etc/letsencrypt/renewal-hooks/deploy/haproxy-deploy.sh` | Cert deploy hook | +| `~/.acme.sh/` | acme.sh certificates and config | | `~/.secrets/cloudflare.ini` | Cloudflare API token | ## Startup Sequence diff --git a/conf/haproxy.cfg b/conf/haproxy.cfg index 6ea7447..d2862e4 100644 --- a/conf/haproxy.cfg +++ b/conf/haproxy.cfg @@ -83,62 +83,42 @@ backend default_backend backend pool_1 balance roundrobin server-template pool_1_ 10 0.0.0.0:0 check disabled - server-template pool_1_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_1_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_2 balance roundrobin server-template pool_2_ 10 0.0.0.0:0 check disabled - server-template pool_2_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_2_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_3 balance roundrobin server-template pool_3_ 10 0.0.0.0:0 check disabled - server-template pool_3_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_3_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_4 balance roundrobin server-template pool_4_ 10 0.0.0.0:0 check disabled - server-template pool_4_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_4_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_5 balance roundrobin server-template pool_5_ 10 0.0.0.0:0 check disabled - server-template pool_5_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_5_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_6 balance roundrobin server-template pool_6_ 10 0.0.0.0:0 check disabled - server-template pool_6_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_6_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_7 balance roundrobin server-template pool_7_ 10 0.0.0.0:0 check disabled - server-template pool_7_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_7_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_8 balance roundrobin server-template pool_8_ 10 0.0.0.0:0 check disabled - server-template pool_8_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_8_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_9 balance roundrobin server-template pool_9_ 10 0.0.0.0:0 check disabled - server-template pool_9_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_9_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_10 balance roundrobin server-template pool_10_ 10 0.0.0.0:0 check disabled - server-template pool_10_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_10_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 # ACME Backend (for certbot) backend acme_backend @@ -147,539 +127,359 @@ backend acme_backend backend pool_11 balance roundrobin server-template pool_11_ 10 0.0.0.0:0 check disabled - server-template pool_11_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_11_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_12 balance roundrobin server-template pool_12_ 10 0.0.0.0:0 check disabled - server-template pool_12_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_12_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_13 balance roundrobin server-template pool_13_ 10 0.0.0.0:0 check disabled - server-template pool_13_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_13_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_14 balance roundrobin server-template pool_14_ 10 0.0.0.0:0 check disabled - server-template pool_14_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_14_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_15 balance roundrobin server-template pool_15_ 10 0.0.0.0:0 check disabled - server-template pool_15_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_15_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_16 balance roundrobin server-template pool_16_ 10 0.0.0.0:0 check disabled - server-template pool_16_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_16_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_17 balance roundrobin server-template pool_17_ 10 0.0.0.0:0 check disabled - server-template pool_17_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_17_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_18 balance roundrobin server-template pool_18_ 10 0.0.0.0:0 check disabled - server-template pool_18_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_18_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_19 balance roundrobin server-template pool_19_ 10 0.0.0.0:0 check disabled - server-template pool_19_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_19_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_20 balance roundrobin server-template pool_20_ 10 0.0.0.0:0 check disabled - server-template pool_20_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_20_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_21 balance roundrobin server-template pool_21_ 10 0.0.0.0:0 check disabled - server-template pool_21_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_21_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_22 balance roundrobin server-template pool_22_ 10 0.0.0.0:0 check disabled - server-template pool_22_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_22_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_23 balance roundrobin server-template pool_23_ 10 0.0.0.0:0 check disabled - server-template pool_23_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_23_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_24 balance roundrobin server-template pool_24_ 10 0.0.0.0:0 check disabled - server-template pool_24_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_24_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_25 balance roundrobin server-template pool_25_ 10 0.0.0.0:0 check disabled - server-template pool_25_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_25_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_26 balance roundrobin server-template pool_26_ 10 0.0.0.0:0 check disabled - server-template pool_26_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_26_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_27 balance roundrobin server-template pool_27_ 10 0.0.0.0:0 check disabled - server-template pool_27_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_27_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_28 balance roundrobin server-template pool_28_ 10 0.0.0.0:0 check disabled - server-template pool_28_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_28_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_29 balance roundrobin server-template pool_29_ 10 0.0.0.0:0 check disabled - server-template pool_29_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_29_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_30 balance roundrobin server-template pool_30_ 10 0.0.0.0:0 check disabled - server-template pool_30_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_30_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_31 balance roundrobin server-template pool_31_ 10 0.0.0.0:0 check disabled - server-template pool_31_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_31_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_32 balance roundrobin server-template pool_32_ 10 0.0.0.0:0 check disabled - server-template pool_32_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_32_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_33 balance roundrobin server-template pool_33_ 10 0.0.0.0:0 check disabled - server-template pool_33_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_33_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_34 balance roundrobin server-template pool_34_ 10 0.0.0.0:0 check disabled - server-template pool_34_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_34_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_35 balance roundrobin server-template pool_35_ 10 0.0.0.0:0 check disabled - server-template pool_35_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_35_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_36 balance roundrobin server-template pool_36_ 10 0.0.0.0:0 check disabled - server-template pool_36_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_36_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_37 balance roundrobin server-template pool_37_ 10 0.0.0.0:0 check disabled - server-template pool_37_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_37_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_38 balance roundrobin server-template pool_38_ 10 0.0.0.0:0 check disabled - server-template pool_38_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_38_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_39 balance roundrobin server-template pool_39_ 10 0.0.0.0:0 check disabled - server-template pool_39_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_39_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_40 balance roundrobin server-template pool_40_ 10 0.0.0.0:0 check disabled - server-template pool_40_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_40_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_41 balance roundrobin server-template pool_41_ 10 0.0.0.0:0 check disabled - server-template pool_41_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_41_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_42 balance roundrobin server-template pool_42_ 10 0.0.0.0:0 check disabled - server-template pool_42_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_42_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_43 balance roundrobin server-template pool_43_ 10 0.0.0.0:0 check disabled - server-template pool_43_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_43_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_44 balance roundrobin server-template pool_44_ 10 0.0.0.0:0 check disabled - server-template pool_44_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_44_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_45 balance roundrobin server-template pool_45_ 10 0.0.0.0:0 check disabled - server-template pool_45_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_45_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_46 balance roundrobin server-template pool_46_ 10 0.0.0.0:0 check disabled - server-template pool_46_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_46_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_47 balance roundrobin server-template pool_47_ 10 0.0.0.0:0 check disabled - server-template pool_47_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_47_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_48 balance roundrobin server-template pool_48_ 10 0.0.0.0:0 check disabled - server-template pool_48_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_48_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_49 balance roundrobin server-template pool_49_ 10 0.0.0.0:0 check disabled - server-template pool_49_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_49_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_50 balance roundrobin server-template pool_50_ 10 0.0.0.0:0 check disabled - server-template pool_50_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_50_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_51 balance roundrobin server-template pool_51_ 10 0.0.0.0:0 check disabled - server-template pool_51_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_51_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_52 balance roundrobin server-template pool_52_ 10 0.0.0.0:0 check disabled - server-template pool_52_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_52_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_53 balance roundrobin server-template pool_53_ 10 0.0.0.0:0 check disabled - server-template pool_53_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_53_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_54 balance roundrobin server-template pool_54_ 10 0.0.0.0:0 check disabled - server-template pool_54_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_54_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_55 balance roundrobin server-template pool_55_ 10 0.0.0.0:0 check disabled - server-template pool_55_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_55_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_56 balance roundrobin server-template pool_56_ 10 0.0.0.0:0 check disabled - server-template pool_56_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_56_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_57 balance roundrobin server-template pool_57_ 10 0.0.0.0:0 check disabled - server-template pool_57_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_57_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_58 balance roundrobin server-template pool_58_ 10 0.0.0.0:0 check disabled - server-template pool_58_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_58_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_59 balance roundrobin server-template pool_59_ 10 0.0.0.0:0 check disabled - server-template pool_59_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_59_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_60 balance roundrobin server-template pool_60_ 10 0.0.0.0:0 check disabled - server-template pool_60_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_60_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_61 balance roundrobin server-template pool_61_ 10 0.0.0.0:0 check disabled - server-template pool_61_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_61_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_62 balance roundrobin server-template pool_62_ 10 0.0.0.0:0 check disabled - server-template pool_62_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_62_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_63 balance roundrobin server-template pool_63_ 10 0.0.0.0:0 check disabled - server-template pool_63_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_63_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_64 balance roundrobin server-template pool_64_ 10 0.0.0.0:0 check disabled - server-template pool_64_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_64_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_65 balance roundrobin server-template pool_65_ 10 0.0.0.0:0 check disabled - server-template pool_65_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_65_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_66 balance roundrobin server-template pool_66_ 10 0.0.0.0:0 check disabled - server-template pool_66_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_66_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_67 balance roundrobin server-template pool_67_ 10 0.0.0.0:0 check disabled - server-template pool_67_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_67_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_68 balance roundrobin server-template pool_68_ 10 0.0.0.0:0 check disabled - server-template pool_68_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_68_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_69 balance roundrobin server-template pool_69_ 10 0.0.0.0:0 check disabled - server-template pool_69_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_69_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_70 balance roundrobin server-template pool_70_ 10 0.0.0.0:0 check disabled - server-template pool_70_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_70_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_71 balance roundrobin server-template pool_71_ 10 0.0.0.0:0 check disabled - server-template pool_71_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_71_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_72 balance roundrobin server-template pool_72_ 10 0.0.0.0:0 check disabled - server-template pool_72_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_72_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_73 balance roundrobin server-template pool_73_ 10 0.0.0.0:0 check disabled - server-template pool_73_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_73_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_74 balance roundrobin server-template pool_74_ 10 0.0.0.0:0 check disabled - server-template pool_74_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_74_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_75 balance roundrobin server-template pool_75_ 10 0.0.0.0:0 check disabled - server-template pool_75_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_75_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_76 balance roundrobin server-template pool_76_ 10 0.0.0.0:0 check disabled - server-template pool_76_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_76_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_77 balance roundrobin server-template pool_77_ 10 0.0.0.0:0 check disabled - server-template pool_77_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_77_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_78 balance roundrobin server-template pool_78_ 10 0.0.0.0:0 check disabled - server-template pool_78_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_78_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_79 balance roundrobin server-template pool_79_ 10 0.0.0.0:0 check disabled - server-template pool_79_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_79_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_80 balance roundrobin server-template pool_80_ 10 0.0.0.0:0 check disabled - server-template pool_80_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_80_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_81 balance roundrobin server-template pool_81_ 10 0.0.0.0:0 check disabled - server-template pool_81_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_81_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_82 balance roundrobin server-template pool_82_ 10 0.0.0.0:0 check disabled - server-template pool_82_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_82_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_83 balance roundrobin server-template pool_83_ 10 0.0.0.0:0 check disabled - server-template pool_83_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_83_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_84 balance roundrobin server-template pool_84_ 10 0.0.0.0:0 check disabled - server-template pool_84_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_84_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_85 balance roundrobin server-template pool_85_ 10 0.0.0.0:0 check disabled - server-template pool_85_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_85_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_86 balance roundrobin server-template pool_86_ 10 0.0.0.0:0 check disabled - server-template pool_86_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_86_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_87 balance roundrobin server-template pool_87_ 10 0.0.0.0:0 check disabled - server-template pool_87_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_87_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_88 balance roundrobin server-template pool_88_ 10 0.0.0.0:0 check disabled - server-template pool_88_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_88_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_89 balance roundrobin server-template pool_89_ 10 0.0.0.0:0 check disabled - server-template pool_89_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_89_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_90 balance roundrobin server-template pool_90_ 10 0.0.0.0:0 check disabled - server-template pool_90_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_90_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_91 balance roundrobin server-template pool_91_ 10 0.0.0.0:0 check disabled - server-template pool_91_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_91_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_92 balance roundrobin server-template pool_92_ 10 0.0.0.0:0 check disabled - server-template pool_92_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_92_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_93 balance roundrobin server-template pool_93_ 10 0.0.0.0:0 check disabled - server-template pool_93_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_93_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_94 balance roundrobin server-template pool_94_ 10 0.0.0.0:0 check disabled - server-template pool_94_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_94_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_95 balance roundrobin server-template pool_95_ 10 0.0.0.0:0 check disabled - server-template pool_95_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_95_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_96 balance roundrobin server-template pool_96_ 10 0.0.0.0:0 check disabled - server-template pool_96_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_96_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_97 balance roundrobin server-template pool_97_ 10 0.0.0.0:0 check disabled - server-template pool_97_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_97_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_98 balance roundrobin server-template pool_98_ 10 0.0.0.0:0 check disabled - server-template pool_98_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_98_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_99 balance roundrobin server-template pool_99_ 10 0.0.0.0:0 check disabled - server-template pool_99_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_99_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 backend pool_100 balance roundrobin server-template pool_100_ 10 0.0.0.0:0 check disabled - server-template pool_100_ssl_ 10 0.0.0.0:0 check disabled ssl verify none - server-template pool_100_h3_ 10 quic4@0.0.0.0:0 check disabled ssl verify none alpn h3 diff --git a/mcp/server.py b/mcp/server.py index e89be52..6fd379d 100644 --- a/mcp/server.py +++ b/mcp/server.py @@ -3,7 +3,7 @@ This module provides an MCP (Model Context Protocol) server for managing HAProxy configuration and runtime state. It supports dynamic domain/server management -with HTTP, HTTPS, and HTTP/3 (QUIC) protocols. +with HTTP backends (SSL termination at HAProxy frontend). """ import socket @@ -395,7 +395,7 @@ def save_servers_config(config: Dict) -> None: pass -def add_server_to_config(domain: str, slot: int, ip: str, http_port: int, https_port: int) -> None: +def add_server_to_config(domain: str, slot: int, ip: str, http_port: int) -> None: """Add server configuration to persistent storage. Args: @@ -403,15 +403,13 @@ def add_server_to_config(domain: str, slot: int, ip: str, http_port: int, https_ slot: Server slot (1 to MAX_SLOTS) ip: Server IP address http_port: HTTP port - https_port: HTTPS port """ config = load_servers_config() if domain not in config: config[domain] = {} config[domain][str(slot)] = { "ip": ip, - "http_port": http_port, - "https_port": https_port + "http_port": http_port } save_servers_config(config) @@ -443,22 +441,16 @@ def remove_domain_from_config(domain: str) -> None: save_servers_config(config) -def get_server_suffixes(http_port: int, https_port: int) -> List[Tuple[str, int]]: +def get_server_suffixes(http_port: int) -> List[Tuple[str, int]]: """Get server suffixes and ports based on port configuration. Args: - http_port: HTTP port - https_port: HTTPS port + http_port: HTTP port for backend Returns: - List of (suffix, port) tuples + List of (suffix, port) tuples - always HTTP only """ - if http_port == 80 and https_port == 443: - # Default ports: HTTP + HTTPS + HTTP/3 - return [("", 80), ("_ssl", 443), ("_h3", 443)] - else: - # Custom port: HTTP only - return [("", http_port)] + return [("", http_port)] def restore_servers_from_config() -> int: @@ -497,13 +489,12 @@ def restore_servers_from_config() -> int: try: http_port = int(server_info.get("http_port", 80)) - https_port = int(server_info.get("https_port", 443)) except (ValueError, TypeError): print(f"Warning: Invalid port for {domain} slot {slot}, skipping", file=sys.stderr) continue try: - for suffix, port in get_server_suffixes(http_port, https_port): + for suffix, port in get_server_suffixes(http_port): server = f"{server_prefix}{suffix}_{slot}" haproxy_cmd(f"set server {backend}/{server} addr {ip} port {port}") haproxy_cmd(f"set server {backend}/{server} state ready") @@ -553,14 +544,13 @@ def haproxy_list_domains() -> str: @mcp.tool() -def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80, https_port: int = 443) -> str: +def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80) -> str: """Add a new domain to HAProxy using map-based routing (no reload required). Args: domain: The domain name to add (e.g., api.example.com) ip: Optional IP address for initial server; if provided, adds to slot 1 http_port: HTTP port for the backend server (default: 80) - https_port: HTTPS port for the backend server (default: 443) Returns: Success message or error description @@ -570,7 +560,7 @@ def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80, https_por return "Error: Invalid domain format" if not validate_ip(ip, allow_empty=True): return "Error: Invalid IP address format" - if not (1 <= http_port <= 65535) or not (1 <= https_port <= 65535): + if not (1 <= http_port <= 65535): return "Error: Port must be between 1 and 65535" # Check if domain already exists @@ -596,18 +586,15 @@ def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80, https_por # If IP provided, add server to slot 1 if ip: - suffixes = get_server_suffixes(http_port, https_port) - for suffix, port in suffixes: + for suffix, port in get_server_suffixes(http_port): server = f"{pool}{suffix}_1" haproxy_cmd(f"set server {pool}/{server} addr {ip} port {port}") haproxy_cmd(f"set server {pool}/{server} state ready") # Save to persistent config - add_server_to_config(domain, 1, ip, http_port, https_port) + add_server_to_config(domain, 1, ip, http_port) - if len(suffixes) == 1: - return f"Domain {domain} added to {pool} with server {ip}:{http_port} (HTTP only)" - return f"Domain {domain} added to {pool} with server {ip}:{http_port}/{https_port}" + return f"Domain {domain} added to {pool} with server {ip}:{http_port}" return f"Domain {domain} added to {pool} (no servers configured)" @@ -651,13 +638,12 @@ def haproxy_remove_domain(domain: str) -> str: # Disable all servers in the pool (reset to 0.0.0.0:0) for slot in range(1, MAX_SLOTS + 1): - for suffix in ["", "_ssl", "_h3"]: - server = f"{backend}{suffix}_{slot}" - try: - haproxy_cmd(f"set server {backend}/{server} state maint") - haproxy_cmd(f"set server {backend}/{server} addr 0.0.0.0 port 0") - except HaproxyError: - pass # Ignore errors for individual servers + server = f"{backend}_{slot}" + try: + haproxy_cmd(f"set server {backend}/{server} state maint") + haproxy_cmd(f"set server {backend}/{server} addr 0.0.0.0 port 0") + except HaproxyError: + pass # Ignore errors for individual servers # Remove from persistent config remove_domain_from_config(domain) @@ -708,7 +694,7 @@ def haproxy_list_servers(domain: str) -> str: @mcp.tool() -def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80, https_port: int = 443) -> str: +def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80) -> str: """Add a server to a domain's backend at specified slot. Args: @@ -716,7 +702,6 @@ def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80, htt slot: Server slot number (1 to MAX_SLOTS) ip: IP address of the server (required) http_port: HTTP port (default: 80) - https_port: HTTPS port (default: 443) Returns: Success message or error description @@ -729,7 +714,7 @@ def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80, htt return "Error: Invalid IP address format" if not (1 <= slot <= MAX_SLOTS): return f"Error: Slot must be between 1 and {MAX_SLOTS}" - if not (1 <= http_port <= 65535) or not (1 <= https_port <= 65535): + if not (1 <= http_port <= 65535): return "Error: Port must be between 1 and 65535" try: @@ -748,14 +733,14 @@ def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80, htt server_prefix = domain_to_backend(domain) results = [] - for suffix, port in get_server_suffixes(http_port, https_port): + for suffix, port in get_server_suffixes(http_port): server = f"{server_prefix}{suffix}_{slot}" haproxy_cmd(f"set server {backend}/{server} addr {ip} port {port}") haproxy_cmd(f"set server {backend}/{server} state ready") results.append(f"{server} → {ip}:{port}") # Save to persistent config - add_server_to_config(domain, slot, ip, http_port, https_port) + add_server_to_config(domain, slot, ip, http_port) return f"Added to {domain} ({backend}) slot {slot}:\n" + "\n".join(results) except (HaproxyError, ValueError) as e: @@ -793,22 +778,10 @@ def haproxy_remove_server(domain: str, slot: int) -> str: # Legacy backends use domain-based naming server_prefix = domain_to_backend(domain) - # Get server config to determine which suffixes to remove - config = load_servers_config() - suffixes = ["", "_ssl", "_h3"] # Default: remove all - if domain in config and str(slot) in config[domain]: - server_info = config[domain][str(slot)] - try: - http_port = int(server_info.get("http_port", 80)) - https_port = int(server_info.get("https_port", 443)) - suffixes = [s for s, _ in get_server_suffixes(http_port, https_port)] - except (ValueError, TypeError): - pass # Use default suffixes - - for suffix in suffixes: - server = f"{server_prefix}{suffix}_{slot}" - haproxy_cmd(f"set server {backend}/{server} state maint") - haproxy_cmd(f"set server {backend}/{server} addr 0.0.0.0 port 0") + # HTTP only - single server per slot + server = f"{server_prefix}_{slot}" + haproxy_cmd(f"set server {backend}/{server} state maint") + haproxy_cmd(f"set server {backend}/{server} addr 0.0.0.0 port 0") # Remove from persistent config remove_server_from_config(domain, slot)