Self-hosted services with HTTPS via Traefik reverse proxy, local DNS resolution via AdGuard Home, and trusted SSL certificates using mkcert.
| Service | Domain | Container IP | Description |
|---|---|---|---|
| Traefik | traefik.local |
172.20.0.10 | Reverse proxy with automatic HTTPS |
| AdGuard Home | adguard.local |
172.20.0.11 | DNS server with ad blocking & local DNS rewrites |
| Glance | glance.local |
172.20.0.12 | Dashboard with service monitoring |
| NetBird | (VPN only) | 172.20.0.13 | Private network mesh VPN client |
| Cert Server | cert.local |
172.20.0.20 | CA certificate download page (nginx) |
| Proxmox | proxmox.local |
External | Hypervisor at 192.168.1.9:8006 |
| Home Assistant | ha.local |
External | Home automation at 192.168.1.100:8123 |
- Docker network:
homelab(external, bridge, 172.20.0.0/24) - All services use static IPs for predictability
- Traefik listens on host ports 80/443 (HTTP/HTTPS) and 8080 (dashboard)
- AdGuard DNS on host port 53 (TCP/UDP)
- Local CA: mkcert-generated root CA trusted by devices
- Certificate: SAN cert covering all
*.localdomains - Location:
/root/homelab/traefik/data/homelab.pem+homelab-key.pem - CA Root:
/root/homelab/traefik/certs/homelab-ca.crt - Auto-redirect: All HTTP requests redirect to HTTPS via Traefik entrypoint
- AdGuard provides DNS rewrites mapping all
*.local→192.168.1.200(Traefik host) - Clients must use AdGuard as DNS server (set via router DHCP or manually)
- Containers inherit DNS from host for external resolution
Glance container needs the CA certificate to monitor HTTPS services:
- CA mounted via volume:
../traefik/certs/homelab-ca.crt - Custom entrypoint (
entrypoint.sh) installsca-certificatespackage on startup - CA automatically trusted for internal HTTPS health checks
- Docker & Docker Compose installed
- External
homelabnetwork created:docker network create --subnet=172.20.0.0/24 homelab
cd /root/homelab
./start-homelab.shServices start in order: AdGuard (with 30s DNS readiness wait) → Traefik → Glance → NetBird → Cert-Server
./stop-homelab.shcd /root/homelab/<service>
docker compose up -d # Start
docker compose down # Stop
docker compose logs -f # Follow logs
docker compose restart # RestartAll devices on your network need the CA certificate installed to avoid "not secure" warnings.
Visit https://cert.local (will show cert warning initially) or:
# From any device on the network
curl -O http://192.168.1.200:80/homelab-ca.crt- Settings → Privacy & Security → Certificates → View Certificates
- Authorities tab → Import
- Select
homelab-ca.crt - Check "Trust this CA to identify websites"
- Restart Firefox
Note: Firefox uses its own trust store and ignores OS trust by default.
# Method 1: GUI
# Double-click homelab-ca.crt → Install Certificate
# Store Location: Local Machine → Trusted Root Certification Authorities
# Method 2: Command line
certutil -addstore -f Root homelab-ca.crtsudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain homelab-ca.crtsudo cp homelab-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates- Download
homelab-ca.crtin Safari (tap download link atcert.local) - Settings → General → VPN & Device Management
- Tap the certificate profile → Install
- Settings → General → About → Certificate Trust Settings
- Enable full trust for "mkcert root@docker"
- Download
homelab-ca.crt - Settings → Security → Encryption & credentials
- Install a certificate → CA certificate
- Select downloaded file
Set DNS server to 192.168.1.200 (your Docker host IP):
- iOS/Android: Wi-Fi settings → Configure DNS → Manual → Add
192.168.1.200 - Windows: Network adapter settings → IPv4 Properties → Preferred DNS
- macOS: System Settings → Network → DNS Servers → Add
192.168.1.200
Configure router DHCP to distribute AdGuard as primary DNS:
- Log into router admin (usually
192.168.1.1) - Find DHCP Server settings
- Set Primary DNS:
192.168.1.200 - Restart router or renew DHCP leases on devices
All devices will automatically use AdGuard for DNS without manual configuration.
homelab/
├── adguard/
│ ├── docker-compose.yml
│ ├── conf/
│ │ └── AdGuardHome.yaml # Config with DNS rewrites
│ └── work/ # Query logs, filter cache
│
├── traefik/
│ ├── docker-compose.yml
│ ├── data/
│ │ ├── dynamic-config.yml # External service routes (Proxmox, HA)
│ │ ├── homelab.pem # TLS certificate (active)
│ │ └── homelab-key.pem # TLS private key (active)
│ ├── certs/
│ │ ├── homelab-ca.crt # CA root certificate (for downloads)
│ │ └── index.html # CA installation instructions page
│ └── logs/ # (empty - stdout logging used)
│
├── glance/
│ ├── docker-compose.yml
│ ├── entrypoint.sh # CA installation wrapper
│ └── config/
│ └── glance.yml # Dashboard & monitor config
│
├── netbird/
│ ├── docker-compose.yml
│ ├── config/ # NetBird client config
│ └── data/ # VPN connection state
│
├── cert-server/
│ └── docker-compose.yml # Nginx serving CA download page
│
├── start-homelab.sh # Start all services
├── stop-homelab.sh # Stop all services
└── README.md # This file
- Issuer: mkcert development CA (mkcert root@docker)
- Valid Until: February 26, 2028
- Domains: traefik.local, adguard.local, glance.local, proxmox.local, ha.local, cert.local
openssl x509 -in /root/homelab/traefik/data/homelab.pem -noout -textWhen approaching expiration (or to add domains):
cd /root/homelab/traefik/data
mkcert -cert-file homelab.pem -key-file homelab-key.pem \
traefik.local adguard.local glance.local proxmox.local ha.local cert.local \
<additional-domain>.local
cd /root/homelab/traefik && docker compose restart- Generate new cert with additional domain (see above)
- Add DNS rewrite in AdGuard:
- Web UI: Settings → DNS Settings → DNS Rewrites → Add
- Or edit
/root/homelab/adguard/conf/AdGuardHome.yaml:rewrites: - domain: newservice.local answer: 192.168.1.200
- Restart AdGuard:
cd /root/homelab/adguard && docker compose restart - Add service to docker-compose with Traefik labels
All services accessible at https://<service>.local:
https://traefik.local- Traefik dashboardhttps://adguard.local- AdGuard admin UIhttps://glance.local- Homepage dashboardhttps://cert.local- CA download page
- Traefik dashboard:
http://192.168.1.200:8080(insecure mode, no auth) - No other services expose host ports (security best practice)
Cause: CA certificate not installed in browser/OS trust store
Solution:
- Visit
https://cert.localand downloadhomelab-ca.crt - Install CA per platform instructions above
- Firefox users: Must import to Firefox specifically (doesn't use OS trust)
- Restart browser after install
Cause: Device not using AdGuard for DNS
Check:
# iOS/Android: Use DNS lookup app
# Windows:
nslookup glance.local
# macOS/Linux:
dig glance.local @192.168.1.200Solution:
- Verify device DNS settings show
192.168.1.200 - Flush DNS cache:
- Windows:
ipconfig /flushdns - macOS:
sudo dscacheutil -flushcache - Linux:
sudo systemd-resolve --flush-caches
- Windows:
- Reconnect to Wi-Fi or renew DHCP lease
Check Traefik routing:
docker logs traefik | grep -i error
curl -H "Host: glance.local" http://192.168.1.200Check container network:
docker inspect glance | grep -i networkTest internal routing:
docker exec traefik wget -O- http://glance:8080Cause: Container can't validate HTTPS certificates
Solution: Already fixed via entrypoint.sh wrapper. If issues persist:
cd /root/homelab/glance
docker compose down && docker compose up -d
docker logs glance # Should show CA installationCheck AdGuard is running:
docker ps | grep adguard
docker logs adguardCheck port 53 is accessible:
sudo netstat -tuln | grep :53Verify rewrites configured:
grep -A 10 "rewrites:" /root/homelab/adguard/conf/AdGuardHome.yamlCommon causes:
- Private DNS enabled: Android/iOS may override network DNS with DoH provider
- Android: Settings → Network → Private DNS → Off
- iOS: Check for DNS profiles in VPN & Device Management
- Guest network isolation: Some routers isolate guest Wi-Fi from LAN
- Firewall: Host firewall blocking port 53/80/443
sudo ufw status # Check if enabled sudo iptables -L INPUT -n # Check rules
- Traefik dashboard: Runs in insecure mode (no auth). Secure with middleware if exposed beyond LAN.
- AdGuard admin: Password-protected (user: 01xq). Change default if needed.
- No host port mappings: Services only accessible via Traefik (except DNS). Reduces attack surface.
- TLS everywhere: HTTP auto-redirects to HTTPS. All internal traffic encrypted.
- CA certificate: Only trusted locally. Valid only for listed SAN domains. Not publicly trusted.
cd /root/homelab/<service>
docker compose pull
docker compose up -d# All logs
docker compose logs -f
# Specific service
docker logs -f traefik
docker logs --tail 100 adguard# AdGuard config & query logs
tar -czf adguard-backup.tar.gz adguard/conf adguard/work
# Glance config
tar -czf glance-backup.tar.gz glance/config
# Traefik certificates
tar -czf traefik-certs-backup.tar.gz traefik/data/*.pem traefik/certs/*.crtdocker system prune -a --volumes # WARNING: Removes all unused images/volumes-
Create service directory:
mkdir -p /root/homelab/newservice cd /root/homelab/newservice -
Create docker-compose.yml:
services: newservice: image: example/service container_name: newservice restart: unless-stopped networks: homelab: ipv4_address: 172.20.0.21 # Pick unused IP labels: - "traefik.enable=true" - "traefik.http.routers.newservice.rule=Host(`newservice.local`)" - "traefik.http.routers.newservice.entrypoints=websecure" - "traefik.http.routers.newservice.tls=true" - "traefik.http.services.newservice.loadbalancer.server.port=8080" networks: homelab: external: true
-
Add DNS rewrite (edit
/root/homelab/adguard/conf/AdGuardHome.yaml):rewrites: - domain: newservice.local answer: 192.168.1.200
-
Regenerate certificate (if you want a clean cert):
cd /root/homelab/traefik/data mkcert -cert-file homelab.pem -key-file homelab-key.pem \ traefik.local adguard.local glance.local proxmox.local ha.local cert.local newservice.local -
Update start/stop scripts:
# Edit start-homelab.sh and stop-homelab.sh # Add "newservice" to the services loop
-
Start everything:
./start-homelab.sh
The .local TLD is reserved for mDNS/Bonjour. For better standards compliance, use .home.arpa:
- Update all DNS rewrites in AdGuard config
- Regenerate certificates with new domains
- Update all Traefik labels in docker-compose files
- Update Glance monitor URLs
Setup Date: November 26, 2025
Last Updated: November 27, 2025
Maintainer: 01xq