tomwojcik/homeserver-traefik-portainer: My homeserver setup. Everything managed securely using Portainer.
Navigation Menu
Search code, repositories, users, issues, pull requests...
Provide feedback
We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Saved searches
Use saved searches to filter your results more quickly
Name
Query
To see all available qualifiers, see our documentation.
Appearance settings
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert
tomwojcik / homeserver-traefik-portainer Public
- Notifications You must be signed in to change notification settings
- Fork 13
- Star 76
My homeserver setup. Everything managed securely using Portainer.
tomwojcik/homeserver-traefik-portainer
3 Branches0 TagsOpen more actions menu
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Latest commitb46803c · Aug 13, 2025 | ||||
Aug 11, 2025 | ||||
Aug 13, 2025 | ||||
Aug 11, 2025 | ||||
Aug 6, 2025 | ||||
Aug 6, 2025 | ||||
Aug 6, 2025 | ||||
Aug 7, 2025 | ||||
Aug 13, 2025 | ||||
Aug 13, 2025 | ||||
Aug 13, 2025 | ||||
Repository files navigation
homeserver-traefik-portainer
A complete homeserver setup using Traefik reverse proxy with automatic HTTPS and Portainer for easy container management.
Features VPN-protected downloading and both local and external access options.
Features✅
Local-first architecture - Fast streaming without internet dependencies
✅ Automatic HTTPS - Set-and-forget SSL certificates via Let's Encrypt
✅ VPN-protected downloads - Secure torrenting through isolated VPN container
✅ Easy service deployment - Deploy services via Portainer's web UI
✅ Hybrid access - Local network speed + selective external access
✅ Service auto-discovery - Traefik automatically detects new services
✅ No port conflicts - Everything routed through Traefik on 80/443
Quick Start
1. Configure Environmentcp .env.example .env
Edit .env and configure:
- SERVER_DOMAIN=example.com
- ACME_EMAIL=your-email@example.com
- CF_DNS_API_TOKEN=your_cloudflare_dns_token
- VPN credentials for downloading services
Setting up Cloudflare DNS API TokenFor automatic HTTPS certificates, you need a Cloudflare API token with DNS permissions:
- Buy a domain - Cloudflare offers domains at cost (no markup) and provides excellent DNS management
- Create API Token:
- Go to Cloudflare API Tokens
- Click "Create Token"
- Use "Custom token" template
- Permissions:
- Zone:Zone:Read
- Zone:DNS:Edit
- Zone Resources:
- Include: Specific zone:
your-domain.com
- Include: Specific zone:
- Client IP Address Filtering: Leave empty (optional)
- Click "Continue to summary" → "Create Token"
- Save the token - You'll use this for
CF_DNS_API_TOKENin your.envfile
Alternative DNS Providers: If not using Cloudflare, check Traefik's supported ACME providers and adjust the configuration accordingly.
2. Set Up DNS#### Local DNS ConfigurationPoint *.example.com to your NAS IP address:
- Router DNS: Add wildcard DNS entry
- Pi-hole: Add local DNS record
- Hosts file:
192.168.1.100 jellyfin.example.com(etc.)
Cloudflare DNS ConfigurationFor external access and Let's Encrypt certificates:
- In Cloudflare Dashboard: Go to your domain → DNS
- Add DNS Record:
- Type:
A - Name:
*(wildcard) - IPv4 address: Your NAS IP address (e.g.,
192.168.1.100) - Proxy status: ☁️ Disabled (DNS only, not proxied)
- TTL: Auto
- Type:
- Click Save
Important: The proxy status must be disabled for Let's Encrypt DNS challenges to work properly.
3. Start Core Servicesdocker-compose up -d
This starts:
- Traefik v3.0 (reverse proxy with automatic HTTPS)
- Portainer 2.32.0 (container management)
- Cloudflared (selective external access)
4. Deploy Services via PortainerIMPORTANT: Deploy in this order!
- Access Portainer:
https://portainer.example.com - Configure App Templates:
- Go to Settings > App Templates
- Set URL:
https://raw.githubusercontent.com/tomwojcik/homeserver-traefik-portainer/master/template.json
- Deploy VPN stack FIRST: Deploy "Gluetun VPN"
- Deploy download services: Deploy metube, media-server (depend on gluetun)
- Deploy other services: Any order
Available ServicesDeploy any of these through Portainer's App Templates:
Media & Entertainment- Jellyfin/Plex - Media streaming servers
- Sonarr/Radarr - TV show/movie management
- Jellyseerr - Media request system
- MeTube - YouTube downloader (VPN-protected)
- qbittorrent - Torrent client (VPN-protected)
Productivity- Nextcloud - File sync and collaboration
- Heimdall - Dashboard for organizing services
- Uptime Kuma - Service monitoring
Development- Gitea/Gogs - Git repositories
- Docker Registry - Private container registry
- n8n - Workflow automation
Utilities- Dozzle - Container log viewer
- CyberChef - Data transformation tools
- MinIO - S3-compatible object storage
Service URLsAfter setup, your services will be available at:
- https://traefik.example.com (Traefik dashboard)
- https://portainer.example.com (Container management)
- https://jellyfin.example.com (Media streaming - local speed)
- https://sonarr.example.com (TV show management)
- https://qbittorrent.example.com (Torrents via VPN)
- https://metube.example.com (YouTube downloads via VPN)
- https://nextcloud.example.com (File sync)
- https://uptime.example.com (Service monitoring)
Network Architecture### Local Access (Primary)```
Local Device → Router DNS → NAS:443 → Traefik → Service
**Benefits**: Full bandwidth, no internet dependency, lowest latency
### **External Access (Selective)**```
External → Cloudflare Tunnel → Specific Services
Use for: Nextcloud (file sync), Jellyseerr (remote requests)
VPN Protection (Downloads)```
qbittorrent/metube → Gluetun VPN → Internet
**Benefits**: IP masking, geographic flexibility, ISP protection
## VPN Setup (Critical for Downloads)### 1\. Deploy Gluetun Stack First1. In Portainer App Templates, deploy "Gluetun VPN"
2. Configure your VPN credentials:
- `VPN_SERVICE_PROVIDER` (surfshark, nordvpn, etc.)
- `WIREGUARD_PRIVATE_KEY`
- `WIREGUARD_ADDRESSES`
### 2\. Verify VPN Connection- Check gluetun logs: `docker logs gluetun`
- Test IP: `docker exec gluetun curl ifconfig.me`
- Should show VPN server IP, not your real IP
### 3\. Deploy Download Services- **metube**: Regular deployment (no VPN needed for YouTube downloads)
- **qbittorrent**: Routes through gluetun VPN for security
### 4\. Access VPN-Protected Services**qBittorrent Access (Setup Only)**
- **Normal operation**: No direct access needed - Sonarr/Radarr communicate automatically
- **Initial setup**: Temporarily expose port in gluetun stack:
# Add to gluetun service temporarily
ports:
- "8080:8080" # Remove after setup complete
- **After setup**: Remove port exposure for maximum security
- **Troubleshooting**: Re-add port temporarily when needed
**Workflow After Setup:**
1. **Request media**: Jellyseerr → Sonarr/Radarr
2. **Automatic download**: \*arr stack → qBittorrent (via VPN)
3. **Watch content**: Jellyfin/Plex (local network speed)
4. **Zero manual intervention**: qBittorrent operates invisibly through VPN
## Adding New Services### Method 1: Portainer App Templates (Recommended)1. Deploy service through Portainer App Templates
2. Service automatically gets Traefik labels
3. Instantly available at `https://service.example.com`
### Method 2: External RepositoryPerfect for deploying your own applications:
version: "3.8"
services:
my-app:
build: .
container\_name: my-app
networks:
- homeserver
restart: unless-stopped
labels:
- "my.zone=homeserver"
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(\`myapp.${SERVER\_DOMAIN}\`)"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.tls.certresolver=myresolver"
- "traefik.http.services.myapp.loadbalancer.server.port=3000"
networks:
homeserver:
name: homeserver
external: true
### Method 3: Manual Stack Deployment1. **In Portainer**: Stacks → Add Stack → Git Repository
2. **Enter your repo URL**: `https://github.com/yourusername/project`
3. **Add environment variables**: Include `SERVER_DOMAIN`
4. **Deploy**: Service available at `https://project.example.com`
## External Access Configuration### Option 1: Cloudflare Tunnels (Secure)Configure tunnels for services needing external access:
1. **Nextcloud**: File sync from anywhere
2. **Jellyseerr**: Remote media requests
3. **Uptime Kuma**: Service monitoring
### Option 2: Port Forwarding (Basic)Forward ports 80/443 to your NAS:
- **Pros**: Simple setup
- **Cons**: Synology nginx port conflicts, security risks
**Recommendation**: Use Cloudflare Tunnels for security
## Synology NAS SetupSynology DSM uses ports 80 and 443 for its web interface, which conflicts with Traefik. Here's how to resolve this:
### Port Conflict Resolution1. **Change DSM ports** (recommended approach):
sed -i -e 's/80/81/' -e 's/443/444/' /usr/syno/share/nginx/server.mustache /usr/syno/share/nginx/DSM.mustache /usr/syno/share/nginx/WWWService.mustache
2. **Restart nginx service**:
- **DSM < 7**: `synoservicecfg --restart nginx`
- **DSM ≥ 7**: `sudo systemctl restart nginx`
3. **Access DSM**: Use `http://nas-ip:81` or `https://nas-ip:444` instead of default ports
### Alternative ApproachInstead of changing DSM ports, you can modify Traefik to use different ports in the docker-compose.yml:
ports:
- "8080:80" # HTTP
- "8443:443" # HTTPS
Then access services via `https://service.example.com:8443`
## Troubleshooting### **HTTPS Issues**- **Check DNS**: Ensure `*.example.com` points to NAS IP
- **Check certificates**: `docker logs traefik`
- **Cloudflare API**: Verify `CF_DNS_API_TOKEN` is correct
- **Domain ownership**: Must control DNS for Let's Encrypt
### **VPN Issues**- **Check gluetun logs**: `docker logs gluetun`
- **Verify credentials**: WireGuard keys must be valid
- **Test connection**: `docker exec gluetun curl ifconfig.me`
- **Port forwarding**: Check if VPN supports it
### **Service Not Accessible**- **Check Traefik dashboard**: `https://traefik.example.com`
- **Verify labels**: Service must have proper Traefik labels
- **Check networks**: Service must be on `homeserver` network
- **DNS cache**: Clear browser/system DNS cache
### **Portainer Security Timeout**If Portainer shows "timeout.html" or security timeout message:
- **Cause**: Portainer requires admin setup within 2 minutes of first start
- **Fix**:
docker restart portainer
# Immediately go to portainer.example.com and create admin user
- **Alternative**: Access directly via `http://nas-ip:9000` during setup
- **Note**: This only happens on first setup - once admin is created, normal access works
### **Services Not Routing Through Traefik****Important**: If a service has exposed ports in docker-compose (e.g., `ports: - "9000:9000"`), it will bypass Traefik routing:
- **Problem**: `portainer.example.com` returns 404, but `nas-ip:9000` works
- **Cause**: Exposed ports take precedence over Traefik routing
- **Solution**:
1. **For initial setup**: Temporarily expose ports, access via `nas-ip:port`
2. **For production**: Comment out port mappings to force Traefik routing
# ports:
# - "9000:9000" # Disable for Traefik routing
- **When to expose ports**: Only for troubleshooting or when Traefik fails
### **Performance Issues**- **Local vs External**: Use local URLs for best performance
- **GPU transcoding**: Uncomment device mappings in media services
- **Storage**: Ensure fast storage for media files
## Security Best Practices### **Network Isolation**- Downloads isolated in VPN container
- Services communicate only through defined networks
- No direct port exposure (except Traefik 80/443)
### **Access Control**- Local network: Full access to all services
- External: Only selected services via Cloudflare
- Authentication: Cloudflare Access for sensitive services
### **Certificate Management**- Automatic Let's Encrypt renewal
- Wildcard certificates for all subdomains
- DNS challenge (no port 80 requirement)
## Performance Optimization### **Media Streaming**- **Local access only**: No tunnel overhead
- **Direct file access**: Mount media directories properly
- **GPU acceleration**: Enable for transcoding if available
### **Resource Management**- **Health checks**: Services restart automatically
- **Resource limits**: Configured for containers
- **Monitoring**: Use cAdvisor and Uptime Kuma
## Deployment Order (Important!)1. **Core services**: `docker-compose up -d` (Traefik + Portainer)
2. **VPN stack**: Deploy gluetun via Portainer (for qBittorrent only)
3. **Download services**:
- Deploy metube (standalone - no VPN needed)
- Deploy media-server (qBittorrent uses gluetun VPN)
4. **Other services**: Deploy in any order
**Important**: Only qBittorrent requires VPN deployment order - metube can be deployed anytime
## ContributingThis is a production-ready homeserver setup optimized for performance and security. If you find it useful:
- ⭐ Star the repository
- 🍴 Fork for your own modifications
- 📝 Share improvements via issues/PRs
## References- [Traefik Documentation](https://doc.traefik.io/traefik/)
- [Gluetun VPN Documentation](https://github.com/qdm12/gluetun)
- [Portainer Templates Format](https://docs.portainer.io/v/ce-2.11/advanced/app-templates/format)
- [Let's Encrypt + Cloudflare](https://doc.traefik.io/traefik/https/acme/#providers)
## About
My homeserver setup. Everything managed securely using Portainer.
### Topics
[homeserver](https://github.com/topics/homeserver "Topic: homeserver") [traefik](https://github.com/topics/traefik "Topic: traefik") [homelab](https://github.com/topics/homelab "Topic: homelab") [portainer-templates](https://github.com/topics/portainer-templates "Topic: portainer-templates")
### Resources
[Readme](https://github.com/tomwojcik/#readme-ov-file)
### License
[GPL-3.0 license](https://github.com/tomwojcik/#GPL-3.0-1-ov-file)
### Uh oh!
There was an error while loading. Please reload this page.
[Activity](https://github.com/tomwojcik/homeserver-traefik-portainer/activity)
### Stars
[**76** stars](https://github.com/tomwojcik/homeserver-traefik-portainer/stargazers)
### Watchers
[**0** watching](https://github.com/tomwojcik/homeserver-traefik-portainer/watchers)
### Forks
[**13** forks](https://github.com/tomwojcik/homeserver-traefik-portainer/forks)
[Report repository](https://github.com/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Ftomwojcik%2Fhomeserver-traefik-portainer&report=tomwojcik+%28user%29)
## Languages
- [Python 98.4%](https://github.com/tomwojcik/homeserver-traefik-portainer/search?l=python)
- [Makefile 1.6%](https://github.com/tomwojcik/homeserver-traefik-portainer/search?l=makefile)
## Footer© 2025 GitHub, Inc.
### Footer navigation
- [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service)
- [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement)
- [Security](https://github.com/security)
- [Status](https://www.githubstatus.com/)
- [Community](https://github.community/)
- [Docs](https://docs.github.com/)
- [Contact](https://support.github.com/?tags=dotcom-footer)
-
-
You can’t perform that action at this time.