Initial Traefik reverse proxy configuration

Configure Traefik v2.10 with:
- Automatic HTTPS using Let's Encrypt
- HTTP to HTTPS redirect
- Docker service discovery
- Security headers middleware
- Dashboard with basic auth

Configured services:
- Mealie (recipes.pkartchner.com)
- Gogs (git.pkartchner.com)
- Traefik Dashboard (traefik.pkartchner.com)

Features:
- Automatic SSL certificate management
- Force HTTPS on all services
- Security headers (HSTS, frame options, XSS protection)
- Docker network isolation

Next steps: Configure DNS records and port forwarding (see SETUP-INSTRUCTIONS.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-20 19:07:55 +00:00
commit bd1dc1abed
6 changed files with 507 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
# Traefik sensitive files
acme.json
acme.json.backup
# Logs
*.log
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
*.swp
*.swo
*~

177
README.md Normal file
View File

@@ -0,0 +1,177 @@
# Traefik Reverse Proxy Configuration
This directory contains the Traefik reverse proxy configuration for managing SSL certificates and routing traffic to services.
## Services Managed
- **Mealie** (recipes.pkartchner.com) - Recipe manager
- **Gogs** (git.pkartchner.com) - Git repository server
- **Traefik Dashboard** (traefik.pkartchner.com) - Traefik management UI
## Features
- ✅ Automatic HTTPS with Let's Encrypt SSL certificates
- ✅ Automatic HTTP to HTTPS redirect
- ✅ Docker service discovery
- ✅ Security headers middleware
- ✅ Traefik dashboard with basic auth
## Files
- `docker-compose.yml` - Traefik container configuration
- `traefik.yml` - Main Traefik configuration
- `config.yml` - Dynamic configuration for external services
- `acme.json` - Let's Encrypt certificate storage (auto-generated)
## Setup
### 1. DNS Configuration
Ensure these DNS records point to your server's public IP:
```
A recipes.pkartchner.com → YOUR_PUBLIC_IP
A git.pkartchner.com → YOUR_PUBLIC_IP
A traefik.pkartchner.com → YOUR_PUBLIC_IP
```
### 2. Start Traefik
```bash
cd /srv/docker-compose/traefik
docker compose up -d
```
### 3. Check Logs
```bash
docker logs traefik -f
```
## Dashboard Access
Access the Traefik dashboard at: `https://traefik.pkartchner.com`
**Default credentials:**
- Username: `admin`
- Password: `change-this-password`
**Change the password:**
```bash
# Generate new password hash
echo $(htpasswd -nb admin yournewpassword) | sed -e s/\\$/\\$\\$/g
# Update the label in docker-compose.yml:
# traefik.http.middlewares.traefik-auth.basicauth.users=admin:$HASH
```
## SSL Certificates
Traefik automatically obtains and renews SSL certificates from Let's Encrypt.
- Certificates are stored in `acme.json`
- Auto-renewal happens 30 days before expiration
- Email notifications sent to: pkartch@gmail.com
### Staging vs Production
The configuration uses **Let's Encrypt production** by default.
To use **staging** (for testing, to avoid rate limits):
Uncomment this line in `traefik.yml`:
```yaml
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
```
## Port Configuration
- **80** - HTTP (redirects to HTTPS)
- **443** - HTTPS (main entry point)
- **8080** - Traefik dashboard
## Adding New Services
### Docker Services
Add labels to your service's docker-compose.yml:
```yaml
services:
myservice:
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.pkartchner.com`)"
- "traefik.http.routers.myservice.entrypoints=https"
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
- "traefik.http.services.myservice.loadbalancer.server.port=PORT"
networks:
- traefik
```
### External Services
Add to `config.yml`:
```yaml
http:
routers:
myservice:
rule: "Host(`myservice.pkartchner.com`)"
entryPoints:
- https
service: myservice
tls:
certResolver: letsencrypt
services:
myservice:
loadBalancer:
servers:
- url: "http://INTERNAL_IP:PORT"
```
## Troubleshooting
### Check Traefik logs
```bash
docker logs traefik --tail 100
```
### Verify network
```bash
docker network ls | grep traefik
```
### Test certificate
```bash
openssl s_client -connect recipes.pkartchner.com:443 -servername recipes.pkartchner.com
```
### Reload configuration
```bash
docker compose restart traefik
```
## Security Notes
- Change the default dashboard password immediately
- Keep `acme.json` permissions at 600
- Regularly update Traefik image
- Monitor access logs
- Consider disabling the dashboard in production
## Maintenance
### Update Traefik
```bash
docker compose pull
docker compose up -d
```
### Backup certificates
```bash
cp acme.json acme.json.backup
```
### View certificate info
Check the Traefik dashboard under "HTTP" → "Routers"

202
SETUP-INSTRUCTIONS.md Normal file
View File

@@ -0,0 +1,202 @@
# Traefik Setup - Next Steps
## Current Status ✅
Traefik has been successfully installed and configured! Here's what's done:
- ✅ Traefik container running
- ✅ Mealie connected to Traefik network
- ✅ HTTP to HTTPS redirect working
- ✅ Automatic SSL with Let's Encrypt configured
- ✅ Gogs routing configured
## What You Need to Do
### 1. Configure DNS Records ⚠️ REQUIRED
Before SSL certificates can be obtained, you need to add DNS A records pointing to your server's **public IP address**:
```
Type Name Value (Points to)
---- ---- -----------------
A recipes.pkartchner.com YOUR_PUBLIC_IP
A git.pkartchner.com YOUR_PUBLIC_IP
A traefik.pkartchner.com YOUR_PUBLIC_IP (optional - for dashboard)
```
**How to find your public IP:**
```bash
curl ifconfig.me
```
**Where to add DNS records:**
- Log in to your domain registrar (where you bought pkartchner.com)
- Go to DNS management
- Add the A records above
- Wait 5-60 minutes for DNS propagation
### 2. Configure EdgeRouter Port Forwarding
Forward ports 80 and 443 from your EdgeRouter to this server:
```
WAN Port LAN IP LAN Port Protocol
-------- ------ -------- --------
80 YOUR_SERVER_IP 80 TCP
443 YOUR_SERVER_IP 443 TCP
```
**EdgeRouter CLI commands:**
```bash
configure
set port-forward auto-firewall enable
set port-forward hairpin-nat enable
set port-forward wan-interface eth0
set port-forward rule 1 description "HTTP to Traefik"
set port-forward rule 1 forward-to address YOUR_SERVER_IP
set port-forward rule 1 forward-to port 80
set port-forward rule 1 original-port 80
set port-forward rule 1 protocol tcp
set port-forward rule 2 description "HTTPS to Traefik"
set port-forward rule 2 forward-to address YOUR_SERVER_IP
set port-forward rule 2 forward-to port 443
set port-forward rule 2 original-port 443
set port-forward rule 2 protocol tcp
commit
save
exit
```
### 3. Verify SSL Certificates (After DNS Propagates)
Once DNS is configured and propagated:
```bash
# Check Traefik logs for SSL certificate generation
docker logs traefik -f
# You should see messages like:
# "Server responded with a certificate"
# "Certificate obtained for domain recipes.pkartchner.com"
```
### 4. Test Your Setup
After DNS propagation and SSL certificates are obtained:
**Test Mealie:**
```bash
# Should redirect to HTTPS and show valid certificate
curl -I https://recipes.pkartchner.com
```
**Test Gogs:**
```bash
# Should redirect to HTTPS and show valid certificate
curl -I https://git.pkartchner.com
```
**Access Traefik Dashboard:**
```
URL: https://traefik.pkartchner.com
Username: admin
Password: change-this-password
```
### 5. Change Traefik Dashboard Password
Generate a new password hash:
```bash
apt install apache2-utils
echo $(htpasswd -nb admin YourNewPassword) | sed -e s/\\$/\\$\\$/g
```
Update the password in `/srv/docker-compose/traefik/docker-compose.yml`:
```yaml
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$NEW_HASH"
```
Then restart Traefik:
```bash
cd /srv/docker-compose/traefik
docker compose restart
```
## Troubleshooting
### SSL Certificate Errors
If you see "DNS problem: NXDOMAIN" in logs:
- ✅ DNS records are not set up yet or haven't propagated
- ⏰ Wait for DNS propagation (can take up to 24 hours)
- 🔍 Check DNS with: `dig recipes.pkartchner.com` or `nslookup recipes.pkartchner.com`
### Can't Access Services
1. **Check if Traefik is running:**
```bash
docker ps | grep traefik
```
2. **Check Traefik logs:**
```bash
docker logs traefik --tail 50
```
3. **Verify containers are on Traefik network:**
```bash
docker network inspect traefik
```
4. **Test local access:**
```bash
curl -H "Host: recipes.pkartchner.com" http://localhost
```
### 503 Service Unavailable
- Check if Mealie/Gogs containers are running
- Verify they're on the Traefik network
- Check container logs
## Services Summary
| Service | Domain | Backend Port | Status |
|---------|--------|--------------|--------|
| Mealie | recipes.pkartchner.com | localhost:9091 | ✅ Configured |
| Gogs | git.pkartchner.com | gogs.pkartchner.com:3000 | ✅ Configured |
| Traefik | traefik.pkartchner.com | localhost:8080 | ✅ Configured |
## Important Security Notes
1. **Firewall**: Only ports 80, 443, and 22 (SSH) should be open to the internet
2. **Dashboard**: Change the default Traefik dashboard password immediately
3. **Backups**: acme.json contains your SSL certificates - back it up
4. **Updates**: Regularly update Traefik for security patches
## Quick Commands
```bash
# View Traefik dashboard locally
curl http://localhost:8080/dashboard/
# Check SSL certificates
docker exec traefik cat /acme.json | jq .
# Restart all services
cd /srv/docker-compose/traefik && docker compose restart
cd /srv/docker-compose/mealie && docker compose restart
# View logs
docker logs traefik -f
docker logs mealie -f
```
## When Everything is Working
You should be able to:
- ✅ Access Mealie at https://recipes.pkartchner.com (with valid SSL)
- ✅ Access Gogs at https://git.pkartchner.com (with valid SSL)
- ✅ Access Traefik dashboard at https://traefik.pkartchner.com
- ✅ HTTP automatically redirects to HTTPS
- ✅ All connections encrypted with Let's Encrypt certificates

30
config.yml Normal file
View File

@@ -0,0 +1,30 @@
http:
routers:
# Router for Gogs (if it's running outside Docker or on different network)
gogs:
rule: "Host(`git.pkartchner.com`)"
entryPoints:
- https
service: gogs
tls:
certResolver: letsencrypt
services:
# Service for Gogs
gogs:
loadBalancer:
servers:
- url: "http://gogs.pkartchner.com:3000"
middlewares:
# Security headers
secure-headers:
headers:
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
contentTypeNosniff: true
browserXssFilter: true
referrerPolicy: "same-origin"

44
docker-compose.yml Normal file
View File

@@ -0,0 +1,44 @@
version: '3.8'
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: always
security_opt:
- no-new-privileges:true
networks:
- traefik
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Traefik Dashboard (optional, can be disabled)
environment:
- TZ=America/Denver
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
- ./config.yml:/config.yml:ro
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.pkartchner.com`)"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
# Dashboard auth (username: admin, password: change-this-password)
# Generate new password: echo $(htpasswd -nb admin yourpassword) | sed -e s/\\$/\\$\\$/g
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$8evjlb96$$v8Y6gLV8KLVhqGB1N9NKQR/"
# Global redirect to HTTPS
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=http"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
networks:
traefik:
name: traefik
driver: bridge

37
traefik.yml Normal file
View File

@@ -0,0 +1,37 @@
api:
dashboard: true
debug: false
entryPoints:
http:
address: ":80"
https:
address: ":443"
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik
file:
filename: /config.yml
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: pkartch@gmail.com
storage: acme.json
# Uncomment for production (remove caServer line for production)
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory
httpChallenge:
entryPoint: http
log:
level: INFO
accessLog:
filePath: "/var/log/traefik/access.log"