DNS and TLS setup for Olympus
Domain configuration from zero to running
A clean DNS + TLS setup for new Olympus deployments. From buying domain to working HTTPS.
Domain setup
Buy a domain (Cloudflare Registrar, Namecheap, etc.). Wait 24h for it to be active.
DNS records
# Primary
A ciam.your-domain.com → host-IP
A iam.your-domain.com → host-IP
# Optional: apex
A your-domain.com → host-IP (or your marketing site)
A www.your-domain.com → host-IP
# Verification (optional)
TXT your-domain.com → "olympus-verification=..."For wildcard:
A *.your-domain.com → host-IPWildcard is risky, covers all subdomains. Be specific.
TLS via Caddy
Caddy auto-fetches Let's Encrypt certs. In Caddyfile:
ciam.your-domain.com {
tls you@your-domain.com # for Let's Encrypt notifications
reverse_proxy hera:3000
}
iam.your-domain.com {
tls you@your-domain.com
reverse_proxy athena:3001
}First request: Caddy fetches cert (~30s). Auto-renews 30 days before expiry.
Wildcard cert
For many subdomains, wildcard via DNS challenge:
*.your-domain.com {
tls {
dns cloudflare api-token-here
}
reverse_proxy hera:3000
}Caddy talks to Cloudflare's API → adds TXT for challenge → Let's Encrypt issues wildcard cert.
Required: Caddy with cloudflare DNS plugin (custom build).
Custom domains (white-label)
For customers who bring their domain:
auth.acme.com {
reverse_proxy hera:3000
}
auth.bigcorp.com {
reverse_proxy hera:3000
}Each custom domain → vhost.
For on-demand (many customers):
{
on_demand_tls {
ask http://your-backend/check-domain
rate_limit_burst 5
rate_limit_window 5m
}
}
:443 {
tls { on_demand }
reverse_proxy hera:3000
}Backend confirms domain is registered:
app.get("/check-domain", async (req, res) => {
const domain = req.query.domain;
const exists = await db`SELECT 1 FROM customer_domains WHERE domain = ${domain}`.first();
if (exists) return res.status(200).send("OK");
return res.status(403).send("Domain not registered");
});DNS propagation
After adding records:
- TTL determines propagation time.
- Set short TTL during setup (5 min).
- Increase after stable (1 day).
A ciam.your-domain.com → host-IP, TTL: 300Check propagation:
dig +short ciam.your-domain.com
nslookup ciam.your-domain.com 8.8.8.8Cloudflare in front
If you proxy through Cloudflare:
- Add A records with proxy enabled (orange cloud).
- Cloudflare's edge IP returned, not yours.
- SSL/TLS mode: Full (strict), Cloudflare ↔ origin TLS.
- Origin cert: Caddy auto-provisions Let's Encrypt OR Cloudflare's "Origin CA cert" (free, 15-year cert).
Caddy needs to know real client IP:
ciam.your-domain.com {
bind 0.0.0.0
servers {
trusted_proxies cloudflare
}
reverse_proxy hera:3000
}Otherwise rate-limiting sees Cloudflare IPs (all the same), not real clients.
CAA records
CAA your-domain.com → 0 issue "letsencrypt.org"Tells CAs: only Let's Encrypt is authorized to issue for this domain. Defense against accidental cert misissuance.
Cert pinning (rare)
For ultra-high security, HPKP (HTTP Public Key Pinning) was deprecated. Don't pin certificates, risky if you lose access to keys.
Instead: Expect-CT header (also deprecated). Modern approach: Certificate Transparency logs (automatic, Let's Encrypt is in CT logs).
Renewal
Caddy auto-renews 30 days before expiry. Logs:
podman logs ciam-caddy | grep certmagicIf renewals fail:
- DNS misconfigured.
- Rate limited by Let's Encrypt.
- Disk full.
Renew manually:
podman exec ciam-caddy caddy reloadTriggers cert check.
Backup certs
Caddy stores certs in /data/caddy. Backup:
tar czf caddy-data-backup.tgz /var/lib/containers/storage/volumes/caddy_dataIf you lose them, Caddy re-fetches (rate-limited).
HSTS
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
}Tells browsers: ALWAYS HTTPS, even on subdomains, for 1 year.
For HSTS preload list:
- Have HSTS header for 1 year.
- Submit at hstspreload.org.
- Browsers ship the preload, even first visit is HTTPS-only.
SNI
If multiple TLS certs on one host (multiple domains), Caddy uses SNI (Server Name Indication) to pick. All modern browsers support.
Older clients (< Android 4) don't support SNI, but probably don't matter to you.
Email DNS
For email auth flows:
- MX records → mail server.
- SPF for sending.
- DKIM for signing.
- DMARC for policy.
Different topic, see email deliverability.
Common mistakes
Forgot apex
If you only set ciam.X but not X itself, https://your-domain.com is broken. Either set it OR redirect at registrar:
your-domain.com → 301 → https://ciam.your-domain.comWildcard with proxied Cloudflare
Cloudflare proxies require listed records, not pure wildcard. Add each subdomain.
Cert not auto-renewing
Check Caddy logs. Common: disk full, permissions, DNS broken.
df -h
ls -la /var/lib/containers/storage/volumes/caddy_data