Fix homepage Traefik network routing and update configurations

- Add traefik.docker.network=traefik-network label to homepage service
- Prevent Traefik from using wrong IP from homelab-network
- Resolve 504 Gateway Timeout issues after authentication
- Update various docker-compose configurations and templates
- Clean up unused configuration files
This commit is contained in:
EZ-Homelab Assistant
2026-01-30 23:29:00 -05:00
parent 465c10ae42
commit 90a26a9ac4
88 changed files with 3841 additions and 3626 deletions

View File

@@ -17,10 +17,23 @@ docker-compose/
├── nextcloud/ # Nextcloud stack
├── productivity/ # Productivity tools
├── utilities/ # Utility services
└── README.md # This file
```
## ⚠️ Important: Core Services First
## Usage
**Before deploying any other stacks, ensure the `core/` services are running:**
- **Traefik**: Reverse proxy and SSL termination
- **Authelia**: Single sign-on authentication
- **DuckDNS**: Dynamic DNS for domain resolution
These services provide the foundation for all other services. Most stacks depend on Traefik for routing and Authelia for authentication.
### Quick Start Core Services
```bash
cd core
cp .env.template .env # Edit with your values
cp docker-compose.yml.template docker-compose.yml # Or use the pre-configured version
docker compose up -d
```
### Starting Services

View File

@@ -10,7 +10,7 @@
services:
# Portainer - Docker management UI (Alternative to Dockge)
# Access at: https://portainer.${DOMAIN}
# Access at: https://portainer.kelinreij.duckdns.org
# NOTE: Dockge is the default Docker management UI. Deploy Portainer only if you prefer its interface
# Docker management interface should always run when deployed
portainer:
@@ -34,14 +34,14 @@ services:
- "homelab.category=alternatives"
- "homelab.description=Docker container management UI (Alternative to Dockge)"
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
- "traefik.http.routers.portainer.rule=Host(`portainer.kelinreij.duckdns.org`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.routers.portainer.middlewares=authelia@docker"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
# Authentik - Alternative SSO/Identity Provider with Web UI
# Access at: https://authentik.${DOMAIN}
# Access at: https://authentik.kelinreij.duckdns.org
# NOTE: Authelia is the default SSO. Deploy Authentik only if you need a web UI for user management
# WARNING: Do not run both Authelia and Authentik at the same time
# SSO service should always run when deployed as alternative to Authelia
@@ -73,7 +73,7 @@ services:
- "homelab.category=alternatives"
- "homelab.description=SSO/Identity provider with web UI (Alternative to Authelia)"
- "traefik.enable=true"
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
- "traefik.http.routers.authentik.rule=Host(`authentik.kelinreij.duckdns.org`)"
- "traefik.http.routers.authentik.entrypoints=websecure"
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
- "traefik.http.routers.authentik.middlewares=authelia@docker"
@@ -181,9 +181,9 @@ services:
- /mnt/media:/media:ro # Large media files on separate drive
- plex-transcode:/transcode
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- PLEX_CLAIM=${PLEX_CLAIM}
# Hardware transcoding support
# Uncomment ONE of the following options:
@@ -211,12 +211,12 @@ services:
- "homelab.description=Alternative media streaming server to Jellyfin"
# Traefik labels - NO Authelia for app access
- "traefik.enable=true"
- "traefik.http.routers.plex.rule=Host(`plex.${DOMAIN}`)"
- "traefik.http.routers.plex.rule=Host(`plex.kelinreij.duckdns.org`)"
- "traefik.http.routers.plex.entrypoints=websecure"
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
- "traefik.http.services.plex.loadbalancer.server.port=32400"
- "x-dockge.url=https://plex.${DOMAIN}"
- "x-dockge.url=https://plex.${DOMAIN}"
- "x-dockge.url=https://plex.kelinreij.duckdns.org"
- "x-dockge.url=https://plex.kelinreij.duckdns.org"
volumes:
portainer-data:

View File

@@ -0,0 +1,236 @@
# Alternative Services Stack
# This stack contains alternative/optional services that are not deployed by default
# Deploy manually through Dockge if you want to use these alternatives
# Place in /opt/stacks/alternatives/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
# Portainer - Docker management UI (Alternative to Dockge)
# Access at: https://portainer.${DOMAIN}
# NOTE: Dockge is the default Docker management UI. Deploy Portainer only if you prefer its interface
# Docker management interface should always run when deployed
portainer:
image: portainer/portainer-ce:2.19.4
container_name: portainer
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "9000:9000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer-data:/data
security_opt:
- no-new-privileges:true
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=Docker container management UI (Alternative to Dockge)"
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.routers.portainer.middlewares=authelia@docker"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
# Authentik - Alternative SSO/Identity Provider with Web UI
# Access at: https://authentik.${DOMAIN}
# NOTE: Authelia is the default SSO. Deploy Authentik only if you need a web UI for user management
# WARNING: Do not run both Authelia and Authentik at the same time
# SSO service should always run when deployed as alternative to Authelia
authentik-server:
image: ghcr.io/goauthentik/server:2024.2.0
container_name: authentik-server
restart: unless-stopped
command: server
networks:
- homelab-network
- traefik-network
ports:
- "9000:9000"
volumes:
- /opt/stacks/authentik/media:/media
- /opt/stacks/authentik/custom-templates:/templates
environment:
- AUTHENTIK_REDIS__HOST=authentik-redis
- AUTHENTIK_POSTGRESQL__HOST=authentik-db
- AUTHENTIK_POSTGRESQL__USER=${AUTHENTIK_DB_USER}
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME}
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=SSO/Identity provider with web UI (Alternative to Authelia)"
- "traefik.enable=true"
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
- "traefik.http.routers.authentik.entrypoints=websecure"
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
- "traefik.http.routers.authentik.middlewares=authelia@docker"
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
depends_on:
- authentik-db
- authentik-redis
# Authentik Worker - Background task processor
# SSO background worker should always run when Authentik is deployed
authentik-worker:
image: ghcr.io/goauthentik/server:2024.2.0
container_name: authentik-worker
restart: unless-stopped
command: worker
networks:
- homelab-network
volumes:
- /opt/stacks/authentik/media:/media
- /opt/stacks/authentik/certs:/certs
- /opt/stacks/authentik/custom-templates:/templates
environment:
- AUTHENTIK_REDIS__HOST=authentik-redis
- AUTHENTIK_POSTGRESQL__HOST=authentik-db
- AUTHENTIK_POSTGRESQL__USER=${AUTHENTIK_DB_USER}
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME}
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=Authentik background worker"
depends_on:
- authentik-db
- authentik-redis
# Authentik Database - PostgreSQL
# Database must always run for Authentik to function
authentik-db:
image: postgres:16-alpine
container_name: authentik-db
restart: unless-stopped
networks:
- homelab-network
volumes:
- authentik-db-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${AUTHENTIK_DB_USER}
- POSTGRES_PASSWORD=${AUTHENTIK_DB_PASSWORD}
- POSTGRES_DB=${AUTHENTIK_DB_NAME}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=Authentik database"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
# Authentik Redis - Cache and message queue
# Cache service must always run for Authentik performance
authentik-redis:
image: redis:7-alpine
container_name: authentik-redis
restart: unless-stopped
networks:
- homelab-network
volumes:
- authentik-redis-data:/data
command: --save 60 1 --loglevel warning
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=Authentik cache and messaging"
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 10s
timeout: 3s
retries: 5
# Plex Media Server - Alternative to Jellyfin
# Access at: https://plex.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
# Media server should always run when deployed as alternative to Jellyfin
plex:
image: plexinc/pms-docker:1.40.0.7998-f68041501
container_name: plex
restart: unless-stopped
networks:
- homelab-network
- homelab-network
- traefik-network
ports:
- "32400:32400"
volumes:
- ./plex/config:/config
- /mnt/media:/media:ro # Large media files on separate drive
- plex-transcode:/transcode
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PLEX_CLAIM=${PLEX_CLAIM}
# Hardware transcoding support
# Uncomment ONE of the following options:
# Option 1: Intel QuickSync (most common)
# devices:
# - /dev/dri:/dev/dri
# Option 2: NVIDIA GPU (requires nvidia-container-toolkit installed)
# runtime: nvidia
# devices:
# - /dev/nvidia0:/dev/nvidia0
# - /dev/nvidiactl:/dev/nvidiactl
# - /dev/nvidia-modeset:/dev/nvidia-modeset
# - /dev/nvidia-uvm:/dev/nvidia-uvm
# - /dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools
# environment:
# - NVIDIA_VISIBLE_DEVICES=all
# - NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=alternatives"
- "homelab.description=Alternative media streaming server to Jellyfin"
# Traefik labels - NO Authelia for app access
- "traefik.enable=true"
- "traefik.http.routers.plex.rule=Host(`plex.${DOMAIN}`)"
- "traefik.http.routers.plex.entrypoints=websecure"
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
- "traefik.http.services.plex.loadbalancer.server.port=32400"
- "x-dockge.url=https://plex.${DOMAIN}"
- "x-dockge.url=https://plex.${DOMAIN}"
volumes:
portainer-data:
driver: local
authentik-db-data:
driver: local
authentik-redis-data:
driver: local
plex-transcode:
driver: local
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -0,0 +1,28 @@
# Environment Variables Template for Core Services
# Copy this file to .env and fill in your values
# User and Group IDs for file permissions (get with: id -u and id -g)
PUID=1000
PGID=1000
TZ=America/New_York
SERVER_IP=192.168.1.100
SERVER_HOSTNAME=your-server-name
# Domain & DuckDNS Configuration
DUCKDNS_SUBDOMAINS=your-subdomain # Without .duckdns.org
DOMAIN=your-subdomain.duckdns.org
DUCKDNS_TOKEN=your-duckdns-token-here
# Default credentials (used by multiple services for easier setup)
DEFAULT_USER=admin
DEFAULT_PASSWORD=change-this-password
# Authelia Configuration
AUTHELIA_JWT_SECRET=your-jwt-secret-here
AUTHELIA_SESSION_SECRET=your-session-secret-here
AUTHELIA_STORAGE_ENCRYPTION_KEY=your-encryption-key-here
# Let's Encrypt Configuration
ACME_EMAIL=your-email@example.com

View File

@@ -0,0 +1,171 @@
# Core Infrastructure Services
This directory contains the core infrastructure services that form the foundation of the homelab. These services should always be running and are critical for the operation of other services.
## Services
### Traefik (v3)
- **Purpose**: Reverse proxy and SSL termination
- **Ports**: 80 (HTTP), 443 (HTTPS), 8080 (Dashboard)
- **Configuration**: Located in `traefik/config/traefik.yml`
- **SSL**: Let's Encrypt with DNS-01 challenge (configurable provider)
- **Dashboard**: Available at configured domain
### Authelia (v4.37.5)
- **Purpose**: Single sign-on authentication service
- **Port**: 9091 (internal)
- **Access**: Configured authentication domain
- **Configuration**: Located in `authelia/config/`
- **Database**: SQLite database in `authelia/config/db.sqlite3`
### DuckDNS
- **Purpose**: Dynamic DNS service for domain resolution
- **Subdomain**: Configurable via environment variables
- **Token**: Configured in environment variables
## ⚠️ Version Pinning & Breaking Changes
### Authelia Version Pinning
**Current Version**: `authelia/authelia:4.37.5`
**Breaking Changes Identified**:
- Authelia v4.39.15+ has breaking configuration changes that are incompatible with the current setup
- Database schema changes may require migration or recreation
- Configuration file format changes may break existing setups
**Action Taken**:
- Pinned to v4.37.5 which is confirmed working
- Database recreated from scratch to ensure compatibility
- Configuration files verified and working
**Upgrade Path**:
- Test upgrades in a separate environment first
- Backup configuration and database before upgrading
- Check Authelia changelog for breaking changes
- Consider using Authelia's migration tools if available
### Traefik Version Pinning
**Current Version**: `traefik:v3`
**Notes**:
- Traefik v3 is stable and working with current configuration
- Configuration format is compatible
- No breaking changes identified in current setup
## Configuration Requirements
### File Structure
```
core/
├── docker-compose.yml # Main service definitions
├── .env # Environment variables
├── authelia/
│ └── config/
│ ├── configuration.yml # Authelia main config
│ ├── users_database.yml # User credentials
│ └── db.sqlite3 # SQLite database
└── traefik/
├── config/
│ └── traefik.yml # Traefik static config
├── dynamic/ # Dynamic configurations
│ ├── routes.yml
│ ├── sablier.yml
│ └── external-host-*.yml
└── letsencrypt/
└── acme.json # SSL certificates
```
### Environment Variables (.env)
```bash
# Required for proper operation
DUCKDNS_TOKEN=your_duckdns_token_here
DUCKDNS_SUBDOMAINS=your_subdomain
DOMAIN=yourdomain.duckdns.org
TZ=America/New_York
PUID=1000
PGID=1000
```
### Network Requirements
- Docker network: `traefik-network`
- External ports: 80, 443 must be accessible
- DNS resolution: Domain must point to server IP
## Deployment
### Prerequisites
1. Docker and Docker Compose installed
2. Ports 80/443 forwarded to server
3. DuckDNS account with valid token
4. Domain configured in DuckDNS
### Startup Order
1. `duckdns` - For DNS updates
2. `traefik` - Reverse proxy
3. `authelia` - Authentication service
### Commands
```bash
# Start all services
docker-compose up -d
# Check status
docker-compose ps
# View logs
docker-compose logs -f [service-name]
# Restart specific service
docker-compose restart [service-name]
```
## Troubleshooting
### Common Issues
1. **Connection Refused**: Check if Traefik config file is in correct location (`traefik/config/traefik.yml`)
2. **SSL Certificate Issues**: Verify DuckDNS token and domain configuration
3. **Authelia Login Issues**: Check database file exists and configuration is valid
4. **Service Not Starting**: Check Docker logs for error messages
### Backup Strategy
- Configuration files are backed up automatically (see backup directories)
- Database should be backed up regularly
- SSL certificates are stored in `letsencrypt/acme.json`
- Use `backup.sh` script for automated backups
## Security Notes
- Authelia provides authentication for protected services
- All external traffic goes through Traefik with SSL termination
- Internal services communicate via Docker networks
- Dashboard access is protected by Authelia middleware
## Maintenance
- Monitor SSL certificate expiration (Let's Encrypt auto-renews)
- Keep Authelia version pinned until tested upgrades are available
- Regularly backup configuration and database files
- Check logs for security issues or errors
- Run `./backup.sh` regularly to backup critical files
## Customization
### Domain Configuration
Update the following files with your domain:
- `docker-compose.yml`: Traefik labels and Authelia configuration
- `authelia/config/configuration.yml`: Domain settings
- `.env`: Domain environment variables
### SSL Certificate Provider
Modify `traefik/config/traefik.yml` to use different DNS providers:
```yaml
certificatesResolvers:
letsencrypt:
acme:
dnsChallenge:
provider: cloudflare # or other supported provider
```
### Adding New Services
1. Add service definition to `docker-compose.yml`
2. Configure Traefik labels for routing
3. Add middleware for authentication if needed
4. Update network configuration

View File

@@ -1,6 +1,6 @@
# Authelia Configuration
# Authelia Configuration Template
# Copy to /opt/stacks/authelia/configuration.yml
# IMPORTANT: Replace '${DOMAIN}' with your actual DuckDNS domain
# IMPORTANT: Replace environment variable placeholders with your actual values
server:
host: 0.0.0.0
@@ -35,7 +35,7 @@ access_control:
default_policy: deny
rules:
# Bypass Authelia for Jellyfin (allow app access)
# Bypass Authelia for media services (allow app access)
- domain: jellyfin.${DOMAIN}
policy: bypass

View File

@@ -1,12 +1,14 @@
###############################################################
# Users Database #
###############################################################
# Template - Replace with your actual user information
# Generate password hash with: docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --password 'yourpassword'
users:
kelin:
displayname: "Admin User"
password: "$argon2id$v=19$m=65536,t=3,p=4$a+3pIrywP/li9wy9J6UkMA$+3THyJiAnS/gNYnLaYtlsRCaYfgnnxsUyGZ4D3xGnUg"
email: ${DEFAULT_EMAIL}
admin: # Change this username
displayname: "Administrator"
password: "GENERATE_NEW_PASSWORD_HASH" # Replace with actual hash
email: your-email@example.com # Replace with your email
groups:
- admins
- users

View File

@@ -3,10 +3,11 @@
###############################################################
users:
kelin:
displayname: "Admin User"
password: "$argon2id$v=19$m=65536,t=3,p=4$a+3pIrywP/li9wy9J6UkMA$+3THyJiAnS/gNYnLaYtlsRCaYfgnnxsUyGZ4D3xGnUg"
${DEFAULT_USER}:
displayname: "Administrator"
password: "${DEFAULT_PASSWORD_HASH}" # Generate with: docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --password 'yourpassword'
email: ${DEFAULT_EMAIL}
groups:
- admins
- users
- users

48
docker-compose/core/backup.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# Core Services Backup Script
# Run this script to backup critical configuration files and database
BACKUP_DIR="/opt/stacks/core/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="core_backup_${TIMESTAMP}"
echo "Creating backup: ${BACKUP_NAME}"
# Create backup directory
mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}"
# Backup Authelia configuration and database
echo "Backing up Authelia..."
cp -r /opt/stacks/core/authelia/config "${BACKUP_DIR}/${BACKUP_NAME}/"
# Backup Traefik configuration (excluding certificates for security)
echo "Backing up Traefik configuration..."
mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}/traefik"
cp -r /opt/stacks/core/traefik/config "${BACKUP_DIR}/${BACKUP_NAME}/traefik/"
cp -r /opt/stacks/core/traefik/dynamic "${BACKUP_DIR}/${BACKUP_NAME}/traefik/"
# Note: letsencrypt/acme.json contains private keys - backup separately if needed
# Backup docker-compose.yml
echo "Backing up docker-compose.yml..."
cp /opt/stacks/core/docker-compose.yml "${BACKUP_DIR}/${BACKUP_NAME}/"
# Backup environment file (contains sensitive data - handle carefully)
echo "Backing up .env file..."
cp /opt/stacks/core/.env "${BACKUP_DIR}/${BACKUP_NAME}/"
# Create archive
echo "Creating compressed archive..."
cd "${BACKUP_DIR}"
tar -czf "${BACKUP_NAME}.tar.gz" "${BACKUP_NAME}"
# Cleanup uncompressed backup
rm -rf "${BACKUP_NAME}"
echo "Backup completed: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
echo "Backup size: $(du -h "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)"
# Keep only last 10 backups
echo "Cleaning up old backups..."
ls -t "${BACKUP_DIR}"/*.tar.gz | tail -n +11 | xargs -r rm -f
echo "Backup script completed successfully"

View File

@@ -15,9 +15,9 @@ services:
container_name: duckdns
restart: unless-stopped
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS}
- TOKEN=${DUCKDNS_TOKEN}
volumes:
@@ -27,6 +27,8 @@ services:
traefik:
# Reverse proxy and SSL termination - core routing service, must always run
# CONFIGURATION REQUIREMENT: traefik.yml MUST be in ./traefik/config/ directory
# VOLUME MOUNT: ./traefik/config:/config - config file location is critical
image: traefik:v3
container_name: traefik
restart: unless-stopped
@@ -62,11 +64,14 @@ services:
authelia:
# Single sign-on authentication service - must always run for user authentication
image: authelia/authelia:latest
# VERSION PINNING: Pinned to v4.37.5 due to breaking changes in v4.39.15+
# BREAKING CHANGES: v4.39.15+ has incompatible configuration and database changes
# UPGRADE NOTES: Test in separate environment before upgrading. Backup config and DB.
image: authelia/authelia:4.37.5
container_name: authelia
restart: unless-stopped
environment:
- TZ=${TZ}
- TZ=America/New_York
ports:
- "9091:9091"
volumes:
@@ -115,11 +120,12 @@ services:
- SABLIER_DOCKER_API_VERSION=1.51
- SABLIER_DOCKER_NETWORK=traefik-network
- SABLIER_LOG_LEVEL=debug
- DOCKER_HOST=tcp://${SERVER_IP}:2376
- DOCKER_TLS_VERIFY=1
- DOCKER_HOST=unix:///var/run/docker.sock
- DOCKER_TLS_VERIFY=0
- DOCKER_CERT_PATH=/certs
volumes:
- ./shared-ca:/certs:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- 10000:10000
labels:

View File

@@ -27,6 +27,8 @@ services:
traefik:
# Reverse proxy and SSL termination - core routing service, must always run
# CONFIGURATION REQUIREMENT: traefik.yml MUST be in ./traefik/config/ directory
# VOLUME MOUNT: ./traefik/config:/config - config file location is critical
image: traefik:v3
container_name: traefik
restart: unless-stopped
@@ -62,7 +64,10 @@ services:
authelia:
# Single sign-on authentication service - must always run for user authentication
image: authelia/authelia:latest
# VERSION PINNING: Pinned to v4.37.5 due to breaking changes in v4.39.15+
# BREAKING CHANGES: v4.39.15+ has incompatible configuration and database changes
# UPGRADE NOTES: Test in separate environment before upgrading. Backup config and DB.
image: authelia/authelia:4.37.5
container_name: authelia
restart: unless-stopped
environment:

View File

@@ -1,16 +0,0 @@
{
"letsencrypt": {
"Account": {
"Email": "kelinfoxy@gmail.com",
"Registration": {
"body": {
"status": "valid"
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2959423246"
},
"PrivateKey": "MIIJJwIBAAKCAgEAtmlI6xzuaJKm8y8lU2CkLsVEB5QEZx777DDUMH7I3kt2zpIBjWFOxp3u+IppzDqC8ih8+2tzkAzIjF34kb45tgKah+gwTPUg20IoqTyg5/YaN/Otnda7Ioo9CS24k6lZ21DDrReT616BIa45dvtxYld8SES0Qx9x+jDTL8os0y2taMn3bX/0OMIE8jerrkzTYpLZ5PLMxKZFvoDClkfs4wAX4VpLh9oN1H45BqzhFZqsuZ2RZSvt/H91QFJWz38FDS0sRNEX83revbNdXEtJIQs+r45nHXiX6ivvfwtCXeGx2+hluCg/QpESCpCYj/JReQ1r2CCbTsfcpqrtIS1/eoLdal+AhrxGM5OlU6yeyclLHNfcZDIJkM54tr+0bPkweMwdqjoXkXWtEyFYE0Ol1CYQek8wHZLof8YYHwoo/zrLAu05igzSOxcaGRO3Inu1cW3TEvQM7nn2KfnWWPdY+u/Is0H2MqodokbzC9xpmPZlEzrnfGkngtcDtTOSNALUbANbFv4Zu9qBj8VtHUz2AYzkMUF5BKyFf4TSRrELEvXz3dMWpWY1Esjft4XaaeYXUnMCemrzuYPjC+gWyHvfNHXzui0bs5fY914cc4Q318x6JX+R/gKCxUfscuiwDRR9ufIilQCHPDw/hIJtZ9dAHeF66JREwdUQBH2tyBP+hvMCAwEAAQKCAgARbNBS6WIa6jt5ipzpsJcugpijkq+y/CI7p1R1x36/wXy5cfgk/dEtJwQfiPVfVY2RvW1nBRY2ggocYpOutHnF2czSQ8ttZpM7br/8nraOQhOyGZyRseQRghwfhtcVf/199mKi49g1CUOTqJWDuLRVnR7Ztnpz2QqlyEk8TPdoOvpQQs7YjnsRevNHAitrzJn61iVregg2lt2du6Ya/gbyjl05oUsK0Lk2fdJLwXMFAdATMSqk/APRdYmJWfRCARPF9PVAI6tCjo+9lmdKPEThm7XixlsyVQVKEOVhgP1Xg4peg/5Hj8yvOrV6/eIdChxfUHlnXYIIjg4Ve8mIPFTrgS4fv1wwIe0+RcLiimkC0+jTPaAqnMY1xEDU8sisVvB7vU9UevnXIR6XHGkGwsxD1Ga48PW5LvtWHG1YfjfxPEU0cHESsGejgCMPl1WT6UPeOYNmKx1I1gQiOQKixJt4fHXghAPmLBZTPZFrmhyFVSRb/wpVY+J4t61s3fzinqjox8P9xDx6I9bLl/2SI5rQ55a2MrGtRK/0l1zQxTE1U+3qVDD8BV0mbkDrPTtUAvoyHSzAAiwQIIdksSNZzTK7fdDSc/T84WbvSd3dcC6n272g5vfAhOycLEetzdigMc9ht8cCjr16UyHL4Br2adWneAwOxBffTVfVKnuAxshDJQKCAQEAx1idLIRlEGBXSC9x8fwIdsbUtH6y5ajE/ahmQ6L2fV+6A8uvlx/0uhMUkyLIjg30zh0Cnb05Cirzqao7EXSYmMUT6HgctPqNGgk0EvsXLa5NffbhOnPWQNPUKbmEZBf1HdG4K3wOv1/ISQ3fitIVsPrD88/OD3TOafXJLCzeRe8rxnoQlKoztszOwJmE28TMBZTYkvRGQZM6FiqvXzJoJFPeudp+8j0yE78fQPbl1uXNq/p9U5xkYid5PIjturrznoL1fy5KLgxHWrSAJd6JqVvajnch8DdEmsGI9MSLDyRszWHhXp7BeG5tl/+aHHdNxkA4y/38lukCETfORIH3jwKCAQEA6kCTzxHTHVXfxTU4YtcLoAUai94U3wBKf5l9yZfY19P9ITcPijw+daXiYaGLaBUtubMXM+KkjSKq7qx1HNB5hBfbHnSLzt0aAxhOlqfVdRaOi6Fn0tmvOPOLuORjlSVLa4Rng/eRE6yFSjEZ79DTAKYREND2Xxnzfqb573wLro/aFY0IcnZyjm9dO33SF3qBoZPuCoI1yPd+cTGYA7lyKIeNqWemXgCtg/tsxmjADgo9JCVxfc/TtQB8dwHN5GN2pw2jA7MGkCSI43F3QvKlXNEF1OI0jZOxOAphpAAyfWxLUUDsUWmCaDcc7keCFsl+41RqOFVaPewF/SCaybLoXQKCAQAFyp1GXdJR13qxri8xSJE2YjBrzgKEiZKvi+Tssh9XJSDSW2iOi28guM0wOSJ6fg1Or6kTzBuMIBNUKo3sw+ZrCc66QkMTPvQ6fWn14zWZLicyMan5eMQQvha735fpEIkehKlFGiWTicTX2n9UGSZoLeDjhHYIHOyiR3HAxszuWzR6X7F7oDZAaVLYZZ1mhSEoSFrCajZgUVauri7KJTzBUW53F9H4V67MxBC0Ynfq9mIzTOO3OiPwdhUfnRrLAgNx53waZc3h6JlqGTRf5Uc6lGCVIwDpabGkjVrdQZiIqBZBIUba6OHWDd9BOzvO9+haiiMcShS8jahxt51WgDAhAoIBAD+Iuk4sSHUpaGLFd4CfUMDbAYMz/bcqDgqjp9E4hRCsp3gNxgI5Kruf/VF7jiLxs5AtObrR2s2IvJG1ZqIlDQA9tCmDdLPrlfWG7zG/XY6/SnQml9FBR1wL+jZwg23dSqJjq+vIBqouXYxs2tsHaWNAp1pHQrsyf683PIyuuUBkNcMomETrSVDGdaQAES5bBLO9Oo/RFyNltP6gc9l2v7asZUiwGxhd2LH2TF9X49crAcA/A5Qa/RGXiyp/68bpDzJp6W/Ea6BGuHXvvWgEBcOx0YIWxCguCZ/oeOkRQKBx8c+c6zt9gWggopEiBe+GQQsJRzH2PF6VGF66LCFOi+UCggEAFEoujlC54OZHcHnJYT9Jb7JU9K/3F7007g23YPrN4ATE+UPT/6Uiod4BCQ5tTauu6EjofHUjImk1NT9dmc+zCnFexsgfJXLbU83qfRunoDATlueWCRCTzeWMkAEwjReabNQrK7xT0Rk4rGKsH0p0SDmUSP5jnt+uctNSMfLZ/SykihuydGrtQOY/lh87Y4/MX4pY5L03ogleDPAXxWpd+ea+0l8fUz3EX+VtWlTVzSuDFPL5zEFxpZrZeDflR+vxhzCw/Taiyz5/K6kUzaRQxwJq6Wvqv9lgngtfHavauWHFtL2pNs6WySk93M0JVmVpTzItf+bObJTvXuZVt+HbPw==",
"KeyType": "4096"
},
"Certificates": null
}
}

View File

@@ -27,9 +27,9 @@ entryPoints:
certificatesResolvers:
letsencrypt:
acme:
email: kelinfoxy@gmail.com # Will be replaced by deploy script
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
storage: /acme.json
email: ${ACME_EMAIL} # Your email for Let's Encrypt notifications
caServer: https://acme-v02.api.letsencrypt.org/directory # Use staging for testing
storage: /letsencrypt/acme.json
# DNS challenge - For wildcard certificates (*.yourdomain.duckdns.org)
# Works with DuckDNS - requires DUCKDNS_TOKEN in environment
dnsChallenge:

View File

@@ -32,10 +32,10 @@ services:
- /var/run/docker.sock:/var/run/docker.sock # For Docker integration do not mount RO
- /opt/stacks:/opt/stacks # To discover other stacks
environment:
- PUID=995 # Must be set to the docker user ID
- PGID=995 # Must be set to the docker group ID
- PUID=${PUID} # Must be set to the docker user ID
- PGID=${PGID} # Must be set to the docker group ID
- TZ=${TZ}
- HOMEPAGE_ALLOWED_HOSTS=homepage.${DOMAIN}
- HOMEPAGE_ALLOWED_HOSTS=${HOMEPAGE_ALLOWED_HOSTS}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -48,14 +48,15 @@ services:
# - Routes are configured via external YAML files on the core server
# - This prevents conflicts between Docker labels and file provider
- "traefik.enable=true"
- "traefik.docker.network=traefik-network"
- "traefik.http.routers.homepage.rule=Host(`homepage.${DOMAIN}`)"
- "traefik.http.routers.homepage.entrypoints=websecure"
- "traefik.http.routers.homepage.tls=true"
- "traefik.http.routers.homepage.middlewares=authelia@docker"
- "traefik.http.services.homepage.loadbalancer.server.port=3003"
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
# Sablier lazy loading (disabled by default - uncomment to enable)
# - "sablier.enable=true"
# - "sablier.group=${SERVER_HOSTNAME}-homarr"
# - "sablier.group=jasper-homarr"
# - "sablier.start-on-demand=true"
# Homarr - Modern dashboard
@@ -85,7 +86,7 @@ services:
- ./homarr/icons:/app/public/icons
- /var/run/docker.sock:/var/run/docker.sock
environment:
- TZ=${TZ}
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7575/"]
interval: 30s
@@ -108,7 +109,7 @@ services:
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-homarr"
- "sablier.group=jasper-homarr"
- "sablier.start-on-demand=true"
# DOCKGE URL CONFIGURATION
@@ -116,9 +117,9 @@ x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://homepage.${DOMAIN}
- https://${SERVER_IP}:3003
- https://192.168.4.4:3003
- https://homarr.${DOMAIN}
- https://${SERVER_IP}:7575
- https://192.168.4.4:7575
networks:
homelab-network:

View File

@@ -0,0 +1,127 @@
# Dashboard Services
# Homepage and Homarr for homelab dashboards
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
# Service Access URLs:
# - Homepage: https://homepage.${DOMAIN}
# - Homarr: https://homarr.${DOMAIN}
services:
# Homepage - Default Application Dashboard
homepage:
image: ghcr.io/gethomepage/homepage:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: homepage
restart: unless-stopped # change to 'no' to enable Sablier lazy loading
networks:
- homelab-network
- traefik-network
ports:
- "3003:3000"
volumes:
- ./homepage:/app/config
- /var/run/docker.sock:/var/run/docker.sock # For Docker integration do not mount RO
- /opt/stacks:/opt/stacks # To discover other stacks
environment:
- PUID=995 # Must be set to the docker user ID
- PGID=995 # Must be set to the docker group ID
- TZ=${TZ}
- HOMEPAGE_ALLOWED_HOSTS=homepage.${DOMAIN}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=dashboard"
- "homelab.description=Application dashboard"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# IMPORTANT: On REMOTE SERVERS (where Traefik runs elsewhere):
# - COMMENT OUT all traefik.* labels below (don't delete them)
# - Routes are configured via external YAML files on the core server
# - This prevents conflicts between Docker labels and file provider
- "traefik.enable=true"
- "traefik.http.routers.homepage.rule=Host(`homepage.${DOMAIN}`)"
- "traefik.http.routers.homepage.entrypoints=websecure"
- "traefik.http.routers.homepage.tls=true"
- "traefik.http.routers.homepage.middlewares=authelia@docker"
- "traefik.http.services.homepage.loadbalancer.server.port=3003"
# Sablier lazy loading (disabled by default - uncomment to enable)
# - "sablier.enable=true"
# - "sablier.group=${SERVER_HOSTNAME}-homarr"
# - "sablier.start-on-demand=true"
# Homarr - Modern dashboard
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
homarr:
image: ghcr.io/ajnart/homarr:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: homarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "7575:7575"
volumes:
- ./homarr/config:/app/config/configs
- ./homarr/data:/data
- ./homarr/icons:/app/public/icons
- /var/run/docker.sock:/var/run/docker.sock
environment:
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7575/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=dashboard"
- "homelab.description=Modern homelab dashboard"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.homarr.rule=Host(`homarr.${DOMAIN}`)"
- "traefik.http.routers.homarr.entrypoints=websecure"
- "traefik.http.routers.homarr.tls=true"
- "traefik.http.routers.homarr.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-homarr"
- "sablier.start-on-demand=true"
# DOCKGE URL CONFIGURATION
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://homepage.${DOMAIN}
- https://${SERVER_IP}:3003
- https://homarr.${DOMAIN}
- https://${SERVER_IP}:7575
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -1,86 +0,0 @@
# Authelia Configuration
# Copy to /opt/stacks/authelia/configuration.yml
# IMPORTANT: Replace 'your-domain.duckdns.org' with your actual DuckDNS domain
server:
host: 0.0.0.0
port: 9091
log:
level: info
theme: dark
jwt_secret: ${AUTHELIA_JWT_SECRET}
default_redirection_url: https://auth.${DOMAIN}
totp:
issuer: ${DOMAIN}
period: 30
skew: 1
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
key_length: 32
salt_length: 16
memory: 1024
parallelism: 8
access_control:
default_policy: deny
rules:
# Bypass Authelia for Jellyfin (allow app access)
- domain: jellyfin.${DOMAIN}
policy: bypass
# Bypass for Plex (allow app access)
- domain: plex.${DOMAIN}
policy: bypass
# Bypass for Home Assistant (has its own auth)
- domain: ha.${DOMAIN}
policy: bypass
# Protected: All other services require authentication
- domain: "*.${DOMAIN}"
policy: one_factor
# Two-factor for admin services (optional)
# - domain:
# - "admin.${DOMAIN}"
# - "portainer.${DOMAIN}"
# policy: two_factor
session:
name: authelia_session
secret: ${AUTHELIA_SESSION_SECRET}
expiration: 24h # Session expires after 24 hours
inactivity: 24h # Session expires after 24 hours of inactivity
remember_me_duration: 1M
domain: ${DOMAIN}
cookies:
- name: authelia_session
domain: ${DOMAIN}
secure: true
same_site: lax
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
local:
path: /config/db.sqlite3
notifier:
# File-based notifications (for development/testing)
filesystem:
filename: /config/notification.txt

View File

@@ -1,20 +0,0 @@
# Authelia Users Database
# Copy to /opt/stacks/authelia/users_database.yml
# Generate password hashes with: docker run authelia/authelia:latest authelia crypto hash generate argon2 --password 'yourpassword'
users:
admin:
displayname: "Admin User"
password: "$argon2id$v=19$m=65536,t=3,p=4$CHANGEME" # Replace with your hashed password
email: admin@example.com
groups:
- admins
- users
# Example: Additional user
# user1:
# displayname: "User One"
# password: "$argon2id$v=19$m=65536,t=3,p=4$CHANGEME"
# email: user1@example.com
# groups:
# - users

View File

@@ -13,6 +13,6 @@
# host: 192.168.4.5
# port: 2375
#${SERVER_HOSTNAME}:
#jasper:
# host: 192.168.4.11
# port: 2375

View File

@@ -1,8 +0,0 @@
## no access to the conf directory
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>

View File

@@ -1,10 +0,0 @@
# acl.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Access Control Lists
#
# Auto-generated by install script
# Date: Tue, 20 Jan 2026 20:06:48 -0500
* @ALL 1
* @user 8

View File

@@ -1,21 +0,0 @@
# acl.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Access Control Lists
#
# Editing this file by hand shouldn't be necessary. Use the ACL
# Manager interface instead.
#
# If your auth backend allows special char like spaces in groups
# or user names you need to urlencode them (only chars <128, leave
# UTF-8 multibyte chars as is)
#
# none 0
# read 1
# edit 2
# create 4
# upload 8
# delete 16
* @ALL 8

View File

@@ -1,62 +0,0 @@
# Acronyms.
ACL Access Control List
AFAICS As far as I can see
AFAIK As far as I know
AFAIR As far as I remember
API Application Programming Interface
ASAP As soon as possible
ASCII American Standard Code for Information Interchange
BTW By the way
CMS Content Management System
CSS Cascading Style Sheets
DNS Domain Name System
EOF End of file
EOL End of line
EOM End of message
EOT End of text
FAQ Frequently Asked Questions
FTP File Transfer Protocol
FOSS Free & Open-Source Software
FLOSS Free/Libre and Open Source Software
FUD Fear, Uncertainty, and Doubt
FYI For your information
GB Gigabyte
GHz Gigahertz
GPL GNU General Public License
GUI Graphical User Interface
HTML HyperText Markup Language
IANAL I am not a lawyer (but)
IE Internet Explorer
IIRC If I remember correctly
IMHO In my humble opinion
IMO In my opinion
IOW In other words
IRC Internet Relay Chat
IRL In real life
KISS Keep it simple stupid
LAN Local Area Network
LGPL GNU Lesser General Public License
LOL Laughing out loud
MathML Mathematical Markup Language
MB Megabyte
MHz Megahertz
MSIE Microsoft Internet Explorer
OMG Oh my God
OS Operating System
OSS Open Source Software
OTOH On the other hand
PITA Pain in the Ass
RFC Request for Comments
ROTFL Rolling on the floor laughing
RTFM Read The Fine Manual
spec specification
TIA Thanks in advance
TL;DR Too long; didn't read
TOC Table of Contents
URI Uniform Resource Identifier
URL Uniform Resource Locator
W3C World Wide Web Consortium
WTF? What the f***
WYSIWYG What You See Is What You Get
YMMV Your mileage may vary

View File

@@ -1,187 +0,0 @@
<?php
/**
* This is DokuWiki's Main Configuration file
*
* All the default values are kept here, you should not modify it but use
* a local.php file instead to override the settings from here.
*
* This is a piece of PHP code so PHP syntax applies!
*
* For help with the configuration and a more detailed explanation of the various options
* see https://www.dokuwiki.org/config
*/
/* Basic Settings */
$conf['title'] = 'DokuWiki'; //what to show in the title
$conf['start'] = 'start'; //name of start page
$conf['lang'] = 'en'; //your language
$conf['template'] = 'dokuwiki'; //see lib/tpl directory
$conf['tagline'] = ''; //tagline in header (if template supports it)
$conf['sidebar'] = 'sidebar'; //name of sidebar in root namespace (if template supports it)
$conf['license'] = 'cc-by-nc-sa'; //see conf/license.php
$conf['savedir'] = './data'; //where to store all the files
$conf['basedir'] = ''; //absolute dir from serveroot - blank for autodetection
$conf['baseurl'] = ''; //URL to server including protocol - blank for autodetect
$conf['cookiedir'] = ''; //path to use in cookies - blank for basedir
$conf['dmode'] = 0755; //set directory creation mode
$conf['fmode'] = 0644; //set file creation mode
$conf['allowdebug'] = 0; //allow debug output, enable if needed 0|1
/* Display Settings */
$conf['recent'] = 20; //how many entries to show in recent
$conf['recent_days'] = 7; //How many days of recent changes to keep. (days)
$conf['breadcrumbs'] = 10; //how many recent visited pages to show
$conf['youarehere'] = 0; //show "You are here" navigation? 0|1
$conf['fullpath'] = 0; //show full path of the document or relative to datadir only? 0|1
$conf['typography'] = 1; //smartquote conversion 0=off, 1=doublequotes, 2=all quotes
$conf['dformat'] = '%Y/%m/%d %H:%M'; //dateformat accepted by PHPs strftime() function
$conf['signature'] = ' --- //[[@MAIL@|@NAME@]] @DATE@//'; //signature see wiki page for details
$conf['showuseras'] = 'loginname'; // 'loginname' users login name
// 'username' users full name
// 'email' e-mail address (will be obfuscated as per mailguard)
// 'email_link' e-mail address as a mailto: link (obfuscated)
$conf['toptoclevel'] = 1; //Level starting with and below to include in AutoTOC (max. 5)
$conf['tocminheads'] = 3; //Minimum amount of headlines that determines if a TOC is built
$conf['maxtoclevel'] = 3; //Up to which level include into AutoTOC (max. 5)
$conf['maxseclevel'] = 3; //Up to which level create editable sections (max. 5)
$conf['camelcase'] = 0; //Use CamelCase for linking? (I don't like it) 0|1
$conf['deaccent'] = 1; //deaccented chars in pagenames (1) or romanize (2) or keep (0)?
$conf['useheading'] = 0; //use the first heading in a page as its name
$conf['sneaky_index']= 0; //check for namespace read permission in index view (0|1) (1 might cause unexpected behavior)
$conf['hidepages'] = ''; //Regexp for pages to be skipped from RSS, Search and Recent Changes
/* Authentication Settings */
$conf['useacl'] = 0; //Use Access Control Lists to restrict access?
$conf['autopasswd'] = 1; //autogenerate passwords and email them to user
$conf['authtype'] = 'authplain'; //which authentication backend should be used
$conf['passcrypt'] = 'bcrypt'; //Used crypt method (smd5,md5,sha1,ssha,crypt,mysql,my411,bcrypt)
$conf['defaultgroup']= 'user'; //Default groups new Users are added to
$conf['superuser'] = '!!not set!!'; //The admin can be user or @group or comma separated list user1,@group1,user2
$conf['manager'] = '!!not set!!'; //The manager can be user or @group or comma separated list user1,@group1,user2
$conf['profileconfirm'] = 1; //Require current password to confirm changes to user profile
$conf['rememberme'] = 1; //Enable/disable remember me on login
$conf['disableactions'] = ''; //comma separated list of actions to disable
$conf['auth_security_timeout'] = 900; //time (seconds) auth data is considered valid, set to 0 to recheck on every page view
$conf['securecookie'] = 1; //never send HTTPS cookies via HTTP
$conf['samesitecookie'] = 'Lax'; //SameSite attribute for cookies (Lax|Strict|None|Empty)
$conf['remote'] = 0; //Enable/disable remote interfaces
$conf['remoteuser'] = '!!not set!!'; //user/groups that have access to remote interface (comma separated). leave empty to allow all users
$conf['remotecors'] = ''; //enable Cross-Origin Resource Sharing (CORS) for the remote interfaces. Asterisk (*) to allow all origins. leave empty to deny.
/* Antispam Features */
$conf['usewordblock']= 1; //block spam based on words? 0|1
$conf['relnofollow'] = 1; //use rel="ugc nofollow" for external links?
$conf['indexdelay'] = 60*60*24*5; //allow indexing after this time (seconds) default is 5 days
$conf['mailguard'] = 'hex'; //obfuscate email addresses against spam harvesters?
//valid entries are:
// 'visible' - replace @ with [at], . with [dot] and - with [dash]
// 'hex' - use hex entities to encode the mail address
// 'none' - do not obfuscate addresses
$conf['iexssprotect']= 1; // check for JavaScript and HTML in uploaded files 0|1
/* Editing Settings */
$conf['usedraft'] = 1; //automatically save a draft while editing (0|1)
$conf['locktime'] = 15*60; //maximum age for lockfiles (defaults to 15 minutes)
$conf['cachetime'] = 60*60*24; //maximum age for cachefile in seconds (defaults to a day)
/* Link Settings */
// Set target to use when creating links - leave empty for same window
$conf['target']['wiki'] = '';
$conf['target']['interwiki'] = '';
$conf['target']['extern'] = '';
$conf['target']['media'] = '';
$conf['target']['windows'] = '';
/* Media Settings */
$conf['mediarevisions'] = 1; //enable/disable media revisions
$conf['refcheck'] = 1; //check for references before deleting media files
$conf['gdlib'] = 2; //the GDlib version (0, 1 or 2) 2 tries to autodetect
$conf['im_convert'] = ''; //path to ImageMagicks convert (will be used instead of GD)
$conf['jpg_quality'] = '70'; //quality of compression when scaling jpg images (0-100)
$conf['fetchsize'] = 0; //maximum size (bytes) fetch.php may download from extern, disabled by default
/* Notification Settings */
$conf['subscribers'] = 0; //enable change notice subscription support
$conf['subscribe_time'] = 24*60*60; //Time after which digests / lists are sent (in sec, default 1 day)
//Should be smaller than the time specified in recent_days
$conf['notify'] = ''; //send change info to this email (leave blank for nobody)
$conf['registernotify'] = ''; //send info about newly registered users to this email (leave blank for nobody)
$conf['mailfrom'] = ''; //use this email when sending mails
$conf['mailreturnpath'] = ''; //use this email as returnpath for bounce mails
$conf['mailprefix'] = ''; //use this as prefix of outgoing mails
$conf['htmlmail'] = 1; //send HTML multipart mails
$conf['dontlog'] = 'debug'; //logging facilities that should be disabled
$conf['logretain'] = 3; //how many days of logs to keep
/* Syndication Settings */
$conf['sitemap'] = 0; //Create a Google sitemap? How often? In days.
$conf['rss_type'] = 'rss1'; //type of RSS feed to provide, by default:
// 'rss' - RSS 0.91
// 'rss1' - RSS 1.0
// 'rss2' - RSS 2.0
// 'atom' - Atom 0.3
// 'atom1' - Atom 1.0
$conf['rss_linkto'] = 'diff'; //what page RSS entries link to:
// 'diff' - page showing revision differences
// 'page' - the revised page itself
// 'rev' - page showing all revisions
// 'current' - most recent revision of page
$conf['rss_content'] = 'abstract'; //what to put in the items by default?
// 'abstract' - plain text, first paragraph or so
// 'diff' - plain text unified diff wrapped in <pre> tags
// 'htmldiff' - diff as HTML table
// 'html' - the full page rendered in XHTML
$conf['rss_media'] = 'both'; //what should be listed?
// 'both' - page and media changes
// 'pages' - page changes only
// 'media' - media changes only
$conf['rss_update'] = 5*60; //Update the RSS feed every n seconds (defaults to 5 minutes)
$conf['rss_show_summary'] = 1; //Add revision summary to title? 0|1
$conf['rss_show_deleted'] = 1; //Show deleted items 0|1
/* Advanced Settings */
$conf['updatecheck'] = 1; //automatically check for new releases?
$conf['userewrite'] = 0; //this makes nice URLs: 0: off 1: .htaccess 2: internal
$conf['useslash'] = 0; //use slash instead of colon? only when rewrite is on
$conf['sepchar'] = '_'; //word separator character in page names; may be a
// letter, a digit, '_', '-', or '.'.
$conf['canonical'] = 0; //Should all URLs use full canonical http://... style?
$conf['fnencode'] = 'url'; //encode filenames (url|safe|utf-8)
$conf['autoplural'] = 0; //try (non)plural form of nonexistent files?
$conf['compression'] = 'gz'; //compress old revisions: (0: off) ('gz': gnuzip) ('bz2': bzip)
// bz2 generates smaller files, but needs more cpu-power
$conf['gzip_output'] = 0; //use gzip content encoding for the output xhtml (if allowed by browser)
$conf['compress'] = 1; //Strip whitespaces and comments from Styles and JavaScript? 1|0
$conf['cssdatauri'] = 512; //Maximum byte size of small images to embed into CSS, won't work on IE<8
$conf['send404'] = 0; //Send an HTTP 404 status for nonexistent pages?
$conf['broken_iua'] = 0; //Platform with broken ignore_user_abort (IIS+CGI) 0|1
$conf['xsendfile'] = 0; //Use X-Sendfile (1 = lighttpd, 2 = standard)
$conf['renderer_xhtml'] = 'xhtml'; //renderer to use for main page generation
$conf['readdircache'] = 0; //time cache in second for the readdir operation, 0 to deactivate.
$conf['search_nslimit'] = 0; //limit the search to the current X namespaces
$conf['search_fragment'] = 'exact'; //specify the default fragment search behavior
/* Feature Flags */
$conf['defer_js'] = 1; // Defer javascript to be executed after the page's HTML has been parsed. Setting will be removed in the next release.
$conf['hidewarnings'] = 0; // Hide warnings
/* Network Settings */
$conf['dnslookups'] = 1; //disable to disallow IP to hostname lookups
$conf['jquerycdn'] = 0; //use a CDN for delivering jQuery?
$conf['trustedproxies'] = array('::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16');
// Trusted proxy servers from which to read the X-Forwarded-For header.
// Each item in the array may be either an IPv4 or IPv6 address, or
// an IPv4 or IPv6 CIDR range (e.g. 10.0.0.0/8).
$conf['realip'] = false; // Enable reading the X-Real-IP header. Default: false.
// Only enable this if your server writes this header, otherwise it may be spoofed.
// Proxy setup - if your Server needs a proxy to access the web set these
$conf['proxy']['host'] = '';
$conf['proxy']['port'] = '';
$conf['proxy']['user'] = '';
$conf['proxy']['pass'] = '';
$conf['proxy']['ssl'] = 0;
$conf['proxy']['except'] = '';

View File

@@ -1,22 +0,0 @@
# Typography replacements
#
# Order does matter!
#
# You can use HTML entities here, but it is not recommended because it may break
# non-HTML renderers. Use UTF-8 chars directly instead.
<-> ↔
-> →
<- ←
<=> ⇔
=> ⇒
<= ⇐
>> »
<< «
--- —
--
(c) ©
(tm) ™
(r) ®
... …

View File

@@ -1,43 +0,0 @@
# Each URL may contain one of these placeholders
# {URL} is replaced by the URL encoded representation of the wikiname
# this is the right thing to do in most cases
# {NAME} this is replaced by the wikiname as given in the document
# only mandatory encoded is done, urlencoding if the link
# is an external URL, or encoding as a wikiname if it is an
# internal link (begins with a colon)
# {SCHEME}
# {HOST}
# {PORT}
# {PATH}
# {QUERY} these placeholders will be replaced with the appropriate part
# of the link when parsed as a URL
# If no placeholder is defined the urlencoded name is appended to the URL
# To prevent losing your added InterWiki shortcuts after an upgrade,
# you should add new ones to interwiki.local.conf
wp https://en.wikipedia.org/wiki/{NAME}
wpfr https://fr.wikipedia.org/wiki/{NAME}
wpde https://de.wikipedia.org/wiki/{NAME}
wpes https://es.wikipedia.org/wiki/{NAME}
wppl https://pl.wikipedia.org/wiki/{NAME}
wpjp https://ja.wikipedia.org/wiki/{NAME}
wpru https://ru.wikipedia.org/wiki/{NAME}
wpmeta https://meta.wikipedia.org/wiki/{NAME}
doku https://www.dokuwiki.org/
rfc https://tools.ietf.org/html/rfc
man http://man.cx/
amazon https://www.amazon.com/dp/{URL}?tag=splitbrain-20
amazon.de https://www.amazon.de/dp/{URL}?tag=splitbrain-21
amazon.uk https://www.amazon.co.uk/dp/{URL}
paypal https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=
phpfn https://secure.php.net/{NAME}
skype skype:{NAME}
google https://www.google.com/search?q=
google.de https://www.google.de/search?q=
go https://www.google.com/search?q={URL}&amp;btnI=lucky
user :user:{NAME}
# To support VoIP/SIP/TEL links
callto callto://{NAME}
tel tel:{NAME}

View File

@@ -1,38 +0,0 @@
<?php
/**
* This file defines multiple available licenses you can license your
* wiki contents under. Do not change this file, but create a
* license.local.php instead.
*/
if(empty($LC)) $LC = empty($conf['lang']) ? 'en' : $conf['lang'];
$license['cc-zero'] = array(
'name' => 'CC0 1.0 Universal',
'url' => 'https://creativecommons.org/publicdomain/zero/1.0/deed.'.$LC,
);
$license['publicdomain'] = array(
'name' => 'Public Domain',
'url' => 'https://creativecommons.org/licenses/publicdomain/deed.'.$LC,
);
$license['cc-by'] = array(
'name' => 'CC Attribution 4.0 International',
'url' => 'https://creativecommons.org/licenses/by/4.0/deed.'.$LC,
);
$license['cc-by-sa'] = array(
'name' => 'CC Attribution-Share Alike 4.0 International',
'url' => 'https://creativecommons.org/licenses/by-sa/4.0/deed.'.$LC,
);
$license['gnufdl'] = array(
'name' => 'GNU Free Documentation License 1.3',
'url' => 'https://www.gnu.org/licenses/fdl-1.3.html',
);
$license['cc-by-nc'] = array(
'name' => 'CC Attribution-Noncommercial 4.0 International',
'url' => 'https://creativecommons.org/licenses/by-nc/4.0/deed.'.$LC,
);
$license['cc-by-nc-sa'] = array(
'name' => 'CC Attribution-Noncommercial-Share Alike 4.0 International',
'url' => 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.'.$LC,
);

View File

@@ -1,13 +0,0 @@
<?php
/**
* Dokuwiki's Main Configuration File - Local Settings
* Auto-generated by install script
* Date: Tue, 20 Jan 2026 20:06:48 -0500
*/
$conf['title'] = 'AI-Homelab';
$conf['lang'] = 'en';
$conf['license'] = 'cc-by-sa';
$conf['useacl'] = 1;
$conf['superuser'] = '@admin';
$conf['disableactions'] = 'register';
$conf['savedir'] = '/app/www/public/data';

View File

@@ -1,16 +0,0 @@
<?php
/**
* This is an example of how a local.php could look like.
* Simply copy the options you want to change from dokuwiki.php
* to this file and change them.
*
* When using the installer, a correct local.php file be generated for
* you automatically.
*/
//$conf['title'] = 'My Wiki'; //what to show in the title
//$conf['useacl'] = 1; //Use Access Control Lists to restrict access?
//$conf['superuser'] = 'joe';

View File

@@ -1,3 +0,0 @@
{
"display": "standalone"
}

View File

@@ -1,91 +0,0 @@
<?php
/**
* This configures which metadata will be editable through
* the media manager. Each field of the array is an array with the
* following contents:
* fieldname - Where data will be saved (EXIF or IPTC field)
* label - key to lookup in the $lang var, if not found printed as is
* htmltype - 'text', 'textarea' or 'date'
* lookups - array additional fields to look up the data (EXIF or IPTC fields)
*
* The fields are not ordered continuously to make inserting additional items
* in between simpler.
*
* This is a PHP snippet, so PHP syntax applies.
*
* Note: $fields is not a global variable and will not be available to any
* other functions or templates later
*
* You may extend or overwrite this variable in an optional
* conf/mediameta.local.php file
*
* For a list of available EXIF/IPTC fields refer to
* http://www.dokuwiki.org/devel:templates:detail.php
*/
$fields = array(
10 => array('Iptc.Headline',
'img_title',
'text'),
20 => array('',
'img_date',
'date',
array('Date.EarliestTime')),
30 => array('',
'img_fname',
'text',
array('File.Name')),
40 => array('Iptc.Caption',
'img_caption',
'textarea',
array('Exif.UserComment',
'Exif.TIFFImageDescription',
'Exif.TIFFUserComment')),
50 => array('Iptc.Byline',
'img_artist',
'text',
array('Exif.TIFFArtist',
'Exif.Artist',
'Iptc.Credit')),
60 => array('Iptc.CopyrightNotice',
'img_copyr',
'text',
array('Exif.TIFFCopyright',
'Exif.Copyright')),
70 => array('',
'img_format',
'text',
array('File.Format')),
80 => array('',
'img_fsize',
'text',
array('File.NiceSize')),
90 => array('',
'img_width',
'text',
array('File.Width')),
100 => array('',
'img_height',
'text',
array('File.Height')),
110 => array('',
'img_camera',
'text',
array('Simple.Camera')),
120 => array('Iptc.Keywords',
'img_keywords',
'text',
array('Exif.Category')),
);

View File

@@ -1,75 +0,0 @@
# Allowed uploadable file extensions and mimetypes are defined here.
# To extend this file it is recommended to create a mime.local.conf
# file. Mimetypes that should be downloadable and not be opened in the
# should be prefixed with a !
jpg image/jpeg
jpeg image/jpeg
gif image/gif
png image/png
webp image/webp
ico image/vnd.microsoft.icon
mp3 audio/mpeg
ogg audio/ogg
wav audio/wav
webm video/webm
ogv video/ogg
mp4 video/mp4
vtt text/vtt
tgz !application/octet-stream
tar !application/x-gtar
gz !application/octet-stream
bz2 !application/octet-stream
zip !application/zip
rar !application/rar
7z !application/x-7z-compressed
pdf application/pdf
ps !application/postscript
rpm !application/octet-stream
deb !application/octet-stream
doc !application/msword
xls !application/msexcel
ppt !application/mspowerpoint
rtf !application/msword
docx !application/vnd.openxmlformats-officedocument.wordprocessingml.document
xlsx !application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
pptx !application/vnd.openxmlformats-officedocument.presentationml.presentation
sxw !application/soffice
sxc !application/soffice
sxi !application/soffice
sxd !application/soffice
odc !application/vnd.oasis.opendocument.chart
odf !application/vnd.oasis.opendocument.formula
odg !application/vnd.oasis.opendocument.graphics
odi !application/vnd.oasis.opendocument.image
odp !application/vnd.oasis.opendocument.presentation
ods !application/vnd.oasis.opendocument.spreadsheet
odt !application/vnd.oasis.opendocument.text
svg image/svg+xml
# You should enable HTML and Text uploads only for restricted Wikis.
# Spammers are known to upload spam pages through unprotected Wikis.
# Note: Enabling HTML opens Cross Site Scripting vulnerabilities
# through JavaScript. Only enable this with trusted users. You
# need to disable the iexssprotect option additionally to
# adding the mime type here
#html text/html
#htm text/html
#txt text/plain
#conf text/plain
#xml text/xml
#csv text/csv
# Also flash may be able to execute arbitrary scripts in the website's
# context
#swf application/x-shockwave-flash

View File

@@ -1,253 +0,0 @@
<?php
/*
* This is an example configuration for the mysql auth plugin.
*
* This SQL statements are optimized for following table structure.
* If you use a different one you have to change them accordingly.
* See comments of every statement for details.
*
* TABLE users
* uid login pass firstname lastname email
*
* TABLE groups
* gid name
*
* TABLE usergroup
* uid gid
*
* To use this configuration you have to copy them to local.protected.php
* or at least include this file in local.protected.php.
*/
/* Options to configure database access. You need to set up this
* options carefully, otherwise you won't be able to access you
* database.
*/
$conf['plugin']['authmysql']['server'] = '';
$conf['plugin']['authmysql']['user'] = '';
$conf['plugin']['authmysql']['password'] = '';
$conf['plugin']['authmysql']['database'] = '';
/* This option enables debug messages in the mysql plugin. It is
* mostly useful for system admins.
*/
$conf['plugin']['authmysql']['debug'] = 0;
/* Normally password encryption is done by DokuWiki (recommended) but for
* some reasons it might be useful to let the database do the encryption.
* Set 'forwardClearPass' to '1' and the cleartext password is forwarded to
* the database, otherwise the encrypted one.
*/
$conf['plugin']['authmysql']['forwardClearPass'] = 0;
/* Multiple table operations will be protected by locks. This array tells
* the plugin which tables to lock. If you use any aliases for table names
* these array must also contain these aliases. Any unnamed alias will cause
* a warning during operation. See the example below.
*/
$conf['plugin']['authmysql']['TablesToLock']= array("users", "users AS u","groups", "groups AS g", "usergroup", "usergroup AS ug");
/***********************************************************************/
/* Basic SQL statements for user authentication (required) */
/***********************************************************************/
/* This statement is used to grant or deny access to the wiki. The result
* should be a table with exact one line containing at least the password
* of the user. If the result table is empty or contains more than one
* row, access will be denied.
*
* The plugin accesses the password as 'pass' so an alias might be necessary.
*
* Following patters will be replaced:
* %{user} user name
* %{pass} encrypted or clear text password (depends on 'encryptPass')
* %{dgroup} default group name
*/
$conf['plugin']['authmysql']['checkPass'] = "SELECT pass
FROM usergroup AS ug
JOIN users AS u ON u.uid=ug.uid
JOIN groups AS g ON g.gid=ug.gid
WHERE login='%{user}'
AND name='%{dgroup}'";
/* This statement should return a table with exact one row containing
* information about one user. The field needed are:
* 'pass' containing the encrypted or clear text password
* 'name' the user's full name
* 'mail' the user's email address
*
* Keep in mind that Dokuwiki will access this information through the
* names listed above so aliases might be necessary.
*
* Following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getUserInfo'] = "SELECT pass, CONCAT(firstname,' ',lastname) AS name, email AS mail
FROM users
WHERE login='%{user}'";
/* This statement is used to get all groups a user is member of. The
* result should be a table containing all groups the given user is
* member of. The plugin accesses the group name as 'group' so an alias
* might be necessary.
*
* Following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getGroups'] = "SELECT name as `group`
FROM groups g, users u, usergroup ug
WHERE u.uid = ug.uid
AND g.gid = ug.gid
AND u.login='%{user}'";
/***********************************************************************/
/* Additional minimum SQL statements to use the user manager */
/***********************************************************************/
/* This statement should return a table containing all user login names
* that meet certain filter criteria. The filter expressions will be added
* case dependent by the plugin. At the end a sort expression will be added.
* Important is that this list contains no double entries for a user. Each
* user name is only allowed once in the table.
*
* The login name will be accessed as 'user' to an alias might be necessary.
* No patterns will be replaced in this statement but following patters
* will be replaced in the filter expressions:
* %{user} in FilterLogin user's login name
* %{name} in FilterName user's full name
* %{email} in FilterEmail user's email address
* %{group} in FilterGroup group name
*/
$conf['plugin']['authmysql']['getUsers'] = "SELECT DISTINCT login AS user
FROM users AS u
LEFT JOIN usergroup AS ug ON u.uid=ug.uid
LEFT JOIN groups AS g ON ug.gid=g.gid";
$conf['plugin']['authmysql']['FilterLogin'] = "login LIKE '%{user}'";
$conf['plugin']['authmysql']['FilterName'] = "CONCAT(firstname,' ',lastname) LIKE '%{name}'";
$conf['plugin']['authmysql']['FilterEmail'] = "email LIKE '%{email}'";
$conf['plugin']['authmysql']['FilterGroup'] = "name LIKE '%{group}'";
$conf['plugin']['authmysql']['SortOrder'] = "ORDER BY login";
/***********************************************************************/
/* Additional SQL statements to add new users with the user manager */
/***********************************************************************/
/* This statement should add a user to the database. Minimum information
* to store are: login name, password, email address and full name.
*
* Following patterns will be replaced:
* %{user} user's login name
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
* %{email} email address
* %{name} user's full name
*/
$conf['plugin']['authmysql']['addUser'] = "INSERT INTO users
(login, pass, email, firstname, lastname)
VALUES ('%{user}', '%{pass}', '%{email}',
SUBSTRING_INDEX('%{name}',' ', 1),
SUBSTRING_INDEX('%{name}',' ', -1))";
/* This statement should add a group to the database.
* Following patterns will be replaced:
* %{group} group name
*/
$conf['plugin']['authmysql']['addGroup'] = "INSERT INTO groups (name)
VALUES ('%{group}')";
/* This statement should connect a user to a group (a user become member
* of that group).
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['addUserGroup']= "INSERT INTO usergroup (uid, gid)
VALUES ('%{uid}', '%{gid}')";
/* This statement should remove a group fom the database.
* Following patterns will be replaced:
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['delGroup'] = "DELETE FROM groups
WHERE gid='%{gid}'";
/* This statement should return the database index of a given user name.
* The plugin will access the index with the name 'id' so an alias might be
* necessary.
* following patters will be replaced:
* %{user} user name
*/
$conf['plugin']['authmysql']['getUserID'] = "SELECT uid AS id
FROM users
WHERE login='%{user}'";
/***********************************************************************/
/* Additional SQL statements to delete users with the user manager */
/***********************************************************************/
/* This statement should remove a user fom the database.
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
*/
$conf['plugin']['authmysql']['delUser'] = "DELETE FROM users
WHERE uid='%{uid}'";
/* This statement should remove all connections from a user to any group
* (a user quits membership of all groups).
* Following patterns will be replaced:
* %{uid} id of a user dataset
*/
$conf['plugin']['authmysql']['delUserRefs'] = "DELETE FROM usergroup
WHERE uid='%{uid}'";
/***********************************************************************/
/* Additional SQL statements to modify users with the user manager */
/***********************************************************************/
/* This statements should modify a user entry in the database. The
* statements UpdateLogin, UpdatePass, UpdateEmail and UpdateName will be
* added to updateUser on demand. Only changed parameters will be used.
*
* Following patterns will be replaced:
* %{user} user's login name
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
* %{email} email address
* %{name} user's full name
* %{uid} user id that should be updated
*/
$conf['plugin']['authmysql']['updateUser'] = "UPDATE users SET";
$conf['plugin']['authmysql']['UpdateLogin'] = "login='%{user}'";
$conf['plugin']['authmysql']['UpdatePass'] = "pass='%{pass}'";
$conf['plugin']['authmysql']['UpdateEmail'] = "email='%{email}'";
$conf['plugin']['authmysql']['UpdateName'] = "firstname=SUBSTRING_INDEX('%{name}',' ', 1),
lastname=SUBSTRING_INDEX('%{name}',' ', -1)";
$conf['plugin']['authmysql']['UpdateTarget']= "WHERE uid=%{uid}";
/* This statement should remove a single connection from a user to a
* group (a user quits membership of that group).
*
* Following patterns will be replaced:
* %{user} user's login name
* %{uid} id of a user dataset
* %{group} group name
* %{gid} id of a group dataset
*/
$conf['plugin']['authmysql']['delUserGroup']= "DELETE FROM usergroup
WHERE uid='%{uid}'
AND gid='%{gid}'";
/* This statement should return the database index of a given group name.
* The plugin will access the index with the name 'id' so an alias might
* be necessary.
*
* Following patters will be replaced:
* %{group} group name
*/
$conf['plugin']['authmysql']['getGroupID'] = "SELECT gid AS id
FROM groups
WHERE name='%{group}'";

View File

@@ -1,12 +0,0 @@
<?php
/*
* Local plugin enable/disable settings
*
* Auto-generated by install script
* Date: Tue, 20 Jan 2026 20:06:48 -0500
*/
$plugins['authad'] = 0;
$plugins['authldap'] = 0;
$plugins['authmysql'] = 0;
$plugins['authpgsql'] = 0;

View File

@@ -1,6 +0,0 @@
<?php
/**
* This file configures the default states of available plugins. All settings in
* the plugins.*.php files will override those here.
*/
$plugins['testing'] = 0;

View File

@@ -1,12 +0,0 @@
<?php
/**
* This file configures the enabled/disabled status of plugins, which are also protected
* from changes by the extension manager. These settings will override any local settings.
* It is not recommended to change this file, as it is overwritten on DokuWiki upgrades.
*/
$plugins['acl'] = 1;
$plugins['authplain'] = 1;
$plugins['extension'] = 1;
$plugins['config'] = 1;
$plugins['usermanager'] = 1;
$plugins['template:dokuwiki'] = 1; // not a plugin, but this should not be uninstalled either

View File

@@ -1,11 +0,0 @@
#Add URL schemes you want to be recognized as links here
http
https
telnet
gopher
wais
ftp
ed2k
irc
ldap

View File

@@ -1,28 +0,0 @@
# Smileys configured here will be replaced by the
# configured images in the smiley directory
8-) cool.svg
8-O eek.svg
8-o eek.svg
:-( sad.svg
:-) smile.svg
=) smile2.svg
:-/ doubt.svg
:-\ doubt2.svg
:-? confused.svg
:-D biggrin.svg
:-P razz.svg
:-o surprised.svg
:-O surprised.svg
:-x silenced.svg
:-X silenced.svg
:-| neutral.svg
;-) wink.svg
m( facepalm.svg
^_^ fun.svg
:?: question.svg
:!: exclaim.svg
LOL lol.svg
FIXME fixme.svg
DELETEME deleteme.svg

View File

@@ -1,13 +0,0 @@
# users.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Userfile
#
# Auto-generated by install script
# Date: Tue, 20 Jan 2026 20:06:48 -0500
#
# Format:
# login:passwordhash:Real Name:email:groups,comma,separated
admin:$2y$10$dX5ryEUsFKXDRNl6DAk5Zem.1KtI8Q45.z0EQ6NLI7HXJjJyx4hqS:Admin:admin@example.com:admin,user

View File

@@ -1,10 +0,0 @@
# users.auth.php
# <?php exit()?>
# Don't modify the lines above
#
# Userfile
#
# Format:
#
# login:passwordhash:Real Name:email:groups,comma,separated

View File

@@ -1,29 +0,0 @@
# This blacklist is maintained by the DokuWiki community
# patches welcome
#
https?:\/\/(\S*?)(-side-effects|top|pharm|pill|discount|discount-|deal|price|order|now|best|cheap|cheap-|online|buy|buy-|sale|sell)(\S*?)(cialis|viagra|prazolam|xanax|zanax|soma|vicodin|zenical|xenical|meridia|paxil|prozac|claritin|allegra|lexapro|wellbutrin|zoloft|retin|valium|levitra|phentermine)
https?:\/\/(\S*?)(bi\s*sex|gay\s*sex|fetish|incest|penis|\brape\b)
zoosex
gang\s*bang
facials
ladyboy
\btits\b
bolea\.com
52crystal
baida\.org
web-directory\.awardspace\.us
korsan-team\.com
BUDA TAMAMDIR
wow-powerleveling-wow\.com
wow gold
wow-gold\.dinmo\.cn
downgrade-vista\.com
downgradetowindowsxp\.com
elegantugg\.com
classicedhardy\.com
research-service\.com
https?:\/\/(\S*?)(2-pay-secure|911essay|academia-research|anypapers|applicationessay|bestbuyessay|bestdissertation|bestessay|bestresume|besttermpaper|businessessay|college-paper|customessay|custom-made-paper|custom-writing|degree-?result|dissertationblog|dissertation-service|dissertations?expert|essaybank|essay-?blog|essaycapital|essaylogic|essaymill|essayontime|essaypaper|essays?land|essaytownsucks|essay-?writ|fastessays|freelancercareers|genuinecontent|genuineessay|genuinepaper|goessay|grandresume|killer-content|ma-dissertation|managementessay|masterpaper|mightystudent|needessay|researchedge|researchpaper-blog|resumecvservice|resumesexperts|resumesplanet|rushessay|samedayessay|superiorcontent|superiorpaper|superiorthesis|term-paper|termpaper-blog|term-paper-research|thesisblog|universalresearch|valwriting|vdwriters|wisetranslation|writersassembly|writers\.com\.ph|writers\.ph)
flatsinmumbai\.co\.in
https?:\/\/(\S*?)penny-?stock
mattressreview\.biz
(just|simply) (my|a) profile (site|webpage|page)

View File

@@ -1,35 +0,0 @@
# Dokuwiki - Self-hosted Wiki Platform
# Place in /opt/stacks/productivity/dokuwiki/docker-compose.yml
services:
dokuwiki:
image: lscr.io/linuxserver/dokuwiki:latest
container_name: dokuwiki
restart: unless-stopped
networks:
- traefik-network
ports:
- "80:80"
volumes:
- ./config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
- "homelab.category=productivity"
- "homelab.description=Self-hosted wiki platform"
- "traefik.enable=true"
- "traefik.http.routers.dokuwiki.rule=Host(`wiki.${DOMAIN}`)"
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
- "traefik.http.services.dokuwiki.loadbalancer.server.port=80"
- "x-dockge.url=https://wiki.${DOMAIN}"
volumes:
dokuwiki-config:
networks:
traefik-network:
external: true

View File

@@ -1,493 +0,0 @@
---
# Homepage Bookmarks - Comprehensive EZ-Homelab Resources
- EZ-Homelab Project:
- EZ-Homelab GitHub:
- icon: github.png
href: https://github.com/kelinfoxy/EZ-Homelab
description: EZ-Homelab Repository & Documentation
- EZ-Homelab Wiki:
- icon: si-readthedocs
href: https://github.com/kelinfoxy/EZ-Homelab/wiki
description: Comprehensive Documentation Wiki
- Homepage Dashboard:
- icon: homepage.png
href: https://gethomepage.dev
description: Homepage Dashboard Documentation
- Infrastructure & Core Services:
- Traefik:
- icon: si-traefikproxy
href: https://traefik.io
description: Traefik Reverse Proxy
- icon: github.png
href: https://github.com/traefik/traefik
description: Traefik GitHub
- icon: docker.png
href: https://hub.docker.com/_/traefik
description: Traefik Docker Image
- Authelia:
- icon: si-authelia
href: https://www.authelia.com
description: Authelia SSO Authentication
- icon: github.png
href: https://github.com/authelia/authelia
description: Authelia GitHub
- icon: docker.png
href: https://hub.docker.com/r/authelia/authelia
description: Authelia Docker Image
- DuckDNS:
- icon: si-duckduckgo
href: https://www.duckdns.org
description: Dynamic DNS Service
- Docker:
- icon: docker.png
href: https://www.docker.com
description: Docker Official Website
- icon: docker.png
href: https://hub.docker.com
description: Docker Hub Registry
- icon: si-docker
href: https://docs.docker.com
description: Docker Documentation
- Portainer:
- icon: si-portainer
href: https://www.portainer.io
description: Portainer Container Management
- icon: github.png
href: https://github.com/portainer/portainer
description: Portainer GitHub
- icon: docker.png
href: https://hub.docker.com/r/portainer/portainer-ce
description: Portainer Docker Image
- Pi-hole:
- icon: si-raspberrypi
href: https://pi-hole.net
description: Pi-hole Network-wide Ad Blocking
- icon: github.png
href: https://github.com/pi-hole/pi-hole
description: Pi-hole GitHub
- icon: docker.png
href: https://hub.docker.com/r/pihole/pihole
description: Pi-hole Docker Image
- LinuxServer.io:
- icon: si-linux
href: https://www.linuxserver.io
description: LinuxServer.io Container Images
- icon: github.png
href: https://github.com/linuxserver
description: LinuxServer GitHub Organization
- Media Services:
- Plex:
- icon: si-plex
href: https://www.plex.tv
description: Plex Media Server
- icon: github.png
href: https://github.com/plexinc/pms-docker
description: Plex Docker GitHub
- icon: docker.png
href: https://hub.docker.com/r/plexinc/pms-docker
description: Plex Docker Image
- Jellyfin:
- icon: si-jellyfin
href: https://jellyfin.org
description: Jellyfin Media Server (Open Source)
- icon: github.png
href: https://github.com/jellyfin/jellyfin
description: Jellyfin GitHub
- icon: docker.png
href: https://hub.docker.com/r/jellyfin/jellyfin
description: Jellyfin Docker Image
- Sonarr:
- icon: si-sonarr
href: https://sonarr.tv
description: Sonarr TV Show Manager
- icon: github.png
href: https://github.com/Sonarr/Sonarr
description: Sonarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/sonarr
description: Sonarr Docker Image
- Radarr:
- icon: si-radarr
href: https://radarr.video
description: Radarr Movie Manager
- icon: github.png
href: https://github.com/Radarr/Radarr
description: Radarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/radarr
description: Radarr Docker Image
- Prowlarr:
- icon: si-prowlarr
href: https://prowlarr.com
description: Prowlarr Indexer Manager
- icon: github.png
href: https://github.com/Prowlarr/Prowlarr
description: Prowlarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/prowlarr
description: Prowlarr Docker Image
- qBittorrent:
- icon: si-qbittorrent
href: https://www.qbittorrent.org
description: qBittorrent Torrent Client
- icon: github.png
href: https://github.com/qbittorrent/qBittorrent
description: qBittorrent GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/qbittorrent
description: qBittorrent Docker Image
- Readarr:
- icon: si-readarr
href: https://readarr.com
description: Readarr Book Manager
- icon: github.png
href: https://github.com/Readarr/Readarr
description: Readarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/readarr
description: Readarr Docker Image
- Lidarr:
- icon: si-lidarr
href: https://lidarr.audio
description: Lidarr Music Manager
- icon: github.png
href: https://github.com/Lidarr/Lidarr
description: Lidarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/lidarr
description: Lidarr Docker Image
- Jellyseerr:
- icon: si-jellyseerr
href: https://jellyseerr.dev
description: Jellyseerr Media Requests
- icon: github.png
href: https://github.com/Fallenbagel/jellyseerr
description: Jellyseerr GitHub
- icon: docker.png
href: https://hub.docker.com/r/fallenbagel/jellyseerr
description: Jellyseerr Docker Image
- Tdarr:
- icon: si-tdarr
href: https://tdarr.io
description: Tdarr Media Transcoding
- icon: github.png
href: https://github.com/HaveAGitGat/Tdarr
description: Tdarr GitHub
- icon: docker.png
href: https://hub.docker.com/r/haveagitgat/tdarr
description: Tdarr Docker Image
- Unmanic:
- icon: si-unmanic
href: https://docs.unmanic.app
description: Unmanic Media Optimizer
- icon: github.png
href: https://github.com/Unmanic/unmanic
description: Unmanic GitHub
- icon: docker.png
href: https://hub.docker.com/r/josh5/unmanic
description: Unmanic Docker Image
- Calibre-Web:
- icon: si-calibre
href: https://github.com/janeczku/calibre-web
description: Calibre-Web Ebook Reader
- icon: github.png
href: https://github.com/janeczku/calibre-web
description: Calibre-Web GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/calibre-web
description: Calibre-Web Docker Image
- Productivity & Collaboration:
- Nextcloud:
- icon: si-nextcloud
href: https://nextcloud.com
description: Nextcloud File Sync & Collaboration
- icon: github.png
href: https://github.com/nextcloud/server
description: Nextcloud GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/nextcloud
description: Nextcloud Docker Image
- Gitea:
- icon: si-gitea
href: https://gitea.io
description: Gitea Git Service
- icon: github.png
href: https://github.com/go-gitea/gitea
description: Gitea GitHub
- icon: docker.png
href: https://hub.docker.com/r/gitea/gitea
description: Gitea Docker Image
- BookStack:
- icon: si-bookstack
href: https://www.bookstackapp.com
description: BookStack Documentation Platform
- icon: github.png
href: https://github.com/BookStackApp/BookStack
description: BookStack GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/bookstack
description: BookStack Docker Image
- DokuWiki:
- icon: si-dokuwiki
href: https://www.dokuwiki.org
description: DokuWiki File-based Wiki
- icon: github.png
href: https://github.com/dokuwiki/dokuwiki
description: DokuWiki GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/dokuwiki
description: DokuWiki Docker Image
- MediaWiki:
- icon: si-mediawiki
href: https://www.mediawiki.org
description: MediaWiki Wiki Platform
- icon: github.png
href: https://github.com/wikimedia/mediawiki
description: MediaWiki GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/mediawiki
description: MediaWiki Docker Image
- WordPress:
- icon: si-wordpress
href: https://wordpress.org
description: WordPress Blog/CMS Platform
- icon: github.png
href: https://github.com/WordPress/WordPress
description: WordPress GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/wordpress
description: WordPress Docker Image
- Mealie:
- icon: si-mealie
href: https://hay-kot.github.io/mealie
description: Mealie Recipe Manager
- icon: github.png
href: https://github.com/hay-kot/mealie
description: Mealie GitHub
- icon: docker.png
href: https://hub.docker.com/r/hkotel/mealie
description: Mealie Docker Image
- Form.io:
- icon: si-formio
href: https://www.form.io
description: Form.io Form Builder
- icon: github.png
href: https://github.com/formio/formio
description: Form.io GitHub
- icon: docker.png
href: https://hub.docker.com/r/formio/formio-enterprise
description: Form.io Docker Image
- Home Automation:
- Home Assistant:
- icon: si-homeassistant
href: https://www.home-assistant.io
description: Home Assistant Smart Home Platform
- icon: github.png
href: https://github.com/home-assistant/core
description: Home Assistant GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/homeassistant
description: Home Assistant Docker Image
- ESPHome:
- icon: si-esphome
href: https://esphome.io
description: ESPHome ESP32/ESP8266 Firmware
- icon: github.png
href: https://github.com/esphome/esphome
description: ESPHome GitHub
- icon: docker.png
href: https://hub.docker.com/r/esphome/esphome
description: ESPHome Docker Image
- Node-RED:
- icon: si-nodered
href: https://nodered.org
description: Node-RED Flow-based Programming
- icon: github.png
href: https://github.com/node-red/node-red
description: Node-RED GitHub
- icon: docker.png
href: https://hub.docker.com/r/nodered/node-red
description: Node-RED Docker Image
- Zigbee2MQTT:
- icon: si-zigbee2mqtt
href: https://www.zigbee2mqtt.io
description: Zigbee2MQTT Zigbee Bridge
- icon: github.png
href: https://github.com/Koenkk/zigbee2mqtt
description: Zigbee2MQTT GitHub
- icon: docker.png
href: https://hub.docker.com/r/koenkk/zigbee2mqtt
description: Zigbee2MQTT Docker Image
- MotionEye:
- icon: si-motioneye
href: https://github.com/motioneye-project/motioneye
description: MotionEye Video Surveillance
- icon: github.png
href: https://github.com/motioneye-project/motioneye
description: MotionEye GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/motioneye
description: MotionEye Docker Image
- TasmoAdmin:
- icon: si-tasmota
href: https://github.com/reloxx13/TasmoAdmin
description: TasmoAdmin Tasmota Device Manager
- icon: github.png
href: https://github.com/reloxx13/TasmoAdmin
description: TasmoAdmin GitHub
- icon: docker.png
href: https://hub.docker.com/r/raymondmm/tasmoadmin
description: TasmoAdmin Docker Image
- Development & Utilities:
- Code Server:
- icon: si-visualstudiocode
href: https://github.com/coder/code-server
description: Code Server (VS Code in Browser)
- icon: github.png
href: https://github.com/coder/code-server
description: Code Server GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/code-server
description: Code Server Docker Image
- Jupyter Lab:
- icon: si-jupyter
href: https://jupyter.org
description: Jupyter Lab Notebooks
- icon: github.png
href: https://github.com/jupyterlab/jupyterlab
description: Jupyter Lab GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/jupyterlab
description: Jupyter Lab Docker Image
- Vaultwarden:
- icon: si-bitwarden
href: https://github.com/dani-garcia/vaultwarden
description: Vaultwarden Password Manager
- icon: github.png
href: https://github.com/dani-garcia/vaultwarden
description: Vaultwarden GitHub
- icon: docker.png
href: https://hub.docker.com/r/vaultwarden/server
description: Vaultwarden Docker Image
- Duplicati:
- icon: si-duplicati
href: https://www.duplicati.com
description: Duplicati Backup Solution
- icon: github.png
href: https://github.com/duplicati/duplicati
description: Duplicati GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/duplicati
description: Duplicati Docker Image
- pgAdmin:
- icon: si-postgresql
href: https://www.pgadmin.org
description: pgAdmin PostgreSQL Management
- icon: github.png
href: https://github.com/pgadmin-org/pgadmin4
description: pgAdmin GitHub
- icon: docker.png
href: https://hub.docker.com/r/dpage/pgadmin4
description: pgAdmin Docker Image
- GitLab CE:
- icon: si-gitlab
href: https://about.gitlab.com
description: GitLab DevOps Platform
- icon: github.png
href: https://gitlab.com/gitlab-org/gitlab
description: GitLab GitHub
- icon: docker.png
href: https://hub.docker.com/r/gitlab/gitlab-ce
description: GitLab CE Docker Image
- Monitoring & Observability:
- Grafana:
- icon: si-grafana
href: https://grafana.com
description: Grafana Visualization Platform
- icon: github.png
href: https://github.com/grafana/grafana
description: Grafana GitHub
- icon: docker.png
href: https://hub.docker.com/r/grafana/grafana
description: Grafana Docker Image
- Prometheus:
- icon: si-prometheus
href: https://prometheus.io
description: Prometheus Metrics Collection
- icon: github.png
href: https://github.com/prometheus/prometheus
description: Prometheus GitHub
- icon: docker.png
href: https://hub.docker.com/r/prom/prometheus
description: Prometheus Docker Image
- Uptime Kuma:
- icon: si-uptimekuma
href: https://uptime.kuma.pet
description: Uptime Kuma Status Monitoring
- icon: github.png
href: https://github.com/louislam/uptime-kuma
description: Uptime Kuma GitHub
- icon: docker.png
href: https://hub.docker.com/r/louislam/uptime-kuma
description: Uptime Kuma Docker Image
- Glances:
- icon: si-glances
href: https://nicolargo.github.io/glances
description: Glances System Monitoring
- icon: github.png
href: https://github.com/nicolargo/glances
description: Glances GitHub
- icon: docker.png
href: https://hub.docker.com/r/linuxserver/glances
description: Glances Docker Image
- Dozzle:
- icon: si-dozzle
href: https://dozzle.dev
description: Dozzle Docker Log Viewer
- icon: github.png
href: https://github.com/amir20/dozzle
description: Dozzle GitHub
- icon: docker.png
href: https://hub.docker.com/r/amir20/dozzle
description: Dozzle Docker Image
- External Resources & Communities:
- Awesome Docker Compose:
- icon: docker.png
href: https://awesome-docker-compose.com
description: Curated Docker Compose Examples
- Servarr Wiki:
- icon: si-servarr
href: https://wiki.servarr.com
description: Servarr Applications Documentation
- Docker Compose Documentation:
- icon: docker.png
href: https://docs.docker.com/compose
description: Docker Compose Official Docs
- Let's Encrypt:
- icon: si-letsencrypt
href: https://letsencrypt.org
description: Free SSL Certificates
- Awesome Selfhosted:
- icon: si-awesome
href: https://awesome-selfhosted.net
description: Self-hosted Software List
- Homelab Wiki:
- icon: si-wikipedia
href: https://homelab.wiki
description: Homelab Community Wiki
- Reddit r/selfhosted:
- icon: si-reddit
href: https://reddit.com/r/selfhosted
description: Self-hosted Community
- Reddit r/homelab:
- icon: si-reddit
href: https://reddit.com/r/homelab
description: Homelab Community

View File

@@ -1,31 +0,0 @@
.information-widgets {
max-width: 1500px;
}
.services-group {
max-width: 250px;
}
#services {
margin: 0px;
}
.service {
height: 70px;
max-height: 80px;
margin-bottom: 0px;
margin-right: 3px;
}
#services #bookmarks {
margin: 0px 0px 0px 20px;
}
.text-sm {
font-size: 16px;
}
.bookmark-group {
min-width: 250px;
max-width: 250px;
}

View File

@@ -1,18 +0,0 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/docker/
# my-docker:
# host: 127.0.0.1
# port: 2375
# my-docker:
# socket: /var/run/docker.sock
# home-assistant:
# host: 192.168.4.5
# port: 2375
#${SERVER_HOSTNAME}:
# host: 192.168.4.11
# port: 2375

View File

@@ -1,2 +0,0 @@
---
# sample kubernetes config

View File

@@ -1,5 +0,0 @@
---
# pve:
# url: https://proxmox.host.or.ip:8006
# token: username@pam!Token ID
# secret: secret

View File

@@ -1,7 +0,0 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/settings/
providers:
openweathermap: openweathermapapikey
weatherapi: weatherapiapikey

View File

@@ -1,19 +0,0 @@
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/info-widgets/
- resources:
cpu: true
memory: true
disk: /
- datetime:
text_size: xl
format:
dateStyle: long
timeStyle: short
hourCycle: h23
- greeting:
text_size: 4xl
text: EZ Homelab

View File

@@ -1,46 +0,0 @@
# Loki Configuration Template
# Copy this file to ./config/loki/loki-config.yml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
# Retention configuration (delete logs older than 30 days)
limits_config:
retention_period: 720h # 30 days
# Compactor to delete old data
compactor:
working_directory: /loki/compactor
shared_store: filesystem
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150

View File

@@ -1,49 +0,0 @@
# Prometheus Configuration Template
# Copy this file to ./config/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
monitor: 'homelab'
# Alertmanager configuration (optional)
# alerting:
# alertmanagers:
# - static_configs:
# - targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them
# rule_files:
# - "alerts/*.yml"
# Scrape configurations
scrape_configs:
# Prometheus itself
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Node Exporter - System metrics
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
labels:
instance: 'homelab-server'
# cAdvisor - Container metrics
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
labels:
instance: 'homelab-server'
# Add your own services here
# Example: Monitor a service with /metrics endpoint
# - job_name: 'my-service'
# static_configs:
# - targets: ['my-service:8080']
# labels:
# instance: 'homelab-server'
# service: 'my-service'

View File

@@ -1,53 +0,0 @@
# Promtail Configuration Template
# Copy this file to ./config/promtail/promtail-config.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
# Docker container logs
- job_name: docker
static_configs:
- targets:
- localhost
labels:
job: docker
__path__: /var/lib/docker/containers/*/*-json.log
pipeline_stages:
# Parse Docker JSON logs
- json:
expressions:
output: log
stream: stream
attrs: attrs
# Extract container name from path
- regex:
expression: '/var/lib/docker/containers/(?P<container_id>[^/]+)/.*'
source: filename
# Add labels
- labels:
stream:
container_id:
# Output the log line
- output:
source: output
# System logs (optional)
# - job_name: system
# static_configs:
# - targets:
# - localhost
# labels:
# job: varlogs
# __path__: /var/log/*.log

View File

@@ -1,42 +0,0 @@
# Redis Configuration Template
# Copy this file to ./config/redis/redis.conf
# Network
bind 0.0.0.0
protected-mode yes
port 6379
# General
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
# Persistence - AOF (Append Only File)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# Persistence - RDB (Snapshotting)
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data
# Memory Management
maxmemory 256mb
maxmemory-policy allkeys-lru
# Security
# requirepass yourpassword # Uncomment and set a strong password
# Limits
maxclients 10000

View File

@@ -4,253 +4,253 @@
- Dashboards:
- Homepage:
icon: homepage.png
href: https://homepage.${DOMAIN}
href: https://homepage.kelinreij.duckdns.org
description: Hosted on Raspberry Pi
- Homarr:
icon: homarr.png
href: https://homarr.${DOMAIN}
href: https://homarr.kelinreij.duckdns.org
description: Alternative Dashboard
- Dockge - ${SERVER_HOSTNAME}:
- Dockge - jasper:
icon: dockge.png
href: https://${SERVER_HOSTNAME}.${DOMAIN}
href: https://jasper.kelinreij.duckdns.org
description: Main Server
- Dockge - ${REMOTE_SERVER_HOSTNAME}:
icon: dockge.png
href: https://${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: Raspberry Pi Authentication Server
- Core:
- Traefik:
icon: traefik.png
href: https://traefik.${DOMAIN}
href: https://traefik.kelinreij.duckdns.org
description: Reverse Proxy & SSL
- Authelia:
icon: authelia.png
href: https://auth.${DOMAIN}
href: https://auth.kelinreij.duckdns.org
description: Authentication SSO Portal
- Pi-hole:
icon: pi-hole.png
href: https://pihole.${DOMAIN}
href: https://pihole.kelinreij.duckdns.org
description: Network-wide Ad Blocking
- Monitoring Stack:
- Dozzle:
icon: dozzle.png
href: https://dozzle.${SERVER_HOSTNAME}.${DOMAIN}
description: ${SERVER_HOSTNAME} - Real-time Log Viewer
href: https://dozzle.jasper.kelinreij.duckdns.org
description: jasper - Real-time Log Viewer
- Dozzle:
icon: dozzle.png
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Real-time Log Viewer
- Glances - ${SERVER_HOSTNAME}:
- Glances - jasper:
icon: glances.png
href: https://glances.${SERVER_HOSTNAME}.${DOMAIN}
description: ${SERVER_HOSTNAME} - System Monitoring
href: https://glances.jasper.kelinreij.duckdns.org
description: jasper - System Monitoring
- Glances - ${REMOTE_SERVER_HOSTNAME}:
icon: glances.png
href: https://glances.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://glances.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - System Monitoring
- Uptime Kuma:
icon: uptime-kuma.png
href: https://uptime-kuma.${DOMAIN}
href: https://uptime-kuma.kelinreij.duckdns.org
description: Uptime Monitoring
- Media:
- Jellyfin:
icon: jellyfin.png
href: https://jellyfin.${DOMAIN}
href: https://jellyfin.kelinreij.duckdns.org
description: Open Source Media Server
- Jellyseerr:
icon: jellyseerr.png
href: https://jellyseerr.${DOMAIN}
href: https://jellyseerr.kelinreij.duckdns.org
description: Media Request Manager
- Calibre-Web:
icon: calibre-web.png
href: https://calibre.${DOMAIN}
href: https://calibre.kelinreij.duckdns.org
description: Ebook Library
- Media Management:
- Sonarr:
icon: sonarr.png
href: https://sonarr.${DOMAIN}
href: https://sonarr.kelinreij.duckdns.org
description: TV Shows Automation
- Radarr:
icon: radarr.png
href: https://radarr.${DOMAIN}
href: https://radarr.kelinreij.duckdns.org
description: Movies Automation
- Prowlarr:
icon: prowlarr.png
href: https://prowlarr.${DOMAIN}
href: https://prowlarr.kelinreij.duckdns.org
description: Indexer Manager
- Readarr:
icon: readarr.png
href: https://readarr.${DOMAIN}
href: https://readarr.kelinreij.duckdns.org
description: Books Automation
- Lidarr:
icon: lidarr.png
href: https://lidarr.${DOMAIN}
href: https://lidarr.kelinreij.duckdns.org
description: Music Automation
- Mylar3:
icon: mylar.png
href: https://mylar.${DOMAIN}
href: https://mylar.kelinreij.duckdns.org
description: Comics Manager
- Home Automation:
- Home Assistant:
icon: home-assistant.png
href: https://hass.${DOMAIN}
href: https://hass.kelinreij.duckdns.org
description: Home Automation Platform
- ESPHome:
icon: esphome.png
href: https://esphome.${DOMAIN}
href: https://esphome.kelinreij.duckdns.org
description: ESP Device Manager
- Node-RED:
icon: node-red.png
href: https://nodered.${DOMAIN}
href: https://nodered.kelinreij.duckdns.org
description: Flow-based Automation
- Zigbee2MQTT:
icon: zigbee2mqtt.png
href: https://zigbee.${DOMAIN}
href: https://zigbee.kelinreij.duckdns.org
description: Zigbee Bridge
- Mosquitto:
icon: mosquitto.png
href: https://mqtt.${DOMAIN}
href: https://mqtt.kelinreij.duckdns.org
description: MQTT Broker
- Productivity:
- Nextcloud:
icon: nextcloud.png
href: https://nextcloud.${DOMAIN}
href: https://nextcloud.kelinreij.duckdns.org
description: Cloud Storage & Collaboration
- Gitea:
icon: gitea.png
href: https://gitea.${DOMAIN}
href: https://gitea.kelinreij.duckdns.org
description: Git Repository
- Mealie:
icon: mealie.png
href: https://mealie.${DOMAIN}
href: https://mealie.kelinreij.duckdns.org
description: Recipe Manager
- WordPress:
icon: wordpress.png
href: https://wordpress.${DOMAIN}
href: https://wordpress.kelinreij.duckdns.org
description: CMS Platform
- Wikis:
- BookStack:
icon: bookstack.png
href: https://bookstack.${DOMAIN}
href: https://bookstack.kelinreij.duckdns.org
description: Wiki Platform
- DokuWiki:
icon: dokuwiki.png
href: https://dokuwiki.${DOMAIN}
href: https://dokuwiki.kelinreij.duckdns.org
description: Simple Wiki
- Mediawiki:
icon: mediawiki.png
href: https://mediawiki.${DOMAIN}
href: https://mediawiki.kelinreij.duckdns.org
description: Collaborative Wiki
- Development:
- VS Code Server:
icon: vscode.png
href: https://code.${DOMAIN}
href: https://code.kelinreij.duckdns.org
description: Browser-based IDE
- Jupyter:
icon: jupyter.png
href: https://jupyter.${DOMAIN}
href: https://jupyter.kelinreij.duckdns.org
description: Data Science Notebooks
- Downloaders:
- qBittorrent:
icon: qbittorrent.png
href: https://qbit.${DOMAIN}
href: https://qbit.kelinreij.duckdns.org
description: Torrent Client
- Transcoders:
- Tdarr:
icon: tdarr.png
href: https://tdarr.${DOMAIN}
href: https://tdarr.kelinreij.duckdns.org
description: Media Transcoding
- Unmanic:
icon: unmanic.png
href: https://unmanic.${DOMAIN}
href: https://unmanic.kelinreij.duckdns.org
description: Media Transcoder
- Utilities:
- Vaultwarden:
icon: vaultwarden.png
href: https://vault.${DOMAIN}
href: https://vault.kelinreij.duckdns.org
description: Password Manager
- Formio:
icon: mdi-form-select
href: https://formio.${DOMAIN}
href: https://formio.kelinreij.duckdns.org
description: Form Builder
- Backup:
- Backrest:
icon: mdi-backup-restore
href: https://backrest.${DOMAIN}
href: https://backrest.kelinreij.duckdns.org
description: Backup Solution
- Duplicati:
icon: duplicati.png
href: https://duplicati.${DOMAIN}
href: https://duplicati.kelinreij.duckdns.org
description: Backup Software
- Metrics:
- Grafana:
icon: grafana.png
href: https://grafana.${DOMAIN}
href: https://grafana.kelinreij.duckdns.org
description: Metrics Dashboard
- Prometheus:
icon: prometheus.png
href: https://prometheus.${DOMAIN}
href: https://prometheus.kelinreij.duckdns.org
description: Metrics Collection
- cAdvisor:
icon: cadvisor.png
href: https://cadvisor.${DOMAIN}
href: https://cadvisor.kelinreij.duckdns.org
description: Container Metrics
- Alternatives:
- Portainer:
icon: portainer.png
href: https://portainer.${DOMAIN}
href: https://portainer.kelinreij.duckdns.org
description: Container Management UI
- Authentik:
icon: authentik.png
href: https://authentik.${DOMAIN}
href: https://authentik.kelinreij.duckdns.org
description: Alternative Auth Provider
- Plex:
icon: plex.png
href: https://plex.${DOMAIN}
href: https://plex.kelinreij.duckdns.org
description: Media Server

View File

@@ -7,21 +7,11 @@
href: https://homepage.${DOMAIN}
description: Hosted on Raspberry Pi
- Homepage - ${REMOTE_SERVER_HOSTNAME}:
icon: homepage.png
href: https://homepage.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Application Dashboard
- Homarr:
icon: homarr.png
href: https://homarr.${DOMAIN}
description: Alternative Dashboard
- Homarr - ${REMOTE_SERVER_HOSTNAME}:
icon: homarr.png
href: https://homarr.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Alternative Dashboard
- Dockge - ${SERVER_HOSTNAME}:
icon: dockge.png
href: https://${SERVER_HOSTNAME}.${DOMAIN}
@@ -74,21 +64,6 @@
href: https://uptime-kuma.${DOMAIN}
description: Uptime Monitoring
- Grafana - ${REMOTE_SERVER_HOSTNAME}:
icon: grafana.png
href: https://grafana.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Dashboard
- Prometheus - ${REMOTE_SERVER_HOSTNAME}:
icon: prometheus.png
href: https://prometheus.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Collection
- Uptime Kuma - ${REMOTE_SERVER_HOSTNAME}:
icon: uptime-kuma.png
href: https://status.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Uptime Monitoring
- Media:
- Jellyfin:
icon: jellyfin.png
@@ -243,21 +218,11 @@
href: https://backrest.${DOMAIN}
description: Backup Solution
- Backrest - ${REMOTE_SERVER_HOSTNAME}:
icon: mdi-backup-restore
href: https://backrest.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Backup Solution
- Duplicati:
icon: duplicati.png
href: https://duplicati.${DOMAIN}
description: Backup Software
- Duplicati - ${REMOTE_SERVER_HOSTNAME}:
icon: duplicati.png
href: https://duplicati.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
description: ${REMOTE_SERVER_HOSTNAME} - Backup Software
- Metrics:
- Grafana:
icon: grafana.png

View File

@@ -1,19 +0,0 @@
http:
routers:
# Individual Services
homeassistant:
rule: "Host(`hass.${DOMAIN}`)"
entryPoints:
- websecure
service: homeassistant
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
services:
# Individual Services
homeassistant:
loadBalancer:
servers:
- url: "http://${HOMEASSISTANT_IP}:8123"
passHostHeader: true

View File

@@ -1,795 +0,0 @@
http:
routers:
backrest-${SERVER_HOSTNAME}:
rule: "Host(`backrest.${DOMAIN}`)"
entryPoints:
- websecure
service: backrest-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-backrest@file
- authelia@docker
bookstack-${SERVER_HOSTNAME}:
rule: "Host(`bookstack.${DOMAIN}`)"
entryPoints:
- websecure
service: bookstack-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-bookstack@file
- authelia@docker
vaultwarden-${SERVER_HOSTNAME}:
rule: "Host(`vault.${DOMAIN}`)"
entryPoints:
- websecure
service: vaultwarden-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
# SSO disabled for browser extension and mobile app compatibility
middlewares:
- sablier-${SERVER_HOSTNAME}-vaultwarden@file
calibre-web-${SERVER_HOSTNAME}:
rule: "Host(`calibre.${DOMAIN}`)"
entryPoints:
- websecure
service: calibre-web-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-calibre-web@file
- authelia@docker
code-${SERVER_HOSTNAME}:
rule: "Host(`code.${DOMAIN}`)"
entryPoints:
- websecure
service: code-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-code-server@file
- authelia@docker
dockge-${SERVER_HOSTNAME}:
rule: "Host(`jarvis.${DOMAIN}`)"
entryPoints:
- websecure
service: dockge-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
dockhand-${SERVER_HOSTNAME}:
rule: "Host(`dockhand.${DOMAIN}`)"
entryPoints:
- websecure
service: dockhand-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
dokuwiki-${SERVER_HOSTNAME}:
rule: "Host(`dokuwiki.${DOMAIN}`)"
entryPoints:
- websecure
service: dokuwiki-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-dokuwiki@file
- authelia@docker
dozzle-${SERVER_HOSTNAME}:
rule: "Host(`dozzle.${DOMAIN}`)"
entryPoints:
- websecure
service: dozzle-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-dozzle@file
- authelia@docker
duplicati-${SERVER_HOSTNAME}:
rule: "Host(`duplicati.${DOMAIN}`)"
entryPoints:
- websecure
service: duplicati-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-duplicati@file
- authelia@docker
ez-assistant-${SERVER_HOSTNAME}:
rule: "Host(`assistant.${DOMAIN}`)"
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
# - sablier-${SERVER_HOSTNAME}-assistant@file
- ez-assistant-websocket
service: ez-assistant-${SERVER_HOSTNAME}
formio-${SERVER_HOSTNAME}:
rule: "Host(`formio.${DOMAIN}`)"
entryPoints:
- websecure
service: formio-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-formio@file
- authelia@docker
gitea-${SERVER_HOSTNAME}:
rule: "Host(`gitea.${DOMAIN}`)"
entryPoints:
- websecure
service: gitea-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-gitea@file
- authelia@docker
glances-${SERVER_HOSTNAME}:
rule: "Host(`glances.jarvis.${DOMAIN}`)"
entryPoints:
- websecure
service: glances-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-glances@file
- authelia@docker
homepage-${SERVER_HOSTNAME}:
rule: "Host(`homepage.jarvis.${DOMAIN}`)"
entryPoints:
- websecure
service: homepage-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
homarr-${SERVER_HOSTNAME}:
rule: "Host(`homarr.${DOMAIN}`)"
entryPoints:
- websecure
service: homarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
- sablier-${SERVER_HOSTNAME}-homarr@file
jellyfin-${SERVER_HOSTNAME}:
rule: "Host(`jellyfin.${DOMAIN}`)"
entryPoints:
- websecure
service: jellyfin-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-jellyfin@file
# No authelia middleware for media apps
jupyter-${SERVER_HOSTNAME}:
rule: "Host(`jupyter.${DOMAIN}`)"
entryPoints:
- websecure
service: jupyter-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-jupyter@file
- authelia@docker
kopia-${SERVER_HOSTNAME}:
rule: "Host(`kopia.${DOMAIN}`)"
entryPoints:
- websecure
service: kopia-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-kopia@file
- authelia@docker
mealie-${SERVER_HOSTNAME}:
rule: "Host(`mealie.${DOMAIN}`)"
entryPoints:
- websecure
service: mealie-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-mealie@file
- authelia@docker
motioneye-${SERVER_HOSTNAME}:
rule: "Host(`motioneye.${DOMAIN}`)"
entryPoints:
- websecure
service: motioneye-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
mediawiki-${SERVER_HOSTNAME}:
rule: "Host(`mediawiki.${DOMAIN}`)"
entryPoints:
- websecure
service: mediawiki-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-mediawiki@file
- authelia@docker
nextcloud-${SERVER_HOSTNAME}:
rule: "Host(`nextcloud.${DOMAIN}`)"
entryPoints:
- websecure
service: nextcloud-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-nextcloud@file
- authelia@docker
openkm-${SERVER_HOSTNAME}:
rule: "Host(`openkm.${DOMAIN}`)"
entryPoints:
- websecure
service: openkm-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-openkm@file
- authelia@docker
openwebui-${SERVER_HOSTNAME}:
rule: "Host(`openwebui.${DOMAIN}`)"
entryPoints:
- websecure
service: openwebui-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-openwebui@file
- authelia@docker
qbittorrent-${SERVER_HOSTNAME}:
rule: "Host(`qbit.${DOMAIN}`)"
entryPoints:
- websecure
service: qbittorrent-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
tdarr-${SERVER_HOSTNAME}:
rule: "Host(`tdarr.${DOMAIN}`)"
entryPoints:
- websecure
service: tdarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
unmanic-${SERVER_HOSTNAME}:
rule: "Host(`unmanic.${DOMAIN}`)"
entryPoints:
- websecure
service: unmanic-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-unmanic@file
- authelia@docker
- authelia@docker
wordpress-${SERVER_HOSTNAME}:
rule: "Host(`wordpress.${DOMAIN}`)"
entryPoints:
- websecure
service: wordpress-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-wordpress@file
- authelia@docker
# Arr Services (no SSO for media apps)
jellyseerr-${SERVER_HOSTNAME}:
rule: "Host(`jellyseerr.${DOMAIN}`)"
entryPoints:
- websecure
service: jellyseerr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
prowlarr-${SERVER_HOSTNAME}:
rule: "Host(`prowlarr.${DOMAIN}`)"
entryPoints:
- websecure
service: prowlarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
radarr-${SERVER_HOSTNAME}:
rule: "Host(`radarr.${DOMAIN}`)"
entryPoints:
- websecure
service: radarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
sonarr-${SERVER_HOSTNAME}:
rule: "Host(`sonarr.${DOMAIN}`)"
entryPoints:
- websecure
service: sonarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
lidarr-${SERVER_HOSTNAME}:
rule: "Host(`lidarr.${DOMAIN}`)"
entryPoints:
- websecure
service: lidarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
readarr-${SERVER_HOSTNAME}:
rule: "Host(`readarr.${DOMAIN}`)"
entryPoints:
- websecure
service: readarr-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
mylar3-${SERVER_HOSTNAME}:
rule: "Host(`mylar3.${DOMAIN}`)"
entryPoints:
- websecure
service: mylar3-${SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- sablier-${SERVER_HOSTNAME}-arr@file
- authelia@docker
# Remote Server Services (${REMOTE_SERVER_HOSTNAME})
dockge-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`dockge.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: dockge-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
dozzle-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`dozzle.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: dozzle-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
glances-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`glances.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: glances-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
backrest-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`backrest.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: backrest-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
duplicati-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`duplicati.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: duplicati-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
homepage-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`homepage.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: homepage-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
homarr-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`homarr.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: homarr-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
grafana-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`grafana.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: grafana-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
prometheus-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`prometheus.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: prometheus-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
uptime-kuma-${REMOTE_SERVER_HOSTNAME}:
rule: "Host(`status.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
entryPoints:
- websecure
service: uptime-kuma-${REMOTE_SERVER_HOSTNAME}
tls:
certResolver: letsencrypt
middlewares:
- authelia@docker
# Service Definitions
services:
backrest-${SERVER_HOSTNAME}:
loadBalancer:
servers:
- url: "http://${SERVER_IP}:9898"
passHostHeader: true
vaultwarden-${SERVER_HOSTNAME}:
loadBalancer:
servers:
- url: "http://${SERVER_IP}:8091"
passHostHeader: true
bookstack-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:6875"
passHostHeader: true
calibre-web-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8083"
passHostHeader: true
code-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8079"
passHostHeader: true
dockge-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:5001"
passHostHeader: true
dockhand-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:3003"
passHostHeader: true
dokuwiki-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8087"
passHostHeader: true
dozzle-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8085"
passHostHeader: true
duplicati-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8200"
passHostHeader: true
ez-assistant-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:18789" # Internal IP of ${SERVER_HOSTNAME} server
passHostHeader: true
formio-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:3002"
passHostHeader: true
gitea-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:3010"
passHostHeader: true
glances-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:61208"
passHostHeader: true
homarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:7575"
passHostHeader: true
homepage-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:3000"
passHostHeader: true
jellyfin-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8096"
passHostHeader: true
jupyter-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8890"
passHostHeader: true
kopia-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:51515"
passHostHeader: true
mealie-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:9000"
passHostHeader: true
mediawiki-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8086"
passHostHeader: true
motioneye-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8081"
passHostHeader: true
nextcloud-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8089"
passHostHeader: true
openkm-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:18080"
passHostHeader: true
openwebui-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:3000"
passHostHeader: true
qbittorrent-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8081"
passHostHeader: true
tdarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8265"
passHostHeader: true
unmanic-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8889"
passHostHeader: true
wordpress-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8088"
passHostHeader: true
# Arr Services
jellyseerr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:5055"
passHostHeader: true
prowlarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:9696"
passHostHeader: true
radarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:7878"
passHostHeader: true
sonarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8989"
passHostHeader: true
lidarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8686"
passHostHeader: true
readarr-${SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${SERVER_IP}:8787"
passHostHeader: true
mylar3-${SERVER_HOSTNAME}:
loadBalancer:
servers:
- url: "http://${SERVER_IP}:8090"
passHostHeader: true
# Remote Server Service Definitions (${REMOTE_SERVER_HOSTNAME})
dockge-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:5001"
passHostHeader: true
dozzle-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:8085"
passHostHeader: true
glances-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:61208"
passHostHeader: true
backrest-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:9898"
passHostHeader: true
duplicati-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:8200"
passHostHeader: true
homepage-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:3000"
passHostHeader: true
homarr-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:7575"
passHostHeader: true
grafana-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:3000"
passHostHeader: true
prometheus-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:9090"
passHostHeader: true
uptime-kuma-${REMOTE_SERVER_HOSTNAME}:
loadbalancer:
servers:
- url: "http://${REMOTE_SERVER_IP}:3001"
passHostHeader: true
# Middleware Definitions
middlewares:
ez-assistant-websocket:
headers:
accessControlAllowHeaders:
- "Connection"
- "Upgrade"
accessControlAllowMethods:
- "GET"
- "POST"
- "OPTIONS"
accessControlMaxAge: 86400

View File

@@ -1,31 +0,0 @@
# Traefik Dynamic Configuration
# Copy to /opt/stacks/traefik/dynamic/routes.yml
# Add custom routes here that aren't defined via Docker labels
http:
routers:
# Example custom route
# custom-service:
# rule: "Host(`custom.example.com`)"
# entryPoints:
# - websecure
# middlewares:
# - authelia@docker
# tls:
# certResolver: letsencrypt
# service: custom-service
services:
# Example custom service
# custom-service:
# loadBalancer:
# servers:
# - url: "http://192.168.1.100:8080"
middlewares:
# Additional middlewares can be defined here
# Example: Rate limiting
# rate-limit:
# rateLimit:
# average: 100
# burst: 50

View File

@@ -1,442 +0,0 @@
# 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:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-arr
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Arr Apps
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-backrest:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-backrest
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Backrest
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-vaultwarden:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-vaultwarden
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Vaultwarden
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-bookstack:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-bookstack
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Bookstack
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-calibre-web:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-calibre-web
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Calibre Web
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-code-server:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-code-server
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Code Server
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-dozzle:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-dozzle
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: dozzle
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-dokuwiki:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-dokuwiki
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: DokuWiki
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
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-formio:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-formio
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: FormIO
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
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-glances:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-glances
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Glances
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-homarr:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-homarr
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Homarr
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}-jupyter:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-jupyter
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Jupyter
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-komodo:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-komodo
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Komodo
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-kopia:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-kopia
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Kopia
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:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-openkm
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: OpenKM
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-openwebui:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-openwebui
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: OpenWebUI
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-pulse:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-pulse
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Pulse
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-tdarr:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-tdarr
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Tdarr
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-unmanic:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-unmanic
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Unmanic
theme: ghost
show-details-by-default: true
sablier-${SERVER_HOSTNAME}-wordpress:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${SERVER_HOSTNAME}-wordpress
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: wordpress
theme: ghost
show-details-by-default: true
# Remote Server (${REMOTE_SERVER_HOSTNAME}) Sablier Middlewares
sablier-${REMOTE_SERVER_HOSTNAME}-dockge:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-dockge
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Dockge (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-dozzle:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-dozzle
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Dozzle (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-glances:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-glances
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Glances (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-backrest:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-backrest
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Backrest (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-duplicati:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-duplicati
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Duplicati (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-homepage:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-homepage
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Homepage (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-homarr:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-homarr
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Homarr (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-grafana:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-grafana
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Grafana (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-prometheus:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-prometheus
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Prometheus (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true
sablier-${REMOTE_SERVER_HOSTNAME}-uptime-kuma:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: ${REMOTE_SERVER_HOSTNAME}-uptime-kuma
sessionDuration: 5m
ignoreUserAgent: curl
dynamic:
displayName: Uptime Kuma (${REMOTE_SERVER_HOSTNAME})
theme: ghost
show-details-by-default: true

View File

@@ -1,43 +0,0 @@
# Traefik Static Configuration
# Copy to /opt/stacks/traefik/traefik.yml
experimental:
plugins:
sablier:
moduleName: github.com/sablierapp/sablier-traefik-plugin
version: v1.1.0
providers:
docker:
exposedByDefault: false
file:
directory: /dynamic
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
traefik:
address: ":8080"
certificatesResolvers:
letsencrypt:
acme:
dnsChallenge:
provider: duckdns
email: ${DEFAULT_EMAIL}
storage: /letsencrypt/acme.json
log:
level: DEBUG
accessLog:
format: json
api:
dashboard: true
insecure: true
ping:
manualRouting: true

View File

@@ -8,11 +8,11 @@
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Dockge: https://dockge.${DOMAIN}
# - Dockge: https://dockge.kelinreij.duckdns.org
services:
# Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer)
# Access at: https://dockge.${DOMAIN}
# Access at: https://dockge.kelinreij.duckdns.org
# Stack management interface should always run for container management
dockge:
image: louislam/dockge:1
@@ -50,7 +50,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)"
- "traefik.http.routers.dockge.rule=Host(`dockge.kelinreij.duckdns.org`)"
- "traefik.http.routers.dockge.entrypoints=websecure"
- "traefik.http.routers.dockge.tls.certresolver=letsencrypt"
- "traefik.http.routers.dockge.middlewares=authelia@docker"

View File

@@ -0,0 +1,63 @@
# Dockge Stack
# Docker Compose Stack Manager
# Place in /opt/dockge/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Dockge: https://dockge.${DOMAIN}
services:
# Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer)
# Access at: https://dockge.${DOMAIN}
# Stack management interface should always run for container management
dockge:
image: louislam/dockge:1
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: dockge
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "5001:5001" # Optional: direct access
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/stacks:/opt/stacks # Dockge manages stacks in this directory
- ./data:/app/data
- /usr/bin/docker:/usr/bin/docker:ro # Mount docker binary for CLI access
environment:
- DOCKGE_STACKS_DIR=/opt/stacks
- DOCKGE_ENABLE_CONSOLE=true
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=infrastructure"
- "homelab.description=Docker Compose stack manager (PRIMARY)"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)"
- "traefik.http.routers.dockge.entrypoints=websecure"
- "traefik.http.routers.dockge.tls.certresolver=letsencrypt"
- "traefik.http.routers.dockge.middlewares=authelia@docker"
- "traefik.http.services.dockge.loadbalancer.server.port=5001"
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -3,15 +3,15 @@
# Place in /opt/stacks/homeassistant/docker-compose.yml
# Service Access URLs:
# - Home Assistant: https://ha.${DOMAIN} (configure via Traefik file provider - uses host network)
# - ESPHome: https://esphome.${DOMAIN}
# - Node-RED: https://nodered.${DOMAIN}
# - Home Assistant: https://ha.kelinreij.duckdns.org (configure via Traefik file provider - uses host network)
# - ESPHome: https://esphome.kelinreij.duckdns.org
# - Node-RED: https://nodered.kelinreij.duckdns.org
# - Mosquitto MQTT: mqtt://server-ip:1883 (no web UI)
# - Zigbee2MQTT: https://zigbee2mqtt.${DOMAIN} (requires USB adapter)
# - Zigbee2MQTT: https://zigbee2mqtt.kelinreij.duckdns.org (requires USB adapter)
services:
# Home Assistant - Home automation platform
# Access at: https://ha.${DOMAIN}
# Access at: https://ha.kelinreij.duckdns.org
# NOTE: No Authelia - HA has its own authentication
homeassistant:
image: ghcr.io/home-assistant/home-assistant:2024.1
@@ -31,7 +31,7 @@ services:
- ./homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=${TZ}
- TZ=America/New_York
privileged: true
labels:
- "homelab.category=iot"
@@ -40,7 +40,7 @@ services:
# Use Traefik's file provider or external host routing
# ESPHome - ESP8266/ESP32 firmware manager
# Access at: https://esphome.${DOMAIN}
# Access at: https://esphome.kelinreij.duckdns.org
esphome:
image: ghcr.io/esphome/esphome:latest
deploy:
@@ -63,7 +63,7 @@ services:
- ./esphome/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=${TZ}
- TZ=America/New_York
- ESPHOME_DASHBOARD_USE_PING=true
privileged: true # For USB device access
labels:
@@ -76,14 +76,14 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.esphome.rule=Host(`esphome.${DOMAIN}`)"
- "traefik.http.routers.esphome.rule=Host(`esphome.kelinreij.duckdns.org`)"
- "traefik.http.routers.esphome.entrypoints=websecure"
- "traefik.http.routers.esphome.tls.certresolver=letsencrypt"
- "traefik.http.routers.esphome.middlewares=authelia@docker"
- "traefik.http.services.esphome.loadbalancer.server.port=6052"
# TasmoAdmin - Tasmota device manager
# Access at: https://tasmoadmin.${DOMAIN}
# Access at: https://tasmoadmin.kelinreij.duckdns.org
tasmoadmin:
image: ghcr.io/tasmoadmin/tasmoadmin:latest
container_name: tasmoadmin
@@ -96,7 +96,7 @@ services:
volumes:
- /opt/stacks/tasmoadmin/data:/data
environment:
- TZ=${TZ}
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -107,14 +107,14 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.${DOMAIN}`)"
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.kelinreij.duckdns.org`)"
- "traefik.http.routers.tasmoadmin.entrypoints=websecure"
- "traefik.http.routers.tasmoadmin.tls.certresolver=letsencrypt"
- "traefik.http.routers.tasmoadmin.middlewares=authelia@docker"
- "traefik.http.services.tasmoadmin.loadbalancer.server.port=80"
# MotionEye - Video surveillance
# Access at: https://motioneye.${DOMAIN}
# Access at: https://motioneye.kelinreij.duckdns.org
motioneye:
image: ccrisan/motioneye:master-amd64
container_name: motioneye
@@ -128,7 +128,7 @@ services:
- ./$(basename $file .yml)/config:/etc/motioneye
- /mnt/surveillance:/var/lib/motioneye # Large video files on separate drive
environment:
- TZ=${TZ}
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -139,14 +139,14 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.motioneye.rule=Host(`motioneye.${DOMAIN}`)"
- "traefik.http.routers.motioneye.rule=Host(`motioneye.kelinreij.duckdns.org`)"
- "traefik.http.routers.motioneye.entrypoints=websecure"
- "traefik.http.routers.motioneye.tls.certresolver=letsencrypt"
- "traefik.http.routers.motioneye.middlewares=authelia@docker"
- "traefik.http.services.motioneye.loadbalancer.server.port=8765"
# Node-RED - Flow-based automation (Home Assistant addon alternative)
# Access at: https://nodered.${DOMAIN}
# Access at: https://nodered.kelinreij.duckdns.org
nodered:
image: nodered/node-red:latest
deploy:
@@ -168,7 +168,7 @@ services:
volumes:
- /opt/stacks/nodered/data:/data
environment:
- TZ=${TZ}
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -179,7 +179,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.nodered.rule=Host(`nodered.${DOMAIN}`)"
- "traefik.http.routers.nodered.rule=Host(`nodered.kelinreij.duckdns.org`)"
- "traefik.http.routers.nodered.entrypoints=websecure"
- "traefik.http.routers.nodered.tls.certresolver=letsencrypt"
- "traefik.http.routers.nodered.middlewares=authelia@docker"
@@ -205,7 +205,7 @@ services:
- "homelab.description=MQTT message broker"
# Zigbee2MQTT - Zigbee to MQTT bridge (DISABLED - requires USB adapter)
# Access at: https://zigbee2mqtt.${DOMAIN}
# Access at: https://zigbee2mqtt.kelinreij.duckdns.org
# NOTE: Requires USB Zigbee adapter (e.g., ConBee II, Sonoff ZBDongle)
# Uncomment after connecting adapter
# zigbee2mqtt:
@@ -224,12 +224,12 @@ services:
# # Common paths: /dev/ttyACM0, /dev/ttyUSB0, /dev/serial/by-id/...
# # Run 'ls -l /dev/serial/by-id/' to find your adapter
# environment:
# - TZ=${TZ}
# - TZ=America/New_York
# labels:
# - "homelab.category=iot"
# - "homelab.description=Zigbee to MQTT bridge"
# - "traefik.enable=true"
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.${DOMAIN}`)"
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.kelinreij.duckdns.org`)"
# - "traefik.http.routers.zigbee2mqtt.entrypoints=websecure"
# - "traefik.http.routers.zigbee2mqtt.tls.certresolver=letsencrypt"
# - "traefik.http.routers.zigbee2mqtt.middlewares=authelia@docker"
@@ -244,15 +244,15 @@ networks:
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://ha.${DOMAIN}
- http://${SERVER_IP}:8123
- https://esphome.${DOMAIN}
- http://${SERVER_IP}:6052
- https://tasmoadmin.${DOMAIN}
- http://${SERVER_IP}:8084
- https://motioneye.${DOMAIN}
- http://${SERVER_IP}:8765
- https://nodered.${DOMAIN}
- http://${SERVER_IP}:1880
- mqtt://${SERVER_IP}:1883
- https://zigbee2mqtt.${DOMAIN}
- https://ha.kelinreij.duckdns.org
- http://192.168.4.4:8123
- https://esphome.kelinreij.duckdns.org
- http://192.168.4.4:6052
- https://tasmoadmin.kelinreij.duckdns.org
- http://192.168.4.4:8084
- https://motioneye.kelinreij.duckdns.org
- http://192.168.4.4:8765
- https://nodered.kelinreij.duckdns.org
- http://192.168.4.4:1880
- mqtt://192.168.4.4:1883
- https://zigbee2mqtt.kelinreij.duckdns.org

View File

@@ -0,0 +1,258 @@
# Home Assistant and IoT Services
# Home automation platform and related tools
# Place in /opt/stacks/homeassistant/docker-compose.yml
# Service Access URLs:
# - Home Assistant: https://ha.${DOMAIN} (configure via Traefik file provider - uses host network)
# - ESPHome: https://esphome.${DOMAIN}
# - Node-RED: https://nodered.${DOMAIN}
# - Mosquitto MQTT: mqtt://server-ip:1883 (no web UI)
# - Zigbee2MQTT: https://zigbee2mqtt.${DOMAIN} (requires USB adapter)
services:
# Home Assistant - Home automation platform
# Access at: https://ha.${DOMAIN}
# NOTE: No Authelia - HA has its own authentication
homeassistant:
image: ghcr.io/home-assistant/home-assistant:2024.1
deploy:
resources:
limits:
cpus: '1.5'
memory: 1G
pids: 2048
reservations:
cpus: '0.75'
memory: 512M
container_name: homeassistant
restart: unless-stopped
network_mode: host # Required for device discovery
volumes:
- ./homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=${TZ}
privileged: true
labels:
- "homelab.category=iot"
- "homelab.description=Home automation platform"
# Note: network_mode: host means Traefik can't proxy this directly
# Use Traefik's file provider or external host routing
# ESPHome - ESP8266/ESP32 firmware manager
# Access at: https://esphome.${DOMAIN}
esphome:
image: ghcr.io/esphome/esphome:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: esphome
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "6052:6052"
volumes:
- ./esphome/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=${TZ}
- ESPHOME_DASHBOARD_USE_PING=true
privileged: true # For USB device access
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=iot"
- "homelab.description=ESP8266/ESP32 firmware manager"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.esphome.rule=Host(`esphome.${DOMAIN}`)"
- "traefik.http.routers.esphome.entrypoints=websecure"
- "traefik.http.routers.esphome.tls.certresolver=letsencrypt"
- "traefik.http.routers.esphome.middlewares=authelia@docker"
- "traefik.http.services.esphome.loadbalancer.server.port=6052"
# TasmoAdmin - Tasmota device manager
# Access at: https://tasmoadmin.${DOMAIN}
tasmoadmin:
image: ghcr.io/tasmoadmin/tasmoadmin:latest
container_name: tasmoadmin
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "8084:80"
volumes:
- /opt/stacks/tasmoadmin/data:/data
environment:
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=iot"
- "homelab.description=Tasmota device management"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.${DOMAIN}`)"
- "traefik.http.routers.tasmoadmin.entrypoints=websecure"
- "traefik.http.routers.tasmoadmin.tls.certresolver=letsencrypt"
- "traefik.http.routers.tasmoadmin.middlewares=authelia@docker"
- "traefik.http.services.tasmoadmin.loadbalancer.server.port=80"
# MotionEye - Video surveillance
# Access at: https://motioneye.${DOMAIN}
motioneye:
image: ccrisan/motioneye:master-amd64
container_name: motioneye
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "8765:8765" # Optional: direct access
volumes:
- ./$(basename $file .yml)/config:/etc/motioneye
- /mnt/surveillance:/var/lib/motioneye # Large video files on separate drive
environment:
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=iot"
- "homelab.description=Video surveillance system"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.motioneye.rule=Host(`motioneye.${DOMAIN}`)"
- "traefik.http.routers.motioneye.entrypoints=websecure"
- "traefik.http.routers.motioneye.tls.certresolver=letsencrypt"
- "traefik.http.routers.motioneye.middlewares=authelia@docker"
- "traefik.http.services.motioneye.loadbalancer.server.port=8765"
# Node-RED - Flow-based automation (Home Assistant addon alternative)
# Access at: https://nodered.${DOMAIN}
nodered:
image: nodered/node-red:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: nodered
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "1880:1880"
volumes:
- /opt/stacks/nodered/data:/data
environment:
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=iot"
- "homelab.description=Flow-based automation programming"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.nodered.rule=Host(`nodered.${DOMAIN}`)"
- "traefik.http.routers.nodered.entrypoints=websecure"
- "traefik.http.routers.nodered.tls.certresolver=letsencrypt"
- "traefik.http.routers.nodered.middlewares=authelia@docker"
- "traefik.http.services.nodered.loadbalancer.server.port=1880"
# Mosquitto - MQTT broker (Home Assistant addon alternative)
# Used by: Home Assistant, ESPHome, Tasmota devices
mosquitto:
image: eclipse-mosquitto:latest
container_name: mosquitto
restart: unless-stopped
networks:
- homelab-network
ports:
- "1883:1883" # MQTT
- "9001:9001" # Websockets
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
labels:
- "homelab.category=iot"
- "homelab.description=MQTT message broker"
# Zigbee2MQTT - Zigbee to MQTT bridge (DISABLED - requires USB adapter)
# Access at: https://zigbee2mqtt.${DOMAIN}
# NOTE: Requires USB Zigbee adapter (e.g., ConBee II, Sonoff ZBDongle)
# Uncomment after connecting adapter
# zigbee2mqtt:
# image: koenkk/zigbee2mqtt:1.35.1
# container_name: zigbee2mqtt
# restart: unless-stopped
# networks:
# - homelab-network
# - traefik-network
# volumes:
# - ./zigbee2mqtt/data:/app/data
# - /run/udev:/run/udev:ro
# # Uncomment and adjust device path after connecting USB adapter:
# # devices:
# # - /dev/ttyACM0:/dev/ttyACM0 # Adjust based on your adapter
# # Common paths: /dev/ttyACM0, /dev/ttyUSB0, /dev/serial/by-id/...
# # Run 'ls -l /dev/serial/by-id/' to find your adapter
# environment:
# - TZ=${TZ}
# labels:
# - "homelab.category=iot"
# - "homelab.description=Zigbee to MQTT bridge"
# - "traefik.enable=true"
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.${DOMAIN}`)"
# - "traefik.http.routers.zigbee2mqtt.entrypoints=websecure"
# - "traefik.http.routers.zigbee2mqtt.tls.certresolver=letsencrypt"
# - "traefik.http.routers.zigbee2mqtt.middlewares=authelia@docker"
# - "traefik.http.services.zigbee2mqtt.loadbalancer.server.port=8080"
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://ha.${DOMAIN}
- http://${SERVER_IP}:8123
- https://esphome.${DOMAIN}
- http://${SERVER_IP}:6052
- https://tasmoadmin.${DOMAIN}
- http://${SERVER_IP}:8084
- https://motioneye.${DOMAIN}
- http://${SERVER_IP}:8765
- https://nodered.${DOMAIN}
- http://${SERVER_IP}:1880
- mqtt://${SERVER_IP}:1883
- https://zigbee2mqtt.${DOMAIN}

View File

@@ -41,7 +41,7 @@ services:
- homelab.description=Docker socket proxy for security
# Pi-hole - Network-wide ad blocker and DNS server
# Access at: https://pihole.${DOMAIN}
# Access at: https://pihole.kelinreij.duckdns.org
# DNS service must always run for network-wide ad blocking
pihole:
image: pihole/pihole:2024.01.0
@@ -66,9 +66,9 @@ services:
- ./pihole/etc-pihole:/etc/pihole
- ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
environment:
- TZ=${TZ}
- TZ=America/New_York
- WEBPASSWORD=${PIHOLE_PASSWORD}
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
- FTLCONF_LOCAL_IPV4=192.168.4.4
dns:
- 127.0.0.1
- 1.1.1.1
@@ -86,7 +86,7 @@ services:
# - Routes are configured via external YAML files on the core server
# - This prevents conflicts between Docker labels and file provider
- "traefik.enable=true"
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
- "traefik.http.routers.pihole.rule=Host(`pihole.kelinreij.duckdns.org`)"
- "traefik.http.routers.pihole.entrypoints=websecure"
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
- "traefik.http.routers.pihole.middlewares=authelia@docker"
@@ -115,7 +115,7 @@ services:
- "homelab.description=Automatic Docker container updates"
# Dozzle - Real-time Docker log viewer
# Access at: https://dozzle.${DOMAIN}
# Access at: https://dozzle.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
dozzle:
image: amir20/dozzle:latest
@@ -155,7 +155,7 @@ services:
- "homelab.description=Real-time Docker log viewer"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.dozzle.rule=Host(`dozzle.${SERVER_HOSTNAME}.${DOMAIN}`)"
- "traefik.http.routers.dozzle.rule=Host(`dozzle.jasper.kelinreij.duckdns.org`)"
- "traefik.http.routers.dozzle.entrypoints=websecure"
- "traefik.http.routers.dozzle.tls=true"
- "traefik.http.routers.dozzle.middlewares=authelia@docker"
@@ -163,11 +163,11 @@ services:
- "traefik.http.services.dozzle.loadbalancer.server.port=8085"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-dozzle"
- "sablier.group=jasper-dozzle"
- "sablier.start-on-demand=true"
# Glances - System monitoring
# Access at: https://glances.${DOMAIN}
# Access at: https://glances.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
glances:
image: nicolargo/glances:latest-full
@@ -207,7 +207,7 @@ services:
- "homelab.description=System and Docker monitoring"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.glances.rule=Host(`glances.${SERVER_HOSTNAME}.${DOMAIN}`)"
- "traefik.http.routers.glances.rule=Host(`glances.jasper.kelinreij.duckdns.org`)"
- "traefik.http.routers.glances.entrypoints=websecure"
- "traefik.http.routers.glances.tls=true"
- "traefik.http.routers.glances.middlewares=authelia@docker"
@@ -215,11 +215,11 @@ services:
- "traefik.http.services.glances.loadbalancer.server.port=61208"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-glances"
- "sablier.group=jasper-glances"
- "sablier.start-on-demand=true"
# Code Server - VS Code in browser
# Access at: https://code.${DOMAIN}
# Access at: https://code.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
code-server:
image: lscr.io/linuxserver/code-server:latest
@@ -244,9 +244,9 @@ services:
- /opt/stacks:/opt/stacks # Access to all stacks
- /mnt:/mnt:ro # Read-only access to data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- PASSWORD=${CODE_SERVER_PASSWORD}
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD}
healthcheck:
@@ -263,7 +263,7 @@ services:
- "homelab.description=VS Code in browser"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.code-server.rule=Host(`code.${DOMAIN}`)"
- "traefik.http.routers.code-server.rule=Host(`code.kelinreij.duckdns.org`)"
- "traefik.http.routers.code-server.entrypoints=websecure"
- "traefik.http.routers.code-server.tls.certresolver=letsencrypt"
- "traefik.http.routers.code-server.middlewares=authelia@docker"
@@ -271,21 +271,21 @@ services:
- "traefik.http.services.code-server.loadbalancer.server.port=8443"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-code-server"
- "sablier.group=jasper-code-server"
- "sablier.start-on-demand=true"
x-dockge:
urls:
- https://pihole.${DOMAIN}
- https://${SERVER_IP}:53
- https://dozzle.${DOMAIN}
- https://${SERVER_IP}:8085
- https://glances.${DOMAIN}
- https://${SERVER_IP}:61208
- https://code.${DOMAIN}
- https://${SERVER_IP}:8079
- http://${SERVER_IP}:2375 # Docker Proxy
- http://${SERVER_IP}:19999 # Netdata
- https://pihole.kelinreij.duckdns.org
- https://192.168.4.4:53
- https://dozzle.kelinreij.duckdns.org
- https://192.168.4.4:8085
- https://glances.kelinreij.duckdns.org
- https://192.168.4.4:61208
- https://code.kelinreij.duckdns.org
- https://192.168.4.4:8079
- http://192.168.4.4:2375 # Docker Proxy
- http://192.168.4.4:19999 # Netdata
networks:
homelab-network:

View File

@@ -0,0 +1,294 @@
# Infrastructure Services
# Core services that other services depend on
# Place in /opt/stacks/infrastructure/docker-compose.yml
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
dockerproxy:
# Docker socket proxy for security - provides safe Docker API access, must always run
# REQUIREMENTS FOR SABLIER INTEGRATION:
# 1. Docker daemon must be configured to listen on TCP port 2375 (not just unix socket)
# 2. Firewall must allow access to port 2375 from Sablier service
# 3. Docker daemon config should include: "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
# 4. For security, consider restricting access to specific IP ranges or using TLS
# 5. dockerproxy runs for additional security but doesn't expose port 2375 (handled by Docker daemon)
image: tecnativa/docker-socket-proxy:latest
container_name: dockerproxy
privileged: true
restart: unless-stopped
# Note: Port 2375 is handled directly by Docker daemon for Sablier access
# dockerproxy provides additional security features but doesn't expose the port
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- CONTAINERS=1
- SERVICES=1
- TASKS=1
- NETWORKS=1
- NODES=1
- EXEC=1
- IMAGES=1
- VOLUMES=1
- SWARM=1
labels:
- homelab.category=infrastructure
- homelab.description=Docker socket proxy for security
# Pi-hole - Network-wide ad blocker and DNS server
# Access at: https://pihole.${DOMAIN}
# DNS service must always run for network-wide ad blocking
pihole:
image: pihole/pihole:2024.01.0
deploy:
resources:
limits:
cpus: '0.25'
memory: 128M
pids: 256
reservations:
cpus: '0.10'
memory: 64M
container_name: pihole
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "53:53/tcp" # DNS TCP
- "53:53/udp" # DNS UDP
volumes:
- ./pihole/etc-pihole:/etc/pihole
- ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
environment:
- TZ=${TZ}
- WEBPASSWORD=${PIHOLE_PASSWORD}
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
dns:
- 127.0.0.1
- 1.1.1.1
cap_add:
- NET_ADMIN
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=infrastructure"
- "homelab.description=Network-wide ad blocking and DNS"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# IMPORTANT: On REMOTE SERVERS (where Traefik runs elsewhere):
# - COMMENT OUT all traefik.* labels below (don't delete them)
# - Routes are configured via external YAML files on the core server
# - This prevents conflicts between Docker labels and file provider
- "traefik.enable=true"
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
- "traefik.http.routers.pihole.entrypoints=websecure"
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
- "traefik.http.routers.pihole.middlewares=authelia@docker"
- "traefik.http.services.pihole.loadbalancer.server.port=80"
# Watchtower - Automatic container updates
# Monitors and updates Docker containers to latest versions
# Runs daily at 4 AM
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
restart: unless-stopped
networks:
- homelab-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_API_VERSION=1.52
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_INCLUDE_RESTARTING=true
- WATCHTOWER_SCHEDULE=0 0 4 * * * # 4 AM daily
- WATCHTOWER_NOTIFICATIONS=shoutrrr
- WATCHTOWER_NOTIFICATION_URL=${WATCHTOWER_NOTIFICATION_URL}
labels:
- "homelab.category=infrastructure"
- "homelab.description=Automatic Docker container updates"
# Dozzle - Real-time Docker log viewer
# Access at: https://dozzle.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
dozzle:
image: amir20/dozzle:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: dozzle
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8085:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- DOZZLE_LEVEL=info
- DOZZLE_TAILSIZE=300
- DOZZLE_FILTER=status=running
healthcheck:
test: ["CMD", "/dozzle", "healthcheck"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=infrastructure"
- "homelab.description=Real-time Docker log viewer"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.dozzle.rule=Host(`dozzle.${SERVER_HOSTNAME}.${DOMAIN}`)"
- "traefik.http.routers.dozzle.entrypoints=websecure"
- "traefik.http.routers.dozzle.tls=true"
- "traefik.http.routers.dozzle.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.dozzle.loadbalancer.server.port=8085"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-dozzle"
- "sablier.start-on-demand=true"
# Glances - System monitoring
# Access at: https://glances.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
glances:
image: nicolargo/glances:latest-full
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: glances
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "61208:61208"
pid: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./glances/config:/glances/conf
environment:
- GLANCES_OPT=-w
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:61208/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=infrastructure"
- "homelab.description=System and Docker monitoring"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.glances.rule=Host(`glances.${SERVER_HOSTNAME}.${DOMAIN}`)"
- "traefik.http.routers.glances.entrypoints=websecure"
- "traefik.http.routers.glances.tls=true"
- "traefik.http.routers.glances.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.glances.loadbalancer.server.port=61208"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-glances"
- "sablier.start-on-demand=true"
# Code Server - VS Code in browser
# Access at: https://code.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
code-server:
image: lscr.io/linuxserver/code-server:latest
deploy:
resources:
limits:
cpus: '1.5'
memory: 1G
pids: 2048
reservations:
cpus: '0.75'
memory: 512M
container_name: code-server
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8079:8443"
volumes:
- ./code-server/config:/config
- /opt/stacks:/opt/stacks # Access to all stacks
- /mnt:/mnt:ro # Read-only access to data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PASSWORD=${CODE_SERVER_PASSWORD}
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8443/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=infrastructure"
- "homelab.description=VS Code in browser"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.code-server.rule=Host(`code.${DOMAIN}`)"
- "traefik.http.routers.code-server.entrypoints=websecure"
- "traefik.http.routers.code-server.tls.certresolver=letsencrypt"
- "traefik.http.routers.code-server.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.code-server.loadbalancer.server.port=8443"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-code-server"
- "sablier.start-on-demand=true"
x-dockge:
urls:
- https://pihole.${DOMAIN}
- https://${SERVER_IP}:53
- https://dozzle.${DOMAIN}
- https://${SERVER_IP}:8085
- https://glances.${DOMAIN}
- https://${SERVER_IP}:61208
- https://code.${DOMAIN}
- https://${SERVER_IP}:8079
- http://${SERVER_IP}:2375 # Docker Proxy
- http://${SERVER_IP}:19999 # Netdata
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -24,9 +24,9 @@ services:
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8989/"]
interval: 30s
@@ -44,13 +44,13 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`)"
- "traefik.http.routers.sonarr.rule=Host(`sonarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.sonarr.entrypoints=websecure"
- "traefik.http.routers.sonarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.sonarr.middlewares=authelia@docker"
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Radarr - Movie automation
@@ -69,9 +69,9 @@ services:
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7878/"]
interval: 30s
@@ -89,13 +89,13 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`)"
- "traefik.http.routers.radarr.rule=Host(`radarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.radarr.entrypoints=websecure"
- "traefik.http.routers.radarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.radarr.middlewares=authelia@docker"
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Prowlarr - Indexer manager
@@ -112,9 +112,9 @@ services:
volumes:
- ./prowlarr/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9696/"]
interval: 30s
@@ -132,17 +132,17 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`)"
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.prowlarr.entrypoints=websecure"
- "traefik.http.routers.prowlarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.prowlarr.middlewares=authelia@docker"
- "traefik.http.services.prowlarr.loadbalancer.server.port=9696"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Readarr - Ebook and audiobook management
# Access at: https://readarr.${DOMAIN}
# Access at: https://readarr.kelinreij.duckdns.org
readarr:
image: linuxserver/readarr:0.4.19-nightly
container_name: readarr
@@ -157,9 +157,9 @@ services:
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -171,17 +171,17 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.readarr.rule=Host(`readarr.${DOMAIN}`)"
- "traefik.http.routers.readarr.rule=Host(`readarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.readarr.entrypoints=websecure"
- "traefik.http.routers.readarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.readarr.middlewares=authelia@docker"
- "traefik.http.services.readarr.loadbalancer.server.port=8787"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Lidarr - Music collection manager
# Access at: https://lidarr.${DOMAIN}
# Access at: https://lidarr.kelinreij.duckdns.org
lidarr:
image: linuxserver/lidarr:2.0.7
container_name: lidarr
@@ -196,9 +196,9 @@ services:
- /mnt/media/music:/music
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -210,17 +210,17 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.lidarr.rule=Host(`lidarr.${DOMAIN}`)"
- "traefik.http.routers.lidarr.rule=Host(`lidarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.lidarr.entrypoints=websecure"
- "traefik.http.routers.lidarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.lidarr.middlewares=authelia@docker"
- "traefik.http.services.lidarr.loadbalancer.server.port=8686"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Lazy Librarian - Book manager
# Access at: https://lazylibrarian.${DOMAIN}
# Access at: https://lazylibrarian.kelinreij.duckdns.org
lazylibrarian:
image: linuxserver/lazylibrarian:latest
container_name: lazylibrarian
@@ -235,9 +235,9 @@ services:
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg
labels:
# TRAEFIK CONFIGURATION
@@ -250,17 +250,17 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.${DOMAIN}`)"
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.kelinreij.duckdns.org`)"
- "traefik.http.routers.lazylibrarian.entrypoints=websecure"
- "traefik.http.routers.lazylibrarian.tls.certresolver=letsencrypt"
- "traefik.http.routers.lazylibrarian.middlewares=authelia@docker"
- "traefik.http.services.lazylibrarian.loadbalancer.server.port=5299"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Mylar3 - Comic book manager
# Access at: https://mylar.${DOMAIN}
# Access at: https://mylar.kelinreij.duckdns.org
mylar3:
image: linuxserver/mylar3:latest
container_name: mylar3
@@ -275,9 +275,9 @@ services:
- /mnt/media/comics:/comics
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -289,17 +289,17 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.mylar.rule=Host(`mylar.${DOMAIN}`)"
- "traefik.http.routers.mylar.rule=Host(`mylar.kelinreij.duckdns.org`)"
- "traefik.http.routers.mylar.entrypoints=websecure"
- "traefik.http.routers.mylar.tls.certresolver=letsencrypt"
- "traefik.http.routers.mylar.middlewares=authelia@docker"
- "traefik.http.services.mylar.loadbalancer.server.port=8090"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# Jellyseerr - Request management for Jellyfin/Plex
# Access at: https://jellyseerr.${DOMAIN}
# Access at: https://jellyseerr.kelinreij.duckdns.org
jellyseerr:
image: fallenbagel/jellyseerr:latest
container_name: jellyseerr
@@ -313,7 +313,7 @@ services:
- ./jellyseerr/config:/app/config
environment:
- LOG_LEVEL=info
- TZ=${TZ}
- TZ=America/New_York
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5055/"]
interval: 30s
@@ -331,13 +331,13 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.${DOMAIN}`)"
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.kelinreij.duckdns.org`)"
- "traefik.http.routers.jellyseerr.entrypoints=websecure"
- "traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt"
- "traefik.http.routers.jellyseerr.middlewares=authelia@docker"
- "traefik.http.services.jellyseerr.loadbalancer.server.port=5055"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
# FlareSolverr - Cloudflare bypass for Prowlarr
@@ -350,32 +350,32 @@ services:
- homelab-network
environment:
- LOG_LEVEL=info
- TZ=${TZ}
- TZ=America/New_York
labels:
- homelab.category=media
- homelab.description=Cloudflare bypass for indexers
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.group=jasper-arr"
- "sablier.start-on-demand=true"
x-dockge:
urls:
- https://sonarr.${DOMAIN}
- http://${SERVER_IP}:8989
- https://radarr.${DOMAIN}
- http://${SERVER_IP}:7878
- https://prowlarr.${DOMAIN}
- http://${SERVER_IP}:9696
- https://readarr.${DOMAIN}
- http://${SERVER_IP}:8787
- https://lidarr.${DOMAIN}
- http://${SERVER_IP}:8686
- https://lazylibrarian.${DOMAIN}
- http://${SERVER_IP}:5299
- https://mylar.${DOMAIN}
- http://${SERVER_IP}:8090
- https://jellyseerr.${DOMAIN}
- http://${SERVER_IP}:5055
- https://sonarr.kelinreij.duckdns.org
- http://192.168.4.4:8989
- https://radarr.kelinreij.duckdns.org
- http://192.168.4.4:7878
- https://prowlarr.kelinreij.duckdns.org
- http://192.168.4.4:9696
- https://readarr.kelinreij.duckdns.org
- http://192.168.4.4:8787
- https://lidarr.kelinreij.duckdns.org
- http://192.168.4.4:8686
- https://lazylibrarian.kelinreij.duckdns.org
- http://192.168.4.4:5299
- https://mylar.kelinreij.duckdns.org
- http://192.168.4.4:8090
- https://jellyseerr.kelinreij.duckdns.org
- http://192.168.4.4:5055
networks:
homelab-network:

View File

@@ -0,0 +1,384 @@
# Media Management Services
# Content automation and library management (*arr apps, transcoders, etc.)
# Place in /opt/stacks/media-management/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
# Sonarr - TV show automation
# Access at: https://sonarr.yourdomain.duckdns.org
sonarr:
image: linuxserver/sonarr:4.0.0
container_name: sonarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8989:8989"
volumes:
- ./sonarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8989/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=TV show management and automation"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`)"
- "traefik.http.routers.sonarr.entrypoints=websecure"
- "traefik.http.routers.sonarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.sonarr.middlewares=authelia@docker"
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Radarr - Movie automation
# Access at: https://radarr.yourdomain.duckdns.org
radarr:
image: linuxserver/radarr:5.2.6
container_name: radarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "7878:7878"
volumes:
- ./radarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7878/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Movie management and automation"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`)"
- "traefik.http.routers.radarr.entrypoints=websecure"
- "traefik.http.routers.radarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.radarr.middlewares=authelia@docker"
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Prowlarr - Indexer manager
# Access at: https://prowlarr.yourdomain.duckdns.org
prowlarr:
image: linuxserver/prowlarr:1.11.4
container_name: prowlarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "9696:9696"
volumes:
- ./prowlarr/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9696/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Indexer manager for Sonarr/Radarr"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`)"
- "traefik.http.routers.prowlarr.entrypoints=websecure"
- "traefik.http.routers.prowlarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.prowlarr.middlewares=authelia@docker"
- "traefik.http.services.prowlarr.loadbalancer.server.port=9696"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Readarr - Ebook and audiobook management
# Access at: https://readarr.${DOMAIN}
readarr:
image: linuxserver/readarr:0.4.19-nightly
container_name: readarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8787:8787"
volumes:
- ./readarr/config:/config
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Ebook and audiobook management"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.readarr.rule=Host(`readarr.${DOMAIN}`)"
- "traefik.http.routers.readarr.entrypoints=websecure"
- "traefik.http.routers.readarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.readarr.middlewares=authelia@docker"
- "traefik.http.services.readarr.loadbalancer.server.port=8787"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Lidarr - Music collection manager
# Access at: https://lidarr.${DOMAIN}
lidarr:
image: linuxserver/lidarr:2.0.7
container_name: lidarr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8686:8686"
volumes:
- ./lidarr/config:/config
- /mnt/media/music:/music
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Music collection manager"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.lidarr.rule=Host(`lidarr.${DOMAIN}`)"
- "traefik.http.routers.lidarr.entrypoints=websecure"
- "traefik.http.routers.lidarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.lidarr.middlewares=authelia@docker"
- "traefik.http.services.lidarr.loadbalancer.server.port=8686"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Lazy Librarian - Book manager
# Access at: https://lazylibrarian.${DOMAIN}
lazylibrarian:
image: linuxserver/lazylibrarian:latest
container_name: lazylibrarian
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "5299:5299"
volumes:
- ./lazylibrarian/config:/config
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Book download automation"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.${DOMAIN}`)"
- "traefik.http.routers.lazylibrarian.entrypoints=websecure"
- "traefik.http.routers.lazylibrarian.tls.certresolver=letsencrypt"
- "traefik.http.routers.lazylibrarian.middlewares=authelia@docker"
- "traefik.http.services.lazylibrarian.loadbalancer.server.port=5299"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Mylar3 - Comic book manager
# Access at: https://mylar.${DOMAIN}
mylar3:
image: linuxserver/mylar3:latest
container_name: mylar3
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8090:8090"
volumes:
- ./mylar3/config:/config
- /mnt/media/comics:/comics
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Comic book collection manager"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.mylar.rule=Host(`mylar.${DOMAIN}`)"
- "traefik.http.routers.mylar.entrypoints=websecure"
- "traefik.http.routers.mylar.tls.certresolver=letsencrypt"
- "traefik.http.routers.mylar.middlewares=authelia@docker"
- "traefik.http.services.mylar.loadbalancer.server.port=8090"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# Jellyseerr - Request management for Jellyfin/Plex
# Access at: https://jellyseerr.${DOMAIN}
jellyseerr:
image: fallenbagel/jellyseerr:latest
container_name: jellyseerr
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "5055:5055"
volumes:
- ./jellyseerr/config:/app/config
environment:
- LOG_LEVEL=info
- TZ=${TZ}
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5055/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Media request management"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.${DOMAIN}`)"
- "traefik.http.routers.jellyseerr.entrypoints=websecure"
- "traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt"
- "traefik.http.routers.jellyseerr.middlewares=authelia@docker"
- "traefik.http.services.jellyseerr.loadbalancer.server.port=5055"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
# FlareSolverr - Cloudflare bypass for Prowlarr
# No web UI - used by Prowlarr
flaresolverr:
image: flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
networks:
- homelab-network
environment:
- LOG_LEVEL=info
- TZ=${TZ}
labels:
- homelab.category=media
- homelab.description=Cloudflare bypass for indexers
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-arr"
- "sablier.start-on-demand=true"
x-dockge:
urls:
- https://sonarr.${DOMAIN}
- http://${SERVER_IP}:8989
- https://radarr.${DOMAIN}
- http://${SERVER_IP}:7878
- https://prowlarr.${DOMAIN}
- http://${SERVER_IP}:9696
- https://readarr.${DOMAIN}
- http://${SERVER_IP}:8787
- https://lidarr.${DOMAIN}
- http://${SERVER_IP}:8686
- https://lazylibrarian.${DOMAIN}
- http://${SERVER_IP}:5299
- https://mylar.${DOMAIN}
- http://${SERVER_IP}:8090
- https://jellyseerr.${DOMAIN}
- http://${SERVER_IP}:5055
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -10,9 +10,9 @@
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Jellyfin: https://jellyfin.${DOMAIN} (no SSO - app access)
# - Plex: https://plex.${DOMAIN} (no SSO - app access)
# - qBittorrent: https://qbit.${DOMAIN} (routed through Gluetun VPN)
# - Jellyfin: https://jellyfin.kelinreij.duckdns.org (no SSO - app access)
# - Plex: https://plex.kelinreij.duckdns.org (no SSO - app access)
# - qBittorrent: https://qbit.kelinreij.duckdns.org (routed through Gluetun VPN)
services:
# Jellyfin - Open-source media streaming server
@@ -42,9 +42,9 @@ services:
- ./jellyfin/cache:/cache
- /mnt/media:/media:ro # Large media files on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/"]
interval: 30s
@@ -62,7 +62,7 @@ services:
- "homelab.description=Open-source media streaming server"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.kelinreij.duckdns.org`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls=true"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
@@ -70,12 +70,12 @@ services:
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-jellyfin"
- "sablier.group=jasper-jellyfin"
- "sablier.start-on-demand=true"
- "sablier.theme=hacker-terminal"
# Calibre-Web - Ebook reader and server
# Access at: https://calibre.${DOMAIN}
# Access at: https://calibre.kelinreij.duckdns.org
calibre-web:
image: lscr.io/linuxserver/calibre-web:latest
deploy:
@@ -98,9 +98,9 @@ services:
- ./calibre-web/config:/config
- /mnt/media/books:/books
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- DOCKER_MODS=linuxserver/mods:universal-calibre
# TRAEFIK CONFIGURATION
labels:
@@ -110,7 +110,7 @@ services:
- "homelab.description=Ebook reader and library management"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.calibre.rule=Host(`calibre.${DOMAIN}`)"
- "traefik.http.routers.calibre.rule=Host(`calibre.kelinreij.duckdns.org`)"
- "traefik.http.routers.calibre.entrypoints=websecure"
- "traefik.http.routers.calibre.tls.certresolver=letsencrypt"
- "traefik.http.routers.calibre.middlewares=authelia@docker"
@@ -118,7 +118,7 @@ services:
- "traefik.http.services.calibre.loadbalancer.server.port=8083"
# Sablier configuration (disabled by default)
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-calibre-web"
- "sablier.group=jasper-calibre-web"
- "sablier.start-on-demand=true"
# ==========================================
@@ -127,10 +127,10 @@ services:
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://jellyfin.${DOMAIN}
- http://${SERVER_IP}:8096
- https://calibre.${DOMAIN}
- http://${SERVER_IP}:8083
- https://jellyfin.kelinreij.duckdns.org
- http://192.168.4.4:8096
- https://calibre.kelinreij.duckdns.org
- http://192.168.4.4:8083
networks:
homelab-network:

View File

@@ -0,0 +1,139 @@
# Media Services
# Default Services for media management and streaming
# Place in /opt/stacks/media/docker-compose.yml
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Jellyfin: https://jellyfin.${DOMAIN} (no SSO - app access)
# - Plex: https://plex.${DOMAIN} (no SSO - app access)
# - qBittorrent: https://qbit.${DOMAIN} (routed through Gluetun VPN)
services:
# Jellyfin - Open-source media streaming server
# Access at: https://jellyfin.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
jellyfin:
image: jellyfin/jellyfin:10.8.13
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
pids: 2048
reservations:
cpus: '1.0'
memory: 1G
container_name: jellyfin
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8096:8096"
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- /mnt/media:/media:ro # Large media files on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# Uncomment for hardware transcoding
# devices:
# - /dev/dri:/dev/dri
# TRAEFIK CONFIGURATION
labels:
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=media"
- "homelab.description=Open-source media streaming server"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls=true"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
# Service configuration
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-jellyfin"
- "sablier.start-on-demand=true"
- "sablier.theme=hacker-terminal"
# Calibre-Web - Ebook reader and server
# Access at: https://calibre.${DOMAIN}
calibre-web:
image: lscr.io/linuxserver/calibre-web:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: calibre-web
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "8083:8083"
volumes:
- ./calibre-web/config:/config
- /mnt/media/books:/books
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- DOCKER_MODS=linuxserver/mods:universal-calibre
# TRAEFIK CONFIGURATION
labels:
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=media"
- "homelab.description=Ebook reader and library management"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.calibre.rule=Host(`calibre.${DOMAIN}`)"
- "traefik.http.routers.calibre.entrypoints=websecure"
- "traefik.http.routers.calibre.tls.certresolver=letsencrypt"
- "traefik.http.routers.calibre.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.calibre.loadbalancer.server.port=8083"
# Sablier configuration (disabled by default)
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-calibre-web"
- "sablier.start-on-demand=true"
# ==========================================
# DOCKGE URL CONFIGURATION
# ==========================================
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://jellyfin.${DOMAIN}
- http://${SERVER_IP}:8096
- https://calibre.${DOMAIN}
- http://${SERVER_IP}:8083
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -8,18 +8,18 @@
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Prometheus: http://${SERVER_IP}:9090 (or configure Traefik)
# - Grafana: http://${SERVER_IP}:3000 (or configure Traefik)
# - Uptime Kuma: https://status.${DOMAIN}
# - Node Exporter: http://${SERVER_IP}:9100/metrics
# - cAdvisor: http://${SERVER_IP}:8082
# - Loki: http://${SERVER_IP}:3100
# - Prometheus: http://192.168.4.4:9090 (or configure Traefik)
# - Grafana: http://192.168.4.4:3000 (or configure Traefik)
# - Uptime Kuma: https://status.kelinreij.duckdns.org
# - Node Exporter: http://192.168.4.4:9100/metrics
# - cAdvisor: http://192.168.4.4:8082
# - Loki: http://192.168.4.4:3100
# NOTE: Prometheus, Grafana, Loki use ports because they need to be accessible to other services
# Add Traefik labels if you want https://prometheus.${DOMAIN} access
# Add Traefik labels if you want https://prometheus.kelinreij.duckdns.org access
services:
# Prometheus - Metrics collection and storage
# Access at: http://${SERVER_IP}:9090
# Access at: http://192.168.4.4:9090
prometheus:
image: prom/prometheus:v2.48.1
deploy:
@@ -58,7 +58,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)"
- "traefik.http.routers.prometheus.rule=Host(`prometheus.kelinreij.duckdns.org`)"
- "traefik.http.routers.prometheus.entrypoints=websecure"
- "traefik.http.routers.prometheus.tls=true"
- "traefik.http.routers.prometheus.tls.certresolver=letsencrypt"
@@ -66,7 +66,7 @@ services:
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
# Grafana - Metrics visualization
# Access at: http://${SERVER_IP}:3000
# Access at: http://192.168.4.4:3000
# Default credentials: admin / admin (change on first login)
grafana:
image: grafana/grafana:10.2.3
@@ -92,9 +92,9 @@ services:
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_ROOT_URL=https://grafana.${DOMAIN}
- GF_SERVER_ROOT_URL=https://grafana.kelinreij.duckdns.org
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel
user: "${PUID}:${PGID}"
user: "1000:1000"
depends_on:
- prometheus
labels:
@@ -107,7 +107,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)"
- "traefik.http.routers.grafana.rule=Host(`grafana.kelinreij.duckdns.org`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls=true"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
@@ -115,7 +115,7 @@ services:
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
# Node Exporter - Host metrics exporter
# Metrics at: http://${SERVER_IP}:9100/metrics
# Metrics at: http://192.168.4.4:9100/metrics
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: node-exporter
@@ -138,7 +138,7 @@ services:
- "homelab.description=Hardware and OS metrics exporter"
# cAdvisor - Container metrics exporter
# Access at: http://${SERVER_IP}:8082
# Access at: http://192.168.4.4:8082
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.47.2
container_name: cadvisor
@@ -167,7 +167,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.${DOMAIN}`)"
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.kelinreij.duckdns.org`)"
- "traefik.http.routers.cadvisor.entrypoints=websecure"
- "traefik.http.routers.cadvisor.tls=true"
- "traefik.http.routers.cadvisor.tls.certresolver=letsencrypt"
@@ -175,7 +175,7 @@ services:
- "traefik.http.services.cadvisor.loadbalancer.server.port=8080"
# Uptime Kuma - Uptime monitoring
# Access at: https://uptime-kuma.${DOMAIN}
# Access at: https://uptime-kuma.kelinreij.duckdns.org
uptime-kuma:
image: louislam/uptime-kuma:1
deploy:
@@ -207,7 +207,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.${DOMAIN}`)"
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.kelinreij.duckdns.org`)"
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
- "traefik.http.routers.uptime-kuma.tls=true"
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
@@ -215,7 +215,7 @@ services:
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
# Loki - Log aggregation
# Access at: http://${SERVER_IP}:3100
# Access at: http://192.168.4.4:3100
loki:
image: grafana/loki:2.9.3
deploy:
@@ -248,7 +248,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)"
- "traefik.http.routers.loki.rule=Host(`loki.kelinreij.duckdns.org`)"
- "traefik.http.routers.loki.entrypoints=websecure"
- "traefik.http.routers.loki.tls=true"
- "traefik.http.routers.loki.tls.certresolver=letsencrypt"
@@ -293,9 +293,9 @@ networks:
x-dockge:
urls:
# Proxied URLs (through Traefik)
- http://${SERVER_IP}:9090
- http://${SERVER_IP}:3000
- https://uptime-kuma.${DOMAIN}
- http://${SERVER_IP}:9100/metrics
- http://${SERVER_IP}:8082
- http://${SERVER_IP}:3100
- http://192.168.4.4:9090
- http://192.168.4.4:3000
- https://uptime-kuma.kelinreij.duckdns.org
- http://192.168.4.4:9100/metrics
- http://192.168.4.4:8082
- http://192.168.4.4:3100

View File

@@ -0,0 +1,301 @@
# Monitoring and Observability Services
# Services for monitoring your homelab infrastructure
# Place in /opt/stacks/monitoring/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
# Service Access URLs:
# - Prometheus: http://${SERVER_IP}:9090 (or configure Traefik)
# - Grafana: http://${SERVER_IP}:3000 (or configure Traefik)
# - Uptime Kuma: https://status.${DOMAIN}
# - Node Exporter: http://${SERVER_IP}:9100/metrics
# - cAdvisor: http://${SERVER_IP}:8082
# - Loki: http://${SERVER_IP}:3100
# NOTE: Prometheus, Grafana, Loki use ports because they need to be accessible to other services
# Add Traefik labels if you want https://prometheus.${DOMAIN} access
services:
# Prometheus - Metrics collection and storage
# Access at: http://${SERVER_IP}:9090
prometheus:
image: prom/prometheus:v2.48.1
deploy:
resources:
limits:
cpus: '0.75'
memory: 512M
pids: 1024
reservations:
cpus: '0.25'
memory: 256M
container_name: prometheus
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "9090:9090"
volumes:
- ./config/prometheus:/etc/prometheus
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--web.enable-lifecycle'
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=monitoring"
- "homelab.description=Metrics collection and time-series database"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)"
- "traefik.http.routers.prometheus.entrypoints=websecure"
- "traefik.http.routers.prometheus.tls=true"
- "traefik.http.routers.prometheus.tls.certresolver=letsencrypt"
- "traefik.http.routers.prometheus.middlewares=authelia@docker"
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
# Grafana - Metrics visualization
# Access at: http://${SERVER_IP}:3000
# Default credentials: admin / admin (change on first login)
grafana:
image: grafana/grafana:10.2.3
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: grafana
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
- ./config/grafana/provisioning:/etc/grafana/provisioning
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_ROOT_URL=https://grafana.${DOMAIN}
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel
user: "${PUID}:${PGID}"
depends_on:
- prometheus
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=monitoring"
- "homelab.description=Metrics visualization and dashboards"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls=true"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
- "traefik.http.routers.grafana.middlewares=authelia@docker"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
# Node Exporter - Host metrics exporter
# Metrics at: http://${SERVER_IP}:9100/metrics
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: node-exporter
restart: unless-stopped
networks:
- homelab-network
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
labels:
- "homelab.category=monitoring"
- "homelab.description=Hardware and OS metrics exporter"
# cAdvisor - Container metrics exporter
# Access at: http://${SERVER_IP}:8082
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.47.2
container_name: cadvisor
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "8082:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
- /dev/disk:/dev/disk:ro
privileged: true
devices:
- /dev/kmsg
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=monitoring"
- "homelab.description=Container metrics and performance monitoring"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.${DOMAIN}`)"
- "traefik.http.routers.cadvisor.entrypoints=websecure"
- "traefik.http.routers.cadvisor.tls=true"
- "traefik.http.routers.cadvisor.tls.certresolver=letsencrypt"
- "traefik.http.routers.cadvisor.middlewares=authelia@docker"
- "traefik.http.services.cadvisor.loadbalancer.server.port=8080"
# Uptime Kuma - Uptime monitoring
# Access at: https://uptime-kuma.${DOMAIN}
uptime-kuma:
image: louislam/uptime-kuma:1
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: uptime-kuma
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "3001:3001"
volumes:
- uptime-kuma-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=monitoring"
- "homelab.description=Service uptime monitoring and alerts"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.${DOMAIN}`)"
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
- "traefik.http.routers.uptime-kuma.tls=true"
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
- "traefik.http.routers.uptime-kuma.middlewares=authelia@docker"
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
# Loki - Log aggregation
# Access at: http://${SERVER_IP}:3100
loki:
image: grafana/loki:2.9.3
deploy:
resources:
limits:
cpus: '0.75'
memory: 512M
pids: 1024
reservations:
cpus: '0.25'
memory: 256M
container_name: loki
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "3100:3100"
volumes:
- ./config/loki:/etc/loki
- loki-data:/loki
command: -config.file=/etc/loki/loki-config.yml
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=monitoring"
- "homelab.description=Log aggregation system"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)"
- "traefik.http.routers.loki.entrypoints=websecure"
- "traefik.http.routers.loki.tls=true"
- "traefik.http.routers.loki.tls.certresolver=letsencrypt"
- "traefik.http.routers.loki.middlewares=authelia@docker"
- "traefik.http.services.loki.loadbalancer.server.port=3100"
# Promtail - Log shipper for Loki
# Ships Docker container logs to Loki
promtail:
image: grafana/promtail:2.9.3
container_name: promtail
restart: unless-stopped
networks:
- homelab-network
volumes:
- ./config/promtail:/etc/promtail
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
command: -config.file=/etc/promtail/promtail-config.yml
depends_on:
- loki
labels:
- "homelab.category=monitoring"
- "homelab.description=Log collector for Loki"
volumes:
prometheus-data:
driver: local
grafana-data:
driver: local
uptime-kuma-data:
driver: local
loki-data:
driver: local
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
# Proxied URLs (through Traefik)
- http://${SERVER_IP}:9090
- http://${SERVER_IP}:3000
- https://uptime-kuma.${DOMAIN}
- http://${SERVER_IP}:9100/metrics
- http://${SERVER_IP}:8082
- http://${SERVER_IP}:3100

View File

@@ -10,7 +10,7 @@
services:
# Nextcloud - File sync and collaboration
# Access at: https://nextcloud.${DOMAIN}
# Access at: https://nextcloud.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
nextcloud:
image: nextcloud:28
@@ -40,10 +40,10 @@ services:
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN}
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.kelinreij.duckdns.org
- TRUSTED_PROXIES=172.18.0.0/16
- OVERWRITEPROTOCOL=https
- OVERWRITEHOST=nextcloud.${DOMAIN}
- OVERWRITEHOST=nextcloud.kelinreij.duckdns.org
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
interval: 30s
@@ -60,7 +60,7 @@ services:
- "homelab.description=File sync and collaboration"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)"
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.kelinreij.duckdns.org`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
- "traefik.http.routers.nextcloud.middlewares=authelia@docker"
@@ -68,7 +68,7 @@ services:
- "traefik.http.services.nextcloud.loadbalancer.server.port=8089"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-nextcloud"
- "sablier.group=jasper-nextcloud"
- "sablier.start-on-demand=true"
nextcloud-db:
@@ -90,7 +90,7 @@ services:
- "homelab.description=Nextcloud database"
# Mealie - Recipe manager
# Access at: https://mealie.${DOMAIN}
# Access at: https://mealie.kelinreij.duckdns.org
mealie:
image: ghcr.io/mealie-recipes/mealie:latest
container_name: mealie
@@ -103,10 +103,10 @@ services:
volumes:
- ./mealie/data:/app/data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- BASE_URL=https://mealie.${DOMAIN}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- BASE_URL=https://mealie.kelinreij.duckdns.org
- DB_ENGINE=sqlite
labels:
# TRAEFIK CONFIGURATION
@@ -116,7 +116,7 @@ services:
- "homelab.description=Recipe manager and meal planner"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)"
- "traefik.http.routers.mealie.rule=Host(`mealie.kelinreij.duckdns.org`)"
- "traefik.http.routers.mealie.entrypoints=websecure"
- "traefik.http.routers.mealie.tls.certresolver=letsencrypt"
- "traefik.http.routers.mealie.middlewares=authelia@docker"
@@ -124,11 +124,11 @@ services:
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-mealie"
- "sablier.group=jasper-mealie"
- "sablier.start-on-demand=true"
# WordPress - Blog/website platform
# Access at: https://blog.${DOMAIN}
# Access at: https://blog.kelinreij.duckdns.org
wordpress:
image: wordpress:latest
container_name: wordpress
@@ -161,7 +161,7 @@ services:
- "homelab.description=Blog and website platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.wordpress.rule=Host(`wordpress.${DOMAIN}`)"
- "traefik.http.routers.wordpress.rule=Host(`wordpress.kelinreij.duckdns.org`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.routers.wordpress.middlewares=authelia@docker"
@@ -169,7 +169,7 @@ services:
- "traefik.http.services.wordpress.loadbalancer.server.port=8088"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-wordpress"
- "sablier.group=jasper-wordpress"
- "sablier.start-on-demand=true"
wordpress-db:
@@ -190,7 +190,7 @@ services:
- "homelab.description=WordPress database"
# Gitea - Self-hosted Git service
# Access at: https://git.${DOMAIN}
# Access at: https://git.kelinreij.duckdns.org
gitea:
image: gitea/gitea:latest
deploy:
@@ -214,8 +214,8 @@ services:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
- USER_UID=${PUID}
- USER_GID=${PGID}
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
@@ -237,7 +237,7 @@ services:
- "homelab.description=Self-hosted Git service"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
- "traefik.http.routers.gitea.rule=Host(`gitea.kelinreij.duckdns.org`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea.middlewares=authelia@docker"
@@ -245,7 +245,7 @@ services:
- "traefik.http.services.gitea.loadbalancer.server.port=3010"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-gitea"
- "sablier.group=jasper-gitea"
- "sablier.start-on-demand=true"
gitea-db:
@@ -266,7 +266,7 @@ services:
# Jupyter Lab - Interactive computing notebooks
# Access at: https://jupyter.${DOMAIN}
# Access at: https://jupyter.kelinreij.duckdns.org
# Token displayed in logs on first start
jupyter:
image: jupyter/scipy-notebook:latest
@@ -302,14 +302,14 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.jupyter.rule=Host(`jupyter.${DOMAIN}`)"
- "traefik.http.routers.jupyter.rule=Host(`jupyter.kelinreij.duckdns.org`)"
- "traefik.http.routers.jupyter.entrypoints=websecure"
- "traefik.http.routers.jupyter.tls.certresolver=letsencrypt"
- "traefik.http.routers.jupyter.middlewares=authelia@docker"
- "traefik.http.services.jupyter.loadbalancer.server.port=8890"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-jupyter"
- "sablier.group=jasper-jupyter"
- "sablier.start-on-demand=true"
volumes:
@@ -326,13 +326,13 @@ networks:
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://nextcloud.${DOMAIN}
- https://${SERVER_IP}:8089
- https://mealie.${DOMAIN}
- https://${SERVER_IP}:9000
- https://wordpress.${DOMAIN}
- https://${SERVER_IP}:8088
- https://gitea.${DOMAIN}
- https://${SERVER_IP}:3010
- https://jupyter.${DOMAIN}
- https://${SERVER_IP}:8890
- https://nextcloud.kelinreij.duckdns.org
- https://192.168.4.4:8089
- https://mealie.kelinreij.duckdns.org
- https://192.168.4.4:9000
- https://wordpress.kelinreij.duckdns.org
- https://192.168.4.4:8088
- https://gitea.kelinreij.duckdns.org
- https://192.168.4.4:3010
- https://jupyter.kelinreij.duckdns.org
- https://192.168.4.4:8890

