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:
@@ -21,8 +21,8 @@ REMOTE_SERVER_PASSWORD=${DEFAULT_PASSWORD}
|
||||
|
||||
# Domain Configuration
|
||||
DUCKDNS_SUBDOMAINS=yourdomain # Without .duckdns.org
|
||||
DOMAIN=${DUCKDNS_SUBDOMAINS}.duckdns.org
|
||||
DUCKDNS_TOKEN=your-duckdns-token
|
||||
DOMAIN=${DUCKDNS_SUBDOMAINS}.duckdns.org
|
||||
|
||||
# Default credentials (used by multiple services for easier setup)
|
||||
DEFAULT_USER=admin
|
||||
@@ -55,7 +55,7 @@ SMTP_EMAIL_SECURITY=starttls
|
||||
ACME_EMAIL=${DEFAULT_EMAIL}
|
||||
|
||||
# Authelia Admin Account
|
||||
# Used by ez-homelab.sh for easy deployment
|
||||
# These 4 Used by ez-homelab.sh for easy deployment
|
||||
# Not used by the Authelia container directly
|
||||
ADMIN_EMAIL=${DEFAULT_EMAIL} # Used for admin user account
|
||||
AUTHELIA_ADMIN_USER=${DEFAULT_USER}
|
||||
@@ -76,6 +76,10 @@ AUTHELIA_STORAGE_ENCRYPTION_KEY=generate-with-openssl-rand-hex-64
|
||||
# SURFSHARK_PRIVATE_KEY=your-wireguard-private-key
|
||||
# SURFSHARK_ADDRESSES=10.14.0.2/16
|
||||
|
||||
# What domains Homepage will accept requests from
|
||||
# comma separated list NO SPACES!!!
|
||||
HOMEPAGE_ALLOWED_HOSTS=homepage.${DOMAIN},${SERVER_IP}:3003
|
||||
|
||||
# #######################################
|
||||
# #### OTHER OPTIONAL CONFIGURATIONS ####
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
# 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$GABqY9zhf83XWZQM5B8vlg$ADtVApDgotqKUb/sefku8hMYwRBDr5rqKIAuFghKzrM" # Default password: admin123
|
||||
email: admin@example.com
|
||||
${AUTHELIA_ADMIN_USER}:
|
||||
displayname: "${AUTHELIA_ADMIN_USER}"
|
||||
password: "${AUTHELIA_ADMIN_PASSWORD}"
|
||||
email: "${AUTHELIA_ADMIN_EMAIL}"
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
236
docker-compose/alternatives/docker-compose.yml.template
Normal file
236
docker-compose/alternatives/docker-compose.yml.template
Normal 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
|
||||
|
||||
28
docker-compose/core/.env.template
Normal file
28
docker-compose/core/.env.template
Normal 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
|
||||
171
docker-compose/core/README.md
Normal file
171
docker-compose/core/README.md
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
48
docker-compose/core/backup.sh
Executable 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"
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
127
docker-compose/dashboards/docker-compose.yml.template
Normal file
127
docker-compose/dashboards/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -13,6 +13,6 @@
|
||||
# host: 192.168.4.5
|
||||
# port: 2375
|
||||
|
||||
#${SERVER_HOSTNAME}:
|
||||
#jasper:
|
||||
# host: 192.168.4.11
|
||||
# port: 2375
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'] = '';
|
||||
@@ -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) ®
|
||||
... …
|
||||
|
||||
@@ -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&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}&btnI=lucky
|
||||
user :user:{NAME}
|
||||
|
||||
# To support VoIP/SIP/TEL links
|
||||
callto callto://{NAME}
|
||||
tel tel:{NAME}
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"display": "standalone"
|
||||
}
|
||||
@@ -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')),
|
||||
);
|
||||
@@ -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
|
||||
|
||||
@@ -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}'";
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -1,11 +0,0 @@
|
||||
#Add URL schemes you want to be recognized as links here
|
||||
|
||||
http
|
||||
https
|
||||
telnet
|
||||
gopher
|
||||
wais
|
||||
ftp
|
||||
ed2k
|
||||
irc
|
||||
ldap
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
# sample kubernetes config
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
# pve:
|
||||
# url: https://proxmox.host.or.ip:8006
|
||||
# token: username@pam!Token ID
|
||||
# secret: secret
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
# For configuration options and examples, please see:
|
||||
# https://gethomepage.dev/configs/settings/
|
||||
|
||||
providers:
|
||||
openweathermap: openweathermapapikey
|
||||
weatherapi: weatherapiapikey
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
63
docker-compose/dockge/docker-compose.yml.template
Normal file
63
docker-compose/dockge/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
258
docker-compose/homeassistant/docker-compose.yml.template
Normal file
258
docker-compose/homeassistant/docker-compose.yml.template
Normal 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}
|
||||
@@ -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:
|
||||
|
||||
294
docker-compose/infrastructure/docker-compose.yml.template
Normal file
294
docker-compose/infrastructure/docker-compose.yml.template
Normal 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
|
||||
@@ -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:
|
||||
|
||||
384
docker-compose/media-management/docker-compose.yml.template
Normal file
384
docker-compose/media-management/docker-compose.yml.template
Normal 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
|
||||
@@ -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:
|
||||
|
||||
139
docker-compose/media/docker-compose.yml.template
Normal file
139
docker-compose/media/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
|
||||
301
docker-compose/monitoring/docker-compose.yml.template
Normal file
301
docker-compose/monitoring/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
|
||||
338
docker-compose/productivity/docker-compose.yml.template
Normal file
338
docker-compose/productivity/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
126
docker-compose/transcoders/docker-compose.yml.template
Normal file
126
docker-compose/transcoders/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
246
docker-compose/utilities/docker-compose.yml.template
Normal file
246
docker-compose/utilities/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
96
docker-compose/vpn/docker-compose.yml.template
Normal file
96
docker-compose/vpn/docker-compose.yml.template
Normal 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
|
||||
@@ -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
|
||||
|
||||
188
docker-compose/wikis/docker-compose.yml.template
Normal file
188
docker-compose/wikis/docker-compose.yml.template
Normal 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
|
||||
240
docs/script-audit-report.md
Normal file
240
docs/script-audit-report.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# EZ-Homelab Script Audit Report
|
||||
## Generated: 30 January 2026
|
||||
|
||||
### Executive Summary
|
||||
The `ez-homelab.sh` script is a comprehensive Bash-based deployment tool for the EZ-Homelab project. It handles system setup, Docker configuration, and multi-stage service deployment. The script supports three main deployment modes with varying complexity. While functional for infrastructure-only deployments (Option 3), the core-only deployment (Option 2) has critical issues with Authelia secret generation and configuration that prevent successful deployment.
|
||||
|
||||
### Script Architecture
|
||||
|
||||
#### Global Variables & Constants
|
||||
- **Color codes**: RED, GREEN, YELLOW, BLUE, NC for console output formatting
|
||||
- **Logging functions**: `log_info()`, `log_success()`, `log_warning()`, `log_error()`
|
||||
- **Deployment flags**: DEPLOY_CORE, DEPLOY_INFRASTRUCTURE, DEPLOY_DASHBOARDS, SETUP_STACKS
|
||||
- **Configuration variables**: DOMAIN, SERVER_IP, ADMIN_USER, etc.
|
||||
- **Path variables**: SCRIPT_DIR, REPO_DIR, ACTUAL_USER
|
||||
|
||||
#### Core Functions
|
||||
|
||||
##### 1. `replace_env_placeholders()`
|
||||
**Purpose**: Replaces `${VAR}` placeholders in files with actual environment variable values
|
||||
**Process**:
|
||||
- Takes file path as argument
|
||||
- Uses `grep` to find all `${VAR}` patterns
|
||||
- Checks if each variable exists in environment
|
||||
- Uses `sed` for replacement: `s|\${VAR}|${!VAR}|g`
|
||||
- Accumulates missing variables in `MISSING_VARS_SUMMARY`
|
||||
**Issues**:
|
||||
- Only reports missing variables at end, doesn't fail deployment
|
||||
- No validation of replacement success
|
||||
|
||||
##### 2. `generate_shared_ca()`
|
||||
**Purpose**: Creates shared Certificate Authority for multi-server TLS
|
||||
**Process**:
|
||||
- Creates `/opt/stacks/core/shared-ca/` directory
|
||||
- Generates 4096-bit RSA CA key and certificate (365 days validity)
|
||||
- Sets ownership to `$ACTUAL_USER:$ACTUAL_USER`
|
||||
**Output**: ca.pem, ca-key.pem files
|
||||
|
||||
##### 3. `setup_multi_server_tls()`
|
||||
**Purpose**: Configures TLS for remote Docker access using shared CA
|
||||
**Process**:
|
||||
- Prompts for core server IP if not set
|
||||
- Tests SSH connectivity (key auth first, then password)
|
||||
- Fetches CA certificates from core server via SCP
|
||||
- Calls `setup_docker_tls()` if successful
|
||||
**Issues**:
|
||||
- Complex SSH authentication logic
|
||||
- No fallback if CA fetch fails
|
||||
- TLS_ISSUES_SUMMARY populated but not always accurate
|
||||
|
||||
##### 4. `load_env_file()`
|
||||
**Purpose**: Loads existing configuration from `.env` file
|
||||
**Process**:
|
||||
- Checks for `$REPO_DIR/.env` existence
|
||||
- Sources the file if found
|
||||
- Displays current configuration values
|
||||
- Returns 0 if file exists, 1 if not
|
||||
**Issues**: No validation of loaded values
|
||||
|
||||
##### 5. `save_env_file()`
|
||||
**Purpose**: Persists configuration to `.env` file
|
||||
**Process**:
|
||||
- Creates `.env` from `.env.example` if needed
|
||||
- Updates values using `sed` replacements
|
||||
- For core deployment: generates Authelia secrets and password hash
|
||||
**Critical Issue**: Authelia secret generation is here, but may not be called in all deployment paths
|
||||
|
||||
##### 6. `prompt_for_values()`
|
||||
**Purpose**: Interactive configuration collection
|
||||
**Process**:
|
||||
- Shows current/default values
|
||||
- Allows user to accept defaults or enter custom values
|
||||
- Handles sensitive inputs (passwords) with `-s` flag
|
||||
- Sets ADMIN_* variables for core deployment
|
||||
**Issues**: Complex logic with many conditional branches
|
||||
|
||||
##### 7. `system_setup()`
|
||||
**Purpose**: Performs initial system configuration (requires root)
|
||||
**Process**:
|
||||
1. System package updates
|
||||
2. Installs prerequisites (curl, wget, git, etc.)
|
||||
3. Installs/configures Docker and Docker Compose
|
||||
4. Generates shared CA
|
||||
5. Configures Docker TLS
|
||||
6. Sets up UFW firewall
|
||||
7. Configures automatic updates
|
||||
8. Creates Docker networks
|
||||
9. Sets directory ownership
|
||||
**Issues**:
|
||||
- Requires logout/login for Docker group changes
|
||||
- No rollback on failure
|
||||
|
||||
##### 8. `deploy_dockge()`
|
||||
**Purpose**: Deploys Dockge stack management interface
|
||||
**Process**:
|
||||
- Copies compose file and .env to `/opt/dockge/`
|
||||
- Replaces placeholders
|
||||
- Runs `docker compose up -d`
|
||||
**Output**: Dockge service running
|
||||
|
||||
##### 9. `deploy_core()`
|
||||
**Purpose**: Deploys core infrastructure stack
|
||||
**Process**:
|
||||
1. Copies compose file and .env to `/opt/stacks/core/`
|
||||
2. Copies Traefik and Authelia config templates
|
||||
3. Replaces placeholders in all config files
|
||||
4. Generates shared CA
|
||||
5. Replaces Authelia-specific secrets and user data
|
||||
6. Runs `docker compose up -d`
|
||||
**Critical Issues**:
|
||||
- Assumes Authelia secrets exist in environment
|
||||
- No validation that secrets were generated
|
||||
- Complex placeholder replacement logic
|
||||
|
||||
##### 10. `deploy_infrastructure()` / `deploy_dashboards()`
|
||||
**Purpose**: Deploy additional service stacks
|
||||
**Process**: Similar to deploy_core but simpler
|
||||
- Copy files, replace placeholders, deploy
|
||||
**Issues**: Conditional Authelia middleware removal when core not deployed
|
||||
|
||||
##### 11. `setup_docker_tls()`
|
||||
**Purpose**: Configures Docker daemon for TLS
|
||||
**Process**:
|
||||
1. Creates TLS directory
|
||||
2. Uses shared CA or generates local CA
|
||||
3. Generates server and client certificates
|
||||
4. Updates Docker daemon.json
|
||||
5. Modifies systemd service for TCP 2376
|
||||
6. Restarts Docker service
|
||||
|
||||
##### 12. `setup_stacks_for_dockge()`
|
||||
**Purpose**: Prepares all service stacks for Dockge management
|
||||
**Process**:
|
||||
- Iterates through predefined stack list
|
||||
- Copies compose files and configs
|
||||
- Replaces placeholders
|
||||
- Prepares but doesn't deploy stacks
|
||||
|
||||
### Deployment Flow Analysis
|
||||
|
||||
#### Option 1: Default Setup
|
||||
**Flags**: DEPLOY_CORE=true, DEPLOY_INFRASTRUCTURE=true, DEPLOY_DASHBOARDS=true, SETUP_STACKS=true
|
||||
**Flow**:
|
||||
1. System setup (if needed)
|
||||
2. Prompt for values
|
||||
3. Save env file (generates Authelia secrets)
|
||||
4. Deploy Dockge
|
||||
5. Deploy core (uses generated secrets)
|
||||
6. Deploy infrastructure
|
||||
7. Deploy dashboards
|
||||
8. Setup stacks for Dockge
|
||||
|
||||
#### Option 2: Core Only
|
||||
**Flags**: DEPLOY_CORE=true, DEPLOY_INFRASTRUCTURE=false, DEPLOY_DASHBOARDS=true, SETUP_STACKS=true
|
||||
**Flow**:
|
||||
1. System setup (if needed)
|
||||
2. Prompt for values
|
||||
3. Save env file (generates Authelia secrets)
|
||||
4. Deploy Dockge
|
||||
5. Deploy core (uses generated secrets)
|
||||
6. Deploy dashboards
|
||||
7. Setup stacks for Dockge
|
||||
|
||||
#### Option 3: Infrastructure Only
|
||||
**Flags**: DEPLOY_CORE=false, DEPLOY_INFRASTRUCTURE=true, DEPLOY_DASHBOARDS=false, SETUP_STACKS=true
|
||||
**Flow**:
|
||||
1. System setup (if needed)
|
||||
2. Prompt for values
|
||||
3. Save env file (no Authelia secrets generated)
|
||||
4. Setup multi-server TLS
|
||||
5. Deploy Dockge
|
||||
6. Deploy infrastructure
|
||||
7. Setup stacks for Dockge
|
||||
|
||||
### Critical Issues Identified
|
||||
|
||||
#### 1. Authelia Secret Generation Timing (Option 2)
|
||||
**Problem**: In Option 2, `save_env_file()` is called and should generate Authelia secrets, but the deployment may fail if secrets aren't properly set.
|
||||
**Root Cause**: The `save_env_file()` function generates secrets only when `DEPLOY_CORE=true`, but the generation logic may not execute or persist correctly.
|
||||
**Impact**: Authelia container fails to start due to missing JWT_SECRET, SESSION_SECRET, or STORAGE_ENCRYPTION_KEY
|
||||
|
||||
#### 2. Environment Variable Persistence
|
||||
**Problem**: After `save_env_file()`, the script sources the .env file, but there may be a timing issue where variables aren't available for `deploy_core()`.
|
||||
**Evidence**: The script does `source "$REPO_DIR/.env"` in `perform_deployment()`, but if secrets weren't saved properly, they'll be empty.
|
||||
|
||||
#### 3. Placeholder Replacement Order
|
||||
**Problem**: `replace_env_placeholders()` is called during deployment, but if environment variables are missing, replacements fail silently.
|
||||
**Impact**: Configuration files contain literal `${VAR}` strings instead of actual values.
|
||||
|
||||
#### 4. Authelia Password Hash Generation
|
||||
**Problem**: Password hash generation happens in `save_env_file()`, but requires Docker to be running and Authelia image to be available.
|
||||
**Issues**:
|
||||
- May fail if Docker isn't ready
|
||||
- Uses complex docker run command that could timeout
|
||||
- No fallback if hash generation fails
|
||||
|
||||
#### 5. Multi-Server TLS Complexity
|
||||
**Problem**: `setup_multi_server_tls()` has complex SSH logic that can fail in multiple ways.
|
||||
**Issues**:
|
||||
- SSH key vs password detection unreliable
|
||||
- No retry logic for connection failures
|
||||
- Error reporting doesn't clearly indicate resolution steps
|
||||
|
||||
#### 6. Directory Creation Race Conditions
|
||||
**Problem**: Script creates directories with sudo, then tries to write files as regular user.
|
||||
**Potential Issue**: Permission conflicts if ownership isn't set correctly.
|
||||
|
||||
### Recommendations
|
||||
|
||||
#### Immediate Fixes for Option 2
|
||||
1. **Add Secret Validation**: After `save_env_file()`, validate that all required Authelia secrets exist before proceeding with deployment.
|
||||
|
||||
2. **Improve Error Handling**: Make `replace_env_placeholders()` fail deployment if critical variables are missing.
|
||||
|
||||
3. **Add Authelia Health Check**: After core deployment, verify Authelia container is running and healthy.
|
||||
|
||||
#### Structural Improvements
|
||||
1. **Separate Secret Generation**: Move Authelia secret generation to a dedicated function called before deployment.
|
||||
|
||||
2. **Add Pre-deployment Validation**: Create a validation function that checks all required environment variables and Docker state before starting deployment.
|
||||
|
||||
3. **Simplify TLS Setup**: Reduce complexity in multi-server TLS setup with better error handling and user guidance.
|
||||
|
||||
4. **Add Rollback Capability**: Implement cleanup functions for failed deployments.
|
||||
|
||||
#### Code Quality
|
||||
1. **Reduce Function Complexity**: Break down large functions like `deploy_core()` into smaller, testable units.
|
||||
|
||||
2. **Add Logging**: Increase verbosity for debugging deployment issues.
|
||||
|
||||
3. **Configuration Management**: Consider using a configuration file format (YAML/JSON) instead of .env for complex setups.
|
||||
|
||||
### Testing Recommendations
|
||||
1. **Unit Test Functions**: Test individual functions like `replace_env_placeholders()` and `generate_shared_ca()` in isolation.
|
||||
|
||||
2. **Integration Testing**: Test each deployment option in a clean environment.
|
||||
|
||||
3. **Error Scenario Testing**: Test failure modes (missing Docker, network issues, invalid credentials).
|
||||
|
||||
### Conclusion
|
||||
The `ez-homelab.sh` script is a solid foundation for automated homelab deployment, but Option 2 (Core Only) has critical issues with Authelia secret management that prevent reliable deployment. The script needs focused improvements in error handling, validation, and secret generation to achieve the reliability required for critical infrastructure deployment.
|
||||
56
docs/todo.md
Normal file
56
docs/todo.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# EZ-Homelab Script Fixes & Improvements
|
||||
|
||||
## Critical Fixes (Implement First)
|
||||
- [x] **Secret Validation**: Add validation after `save_env_file()` to ensure Authelia secrets exist before deployment
|
||||
- [x] **Better Placeholder Error Handling**: Make `replace_env_placeholders()` fail deployment if critical variables are missing
|
||||
- [x] **Debug Logging**: Add toggleable comprehensive logging to file for troubleshooting
|
||||
- [x] **Simplified Placeholder Logic**: Streamline the replacement process in `deploy_core()`
|
||||
- [x] **Standardized .env Placeholders**: Update .env.example and .env with consistent placeholder format
|
||||
- [x] **File Permission Issues**: Fix ownership problems when copying files as root then accessing as user
|
||||
- [x] **REMOTE_SERVER_HOSTNAME Error**: Remove multi-server config files from core deployments to prevent critical errors
|
||||
- [x] **Docker Compose Variable Expansion**: Remove AUTHELIA_ADMIN_PASSWORD from core stack .env to prevent argon2id hash expansion warnings
|
||||
|
||||
## High Priority Issues
|
||||
- [ ] **Authelia Password Hash Generation Reliability**
|
||||
- Issue: Docker-based password hash generation can fail if Docker isn't ready or Authelia image pull fails
|
||||
- Impact: Deployment fails with cryptic errors
|
||||
- Fix: Add retry logic and fallback to local hash generation
|
||||
|
||||
- [x] **Environment Variable Persistence Issues**
|
||||
- Issue: Timing issues with when .env is sourced vs when variables are needed
|
||||
- Impact: Variables not available when functions expect them
|
||||
- Fix: Implemented safe .env loading that doesn't expand special characters + filtered .env files per stack
|
||||
|
||||
## Medium Priority Issues
|
||||
- [ ] **Multi-Server TLS Setup Complexity**
|
||||
- Issue: Complex SSH authentication logic with multiple failure points
|
||||
- Impact: TLS setup often fails, preventing remote Docker access
|
||||
- Fix: Simplify to use SSH config files and better error messages
|
||||
|
||||
- [ ] **Directory Permission Race Conditions**
|
||||
- Issue: Script creates directories with sudo then writes as regular user
|
||||
- Impact: Permission conflicts during file operations
|
||||
- Fix: Consistent ownership handling throughout
|
||||
|
||||
- [ ] **Missing Pre-deployment Validation**
|
||||
- Issue: No comprehensive checks before starting deployment
|
||||
- Impact: Failures occur mid-deployment after time investment
|
||||
- Fix: Add validation phase checking Docker, networks, environment
|
||||
|
||||
## Low Priority Issues
|
||||
- [ ] **Function Complexity**
|
||||
- Issue: Large functions like `deploy_core()` and `prompt_for_values()` are hard to test/debug
|
||||
- Impact: Bugs are harder to isolate and fix
|
||||
- Fix: Break down into smaller, focused functions
|
||||
|
||||
- [ ] **No Rollback Capability**
|
||||
- Issue: Failed deployments leave partial state
|
||||
- Impact: Manual cleanup required, risk of inconsistent state
|
||||
- Fix: Add cleanup functions for failed deployments
|
||||
|
||||
## Implementation Notes
|
||||
- Start with Critical Fixes to make Option 2 deployment reliable
|
||||
- Test each fix individually before moving to next
|
||||
- Use debug logging to validate fixes work correctly
|
||||
- Update documentation after each major change
|
||||
- Consider backward compatibility with existing deployments
|
||||
89
instructions.md
Normal file
89
instructions.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Manual installation
|
||||
|
||||
```bash
|
||||
sudo apt update && sudo apt upgrade -y && sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
|
||||
sudo curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker $USER
|
||||
sudo usermod -aG sudo $USER
|
||||
|
||||
# Log out and back in, or run: newgrp docker
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/kelinfoxy/AI-Homelab.git
|
||||
cd AI-Homelab
|
||||
cp .env.example .env
|
||||
nano .env # Edit all required variables
|
||||
|
||||
sudo mkdir -p /opt/stacks /mnt/{media,database,downloads,backups}
|
||||
sudo chown -R $USER:$USER /opt/stacks /mnt
|
||||
docker network create traefik-network
|
||||
docker network create homelab-network
|
||||
docker network create dockerproxy-network
|
||||
docker network create media-network
|
||||
|
||||
# Deploy
|
||||
sudo mkdir -p /opt/stacks/core
|
||||
sudo cp docker-compose/core/docker-compose.yml /opt/stacks/core/docker-compose.yml
|
||||
sudo cp -r config-templates/traefik /opt/stacks/core/
|
||||
sudo cp .env /opt/stacks/core/
|
||||
sudo mkdir -p /opt/stacks/infrastructure
|
||||
sudo cp docker-compose/infrastructure/docker-compose.yml /opt/stacks/infrastructure/docker-compose.yml
|
||||
sudo cp .env /opt/stacks/infrastructure/
|
||||
sudo mkdir -p /opt/stacks/dashboards
|
||||
sudo cp docker-compose/dashboards/docker-compose.yml /opt/stacks/dashboards/docker-compose.yml
|
||||
sudo cp -r config-templates/homepage /opt/stacks/dashboards/
|
||||
sudo cp .env /opt/stacks/dashboards/
|
||||
mkdir -p /opt/stacks/core/authelia
|
||||
sudo cp config-templates/authelia/* /opt/stacks/core/authelia/
|
||||
|
||||
# Generate password hash (takes 30-60 seconds)
|
||||
docker run --rm authelia/authelia:4.37 authelia crypto hash generate argon2 --password 'YourSecurePassword'
|
||||
|
||||
|
||||
# Edit users_database.yml
|
||||
nano /opt/stacks/core/authelia/users_database.yml
|
||||
|
||||
# Replace password hash and email in the users section:
|
||||
users:
|
||||
admin:
|
||||
displayname: "Admin User"
|
||||
password: "$argon2id$v=19$m=65536,t=3,p=4$..." # Your hash here
|
||||
email: your.email@example.com
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
|
||||
# Update Traefik email
|
||||
sed -i "s/admin@example.com/$ACME_EMAIL/" /opt/stacks/core/traefik/traefik.yml
|
||||
|
||||
# Replace Homepage domain variables
|
||||
find /opt/stacks/dashboards/homepage -type f \( -name "*.yaml" -o -name "*.yml" \) -exec sed -i "s/{{HOMEPAGE_VAR_DOMAIN}}/$DOMAIN/g" {} \;
|
||||
|
||||
cd /opt/stacks/core
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/stacks/infrastructure
|
||||
docker compose up -d
|
||||
|
||||
cd /opt/stacks/dashboards
|
||||
docker compose up -d
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
@@ -383,7 +383,9 @@ save_env_file() {
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%AUTHELIA_SESSION_SECRET=.*%AUTHELIA_SESSION_SECRET=$AUTHELIA_SESSION_SECRET%" "$REPO_DIR/.env"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%AUTHELIA_STORAGE_ENCRYPTION_KEY=.*%AUTHELIA_STORAGE_ENCRYPTION_KEY=$AUTHELIA_STORAGE_ENCRYPTION_KEY%" "$REPO_DIR/.env"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%# AUTHELIA_ADMIN_USER=.*%AUTHELIA_ADMIN_USER=$ADMIN_USER%" "$REPO_DIR/.env"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%AUTHELIA_ADMIN_USER=.*%AUTHELIA_ADMIN_USER=$ADMIN_USER%" "$REPO_DIR/.env"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%# AUTHELIA_ADMIN_EMAIL=.*%AUTHELIA_ADMIN_EMAIL=$ADMIN_EMAIL%" "$REPO_DIR/.env"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%AUTHELIA_ADMIN_EMAIL=.*%AUTHELIA_ADMIN_EMAIL=$ADMIN_EMAIL%" "$REPO_DIR/.env"
|
||||
|
||||
# Generate password hash if needed
|
||||
if [ -z "$AUTHELIA_ADMIN_PASSWORD" ]; then
|
||||
@@ -404,6 +406,10 @@ save_env_file() {
|
||||
sudo -u "$ACTUAL_USER" sed -i "s%AUTHELIA_ADMIN_PASSWORD=.*%AUTHELIA_ADMIN_PASSWORD=\"$AUTHELIA_ADMIN_PASSWORD\"%" "$REPO_DIR/.env"
|
||||
fi
|
||||
|
||||
# Update HOMEPAGE_ALLOWED_HOSTS with expanded values
|
||||
HOMEPAGE_ALLOWED_HOSTS="homepage.${DOMAIN},${SERVER_IP}:3003"
|
||||
sudo -u "$ACTUAL_USER" sed -i "s|HOMEPAGE_ALLOWED_HOSTS=.*|HOMEPAGE_ALLOWED_HOSTS=$HOMEPAGE_ALLOWED_HOSTS|" "$REPO_DIR/.env"
|
||||
|
||||
debug_log "Configuration saved to .env file"
|
||||
log_success "Configuration saved to .env file"
|
||||
}
|
||||
@@ -946,7 +952,6 @@ deploy_dashboards() {
|
||||
# Remove remote server entries from homepage services for single-server setup
|
||||
if [ -z "${REMOTE_SERVER_HOSTNAME:-}" ]; then
|
||||
sed -i '/\${REMOTE_SERVER_HOSTNAME}/d' /opt/stacks/dashboards/homepage/services.yaml
|
||||
sed -i '/\${REMOTE_SERVER_HOSTNAME}/d' /opt/stacks/dashboards/homepage/homepage/services.yaml
|
||||
log_info "Single-server setup - removed remote server entries from homepage services"
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user