Custom Domain & TLS
Pointing your site at your own domain, and getting HTTPS certificates that renew themselves (or that you manage intentionally), is a short sequence: point DNS, choose the canonical spelling, configure the proxy, verify TLS. This guide walks it with the settings and checks the software expects.
Step 1: Point the domain
- Add a DNS A/AAAA record for your public domain (and a separate one for the admin, e.g.
admin.example.com, if you use the pattern in the examples), pointing at your server. - For multi-language sites decide early whether each language gets its own subdomain or lives under one host (both layouts are shipped; see Reverse Proxy). Subdomain mode means
es.example.com-style addresses for each language.
DNS is entirely outside the software: no provider is assumed.
Step 2: Set your canonical URL
In Settings, set Site URL: the exact spelling you want as the site’s one true address, including whether you use www.
Why this single setting matters:
- Every canonical page URL, every sitemap entry, every feed address is generated from it.
- The build writes a permanent (301) redirect rule that sends the other spelling of your host (whatever you didn’t choose) to the one you did, so search engines and visitors land on one address.
- In subdomain language mode, each language’s URLs are automatically rewritten to its own subdomain based on this setting.
Get this right first; it decides what every generated address will be.
Step 3: Configure the proxy and certificates
- Caddy (recommended): drop your domains into the example config. That’s it: Caddy requests and renews Let’s Encrypt certificates automatically once your DNS points at the server and ports 80/443 are reachable. No cert lines to manage.
- nginx: bring up the HTTP vhost from the shipped example, then run Certbot for your domain; it injects the HTTPS listener and certificate references for you.
- Keep the CMS bound to loopback (e.g.
127.0.0.1:3001) and let the proxy do TLS. Check: after first start,curl -I https://your.admin.domainshould answer cleanly. - Don’t forget the small proxy rules:
/forms/if your site has forms,/documents/if you use documents, and the honeypot list (all shipped in the examples).
Step 4: Verify
Check before calling it done:
- Public page over HTTPS loads without mixed-content warnings (the CMS and proxy both send correct cache/security headers).
- The admin domain answers over HTTPS too.
- The non-canonical host spelling redirects to the chosen one (or your Caddyfile-level host rule does; see below).
- Each language’s URL responds at its expected host/subdomain.
Details that matter
- Canonical enforcement is strongest on hosts that read the Netlify-format redirect file: the build writes a host-level 301 rule into
_redirects. On Caddy deployments the rules file equivalent doesn’t include it, so add the host redirect in your Caddyfile when you need the hard redirect (the per-page canonical tags come from the CMS on every host). - HSTS is emitted by the CMS for admin traffic (one year, include subdomains) and mirrored in the shipped nginx example; once browsers have seen it, TLS must stay present, so make sure renewals work before relying on it.
- Port mapping: each instance keeps a unique port (3001, 3002, …) behind the proxy; the proxy routes each domain to its instance. If you adopt the Manager, you attach domains there and it regenerates/reloads the proxy config for you; the daemon itself never moves off loopback.
- Extremely air-gapped hosts: there’s a documented mode with no DNS and no certificates: plain HTTP on a local port, protected by VPN/firewall instead of TLS. It’s the deliberate escape hatch when renewal is impossible; treat it as a physical-security deployment.
What not to worry about
- The software never needs a DNS provider or API connection for domains.
- Certificate renewal (in normal deployments) is handled by the proxy, not the CMS.
- Security headers arrive from the CMS on every response regardless of the proxy’s configuration; the examples duplicate them only as a safety net.
The short version
Point DNS, fix the canonical spelling in Settings, put the proxy in front with Let’s Encrypt doing the certificates (or deliberately choose the offline no-TLS mode), verify with curl -I, and both www/no-www variants end up on the one domain, permanently.