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:
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal 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
177
README.md
Normal 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
202
SETUP-INSTRUCTIONS.md
Normal 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
30
config.yml
Normal 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
44
docker-compose.yml
Normal 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
37
traefik.yml
Normal 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"
|
||||||
Reference in New Issue
Block a user