Internal HTTPS (home.example.com)¶
Every internal service is reachable at <service>.home.example.com (HTTPS, real Let's Encrypt cert) - user-facing services on :443, admin tools on :<admin-port>. This is the only URL scheme: the old <service>.homelab (HTTP) was retired 2026-07-02.
Architecture¶
Client (LAN/Tailscale) → Unbound (CT 101) redirects *.home.example.com → 192.168.50.100
→ Traefik (CT 100) :443, wildcard cert *.home.example.com
*.home.example.comresolves only inside the network - no public DNS record exists for it- Traefik holds a real wildcard cert for
home.example.com+*.home.example.com, obtained via Cloudflare DNS-01 challenge (TXT-only validation, no public exposure needed) .homelab(HTTP, port 80) has been retired (2026-07-02) -.home.example.comis the only scheme
DNS - CT 101 (Unbound)¶
local-zone redirect pattern in Unbound (see pihole), file /etc/unbound/unbound.conf.d/home-internal.conf:
systemctl restart unbound after creating. Pi-hole forwards *.home.example.com to Unbound (it's a real domain with no local record) - Unbound's redirect answers before any recursive lookup.
Traefik - CT 100¶
Static config additions¶
websecure entrypoint (:443) already existed. Added certificatesResolvers:
certificatesResolvers:
cloudflare:
acme:
email: admin@example.com
storage: /etc/traefik/acme/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
Cloudflare API token¶
Scoped token (Zone:DNS:Edit + Zone:Zone:Read on example.com), stored as a Komodo stack env var on the traefik stack:
compose.yaml - Komodo stack env vars are not auto-injected into the container:
acme.json setup¶
Must exist before first start as an empty JSON file with 600 permissions:
echo '{}' > /data/config/management/traefik/acme/acme.json
chmod 600 /data/config/management/traefik/acme/acme.json
Wildcard cert request¶
One router requests the wildcard; all others reuse it from the cert store. Defined on the traefik-tls router in stacks/management/traefik/traefik-route.yml:
traefik-tls:
rule: "Host(`traefik.home.example.com`)"
service: traefik-dashboard
entryPoints:
- websecure
tls:
certResolver: cloudflare
domains:
- main: "home.example.com"
sans:
- "*.home.example.com"
Per-service routes¶
Each service has a single .home.example.com router - entryPoints: [websecure] (443, user-facing) or [admin] (8443, admin tools), Host(<name>.home.example.com), tls: {} (no cert resolver needed, reuses the cached wildcard). Applied to all routes in management lxc's Traefik table, plus per-LXC route tables (media arr, media dl, media server, game panel, monitoring).
Adding a new service¶
Add one router: Host(<name>.home.example.com), tls: {}, and entryPoints: [websecure] (443, user-facing) or [admin] + admin-only middleware (8443, admin tools) - no DNS or cert changes needed, the wildcard already covers it. Do not add a web/:80 .homelab router (retired).
Key Takeaways¶
*.home.example.comis internal-only - no public DNS record, resolved via Unbound redirect on CT 101- Wildcard Let's Encrypt cert obtained once via Cloudflare DNS-01 - covers all current and future
*.home.example.comsubdomains automatically - This Traefik version's lego Cloudflare provider expects
CLOUDFLARE_DNS_API_TOKEN(not the olderCF_DNS_API_TOKEN) - Komodo stack env vars must be explicitly mapped via
environment:in compose.yaml - not auto-injected into the container acme.jsonmust pre-exist as{}with mode600before first Traefik start.homelab(HTTP) was retired 2026-07-02 -.home.example.com(HTTPS) is the only URL scheme