View File

@@ -0,0 +1,338 @@
# Productivity and Content Management Services
# Place in /opt/stacks/productivity/docker-compose.yml
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
# Nextcloud - File sync and collaboration
# Access at: https://nextcloud.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
nextcloud:
image: nextcloud:28
deploy:
resources:
limits:
cpus: '1.5'
memory: 1G
pids: 2048
reservations:
cpus: '0.75'
memory: 512M
container_name: nextcloud
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8089:80"
volumes:
- ./nextcloud/html:/var/www/html
- /mnt/nextcloud-data:/var/www/html/data # Large data on separate drive
environment:
- MYSQL_HOST=nextcloud-db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN}
- TRUSTED_PROXIES=172.18.0.0/16
- OVERWRITEPROTOCOL=https
- OVERWRITEHOST=nextcloud.${DOMAIN}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- nextcloud-db
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=File sync and collaboration"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
- "traefik.http.routers.nextcloud.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.nextcloud.loadbalancer.server.port=8089"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-nextcloud"
- "sablier.start-on-demand=true"
nextcloud-db:
image: mariadb:10.11
container_name: nextcloud-db
restart: no
networks:
- homelab-network
volumes:
- nextcloud-db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${NEXTCLOUD_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
labels:
- "homelab.category=productivity"
- "homelab.description=Nextcloud database"
# Mealie - Recipe manager
# Access at: https://mealie.${DOMAIN}
mealie:
image: ghcr.io/mealie-recipes/mealie:latest
container_name: mealie
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "9000:9000"
volumes:
- ./mealie/data:/app/data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- BASE_URL=https://mealie.${DOMAIN}
- DB_ENGINE=sqlite
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=Recipe manager and meal planner"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)"
- "traefik.http.routers.mealie.entrypoints=websecure"
- "traefik.http.routers.mealie.tls.certresolver=letsencrypt"
- "traefik.http.routers.mealie.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-mealie"
- "sablier.start-on-demand=true"
# WordPress - Blog/website platform
# Access at: https://blog.${DOMAIN}
wordpress:
image: wordpress:latest
container_name: wordpress
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8088:80"
volumes:
- ./wordpress/html:/var/www/html
environment:
- WORDPRESS_DB_HOST=wordpress-db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
- WORDPRESS_DB_NAME=wordpress
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- wordpress-db
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=Blog and website platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.wordpress.rule=Host(`wordpress.${DOMAIN}`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.routers.wordpress.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.wordpress.loadbalancer.server.port=8088"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-wordpress"
- "sablier.start-on-demand=true"
wordpress-db:
image: mariadb:10.11
container_name: wordpress-db
restart: no
networks:
- homelab-network
volumes:
- wordpress-db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${WORDPRESS_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=${WORDPRESS_DB_PASSWORD}
labels:
- "homelab.category=productivity"
- "homelab.description=WordPress database"
# Gitea - Self-hosted Git service
# Access at: https://git.${DOMAIN}
gitea:
image: gitea/gitea:latest
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
pids: 512
reservations:
cpus: '0.25'
memory: 128M
container_name: gitea
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "3010:3000"
volumes:
- ./gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
- USER_UID=${PUID}
- USER_GID=${PGID}
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- gitea-db
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=Self-hosted Git service"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.gitea.loadbalancer.server.port=3010"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-gitea"
- "sablier.start-on-demand=true"
gitea-db:
image: postgres:14-alpine
container_name: gitea-db
restart: no
networks:
- homelab-network
volumes:
- gitea-db-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=${GITEA_DB_PASSWORD}
- POSTGRES_DB=gitea
labels:
- "homelab.category=productivity"
- "homelab.description=Gitea database"
# Jupyter Lab - Interactive computing notebooks
# Access at: https://jupyter.${DOMAIN}
# Token displayed in logs on first start
jupyter:
image: jupyter/scipy-notebook:latest
container_name: jupyter
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8890:8888"
volumes:
- ./config/jupyter:/home/jovyan/work
environment:
- JUPYTER_ENABLE_LAB=yes
- GRANT_SUDO=yes
user: root
command: start-notebook.sh --NotebookApp.token='${JUPYTER_TOKEN}'
# Uncomment for GPU support (NVIDIA, requires nvidia-container-toolkit)
# runtime: nvidia
# devices:
# - /dev/nvidia0:/dev/nvidia0
# - /dev/nvidiactl:/dev/nvidiactl
# Add these to environment above:
# - NVIDIA_VISIBLE_DEVICES=all
# - NVIDIA_DRIVER_CAPABILITIES=compute,utility
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=productivity"
- "homelab.description=Jupyter Lab for data science and ML"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.jupyter.rule=Host(`jupyter.${DOMAIN}`)"
- "traefik.http.routers.jupyter.entrypoints=websecure"
- "traefik.http.routers.jupyter.tls.certresolver=letsencrypt"
- "traefik.http.routers.jupyter.middlewares=authelia@docker"
- "traefik.http.services.jupyter.loadbalancer.server.port=8890"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-jupyter"
- "sablier.start-on-demand=true"
volumes:
nextcloud-db-data:
wordpress-db-data:
gitea-db-data:
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://nextcloud.${DOMAIN}
- https://${SERVER_IP}:8089
- https://mealie.${DOMAIN}
- https://${SERVER_IP}:9000
- https://wordpress.${DOMAIN}
- https://${SERVER_IP}:8088
- https://gitea.${DOMAIN}
- https://${SERVER_IP}:3010
- https://jupyter.${DOMAIN}
- https://${SERVER_IP}:8890

View File

@@ -1,6 +1,6 @@
services:
# Tdarr Server - Distributed transcoding server
# Access at: https://tdarr.${DOMAIN}
# Access at: https://tdarr.kelinreij.duckdns.org
tdarr-server:
image: ghcr.io/haveagitgat/tdarr:latest
container_name: tdarr-server
@@ -18,9 +18,9 @@ services:
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp # Transcode cache on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- serverIP=0.0.0.0
- serverPort=8266
- webUIPort=8265
@@ -35,13 +35,13 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.tdarr.rule=Host(`tdarr.${DOMAIN}`)"
- "traefik.http.routers.tdarr.rule=Host(`tdarr.kelinreij.duckdns.org`)"
- "traefik.http.routers.tdarr.entrypoints=websecure"
- "traefik.http.routers.tdarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.tdarr.middlewares=authelia@docker"
- "traefik.http.services.tdarr.loadbalancer.server.port=8265"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.group=jasper-tdarr"
- "sablier.start-on-demand=true"
# Tdarr Node - Transcoding worker
@@ -58,9 +58,9 @@ services:
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- nodeID=MainNode
- nodeIP=0.0.0.0
- nodePort=8267
@@ -70,11 +70,11 @@ services:
- homelab.category=media
- homelab.description=Tdarr transcoding worker node
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.group=jasper-tdarr"
- "sablier.start-on-demand=true"
# Unmanic - Another transcoding option
# Access at: https://unmanic.${DOMAIN}
# Access at: https://unmanic.kelinreij.duckdns.org
unmanic:
image: josh5/unmanic:latest
container_name: unmanic
@@ -89,9 +89,9 @@ services:
- /mnt/media:/library
- /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# ==========================================
@@ -103,13 +103,13 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.unmanic.rule=Host(`unmanic.${DOMAIN}`)"
- "traefik.http.routers.unmanic.rule=Host(`unmanic.kelinreij.duckdns.org`)"
- "traefik.http.routers.unmanic.entrypoints=websecure"
- "traefik.http.routers.unmanic.tls.certresolver=letsencrypt"
- "traefik.http.routers.unmanic.middlewares=authelia@docker"
- "traefik.http.services.unmanic.loadbalancer.server.port=8889"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-unmanic"
- "sablier.group=jasper-unmanic"
- "sablier.start-on-demand=true"
networks:
@@ -120,7 +120,7 @@ networks:
x-dockge:
urls:
- https://tdarr.${DOMAIN}
- http://${SERVER_IP}:8265
- https://unmanic.${DOMAIN}
- http://${SERVER_IP}:8888
- https://tdarr.kelinreij.duckdns.org
- http://192.168.4.4:8265
- https://unmanic.kelinreij.duckdns.org
- http://192.168.4.4:8888

View File

@@ -0,0 +1,126 @@
services:
# Tdarr Server - Distributed transcoding server
# Access at: https://tdarr.${DOMAIN}
tdarr-server:
image: ghcr.io/haveagitgat/tdarr:latest
container_name: tdarr-server
restart: no
networks:
- homelab-network
- traefik-network
ports:
- 8265:8265 # Web UI port
- 8266:8266 # Server port
volumes:
- ./tdarr/server:/app/server
- ./tdarr/configs:/app/configs
- ./tdarr/logs:/app/logs
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp # Transcode cache on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- serverIP=0.0.0.0
- serverPort=8266
- webUIPort=8265
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Distributed transcoding server"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.tdarr.rule=Host(`tdarr.${DOMAIN}`)"
- "traefik.http.routers.tdarr.entrypoints=websecure"
- "traefik.http.routers.tdarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.tdarr.middlewares=authelia@docker"
- "traefik.http.services.tdarr.loadbalancer.server.port=8265"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.start-on-demand=true"
# Tdarr Node - Transcoding worker
# No web UI - controlled by server
tdarr-node:
image: ghcr.io/haveagitgat/tdarr_node:latest
container_name: tdarr-node
restart: unless-stopped
networks:
- homelab-network
volumes:
- ./tdarr/configs:/app/configs
- ./tdarr/logs:/app/logs
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- nodeID=MainNode
- nodeIP=0.0.0.0
- nodePort=8267
- serverIP=tdarr-server
- serverPort=8266
labels:
- homelab.category=media
- homelab.description=Tdarr transcoding worker node
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
- "sablier.start-on-demand=true"
# Unmanic - Another transcoding option
# Access at: https://unmanic.${DOMAIN}
unmanic:
image: josh5/unmanic:latest
container_name: unmanic
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8889:8888"
volumes:
- ./unmanic/config:/config
- /mnt/media:/library
- /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=media"
- "homelab.description=Library optimization and transcoding"
- "com.centurylinklabs.watchtower.enable=true"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.unmanic.rule=Host(`unmanic.${DOMAIN}`)"
- "traefik.http.routers.unmanic.entrypoints=websecure"
- "traefik.http.routers.unmanic.tls.certresolver=letsencrypt"
- "traefik.http.routers.unmanic.middlewares=authelia@docker"
- "traefik.http.services.unmanic.loadbalancer.server.port=8889"
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-unmanic"
- "sablier.start-on-demand=true"
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
- https://tdarr.${DOMAIN}
- http://${SERVER_IP}:8265
- https://unmanic.${DOMAIN}
- http://${SERVER_IP}:8888

View File

@@ -8,7 +8,7 @@
services:
# Backrest - Backup solution for restic
# Access at: https://backrest.${DOMAIN}
# Access at: https://backrest.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
backrest:
image: garethgeorge/backrest:latest
@@ -28,7 +28,7 @@ services:
environment:
- BACKREST_DATA=/data
- BACKREST_CONFIG=/config/config.json
- TZ=${TZ}
- TZ=America/New_York
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9898/"]
interval: 30s
@@ -43,7 +43,7 @@ services:
- "homelab.description=Backup management with restic"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.backrest.rule=Host(`backrest.${DOMAIN}`)"
- "traefik.http.routers.backrest.rule=Host(`backrest.kelinreij.duckdns.org`)"
- "traefik.http.routers.backrest.entrypoints=websecure"
- "traefik.http.routers.backrest.tls.certresolver=letsencrypt"
- "traefik.http.routers.backrest.middlewares=authelia@docker"
@@ -51,11 +51,11 @@ services:
- "traefik.http.services.backrest.loadbalancer.server.port=9898"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-backrest"
- "sablier.group=jasper-backrest"
- "sablier.start-on-demand=true"
# Duplicati - Backup solution
# Access at: https://duplicati.${DOMAIN}
# Access at: https://duplicati.kelinreij.duckdns.org
duplicati:
image: lscr.io/linuxserver/duplicati:2.0.7
container_name: duplicati
@@ -71,9 +71,9 @@ services:
- /mnt:/source/mnt:ro
- /mnt/backups:/backups
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8200/"]
interval: 30s
@@ -88,7 +88,7 @@ services:
- "homelab.description=Backup software with encryption"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.duplicati.rule=Host(`duplicati.${DOMAIN}`)"
- "traefik.http.routers.duplicati.rule=Host(`duplicati.kelinreij.duckdns.org`)"
- "traefik.http.routers.duplicati.entrypoints=websecure"
- "traefik.http.routers.duplicati.tls.certresolver=letsencrypt"
- "traefik.http.routers.duplicati.middlewares=authelia@docker"
@@ -96,7 +96,7 @@ services:
- "traefik.http.services.duplicati.loadbalancer.server.port=8200"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-duplicati"
- "sablier.group=jasper-duplicati"
- "sablier.start-on-demand=true"
# Form.io - Form builder
@@ -132,7 +132,7 @@ services:
# Traefik labels
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.formio.rule=Host(`forms.${DOMAIN}`)"
- "traefik.http.routers.formio.rule=Host(`forms.kelinreij.duckdns.org`)"
- "traefik.http.routers.formio.entrypoints=websecure"
- "traefik.http.routers.formio.tls.certresolver=letsencrypt"
- "traefik.http.routers.formio.middlewares=authelia@docker"
@@ -140,7 +140,7 @@ services:
- "traefik.http.services.formio.loadbalancer.server.port=3001"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-formio"
- "sablier.group=jasper-formio"
- "sablier.start-on-demand=true"
formio-mongo:
@@ -154,7 +154,7 @@ services:
- "homelab.description=Form.io database"
# Bitwarden (Vaultwarden) - Password manager
# Access at: https://vault.${DOMAIN}
# Access at: https://vault.kelinreij.duckdns.org
# Note: SSO disabled for browser extension and mobile app compatibility
vaultwarden:
@@ -169,7 +169,7 @@ services:
volumes:
- ./vaultwarden/data:/data
environment:
- DOMAIN=https://vault.${DOMAIN}
- DOMAIN=https://vault.kelinreij.duckdns.org
- SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED}
- INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED}
- ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN}
@@ -196,7 +196,7 @@ services:
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`vault.${DOMAIN}`)"
- "traefik.http.routers.vaultwarden.rule=Host(`vault.kelinreij.duckdns.org`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "traefik.http.routers.vaultwarden.tls=true"
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
@@ -205,7 +205,7 @@ services:
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-vaultwarden"
- "sablier.group=jasper-vaultwarden"
- "sablier.start-on-demand=true"
# Authelia Redis - Session storage for Authelia
@@ -236,11 +236,11 @@ networks:
x-dockge:
urls:
- https://backrest.${DOMAIN}
- https://${SERVER_IP}:9898
- https://duplicati.${DOMAIN}
- https://${SERVER_IP}:8200
- https://forms.${DOMAIN}
- https://${SERVER_IP}:3002
- https://vault.${DOMAIN}
- https://${SERVER_IP}:8091
- https://backrest.kelinreij.duckdns.org
- https://192.168.4.4:9898
- https://duplicati.kelinreij.duckdns.org
- https://192.168.4.4:8200
- https://forms.kelinreij.duckdns.org
- https://192.168.4.4:3002
- https://vault.kelinreij.duckdns.org
- https://192.168.4.4:8091

