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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user