From 05bff61b8560709da26c798fb307e7d1025e3c20 Mon Sep 17 00:00:00 2001 From: kappa Date: Sun, 8 Feb 2026 01:11:56 +0900 Subject: [PATCH] fix: Use Runtime API for zero-downtime cert reload in issue_cert reloadcmd Previously issue_cert saved a reloadcmd that only combined PEM files, so cron renewals would not reload certs into HAProxy. Now the reloadcmd uses the Runtime API (set/commit ssl cert) for zero-downtime reload, matching the existing domain reloadcmd configuration. Co-Authored-By: Claude Opus 4.6 --- haproxy_mcp/tools/certificates.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/haproxy_mcp/tools/certificates.py b/haproxy_mcp/tools/certificates.py index 6f04484..bbc327b 100644 --- a/haproxy_mcp/tools/certificates.py +++ b/haproxy_mcp/tools/certificates.py @@ -12,6 +12,7 @@ from ..config import ( CERTS_DIR, CERTS_DIR_CONTAINER, ACME_HOME, + HAPROXY_PORT, REMOTE_MODE, ) from ..exceptions import HaproxyError @@ -218,13 +219,18 @@ def _haproxy_issue_cert_impl(domain: str, wildcard: bool) -> str: if _file_exists(cert_dir): return f"Error: Certificate for {domain} already exists. Use haproxy_renew_cert to renew." - host_path, _ = get_pem_paths(domain) - install_cmd = f"cat {ACME_HOME}/{domain}_ecc/fullchain.cer {ACME_HOME}/{domain}_ecc/{domain}.key > {host_path}" + host_path, container_path = get_pem_paths(domain) + cert_dir = f"{ACME_HOME}/{domain}_ecc" + reload_cmd = ( + f"cat {cert_dir}/fullchain.cer {cert_dir}/{domain}.key > {host_path}" + f' && printf "set ssl cert {container_path} <<\\n%s\\n\\n" "$(cat {host_path})" | nc localhost {HAPROXY_PORT}' + f' && echo "commit ssl cert {container_path}" | nc localhost {HAPROXY_PORT}' + ) cmd = [ACME_SH, "--issue", "--dns", "dns_cf", "-d", domain] if wildcard: cmd.extend(["-d", f"*.{domain}"]) - cmd.extend(["--reloadcmd", install_cmd]) + cmd.extend(["--reloadcmd", reload_cmd]) try: logger.info("Issuing certificate for %s", domain)