feat: standardize Traefik configuration and update documentation
- Reorganize Sablier middlewares in alphabetical order with authelia first - Add service definitions comment to external-host-production.yml - Update docker-guidelines.md with comprehensive Traefik configuration: * Emphasize authelia SSO and sablier lazy loading as defaults * Add detailed remote server configuration instructions * Include complete TRAEFIK CONFIGURATION examples in service creation/modification guidelines * Expand remote server setup with YAML file examples * Update planning phase with Traefik considerations * Enhance documentation phase with HTTPS URLs and routing notes
This commit is contained in:
@@ -372,6 +372,8 @@ http:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
|
||||
# Service Definitions
|
||||
services:
|
||||
backrest-${SERVER_HOSTNAME}:
|
||||
loadBalancer:
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
# Session duration set to 5m for testing. Increase to 30m for production.
|
||||
http:
|
||||
middlewares:
|
||||
authelia:
|
||||
forwardauth:
|
||||
address: http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/
|
||||
authResponseHeaders:
|
||||
- X-Secret
|
||||
trustForwardHeader: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-arr:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -25,6 +32,18 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-bitwarden:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-bitwarden
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: bitwarden
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-bookstack:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -37,18 +56,6 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-jellyfin:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-jellyfin
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Jellyfin
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-calibre-web:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -73,75 +80,39 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-bitwarden:
|
||||
sablier-${SERVER_HOSTNAME}-dozzle:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-bitwarden
|
||||
group: ${SERVER_HOSTNAME}-dozzle
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: bitwarden
|
||||
displayName: dozzle
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-wordpress:
|
||||
sablier-${SERVER_HOSTNAME}-dokuwiki:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-wordpress
|
||||
group: ${SERVER_HOSTNAME}-dokuwiki
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: wordpress
|
||||
displayName: DokuWiki
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-nextcloud:
|
||||
sablier-${SERVER_HOSTNAME}-duplicati:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-nextcloud
|
||||
group: ${SERVER_HOSTNAME}-duplicati
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: NextCloud
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mediawiki:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mediawiki
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: mediawiki
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mealie:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mealie
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Mealie
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-gitea:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-gitea
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Gitea
|
||||
displayName: Duplicati
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
@@ -157,27 +128,15 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-dozzle:
|
||||
sablier-${SERVER_HOSTNAME}-gitea:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-dozzle
|
||||
group: ${SERVER_HOSTNAME}-gitea
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: dozzle
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-duplicati:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-duplicati
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Duplicati
|
||||
displayName: Gitea
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
@@ -205,6 +164,18 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-jellyfin:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-jellyfin
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Jellyfin
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-komodo:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -217,7 +188,6 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-kopia:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -230,6 +200,42 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mealie:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mealie
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Mealie
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mediawiki:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mediawiki
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: mediawiki
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-nextcloud:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-nextcloud
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: NextCloud
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-openkm:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -253,7 +259,7 @@ http:
|
||||
displayName: OpenWebUI
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-pulse:
|
||||
plugin:
|
||||
sablier:
|
||||
@@ -290,21 +296,14 @@ http:
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-dokuwiki:
|
||||
sablier-${SERVER_HOSTNAME}-wordpress:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-dokuwiki
|
||||
group: ${SERVER_HOSTNAME}-wordpress
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: DokuWiki
|
||||
displayName: wordpress
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
authelia:
|
||||
forwardauth:
|
||||
address: http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/
|
||||
authResponseHeaders:
|
||||
- X-Secret
|
||||
trustForwardHeader: true
|
||||
|
||||
@@ -102,7 +102,9 @@ AI will suggest `/mnt/` when data may exceed 50GB or grow continuously.
|
||||
|
||||
### Every Local (on the same server) Service Needs Traefik Labels
|
||||
|
||||
Standard pattern for all services:
|
||||
**Default Configuration**: All services should use authelia SSO, traefik routing, and sablier lazy loading by default.
|
||||
|
||||
Standard pattern for all services using the standardized TRAEFIK CONFIGURATION format:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -113,40 +115,224 @@ services:
|
||||
- homelab-network
|
||||
- traefik-network # Required for Traefik
|
||||
labels:
|
||||
# Enable Traefik
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=category-name"
|
||||
- "homelab.description=Brief service description"
|
||||
# Traefik labels
|
||||
- "traefik.enable=true"
|
||||
|
||||
# Define routing rule
|
||||
# Router configuration
|
||||
- "traefik.http.routers.myservice.rule=Host(`myservice.${DOMAIN}`)"
|
||||
|
||||
# Use websecure entrypoint (HTTPS)
|
||||
- "traefik.http.routers.myservice.entrypoints=websecure"
|
||||
|
||||
# Enable Let's Encrypt
|
||||
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
|
||||
|
||||
# Add Authelia SSO (if needed) - comment out to disable SSO
|
||||
- "traefik.http.routers.myservice.middlewares=authelia@docker"
|
||||
|
||||
# Specify port (if not default 80)
|
||||
# Service configuration
|
||||
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
|
||||
|
||||
# Optional: Sablier lazy loading (comment out to disable)
|
||||
# - "sablier.enable=true"
|
||||
# - "sablier.group=core-myservice"
|
||||
# - "sablier.start-on-demand=true"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-myservice"
|
||||
- "sablier.start-on-demand=true"
|
||||
```
|
||||
|
||||
### Label Structure Explanation
|
||||
|
||||
**Service Metadata Section:**
|
||||
- `com.centurylinklabs.watchtower.enable=true` - Enables automatic container updates
|
||||
- `homelab.category=category-name` - Groups services by function (media, productivity, infrastructure, etc.)
|
||||
- `homelab.description=Brief description` - Documents service purpose
|
||||
|
||||
**Router Configuration Section:**
|
||||
- `traefik.enable=true` - Enables Traefik routing for this service
|
||||
- `rule=Host(\`myservice.${DOMAIN}\`)` - Defines the domain routing rule
|
||||
- `entrypoints=websecure` - Routes through HTTPS entrypoint
|
||||
- `tls.certresolver=letsencrypt` - Enables automatic SSL certificates
|
||||
- `middlewares=authelia@docker` - **Default: Enables SSO protection** (remove line to disable)
|
||||
|
||||
**Service Configuration Section:**
|
||||
- `loadbalancer.server.port=8080` - Specifies internal container port (if not 80)
|
||||
|
||||
**Sablier Configuration Section:**
|
||||
- `sablier.enable=true` - **Default: Enables lazy loading** (remove section to disable)
|
||||
- `sablier.group=${SERVER_HOSTNAME}-myservice` - Groups containers for coordinated startup
|
||||
- `sablier.start-on-demand=true` - Starts containers only when accessed
|
||||
|
||||
### If Traefik is on a Remote Server, configure routes & services on the Remote Server
|
||||
|
||||
Add a yaml file to the traefik/dynamic folder for each remote server
|
||||
When Traefik runs on a separate server from your application services, you cannot use Docker labels for configuration. Instead, create YAML files in the Traefik server's `dynamic/` directory to define routes and services.
|
||||
|
||||
Add a section under routers: and a section on services: for each service
|
||||
#### When to Use Remote Traefik Configuration
|
||||
|
||||
Use this approach when:
|
||||
- Traefik runs on a dedicated reverse proxy server
|
||||
- Application services run on separate application servers
|
||||
- You want centralized routing configuration
|
||||
- Docker labels cannot be used (different servers)
|
||||
|
||||
#### File Organization
|
||||
|
||||
Create one YAML file per application server in `/opt/stacks/traefik/dynamic/`:
|
||||
|
||||
```
|
||||
/opt/stacks/traefik/dynamic/
|
||||
├── server1.example.com.yml # Services on server1
|
||||
├── server2.example.com.yml # Services on server2
|
||||
├── shared-services.yml # Common services
|
||||
└── sablier.yml # Sablier middlewares
|
||||
```
|
||||
|
||||
#### YAML File Structure
|
||||
|
||||
Each server-specific YAML file should contain:
|
||||
|
||||
```yaml
|
||||
# /opt/stacks/traefik/dynamic/server1.example.com.yml
|
||||
http:
|
||||
routers:
|
||||
# Router definitions for services on server1
|
||||
sonarr:
|
||||
rule: "Host(`sonarr.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia
|
||||
- sablier-server1-sonarr
|
||||
service: sonarr
|
||||
|
||||
radarr:
|
||||
rule: "Host(`radarr.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia
|
||||
- sablier-server1-radarr
|
||||
service: radarr
|
||||
|
||||
services:
|
||||
# Service definitions for services on server1
|
||||
sonarr:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://server1.example.com:8989" # Internal IP/port of service
|
||||
passhostheader: true
|
||||
|
||||
radarr:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://server1.example.com:7878" # Internal IP/port of service
|
||||
passhostheader: true
|
||||
```
|
||||
|
||||
#### Complete Example for a Media Server
|
||||
|
||||
```yaml
|
||||
# /opt/stacks/traefik/dynamic/media-server.yml
|
||||
http:
|
||||
routers:
|
||||
jellyfin:
|
||||
rule: "Host(`jellyfin.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
# No authelia for app access
|
||||
middlewares:
|
||||
- sablier-media-server-jellyfin
|
||||
service: jellyfin
|
||||
|
||||
sonarr:
|
||||
rule: "Host(`sonarr.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia
|
||||
- sablier-media-server-sonarr
|
||||
service: sonarr
|
||||
|
||||
radarr:
|
||||
rule: "Host(`radarr.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia
|
||||
- sablier-media-server-radarr
|
||||
service: radarr
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://192.168.1.100:8096" # Media server internal IP
|
||||
passhostheader: true
|
||||
|
||||
sonarr:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://192.168.1.100:8989" # Media server internal IP
|
||||
passhostheader: true
|
||||
|
||||
radarr:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://192.168.1.100:7878" # Media server internal IP
|
||||
passhostheader: true
|
||||
```
|
||||
|
||||
#### Key Configuration Notes
|
||||
|
||||
**Router Configuration:**
|
||||
- `rule`: Domain matching rule (same as Docker labels)
|
||||
- `entrypoints`: Use `websecure` for HTTPS
|
||||
- `tls.certresolver`: Use `letsencrypt` for automatic SSL
|
||||
- `middlewares`: List of middlewares (authelia, sablier, custom)
|
||||
- `service`: Reference to service definition below
|
||||
|
||||
**Service Configuration:**
|
||||
- `url`: Internal IP address and port of the actual service
|
||||
- `passhostheader: true`: Required for most web applications
|
||||
- Use internal IPs, not public domains
|
||||
|
||||
**Middleware References:**
|
||||
- `authelia`: References the authelia middleware (defined in another file)
|
||||
- `sablier-server1-sonarr`: References sablier middleware for lazy loading
|
||||
- Custom middlewares can be added as needed
|
||||
|
||||
#### Deployment Process
|
||||
|
||||
1. **Create/Update YAML files** in `/opt/stacks/traefik/dynamic/`
|
||||
2. **Validate syntax**:
|
||||
```bash
|
||||
docker exec traefik traefik validate --configFile=/etc/traefik/traefik.yml
|
||||
```
|
||||
3. **Reload configuration** (if hot-reload enabled) or restart Traefik
|
||||
4. **Test services** by accessing their domains
|
||||
5. **Monitor logs** for any routing errors
|
||||
|
||||
#### Migration from Docker Labels
|
||||
|
||||
When moving from Docker labels to YAML configuration:
|
||||
|
||||
1. Copy router rules from Docker labels to YAML format
|
||||
2. Convert service ports to full URLs with internal IPs
|
||||
3. Ensure middlewares are properly referenced
|
||||
4. Remove Traefik labels from docker-compose files
|
||||
5. Test all services after migration
|
||||
|
||||
This approach provides centralized, version-controllable routing configuration while maintaining the same security and performance benefits as Docker label-based configuration.
|
||||
|
||||
|
||||
### When to Use Authelia SSO
|
||||
|
||||
**Protect with Authelia**:
|
||||
**Protect with Authelia** (Default for all services):
|
||||
- Admin interfaces (Sonarr, Radarr, Prowlarr, etc.)
|
||||
- Infrastructure tools (Portainer, Dockge, Grafana)
|
||||
- Personal data (Nextcloud, Mealie, wikis)
|
||||
@@ -259,12 +445,18 @@ docker run --rm -v mydata:/data busybox tar czf /backup/data.tar.gz /data
|
||||
- [ ] What ports are needed?
|
||||
- [ ] What data needs to persist?
|
||||
- [ ] What environment variables are required?
|
||||
- [ ] What networks should it connect to?
|
||||
- [ ] What networks should it connect to? (include `traefik-network`)
|
||||
- [ ] Are there any security considerations?
|
||||
- [ ] **Should this service be protected by Authelia SSO?** (default: yes)
|
||||
- [ ] **Should this service use lazy loading?** (default: yes)
|
||||
- [ ] **What category does this service belong to?** (media, productivity, infrastructure, etc.)
|
||||
- [ ] **What subdomain should it use?** (service-name.${DOMAIN})
|
||||
|
||||
#### 2. Research Phase
|
||||
|
||||
- Read the official image documentation
|
||||
- Check for a service-doc in the EZ-Homelab/docs/service-docs folder, if the new service doesn't have one, be prepared to create it at the end
|
||||
- Utilize https://awesome-docker-compose.com/apps
|
||||
- Check example configurations
|
||||
- Review resource requirements
|
||||
- Understand health check requirements
|
||||
@@ -279,13 +471,14 @@ services:
|
||||
service-name:
|
||||
image: vendor/image:specific-version
|
||||
container_name: service-name
|
||||
restart: unless-stopped
|
||||
restart: unless-stopped # Set to 'no' if lazyloading (Sablier) is to be enabled
|
||||
```
|
||||
|
||||
**Add networks:**
|
||||
**Add networks (required for Traefik):**
|
||||
```yaml
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network # Required for Traefik routing
|
||||
```
|
||||
|
||||
**Add ports (if externally accessible):**
|
||||
@@ -319,6 +512,102 @@ services:
|
||||
start_period: 40s
|
||||
```
|
||||
|
||||
**Add TRAEFIK CONFIGURATION labels (required for all web services):**
|
||||
```yaml
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=category-name"
|
||||
- "homelab.description=Brief service description"
|
||||
# Traefik labels
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.service-name.rule=Host(`service-name.${DOMAIN}`)"
|
||||
- "traefik.http.routers.service-name.entrypoints=websecure"
|
||||
- "traefik.http.routers.service-name.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.service-name.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.service-name.loadbalancer.server.port=8080"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-service-name"
|
||||
- "sablier.start-on-demand=true"
|
||||
```
|
||||
If Traefik & Sablier are on a remote server:
|
||||
* Comment out the traefik labels since they won't be used, don't delete them.
|
||||
* Notify user to add the service and middleware to the traefic external host yml file, and the sablier.yml file.
|
||||
|
||||
**Example: Comment out Traefik labels in docker-compose.yml:**
|
||||
```yaml
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=category-name"
|
||||
- "homelab.description=Brief service description"
|
||||
# Traefik labels - COMMENTED OUT for remote server
|
||||
# - "traefik.enable=true"
|
||||
# - "traefik.http.routers.service-name.rule=Host(`service-name.${DOMAIN}`)"
|
||||
# - "traefik.http.routers.service-name.entrypoints=websecure"
|
||||
# - "traefik.http.routers.service-name.tls.certresolver=letsencrypt"
|
||||
# - "traefik.http.routers.service-name.middlewares=authelia@docker"
|
||||
# - "traefik.http.services.service-name.loadbalancer.server.port=8080"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-service-name"
|
||||
- "sablier.start-on-demand=true"
|
||||
```
|
||||
|
||||
**Required: Add to Traefik external host YAML file (e.g., `/opt/stacks/traefik/dynamic/remote-host-server1.yml`):**
|
||||
```yaml
|
||||
http:
|
||||
routers:
|
||||
service-name:
|
||||
rule: "Host(`service-name.yourdomain.duckdns.org`)"
|
||||
entrypoints:
|
||||
- websecure
|
||||
tls:
|
||||
certresolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia
|
||||
- sablier-server1-service-name
|
||||
service: service-name
|
||||
|
||||
services:
|
||||
service-name:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://192.168.1.100:8080" # Internal IP of application server
|
||||
passhostheader: true
|
||||
```
|
||||
|
||||
**Required: Add to Sablier YAML file (e.g., `/opt/stacks/traefik/dynamic/sablier.yml`):**
|
||||
```yaml
|
||||
sablier-server1-servicename:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: server1-servicename
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Service Name
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
```
|
||||
|
||||
**Deployment Steps:**
|
||||
1. Comment out Traefik labels in the service's docker-compose.yml
|
||||
2. Add router and service definitions to the appropriate Traefik dynamic YAML file
|
||||
3. Add sablier middleware to the sablier.yml file
|
||||
4. Validate Traefik configuration: `docker exec traefik traefik validate --configFile=/etc/traefik/traefik.yml`
|
||||
5. Restart Traefik or wait for hot-reload
|
||||
6. Test service access through Traefik
|
||||
|
||||
|
||||
#### 4. Testing Phase
|
||||
|
||||
```bash
|
||||
@@ -342,17 +631,21 @@ services:
|
||||
image: lscr.io/linuxserver/sonarr:4.0.0
|
||||
container_name: sonarr
|
||||
# Sonarr - TV Show management and automation
|
||||
# Web UI: http://server-ip:8989
|
||||
# Access at: https://sonarr.yourdomain.duckdns.org (via Traefik)
|
||||
# Connects to: Prowlarr (indexers), qBittorrent (downloads)
|
||||
restart: unless-stopped
|
||||
# Protected by: Authelia SSO, Sablier lazy loading
|
||||
restart: no
|
||||
```
|
||||
|
||||
Update your main README or service-specific README with:
|
||||
- Service purpose
|
||||
- Access URLs
|
||||
- Access URLs (Traefik HTTPS URLs)
|
||||
- Default credentials (if any)
|
||||
- Configuration notes
|
||||
- Configuration notes (SSO enabled/disabled, lazy loading, etc.)
|
||||
- Backup instructions
|
||||
- Any special routing considerations (VPN, remote server, etc.)
|
||||
|
||||
If the service doesn't already have a service doc in EZ-Homelab/docs/service-docs folder, create it using the compiled information about the service with the same format as the other service-docs
|
||||
|
||||
## Service Modification Guidelines
|
||||
|
||||
@@ -428,25 +721,49 @@ docker compose -f docker-compose/service.yml up -d
|
||||
|
||||
### Common Modifications
|
||||
|
||||
**Add TRAEFIK CONFIGURATION to existing service:**
|
||||
```yaml
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=category-name"
|
||||
- "homelab.description=Brief service description"
|
||||
# Traefik labels
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.service-name.rule=Host(`service-name.${DOMAIN}`)"
|
||||
- "traefik.http.routers.service-name.entrypoints=websecure"
|
||||
- "traefik.http.routers.service-name.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.service-name.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.service-name.loadbalancer.server.port=8080"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-service-name"
|
||||
- "sablier.start-on-demand=true"
|
||||
```
|
||||
|
||||
**Toggle SSO**: Comment/uncomment the Authelia middleware label:
|
||||
```yaml
|
||||
# Enable SSO
|
||||
# Enable SSO (default)
|
||||
- "traefik.http.routers.service.middlewares=authelia@docker"
|
||||
|
||||
# Disable SSO (comment out)
|
||||
# Disable SSO (remove line for media servers, public services)
|
||||
# - "traefik.http.routers.service.middlewares=authelia@docker"
|
||||
```
|
||||
|
||||
**Toggle Lazy Loading**: Comment/uncomment Sablier labels:
|
||||
```yaml
|
||||
# Enable lazy loading
|
||||
# Enable lazy loading (default)
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=core-service"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-service"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Disable lazy loading (comment out)
|
||||
# Disable lazy loading (remove section for always-on services)
|
||||
# - "sablier.enable=true"
|
||||
# - "sablier.group=core-service"
|
||||
# - "sablier.group=${SERVER_HOSTNAME}-service"
|
||||
# - "sablier.start-on-demand=true"
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user