Site Router
The site router is the heart of my HomeStack infrastructure - it's what makes the single-domain, path-based routing architecture possible. After starting with nginx-proxy, I migrated to Traefik and haven't looked back.
Why Traefik?
Traefik excels at dynamic service discovery and automatic SSL certificate management. Unlike nginx-proxy which required manual configuration, Traefik automatically discovers services through Docker labels and configures routing rules on the fly.
The key advantages that sold me on Traefik:
- Automatic service discovery: No config files to maintain - just Docker labels
- Built-in Let's Encrypt integration: SSL certificates are automatically obtained and renewed
- Path-based routing: Multiple services can share a single domain with different paths
- Zero-downtime deployments: Services can be updated without affecting the router
Configuration
My Traefik setup uses Docker Compose with configuration passed as command-line arguments. Here's the core site-router
service:
site-router:
container_name: site-router
image: traefik:v3.3.1
command:
- --providers.docker
- --providers.docker.network=mono_default
- --providers.docker.exposedbydefault=false
- --entryPoints.web.address=:80
- --entryPoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entryPoints.websecure.address=:443
- --certificatesresolvers.wwwresolver.acme.httpchallenge=true
- --certificatesresolvers.wwwresolver.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.wwwresolver.acme.email=nhedberg@me.com
- --certificatesresolvers.wwwresolver.acme.storage=/letsencrypt/acme.json
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./letsencrypt:/letsencrypt
Key configuration points:
- Docker provider: Traefik watches Docker events to discover services
- Expose by default disabled: Services must opt-in with labels
- HTTP to HTTPS redirect: All traffic automatically upgraded to SSL
- Let's Encrypt: Automatic certificate management using HTTP challenge
Service Integration
Each service in my stack integrates with Traefik using Docker labels. Here's a typical example from my chat-gpt service:
chat-gpt:
labels:
- traefik.enable=true
- traefik.http.services.chat-gpt.loadbalancer.server.port=10109
- traefik.http.routers.chat-gpt.rule=Host(`www.nickhedberg.com`) && PathPrefix(`/chat-gpt`)
- traefik.http.routers.chat-gpt.entrypoints=websecure
- traefik.http.routers.chat-gpt.tls.certresolver=wwwresolver
This configuration:
- Enables Traefik routing for the service
- Defines the internal port Traefik should proxy to
- Sets up path-based routing (
/chat-gpt
routes to this service) - Configures HTTPS with automatic certificates
Advanced Features
Strip Prefix Middleware
Some services need URL path modification. For example, my blog API expects requests without the /blog-api
prefix:
nickhedberg_blog_api:
labels:
- traefik.http.routers.nickhedberg_blog_api.middlewares=nickhedberg_blog_api-stripprefix
- traefik.http.middlewares.nickhedberg_blog_api-stripprefix.stripprefix.prefixes=/blog-api
Domain Redirects
My main site handles both nickhedberg.com
and www.nickhedberg.com
, with automatic redirects:
nickhedberg_site:
labels:
- traefik.http.routers.nickhedberg_site.rule=Host(`www.nickhedberg.com`) || Host(`nickhedberg.com`)
- traefik.http.routers.nickhedberg_site.middlewares=addwww-nickhedberg_site
- traefik.http.middlewares.addwww-nickhedberg_site.redirectregex.regex=^https?://nickhedberg\.com(.*)
- traefik.http.middlewares.addwww-nickhedberg_site.redirectregex.replacement=https://www.nickhedberg.com$$1
Benefits in Practice
This setup has transformed how I deploy and manage services:
- New services are instantly routable - just add the labels
- SSL is completely automated - certificates appear and renew without intervention
- No service downtime during Traefik updates or configuration changes
- Clean URLs - everything lives under
www.nickhedberg.com/service-name
- Development parity - same routing logic works locally and in production
The router handles all the networking complexity, letting me focus on building features instead of managing infrastructure. It's the foundation that makes my service-oriented HomeStack architecture practical and maintainable.