Local HTTPS development environment using Traefik reverse proxy with Let's Encrypt wildcard certificates.
- ✅ Wildcard HTTPS for
*.example.devdomains - ✅ Local routing via loopback alias (configurable IP)
- ✅ Automatic SSL with Let's Encrypt certificates
- ✅ Service discovery via Docker labels
- ✅ Automatic renewal (optional)
- ✅ Configurable via
.envfile - ✅ Team-friendly setup with admin/member roles
Set up your own domain, DNS, and certificates for local HTTPS development.
- Admin: Configure DNS and certificates once
- Team Members: Use shared domain and certificates
All Users:
- Docker & Docker Compose installed
- macOS 10.15+ or Linux with systemd
Admin Only (for initial setup):
- Domain with DNS management access (Cloudflare recommended)
- Certbot:
brew install certbot(macOS) orapt install certbot(Linux)
# 1. Clone and configure
git clone <repository-url>
cd traefik
cp .env.example .env
nano .env # Edit DOMAIN, LOOPBACK_IP, LETSENCRYPT_EMAIL
# 2. Initialize
make init
# 3. Configure DNS (one-time)
# Add DNS A record: *.example.dev → 172.16.123.1
# 4. Generate SSL certificate (one-time)
make help-ssl # Shows certificate generation instructions
# 5. Copy certificates
make setup-certs
# 6. Start Traefik
make createIf your admin has already set up DNS and certificates:
# 1. Clone and configure
git clone <repository-url>
cd traefik
cp .env.example .env
nano .env # Use DOMAIN provided by admin
# 2. Initialize
make init
# 3. Get certificates from admin
# Place .crt and .key files in ssl/ directory
# 4. Start Traefik
make createSee SETUP.md for detailed step-by-step instructions.
All settings are configured via .env file:
cp .env.example .env
nano .envKey settings:
| Variable | Description | Default |
|---|---|---|
DOMAIN |
Your domain name | example.dev |
LOOPBACK_IP |
Loopback IP address | 172.16.123.1 |
LETSENCRYPT_EMAIL |
Email for Let's Encrypt notifications | - |
CLOUDFLARE_API_TOKEN |
For automated renewals (optional) | - |
See .env.example for all available options.
make init # Initialize project (first time)
make check-env # Verify .env and regenerate configs
make help-ssl # Show SSL certificate generation helpmake create # Full setup (network + loopback + start)
make start # Start Traefik
make stop # Stop Traefik
make destroy # Remove everythingmake create-network # Create Docker network
make create-loopback # Setup loopback alias (requires sudo)
make remove-loopback # Remove loopback aliasmake setup-certs # Copy certificates from Let's Encrypt
make install-renew-hook # Install post-renewal hook
make setup-auto-renewal # Setup automatic renewal (macOS)
make test-renewal # Test renewal process
make check-renewal-status # Check if auto-renewal is configuredThis setup creates a local HTTPS reverse proxy using Traefik and Docker:
Browser Request (https://myapp.example.dev)
↓
DNS Resolution (*.example.dev → 172.16.123.1)
↓
Loopback Alias (172.16.123.1 on lo0/lo interface)
↓
Traefik (listening on 172.16.123.1:443 with SSL)
↓
Docker Network (local)
↓
Your Application Container (via service discovery)
-
Configuration (
.envfile)- Defines your domain, loopback IP, and certificate paths
- Generates Traefik configuration from templates
-
DNS Resolution (Wildcard DNS)
*.example.devresolves to your loopback IP (e.g.,172.16.123.1)- Configured once at your DNS provider (Cloudflare, etc.)
- All subdomains automatically resolve to your local machine
-
Loopback Alias (Network Interface)
- System-level network alias on loopback interface
- Allows binding to private IP without actual network adapter
- Persists across reboots (via LaunchDaemon/systemd)
-
Traefik (Reverse Proxy)
- Listens on
172.16.123.1:80(HTTP) and172.16.123.1:443(HTTPS) - Automatically redirects HTTP → HTTPS
- Uses wildcard SSL certificate for all subdomains
- Discovers services via Docker labels
- Listens on
-
Service Discovery (Docker Labels)
- Traefik watches Docker for containers with
traefik.enable=true - Reads routing rules from container labels
- Automatically configures routes and SSL
- Traefik watches Docker for containers with
-
SSL Termination
- Traefik handles SSL/TLS with Let's Encrypt certificates
- Services receive plain HTTP traffic internally
- Automatic HTTPS for all configured services
Traefik Configuration:
traefik.toml- Static configuration (entrypoints, providers)configs/certs.toml- TLS certificate configuration (generated)- Docker provider - Automatic service discovery
Docker Network:
local- External bridge network- All services must connect to this network
- Traefik and your applications communicate here
SSL Certificates:
- Wildcard certificate (
*.example.dev) - Single certificate covers all subdomains
- Stored in
ssl/directory
For detailed information about Traefik configuration:
- Traefik Documentation - Official docs
- Docker Provider - Docker integration
- Routing & Labels - Label configuration
- TLS Configuration - SSL/TLS setup
- Routers - HTTP/HTTPS routing rules
Add a service to your application's docker-compose.yaml:
services:
myapp:
image: myapp:latest
networks:
- local
labels:
# Enable Traefik for this service
traefik.enable: true
# HTTP Router configuration
traefik.http.routers.myapp.rule: "Host(`myapp.example.dev`)"
traefik.http.routers.myapp.entrypoints: websecure
traefik.http.routers.myapp.tls: true
# Service configuration (tell Traefik which port to use)
traefik.http.services.myapp.loadbalancer.server.port: 8080
networks:
local:
external: trueAccess at: https://myapp.example.dev
| Label | Purpose | Example |
|---|---|---|
traefik.enable |
Enable Traefik for this container | true |
traefik.http.routers.<name>.rule |
Routing rule (domain matching) | "Host(\app.example.dev`)"` |
traefik.http.routers.<name>.entrypoints |
Which entrypoint to use | websecure (HTTPS) |
traefik.http.routers.<name>.tls |
Enable TLS/SSL | true |
traefik.http.services.<name>.loadbalancer.server.port |
Container's internal port | 8080, 3000, etc. |
Note: Replace <name> with your service name (e.g., myapp, api, frontend).
Route multiple domains to the same service:
labels:
traefik.enable: true
traefik.http.routers.myapp.rule: "Host(`app.example.dev`) || Host(`www.example.dev`)"
traefik.http.routers.myapp.entrypoints: websecure
traefik.http.routers.myapp.tls: true
traefik.http.services.myapp.loadbalancer.server.port: 8080Route based on URL path:
labels:
traefik.enable: true
traefik.http.routers.api.rule: "Host(`example.dev`) && PathPrefix(`/api`)"
traefik.http.routers.api.entrypoints: websecure
traefik.http.routers.api.tls: true
traefik.http.services.api.loadbalancer.server.port: 3000
# Strip /api prefix before forwarding
traefik.http.routers.api.middlewares: api-stripprefix
traefik.http.middlewares.api-stripprefix.stripprefix.prefixes: /apiservices:
frontend:
image: my-frontend:latest
networks:
- local
labels:
traefik.enable: true
traefik.http.routers.frontend.rule: "Host(`example.dev`)"
traefik.http.routers.frontend.entrypoints: websecure
traefik.http.routers.frontend.tls: true
traefik.http.services.frontend.loadbalancer.server.port: 80
backend:
image: my-backend:latest
networks:
- local
labels:
traefik.enable: true
traefik.http.routers.backend.rule: "Host(`api.example.dev`)"
traefik.http.routers.backend.entrypoints: websecure
traefik.http.routers.backend.tls: true
traefik.http.services.backend.loadbalancer.server.port: 3000
networks:
local:
external: trueAccess:
- Frontend:
https://example.dev - Backend:
https://api.example.dev
For complete label documentation, see:
- Docker Labels - All available labels
- Routers - Router configuration
- Services - Service configuration
- Middlewares - Middleware options (auth, headers, etc.)
API with CORS:
traefik.http.routers.api.middlewares: api-cors
traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods: GET,POST,PUT,DELETE
traefik.http.middlewares.api-cors.headers.accesscontrolalloworigin: "*"Basic Auth:
traefik.http.routers.admin.middlewares: admin-auth
traefik.http.middlewares.admin-auth.basicauth.users: "admin:$$apr1$$..."Redirect www to non-www:
traefik.http.routers.www-redirect.rule: "Host(`www.example.dev`)"
traefik.http.routers.www-redirect.middlewares: redirect-www
traefik.http.middlewares.redirect-www.redirectregex.regex: "^https://www\\.(.+)"
traefik.http.middlewares.redirect-www.redirectregex.replacement: "https://$${1}"traefik/
├── .env.example # Environment configuration template
├── .env # Your personal config (gitignored)
├── Makefile # Development workflow automation
├── compose.yaml # Docker Compose configuration
├── traefik.toml # Traefik static configuration
├── scripts/ # Automation scripts
│ ├── common/ # Shared utilities
│ ├── loopback/ # Loopback alias management
│ ├── certificates/ # SSL certificate management
│ └── setup/ # Setup and config generation
├── configs/ # Traefik dynamic configuration
│ ├── certs.toml.template # TLS template
│ └── certs.toml # Generated TLS config (gitignored)
├── ssl/ # SSL certificates (gitignored)
└── guides/ # Detailed guides
├── cloudflare-dns-plugin.md
├── certificate-distribution.md
└── certificate-renewal-issues.md
- SETUP.md - Detailed step-by-step setup guide
- CONTRIBUTING.md - How to contribute to this project
- TROUBLESHOOTING.md - Common issues and solutions
- CLAUDE.md - Guide for Claude Code AI assistant
- Cloudflare DNS Plugin - Automated certificate renewal
- Certificate Distribution - Sharing certificates with team
- Certificate Renewal Issues - Troubleshooting renewal
# DNS resolution
dig traefik.example.dev # Should return your LOOPBACK_IP
# Loopback alias
ifconfig lo0 | grep 172.16.123.1 # macOS
ifconfig lo | grep 172.16.123.1 # Linux
# Traefik status
docker compose ps
docker compose logs traefik --tail=20
# Certificate validity
openssl x509 -in ssl/example.dev.crt -noout -datesSee TROUBLESHOOTING.md for detailed solutions.
| Platform | Support | Notes |
|---|---|---|
| macOS | ✅ Full | Automated scripts, LaunchDaemon |
| Linux | ✅ Full | Automated scripts, systemd |
| Windows | Manual setup required |
- Development only - Not for production use
- Private keys stored in
ssl/(gitignored) - Never commit certificates to version control
- See guides/certificate-distribution.md for team sharing
- Docker 20.10+
- Docker Compose 2.0+
- Certbot (for certificate generation)
- Domain with DNS management access
- Issues: Check TROUBLESHOOTING.md
- Setup Help: See SETUP.md
- Contributing: See CONTRIBUTING.md