Secure Custom Domain Setup for Client Status Pages Using CNAME, Certbot and Go Instead of ACME On-Demand

A detailed case study describes how a monitoring service implemented white-label status pages on customer domains without relying on ACME on-demand certificate issuance. The approach uses pre-validated domains stored in a database, background DNS checks via CNAME or A-record matching, and a root helper script running on a systemd timer to handle certbot issuance and nginx configuration. Key design choices separate privileges so the Go application never touches certificates or nginx directly, while loopback endpoints are protected against proxy header spoofing. The solution explicitly addresses risks such as DoS through malicious Host headers exhausting Let's Encrypt rate limits, private key exposure, and first-visitor latency during TLS handshakes. Hysteresis in DNS status prevents temporary resolution glitches from disabling active customer pages. The entire implementation stays under a few hundred lines of code and runs reliably on a single server with nginx in front of the Go application.

HabrTranslated from Russian

Read at source

A monitoring service needed to offer public status pages on customer domains for white-label use by web studios. Clients add a CNAME record pointing their subdomain to the service endpoint, after which the platform must serve the page over HTTPS with a valid certificate.

The team rejected ACME on-demand solutions such as Caddy or OpenResty auto-SSL for three reasons. Private keys would reside inside the application process or require an additional stateful component. Any attacker could point arbitrary domains at the IP and trigger Let's Encrypt issuance, exhausting the 300-order rate limit per account. Issuing certificates during the TLS handshake also imposes latency on the first visitor and risks connection drops if the CA is unreachable.

Instead, domains are stored in the database when users enter them in settings. A four-stage pipeline handles the rest: input normalization and validation in Go, periodic DNS verification by a background goroutine, certificate issuance and nginx configuration by a privileged helper script, and request routing inside the application.

Validation rejects empty strings only when removing a domain, blocks the service's own domains to prevent takeover of internal pages, and requires Punycode for internationalized names so users see exactly what they must configure at their registrar. After saving, the domain enters pending status.

The DNS verifier runs every five minutes. It first checks for a matching CNAME and falls back to comparing A records for apex domains where CNAME is prohibited by RFC. Temporary DNS failures do not downgrade an already verified or active domain; only a warning is recorded. This hysteresis avoids random outages for customers whose pages are already live.

A systemd-timer script running as root queries the application over loopback, runs certbot with the webroot challenge, writes per-domain nginx server blocks from a template, and notifies the application when a domain becomes active. Certificates for removed domains are left untouched and simply expire naturally. The script always validates input with a regex and runs nginx -t before reloading.

Inside the Go application a HostRouter middleware maps verified custom hosts to the corresponding status page while returning 404 for all other paths, preventing exposure of dashboards or APIs. Internal endpoints used by the helper are protected by checking for the absence of X-Forwarded-For and X-Real-IP headers in addition to loopback address validation.

The scheme works well for hundreds of domains on a single server. It avoids rate-limit exhaustion because issuance occurs only after confirmed DNS ownership, keeps certificate handling outside the application, and ensures that failure of any single component does not affect already-active customer pages.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Other

Mail.ru Reduces Lifetime 1TB Cloud Storage Promo to Standard 8GB Quota for Select Users
Kimi K3 Open Model Surpasses Closed AI Leaders with Million-Token Context and 896 Experts
Innostage Completes Functional Testing of PT NGFW 1.10.3 Across 156 Criteria