View File

@@ -0,0 +1,246 @@
# Backup and Utility Services
# Place in /opt/stacks/utilities/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
# Backrest - Backup solution for restic
# Access at: https://backrest.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "9898:9898"
volumes:
- ./backrest/data:/data
- ./backrest/config:/config
- /opt/stacks:/opt/stacks:ro # Backup source
- /mnt:/mnt:ro # Backup additional drives
- backrest-cache:/cache
environment:
- BACKREST_DATA=/data
- BACKREST_CONFIG=/config/config.json
- TZ=${TZ}
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9898/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=utilities"
- "homelab.description=Backup management with restic"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.backrest.rule=Host(`backrest.${DOMAIN}`)"
- "traefik.http.routers.backrest.entrypoints=websecure"
- "traefik.http.routers.backrest.tls.certresolver=letsencrypt"
- "traefik.http.routers.backrest.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.backrest.loadbalancer.server.port=9898"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-backrest"
- "sablier.start-on-demand=true"
# Duplicati - Backup solution
# Access at: https://duplicati.${DOMAIN}
duplicati:
image: lscr.io/linuxserver/duplicati:2.0.7
container_name: duplicati
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8200:8200"
volumes:
- ./duplicati/config:/config
- /opt/stacks:/source/stacks:ro
- /mnt:/source/mnt:ro
- /mnt/backups:/backups
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8200/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=utilities"
- "homelab.description=Backup software with encryption"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.duplicati.rule=Host(`duplicati.${DOMAIN}`)"
- "traefik.http.routers.duplicati.entrypoints=websecure"
- "traefik.http.routers.duplicati.tls.certresolver=letsencrypt"
- "traefik.http.routers.duplicati.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.duplicati.loadbalancer.server.port=8200"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-duplicati"
- "sablier.start-on-demand=true"
# Form.io - Form builder
# Uncomment and configure if formio/formio image becomes available
formio:
image: calipseo/formio:latest
container_name: formio
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "3002:3001"
environment:
- MONGO=mongodb://formio-mongo:27017/formio
- JWT_SECRET=${FORMIO_JWT_SECRET}
- DB_SECRET=${FORMIO_DB_SECRET}
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3001/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- formio-mongo
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=utilities"
- "homelab.description=Form builder platform"
# Traefik labels
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.formio.rule=Host(`forms.${DOMAIN}`)"
- "traefik.http.routers.formio.entrypoints=websecure"
- "traefik.http.routers.formio.tls.certresolver=letsencrypt"
- "traefik.http.routers.formio.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.formio.loadbalancer.server.port=3001"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-formio"
- "sablier.start-on-demand=true"
formio-mongo:
image: mongo:4.4
container_name: formio-mongo
restart: unless-stopped
networks:
- homelab-network
labels:
- "homelab.category=utilities"
- "homelab.description=Form.io database"
# Bitwarden (Vaultwarden) - Password manager
# Access at: https://vault.${DOMAIN}
# Note: SSO disabled for browser extension and mobile app compatibility
vaultwarden:
image: vaultwarden/server:1.30.1
container_name: vaultwarden
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8091:80"
volumes:
- ./vaultwarden/data:/data
environment:
- DOMAIN=https://vault.${DOMAIN}
- SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED}
- INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED}
- ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN}
# SMTP disabled - uncomment and configure to enable email
# - SMTP_HOST=${SMTP_HOST}
# - SMTP_FROM=${SMTP_FROM}
# - SMTP_PORT=${SMTP_PORT}
# - SMTP_SECURITY=${SMTP_SECURITY}
# - SMTP_USERNAME=${SMTP_USERNAME}
# - SMTP_PASSWORD=${SMTP_PASSWORD}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "homelab.category=utilities"
- "homelab.description=Self-hosted password manager (Bitwarden)"
# Traefik reverse proxy (comment/uncomment to disable/enable)
# If Traefik is on a remote server: these labels are NOT USED;
# configure external yml files in /traefik/dynamic folder instead.
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`vault.${DOMAIN}`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "traefik.http.routers.vaultwarden.tls=true"
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
# SSO disabled for browser extension and mobile app compatibility
# - "traefik.http.routers.vaultwarden.middlewares=authelia@docker"
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-vaultwarden"
- "sablier.start-on-demand=true"
# Authelia Redis - Session storage for Authelia
# No web UI - backend service
# authelia-redis:
# image: redis:7-alpine
# container_name: authelia-redis
# restart: unless-stopped
# networks:
# - homelab-network
# volumes:
# - authelia-redis-data:/data
# command: redis-server --save 60 1 --loglevel warning
# labels:
# - homelab.category=utilities
# - homelab.description=Session storage for Authelia
volumes:
backrest-cache: null
formio-mongo-data: null
authelia-redis-data: null
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
- https://backrest.${DOMAIN}
- https://${SERVER_IP}:9898
- https://duplicati.${DOMAIN}
- https://${SERVER_IP}:8200
- https://forms.${DOMAIN}
- https://${SERVER_IP}:3002
- https://vault.${DOMAIN}
- https://${SERVER_IP}:8091

