diff --git a/.env.example b/.env.example index a35b1cd..d6cd746 100644 --- a/.env.example +++ b/.env.example @@ -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 #### diff --git a/config-templates/authelia/users_database.yml b/config-templates/authelia/users_database.yml index 1443893..3bb6855 100644 --- a/config-templates/authelia/users_database.yml +++ b/config-templates/authelia/users_database.yml @@ -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 diff --git a/docker-compose/README.md b/docker-compose/README.md index 4e2c3b9..78c69d4 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -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 diff --git a/docker-compose/alternatives/docker-compose.yml b/docker-compose/alternatives/docker-compose.yml index b4f0df9..0f7a384 100644 --- a/docker-compose/alternatives/docker-compose.yml +++ b/docker-compose/alternatives/docker-compose.yml @@ -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: diff --git a/docker-compose/alternatives/docker-compose.yml.template b/docker-compose/alternatives/docker-compose.yml.template new file mode 100644 index 0000000..b4f0df9 --- /dev/null +++ b/docker-compose/alternatives/docker-compose.yml.template @@ -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 + diff --git a/docker-compose/core/.env.template b/docker-compose/core/.env.template new file mode 100644 index 0000000..9bef1d5 --- /dev/null +++ b/docker-compose/core/.env.template @@ -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 \ No newline at end of file diff --git a/docker-compose/core/README.md b/docker-compose/core/README.md new file mode 100644 index 0000000..5c3b0aa --- /dev/null +++ b/docker-compose/core/README.md @@ -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 diff --git a/docker-compose/core/authelia/configuration.yml b/docker-compose/core/authelia/configuration.yml index 5402935..6141a83 100644 --- a/docker-compose/core/authelia/configuration.yml +++ b/docker-compose/core/authelia/configuration.yml @@ -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 diff --git a/docker-compose/core/authelia/users_database.yml b/docker-compose/core/authelia/users_database.yml index 1981cfb..a11aefb 100644 --- a/docker-compose/core/authelia/users_database.yml +++ b/docker-compose/core/authelia/users_database.yml @@ -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 diff --git a/docker-compose/core/authelia/users_database.yml.template b/docker-compose/core/authelia/users_database.yml.template index 1981cfb..d144df1 100644 --- a/docker-compose/core/authelia/users_database.yml.template +++ b/docker-compose/core/authelia/users_database.yml.template @@ -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 diff --git a/docker-compose/core/backup.sh b/docker-compose/core/backup.sh new file mode 100755 index 0000000..74405bb --- /dev/null +++ b/docker-compose/core/backup.sh @@ -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" \ No newline at end of file diff --git a/docker-compose/core/docker-compose.yml b/docker-compose/core/docker-compose.yml index a930ed0..04df3be 100644 --- a/docker-compose/core/docker-compose.yml +++ b/docker-compose/core/docker-compose.yml @@ -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: diff --git a/docker-compose/core/docker-compose.yml.template b/docker-compose/core/docker-compose.yml.template index a930ed0..b140da8 100644 --- a/docker-compose/core/docker-compose.yml.template +++ b/docker-compose/core/docker-compose.yml.template @@ -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: diff --git a/docker-compose/core/traefik/acme.json b/docker-compose/core/traefik/acme.json deleted file mode 100644 index 3a63215..0000000 --- a/docker-compose/core/traefik/acme.json +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/docker-compose/core/traefik/traefik.yml b/docker-compose/core/traefik/traefik.yml index 4f2d6bb..1dc73a0 100644 --- a/docker-compose/core/traefik/traefik.yml +++ b/docker-compose/core/traefik/traefik.yml @@ -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: diff --git a/docker-compose/dashboards/docker-compose.yml b/docker-compose/dashboards/docker-compose.yml index 08b0dcb..2115446 100644 --- a/docker-compose/dashboards/docker-compose.yml +++ b/docker-compose/dashboards/docker-compose.yml @@ -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: diff --git a/docker-compose/dashboards/docker-compose.yml.template b/docker-compose/dashboards/docker-compose.yml.template new file mode 100644 index 0000000..08b0dcb --- /dev/null +++ b/docker-compose/dashboards/docker-compose.yml.template @@ -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 diff --git a/docker-compose/dashboards/homepage/authelia/configuration.yml b/docker-compose/dashboards/homepage/authelia/configuration.yml deleted file mode 100644 index 500d4aa..0000000 --- a/docker-compose/dashboards/homepage/authelia/configuration.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/authelia/users_database.yml b/docker-compose/dashboards/homepage/authelia/users_database.yml deleted file mode 100644 index dec2f75..0000000 --- a/docker-compose/dashboards/homepage/authelia/users_database.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/docker.yaml b/docker-compose/dashboards/homepage/docker.yaml index 7080ea2..8666f25 100644 --- a/docker-compose/dashboards/homepage/docker.yaml +++ b/docker-compose/dashboards/homepage/docker.yaml @@ -13,6 +13,6 @@ # host: 192.168.4.5 # port: 2375 -#${SERVER_HOSTNAME}: +#jasper: # host: 192.168.4.11 # port: 2375 diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/.htaccess b/docker-compose/dashboards/homepage/dokuwiki/conf/.htaccess deleted file mode 100644 index 9f49132..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/.htaccess +++ /dev/null @@ -1,8 +0,0 @@ -## no access to the conf directory - - Require all denied - - - Order allow,deny - Deny from all - diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php b/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php deleted file mode 100644 index bd65f3e..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php +++ /dev/null @@ -1,10 +0,0 @@ -# acl.auth.php -# -# 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 diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php.dist b/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php.dist deleted file mode 100644 index 14344d7..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/acl.auth.php.dist +++ /dev/null @@ -1,21 +0,0 @@ -# acl.auth.php -# -# 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 diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/acronyms.conf b/docker-compose/dashboards/homepage/dokuwiki/conf/acronyms.conf deleted file mode 100644 index 2ecdeda..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/acronyms.conf +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/dokuwiki.php b/docker-compose/dashboards/homepage/dokuwiki/conf/dokuwiki.php deleted file mode 100644 index 6990b23..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/dokuwiki.php +++ /dev/null @@ -1,187 +0,0 @@ - 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'] = ''; diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/entities.conf b/docker-compose/dashboards/homepage/dokuwiki/conf/entities.conf deleted file mode 100644 index c0d653c..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/entities.conf +++ /dev/null @@ -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) ® -... … - diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/interwiki.conf b/docker-compose/dashboards/homepage/dokuwiki/conf/interwiki.conf deleted file mode 100644 index a509056..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/interwiki.conf +++ /dev/null @@ -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} diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/license.php b/docker-compose/dashboards/homepage/dokuwiki/conf/license.php deleted file mode 100644 index 845c59f..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/license.php +++ /dev/null @@ -1,38 +0,0 @@ - '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, -); - diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/local.php b/docker-compose/dashboards/homepage/dokuwiki/conf/local.php deleted file mode 100644 index 1f33c80..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/local.php +++ /dev/null @@ -1,13 +0,0 @@ - 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')), -); diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/mime.conf b/docker-compose/dashboards/homepage/dokuwiki/conf/mime.conf deleted file mode 100644 index b271322..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/mime.conf +++ /dev/null @@ -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 - diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/mysql.conf.php.example b/docker-compose/dashboards/homepage/dokuwiki/conf/mysql.conf.php.example deleted file mode 100644 index eef99fc..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/mysql.conf.php.example +++ /dev/null @@ -1,253 +0,0 @@ - -# 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 diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/users.auth.php.dist b/docker-compose/dashboards/homepage/dokuwiki/conf/users.auth.php.dist deleted file mode 100644 index 8231aa5..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/users.auth.php.dist +++ /dev/null @@ -1,10 +0,0 @@ -# users.auth.php -# -# Don't modify the lines above -# -# Userfile -# -# Format: -# -# login:passwordhash:Real Name:email:groups,comma,separated - diff --git a/docker-compose/dashboards/homepage/dokuwiki/conf/wordblock.conf b/docker-compose/dashboards/homepage/dokuwiki/conf/wordblock.conf deleted file mode 100644 index 3040fa0..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/conf/wordblock.conf +++ /dev/null @@ -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) diff --git a/docker-compose/dashboards/homepage/dokuwiki/docker-compose.yml b/docker-compose/dashboards/homepage/dokuwiki/docker-compose.yml deleted file mode 100644 index c6e9a3c..0000000 --- a/docker-compose/dashboards/homepage/dokuwiki/docker-compose.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/docker-compose/dashboards/homepage/homepage/bookmarks.yaml b/docker-compose/dashboards/homepage/homepage/bookmarks.yaml deleted file mode 100644 index 68e770e..0000000 --- a/docker-compose/dashboards/homepage/homepage/bookmarks.yaml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/homepage/custom.css b/docker-compose/dashboards/homepage/homepage/custom.css deleted file mode 100644 index 760f301..0000000 --- a/docker-compose/dashboards/homepage/homepage/custom.css +++ /dev/null @@ -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; -} diff --git a/docker-compose/dashboards/homepage/homepage/custom.js b/docker-compose/dashboards/homepage/homepage/custom.js deleted file mode 100644 index e69de29..0000000 diff --git a/docker-compose/dashboards/homepage/homepage/docker.yaml b/docker-compose/dashboards/homepage/homepage/docker.yaml deleted file mode 100644 index 7080ea2..0000000 --- a/docker-compose/dashboards/homepage/homepage/docker.yaml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/homepage/kubernetes.yaml b/docker-compose/dashboards/homepage/homepage/kubernetes.yaml deleted file mode 100644 index aca6e82..0000000 --- a/docker-compose/dashboards/homepage/homepage/kubernetes.yaml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# sample kubernetes config diff --git a/docker-compose/dashboards/homepage/homepage/proxmox.yaml b/docker-compose/dashboards/homepage/homepage/proxmox.yaml deleted file mode 100644 index 90aacd7..0000000 --- a/docker-compose/dashboards/homepage/homepage/proxmox.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -# pve: -# url: https://proxmox.host.or.ip:8006 -# token: username@pam!Token ID -# secret: secret diff --git a/docker-compose/dashboards/homepage/homepage/settings.yaml b/docker-compose/dashboards/homepage/homepage/settings.yaml deleted file mode 100644 index 2e828c0..0000000 --- a/docker-compose/dashboards/homepage/homepage/settings.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# For configuration options and examples, please see: -# https://gethomepage.dev/configs/settings/ - -providers: - openweathermap: openweathermapapikey - weatherapi: weatherapiapikey diff --git a/docker-compose/dashboards/homepage/homepage/widgets.yaml b/docker-compose/dashboards/homepage/homepage/widgets.yaml deleted file mode 100644 index ff02225..0000000 --- a/docker-compose/dashboards/homepage/homepage/widgets.yaml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/loki/loki-config.yml b/docker-compose/dashboards/homepage/loki/loki-config.yml deleted file mode 100644 index 2d7c57c..0000000 --- a/docker-compose/dashboards/homepage/loki/loki-config.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/prometheus/prometheus.yml b/docker-compose/dashboards/homepage/prometheus/prometheus.yml deleted file mode 100644 index ab3ee50..0000000 --- a/docker-compose/dashboards/homepage/prometheus/prometheus.yml +++ /dev/null @@ -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' diff --git a/docker-compose/dashboards/homepage/promtail/promtail-config.yml b/docker-compose/dashboards/homepage/promtail/promtail-config.yml deleted file mode 100644 index 19f4f24..0000000 --- a/docker-compose/dashboards/homepage/promtail/promtail-config.yml +++ /dev/null @@ -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[^/]+)/.*' - 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 diff --git a/docker-compose/dashboards/homepage/redis/redis.conf b/docker-compose/dashboards/homepage/redis/redis.conf deleted file mode 100644 index d6990bb..0000000 --- a/docker-compose/dashboards/homepage/redis/redis.conf +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/services.yaml b/docker-compose/dashboards/homepage/services.yaml index a9844c5..c035ed7 100644 --- a/docker-compose/dashboards/homepage/services.yaml +++ b/docker-compose/dashboards/homepage/services.yaml @@ -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 diff --git a/docker-compose/dashboards/homepage/homepage/services.yaml b/docker-compose/dashboards/homepage/services.yaml.template similarity index 81% rename from docker-compose/dashboards/homepage/homepage/services.yaml rename to docker-compose/dashboards/homepage/services.yaml.template index 562f3e0..a9844c5 100644 --- a/docker-compose/dashboards/homepage/homepage/services.yaml +++ b/docker-compose/dashboards/homepage/services.yaml.template @@ -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 diff --git a/docker-compose/dashboards/homepage/traefik/dynamic/external-host-homeassistant.yml b/docker-compose/dashboards/homepage/traefik/dynamic/external-host-homeassistant.yml deleted file mode 100644 index 783903c..0000000 --- a/docker-compose/dashboards/homepage/traefik/dynamic/external-host-homeassistant.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/traefik/dynamic/external-host-production.yml b/docker-compose/dashboards/homepage/traefik/dynamic/external-host-production.yml deleted file mode 100644 index 5fd1121..0000000 --- a/docker-compose/dashboards/homepage/traefik/dynamic/external-host-production.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/traefik/dynamic/routes.yml b/docker-compose/dashboards/homepage/traefik/dynamic/routes.yml deleted file mode 100644 index cdaf10e..0000000 --- a/docker-compose/dashboards/homepage/traefik/dynamic/routes.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/traefik/dynamic/sablier.yml b/docker-compose/dashboards/homepage/traefik/dynamic/sablier.yml deleted file mode 100644 index 85fb385..0000000 --- a/docker-compose/dashboards/homepage/traefik/dynamic/sablier.yml +++ /dev/null @@ -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 diff --git a/docker-compose/dashboards/homepage/traefik/traefik.yml b/docker-compose/dashboards/homepage/traefik/traefik.yml deleted file mode 100644 index 4ca22cb..0000000 --- a/docker-compose/dashboards/homepage/traefik/traefik.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/docker-compose/dockge/docker-compose.yml b/docker-compose/dockge/docker-compose.yml index 52cea6f..03219be 100644 --- a/docker-compose/dockge/docker-compose.yml +++ b/docker-compose/dockge/docker-compose.yml @@ -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" diff --git a/docker-compose/dockge/docker-compose.yml.template b/docker-compose/dockge/docker-compose.yml.template new file mode 100644 index 0000000..52cea6f --- /dev/null +++ b/docker-compose/dockge/docker-compose.yml.template @@ -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 \ No newline at end of file diff --git a/docker-compose/homeassistant/docker-compose.yml b/docker-compose/homeassistant/docker-compose.yml index 50d8c7a..5b42687 100644 --- a/docker-compose/homeassistant/docker-compose.yml +++ b/docker-compose/homeassistant/docker-compose.yml @@ -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} \ No newline at end of file + - 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 \ No newline at end of file diff --git a/docker-compose/homeassistant/docker-compose.yml.template b/docker-compose/homeassistant/docker-compose.yml.template new file mode 100644 index 0000000..50d8c7a --- /dev/null +++ b/docker-compose/homeassistant/docker-compose.yml.template @@ -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} \ No newline at end of file diff --git a/docker-compose/infrastructure/docker-compose.yml b/docker-compose/infrastructure/docker-compose.yml index 628a623..6664700 100644 --- a/docker-compose/infrastructure/docker-compose.yml +++ b/docker-compose/infrastructure/docker-compose.yml @@ -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: diff --git a/docker-compose/infrastructure/docker-compose.yml.template b/docker-compose/infrastructure/docker-compose.yml.template new file mode 100644 index 0000000..628a623 --- /dev/null +++ b/docker-compose/infrastructure/docker-compose.yml.template @@ -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 diff --git a/docker-compose/media-management/docker-compose.yml b/docker-compose/media-management/docker-compose.yml index 77a9079..a496cbc 100644 --- a/docker-compose/media-management/docker-compose.yml +++ b/docker-compose/media-management/docker-compose.yml @@ -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: diff --git a/docker-compose/media-management/docker-compose.yml.template b/docker-compose/media-management/docker-compose.yml.template new file mode 100644 index 0000000..77a9079 --- /dev/null +++ b/docker-compose/media-management/docker-compose.yml.template @@ -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 diff --git a/docker-compose/media/docker-compose.yml b/docker-compose/media/docker-compose.yml index 555b2a8..3027363 100644 --- a/docker-compose/media/docker-compose.yml +++ b/docker-compose/media/docker-compose.yml @@ -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: diff --git a/docker-compose/media/docker-compose.yml.template b/docker-compose/media/docker-compose.yml.template new file mode 100644 index 0000000..555b2a8 --- /dev/null +++ b/docker-compose/media/docker-compose.yml.template @@ -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 diff --git a/docker-compose/monitoring/docker-compose.yml b/docker-compose/monitoring/docker-compose.yml index 4b1cb96..7c888e4 100644 --- a/docker-compose/monitoring/docker-compose.yml +++ b/docker-compose/monitoring/docker-compose.yml @@ -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 diff --git a/docker-compose/monitoring/docker-compose.yml.template b/docker-compose/monitoring/docker-compose.yml.template new file mode 100644 index 0000000..4b1cb96 --- /dev/null +++ b/docker-compose/monitoring/docker-compose.yml.template @@ -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 diff --git a/docker-compose/productivity/docker-compose.yml b/docker-compose/productivity/docker-compose.yml index dcda945..e7ff3ae 100644 --- a/docker-compose/productivity/docker-compose.yml +++ b/docker-compose/productivity/docker-compose.yml @@ -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 diff --git a/docker-compose/productivity/docker-compose.yml.template b/docker-compose/productivity/docker-compose.yml.template new file mode 100644 index 0000000..dcda945 --- /dev/null +++ b/docker-compose/productivity/docker-compose.yml.template @@ -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 diff --git a/docker-compose/transcoders/docker-compose.yml b/docker-compose/transcoders/docker-compose.yml index d82f889..8353dde 100644 --- a/docker-compose/transcoders/docker-compose.yml +++ b/docker-compose/transcoders/docker-compose.yml @@ -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 \ No newline at end of file + - https://tdarr.kelinreij.duckdns.org + - http://192.168.4.4:8265 + - https://unmanic.kelinreij.duckdns.org + - http://192.168.4.4:8888 \ No newline at end of file diff --git a/docker-compose/transcoders/docker-compose.yml.template b/docker-compose/transcoders/docker-compose.yml.template new file mode 100644 index 0000000..d82f889 --- /dev/null +++ b/docker-compose/transcoders/docker-compose.yml.template @@ -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 \ No newline at end of file diff --git a/docker-compose/utilities/docker-compose.yml b/docker-compose/utilities/docker-compose.yml index d1cfd33..24db395 100644 --- a/docker-compose/utilities/docker-compose.yml +++ b/docker-compose/utilities/docker-compose.yml @@ -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 \ No newline at end of file + - 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 \ No newline at end of file diff --git a/docker-compose/utilities/docker-compose.yml.template b/docker-compose/utilities/docker-compose.yml.template new file mode 100644 index 0000000..d1cfd33 --- /dev/null +++ b/docker-compose/utilities/docker-compose.yml.template @@ -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 \ No newline at end of file diff --git a/docker-compose/vpn/docker-compose.yml b/docker-compose/vpn/docker-compose.yml index 44183f5..809e55e 100644 --- a/docker-compose/vpn/docker-compose.yml +++ b/docker-compose/vpn/docker-compose.yml @@ -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 \ No newline at end of file + - https://qbit.kelinreij.duckdns.org + - https://192.168.4.4:8081 \ No newline at end of file diff --git a/docker-compose/vpn/docker-compose.yml.template b/docker-compose/vpn/docker-compose.yml.template new file mode 100644 index 0000000..44183f5 --- /dev/null +++ b/docker-compose/vpn/docker-compose.yml.template @@ -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 \ No newline at end of file diff --git a/docker-compose/wikis/docker-compose.yml b/docker-compose/wikis/docker-compose.yml index 3693699..8b66a3c 100644 --- a/docker-compose/wikis/docker-compose.yml +++ b/docker-compose/wikis/docker-compose.yml @@ -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 diff --git a/docker-compose/wikis/docker-compose.yml.template b/docker-compose/wikis/docker-compose.yml.template new file mode 100644 index 0000000..3693699 --- /dev/null +++ b/docker-compose/wikis/docker-compose.yml.template @@ -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 diff --git a/docs/script-audit-report.md b/docs/script-audit-report.md new file mode 100644 index 0000000..7a8cb32 --- /dev/null +++ b/docs/script-audit-report.md @@ -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. \ No newline at end of file diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..230eafa --- /dev/null +++ b/docs/todo.md @@ -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 \ No newline at end of file diff --git a/instructions.md b/instructions.md new file mode 100644 index 0000000..0ece26d --- /dev/null +++ b/instructions.md @@ -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 + + + + + + + + + + + + + + + + + + +``` + diff --git a/scripts/ez-homelab.sh b/scripts/ez-homelab.sh index 972a689..17d41d3 100755 --- a/scripts/ez-homelab.sh +++ b/scripts/ez-homelab.sh @@ -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