View File

@@ -37,7 +37,7 @@ services:
- OPENVPN_USER=${SURFSHARK_USERNAME}
- OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES}
- TZ=${TZ}
- TZ=America/New_York
# TRAEFIK CONFIGURATION
labels:
# Service metadata
@@ -46,7 +46,7 @@ services:
- "homelab.description=VPN client for secure downloads"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.${DOMAIN}`)"
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.kelinreij.duckdns.org`)"
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
- "traefik.http.routers.qbittorrent.tls=true"
- "traefik.http.routers.qbittorrent.middlewares=authelia@docker"
@@ -54,7 +54,7 @@ services:
- "traefik.http.services.qbittorrent.loadbalancer.server.port=8081"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-qbittorrent"
- "sablier.group=jasper-qbittorrent"
- "sablier.sessionDuration=1h"
# qBittorrent - Torrent client
@@ -77,9 +77,9 @@ services:
- ./qbittorrent/config:/config
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
- WEBUI_PORT=8080
depends_on:
- gluetun
@@ -92,5 +92,5 @@ networks:
x-dockge:
urls:
- https://qbit.${DOMAIN}
- https://${SERVER_IP}:8081
- https://qbit.kelinreij.duckdns.org
- https://192.168.4.4:8081

View File

@@ -0,0 +1,96 @@
# VPN Stack
# VPN client and VPN-routed download clients
# Place in /opt/stacks/vpn/docker-compose.yml
# RESTART POLICY GUIDE:
# - unless-stopped: Core infrastructure services that should always run
# - no: Services with Sablier lazy loading (start on-demand)
# - See individual service comments for specific reasoning
services:
# Gluetun - VPN client (Surfshark)
# Routes download clients through VPN for security
# VPN service should always run to maintain secure connections
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
networks:
- homelab-network
- traefik-network
ports:
- "8888:8888/tcp" # HTTP proxy
- "8388:8388/tcp" # Shadowsocks
- "8388:8388/udp" # Shadowsocks
- "8081:8080" # qBittorrent web UI
- "6881:6881" # qBittorrent
- "6881:6881/udp" # qBittorrent
volumes:
- ./gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=surfshark
- VPN_TYPE=openvpn
- OPENVPN_USER=${SURFSHARK_USERNAME}
- OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES}
- TZ=${TZ}
# TRAEFIK CONFIGURATION
labels:
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=downloaders"
- "homelab.description=VPN client for secure downloads"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.${DOMAIN}`)"
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
- "traefik.http.routers.qbittorrent.tls=true"
- "traefik.http.routers.qbittorrent.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.qbittorrent.loadbalancer.server.port=8081"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-qbittorrent"
- "sablier.sessionDuration=1h"
# qBittorrent - Torrent client
# Routes through Gluetun VPN
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
pids: 1024
reservations:
cpus: '0.50'
memory: 256M
container_name: qbittorrent
restart: unless-stopped
network_mode: "service:gluetun" # Routes through VPN in same compose file
volumes:
- ./qbittorrent/config:/config
- /mnt/downloads:/downloads
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- WEBUI_PORT=8080
depends_on:
- gluetun
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
- https://qbit.${DOMAIN}
- https://${SERVER_IP}:8081

View File

@@ -1,6 +1,6 @@
services:
# DokuWiki - Wiki without database
# Access at: https://wiki.${DOMAIN}
# Access at: https://wiki.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
dokuwiki:
image: lscr.io/linuxserver/dokuwiki:latest
@@ -14,9 +14,9 @@ services:
volumes:
- ./dokuwiki/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# TRAEFIK CONFIGURATION
# Service metadata
@@ -25,7 +25,7 @@ services:
- "homelab.description=File-based wiki"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.${DOMAIN}`)"
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.kelinreij.duckdns.org`)"
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
@@ -33,11 +33,11 @@ services:
- "traefik.http.services.dokuwiki.loadbalancer.server.port=8087"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-dokuwiki"
- "sablier.group=jasper-dokuwiki"
- "sablier.start-on-demand=true"
# BookStack - Documentation platform
# Access at: https://docs.${DOMAIN}
# Access at: https://docs.kelinreij.duckdns.org
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
bookstack:
image: lscr.io/linuxserver/bookstack:latest
@@ -51,9 +51,9 @@ services:
volumes:
- ./bookstack/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- APP_URL=https://bookstack.${DOMAIN}
- PUID=1000
- PGID=1000
- APP_URL=https://bookstack.kelinreij.duckdns.org
- DB_HOST=bookstack-db
- DB_PORT=3306
- DB_DATABASE=bookstack
@@ -76,7 +76,7 @@ services:
- "homelab.description=Documentation and wiki platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.bookstack.rule=Host(`bookstack.${DOMAIN}`)"
- "traefik.http.routers.bookstack.rule=Host(`bookstack.kelinreij.duckdns.org`)"
- "traefik.http.routers.bookstack.entrypoints=websecure"
- "traefik.http.routers.bookstack.tls.certresolver=letsencrypt"
- "traefik.http.routers.bookstack.middlewares=authelia@docker"
@@ -84,7 +84,7 @@ services:
- "traefik.http.services.bookstack.loadbalancer.server.port=6875"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-bookstack"
- "sablier.group=jasper-bookstack"
- "sablier.start-on-demand=true"
bookstack-db:
@@ -105,7 +105,7 @@ services:
- "homelab.description=BookStack database"
# MediaWiki - Wiki platform
# Access at: https://mediawiki.${DOMAIN}
# Access at: https://mediawiki.kelinreij.duckdns.org
mediawiki:
image: mediawiki:latest
container_name: mediawiki
@@ -139,7 +139,7 @@ services:
- "homelab.description=MediaWiki platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.${DOMAIN}`)"
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.kelinreij.duckdns.org`)"
- "traefik.http.routers.mediawiki.entrypoints=websecure"
- "traefik.http.routers.mediawiki.tls.certresolver=letsencrypt"
- "traefik.http.routers.mediawiki.middlewares=authelia@docker"
@@ -147,7 +147,7 @@ services:
- "traefik.http.services.mediawiki.loadbalancer.server.port=8086"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-mediawiki"
- "sablier.group=jasper-mediawiki"
- "sablier.start-on-demand=true"
mediawiki-db:
@@ -180,9 +180,9 @@ networks:
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://bookstack.${DOMAIN}
- https://${SERVER_IP}:6875
- https://dokuwiki.${DOMAIN}
- https://${SERVER_IP}:8087
- https://mediawiki.${DOMAIN}
- https://${SERVER_IP}:8086
- https://bookstack.kelinreij.duckdns.org
- https://192.168.4.4:6875
- https://dokuwiki.kelinreij.duckdns.org
- https://192.168.4.4:8087
- https://mediawiki.kelinreij.duckdns.org
- https://192.168.4.4:8086

View File

@@ -0,0 +1,188 @@
services:
# DokuWiki - Wiki without database
# Access at: https://wiki.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
dokuwiki:
image: lscr.io/linuxserver/dokuwiki:latest
container_name: dokuwiki
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8087:80"
volumes:
- ./dokuwiki/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=File-based wiki"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.${DOMAIN}`)"
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.dokuwiki.loadbalancer.server.port=8087"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-dokuwiki"
- "sablier.start-on-demand=true"
# BookStack - Documentation platform
# Access at: https://docs.${DOMAIN}
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "6875:80"
volumes:
- ./bookstack/config:/config
environment:
- PUID=${PUID}
- PGID=${PGID}
- APP_URL=https://bookstack.${DOMAIN}
- DB_HOST=bookstack-db
- DB_PORT=3306
- DB_DATABASE=bookstack
- DB_USERNAME=bookstack
- DB_PASSWORD=${BOOKSTACK_DB_PASSWORD}
- APP_KEY=base64:NsYD8+8MAvtBhK8xw9p8pxQDy4x8aOQi/78M3CsseAw=
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- bookstack-db
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=Documentation and wiki platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.bookstack.rule=Host(`bookstack.${DOMAIN}`)"
- "traefik.http.routers.bookstack.entrypoints=websecure"
- "traefik.http.routers.bookstack.tls.certresolver=letsencrypt"
- "traefik.http.routers.bookstack.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.bookstack.loadbalancer.server.port=6875"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-bookstack"
- "sablier.start-on-demand=true"
bookstack-db:
image: mariadb:10.11
container_name: bookstack-db
restart: no
networks:
- homelab-network
volumes:
- bookstack-db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${BOOKSTACK_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=bookstack
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=${BOOKSTACK_DB_PASSWORD}
labels:
- "homelab.category=productivity"
- "homelab.description=BookStack database"
# MediaWiki - Wiki platform
# Access at: https://mediawiki.${DOMAIN}
mediawiki:
image: mediawiki:latest
container_name: mediawiki
restart: no
networks:
- homelab-network
- traefik-network
ports:
- "8086:80"
volumes:
- ./mediawiki/images:/var/www/html/images
- ./mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php
environment:
- MEDIAWIKI_DB_HOST=mediawiki-db
- MEDIAWIKI_DB_NAME=mediawiki
- MEDIAWIKI_DB_USER=mediawiki
- MEDIAWIKI_DB_PASSWORD=${MEDIAWIKI_DB_PASSWORD}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- mediawiki-db
labels:
# TRAEFIK CONFIGURATION
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=productivity"
- "homelab.description=MediaWiki platform"
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.${DOMAIN}`)"
- "traefik.http.routers.mediawiki.entrypoints=websecure"
- "traefik.http.routers.mediawiki.tls.certresolver=letsencrypt"
- "traefik.http.routers.mediawiki.middlewares=authelia@docker"
# Service configuration
- "traefik.http.services.mediawiki.loadbalancer.server.port=8086"
# Sablier configuration
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-mediawiki"
- "sablier.start-on-demand=true"
mediawiki-db:
image: mariadb:10.11
container_name: mediawiki-db
restart: no
networks:
- homelab-network
volumes:
- mediawiki-db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MEDIAWIKI_DB_ROOT_PASSWORD}
- MYSQL_DATABASE=mediawiki
- MYSQL_USER=mediawiki
- MYSQL_PASSWORD=${MEDIAWIKI_DB_PASSWORD}
labels:
- "homelab.category=productivity"
- "homelab.description=MediaWiki database"
volumes:
bookstack-db-data:
mediawiki-db-data:
networks:
homelab-network:
external: true
traefik-network:
external: true
x-dockge:
urls:
# Proxied URLs (through Traefik)
- https://bookstack.${DOMAIN}
- https://${SERVER_IP}:6875
- https://dokuwiki.${DOMAIN}
- https://${SERVER_IP}:8087
- https://mediawiki.${DOMAIN}
- https://${SERVER_IP}:8086