Fix homepage Traefik network routing and update configurations
- Add traefik.docker.network=traefik-network label to homepage service - Prevent Traefik from using wrong IP from homelab-network - Resolve 504 Gateway Timeout issues after authentication - Update various docker-compose configurations and templates - Clean up unused configuration files
This commit is contained in:
@@ -17,10 +17,23 @@ docker-compose/
|
||||
├── nextcloud/ # Nextcloud stack
|
||||
├── productivity/ # Productivity tools
|
||||
├── utilities/ # Utility services
|
||||
└── README.md # This file
|
||||
```
|
||||
## ⚠️ Important: Core Services First
|
||||
|
||||
## Usage
|
||||
**Before deploying any other stacks, ensure the `core/` services are running:**
|
||||
|
||||
- **Traefik**: Reverse proxy and SSL termination
|
||||
- **Authelia**: Single sign-on authentication
|
||||
- **DuckDNS**: Dynamic DNS for domain resolution
|
||||
|
||||
These services provide the foundation for all other services. Most stacks depend on Traefik for routing and Authelia for authentication.
|
||||
|
||||
### Quick Start Core Services
|
||||
```bash
|
||||
cd core
|
||||
cp .env.template .env # Edit with your values
|
||||
cp docker-compose.yml.template docker-compose.yml # Or use the pre-configured version
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Starting Services
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
services:
|
||||
# Portainer - Docker management UI (Alternative to Dockge)
|
||||
# Access at: https://portainer.${DOMAIN}
|
||||
# Access at: https://portainer.kelinreij.duckdns.org
|
||||
# NOTE: Dockge is the default Docker management UI. Deploy Portainer only if you prefer its interface
|
||||
# Docker management interface should always run when deployed
|
||||
portainer:
|
||||
@@ -34,14 +34,14 @@ services:
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Docker container management UI (Alternative to Dockge)"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.portainer.middlewares=authelia@docker"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
|
||||
|
||||
# Authentik - Alternative SSO/Identity Provider with Web UI
|
||||
# Access at: https://authentik.${DOMAIN}
|
||||
# Access at: https://authentik.kelinreij.duckdns.org
|
||||
# NOTE: Authelia is the default SSO. Deploy Authentik only if you need a web UI for user management
|
||||
# WARNING: Do not run both Authelia and Authentik at the same time
|
||||
# SSO service should always run when deployed as alternative to Authelia
|
||||
@@ -73,7 +73,7 @@ services:
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=SSO/Identity provider with web UI (Alternative to Authelia)"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
|
||||
- "traefik.http.routers.authentik.rule=Host(`authentik.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.authentik.entrypoints=websecure"
|
||||
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.authentik.middlewares=authelia@docker"
|
||||
@@ -181,9 +181,9 @@ services:
|
||||
- /mnt/media:/media:ro # Large media files on separate drive
|
||||
- plex-transcode:/transcode
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- PLEX_CLAIM=${PLEX_CLAIM}
|
||||
# Hardware transcoding support
|
||||
# Uncomment ONE of the following options:
|
||||
@@ -211,12 +211,12 @@ services:
|
||||
- "homelab.description=Alternative media streaming server to Jellyfin"
|
||||
# Traefik labels - NO Authelia for app access
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.plex.rule=Host(`plex.${DOMAIN}`)"
|
||||
- "traefik.http.routers.plex.rule=Host(`plex.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.plex.entrypoints=websecure"
|
||||
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.plex.loadbalancer.server.port=32400"
|
||||
- "x-dockge.url=https://plex.${DOMAIN}"
|
||||
- "x-dockge.url=https://plex.${DOMAIN}"
|
||||
- "x-dockge.url=https://plex.kelinreij.duckdns.org"
|
||||
- "x-dockge.url=https://plex.kelinreij.duckdns.org"
|
||||
|
||||
volumes:
|
||||
portainer-data:
|
||||
|
||||
236
docker-compose/alternatives/docker-compose.yml.template
Normal file
236
docker-compose/alternatives/docker-compose.yml.template
Normal file
@@ -0,0 +1,236 @@
|
||||
# Alternative Services Stack
|
||||
# This stack contains alternative/optional services that are not deployed by default
|
||||
# Deploy manually through Dockge if you want to use these alternatives
|
||||
# Place in /opt/stacks/alternatives/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
# Portainer - Docker management UI (Alternative to Dockge)
|
||||
# Access at: https://portainer.${DOMAIN}
|
||||
# NOTE: Dockge is the default Docker management UI. Deploy Portainer only if you prefer its interface
|
||||
# Docker management interface should always run when deployed
|
||||
portainer:
|
||||
image: portainer/portainer-ce:2.19.4
|
||||
container_name: portainer
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer-data:/data
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Docker container management UI (Alternative to Dockge)"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.portainer.middlewares=authelia@docker"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
|
||||
|
||||
# Authentik - Alternative SSO/Identity Provider with Web UI
|
||||
# Access at: https://authentik.${DOMAIN}
|
||||
# NOTE: Authelia is the default SSO. Deploy Authentik only if you need a web UI for user management
|
||||
# WARNING: Do not run both Authelia and Authentik at the same time
|
||||
# SSO service should always run when deployed as alternative to Authelia
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2024.2.0
|
||||
container_name: authentik-server
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- /opt/stacks/authentik/media:/media
|
||||
- /opt/stacks/authentik/custom-templates:/templates
|
||||
environment:
|
||||
- AUTHENTIK_REDIS__HOST=authentik-redis
|
||||
- AUTHENTIK_POSTGRESQL__HOST=authentik-db
|
||||
- AUTHENTIK_POSTGRESQL__USER=${AUTHENTIK_DB_USER}
|
||||
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME}
|
||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
|
||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
|
||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=SSO/Identity provider with web UI (Alternative to Authelia)"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
|
||||
- "traefik.http.routers.authentik.entrypoints=websecure"
|
||||
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.authentik.middlewares=authelia@docker"
|
||||
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
|
||||
depends_on:
|
||||
- authentik-db
|
||||
- authentik-redis
|
||||
|
||||
# Authentik Worker - Background task processor
|
||||
# SSO background worker should always run when Authentik is deployed
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2024.2.0
|
||||
container_name: authentik-worker
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- /opt/stacks/authentik/media:/media
|
||||
- /opt/stacks/authentik/certs:/certs
|
||||
- /opt/stacks/authentik/custom-templates:/templates
|
||||
environment:
|
||||
- AUTHENTIK_REDIS__HOST=authentik-redis
|
||||
- AUTHENTIK_POSTGRESQL__HOST=authentik-db
|
||||
- AUTHENTIK_POSTGRESQL__USER=${AUTHENTIK_DB_USER}
|
||||
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME}
|
||||
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
|
||||
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
|
||||
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Authentik background worker"
|
||||
depends_on:
|
||||
- authentik-db
|
||||
- authentik-redis
|
||||
|
||||
# Authentik Database - PostgreSQL
|
||||
# Database must always run for Authentik to function
|
||||
authentik-db:
|
||||
image: postgres:16-alpine
|
||||
container_name: authentik-db
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- authentik-db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=${AUTHENTIK_DB_USER}
|
||||
- POSTGRES_PASSWORD=${AUTHENTIK_DB_PASSWORD}
|
||||
- POSTGRES_DB=${AUTHENTIK_DB_NAME}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Authentik database"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_DB_USER}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Authentik Redis - Cache and message queue
|
||||
# Cache service must always run for Authentik performance
|
||||
authentik-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: authentik-redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- authentik-redis-data:/data
|
||||
command: --save 60 1 --loglevel warning
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Authentik cache and messaging"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# Plex Media Server - Alternative to Jellyfin
|
||||
# Access at: https://plex.yourdomain.duckdns.org
|
||||
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
|
||||
# Media server should always run when deployed as alternative to Jellyfin
|
||||
plex:
|
||||
image: plexinc/pms-docker:1.40.0.7998-f68041501
|
||||
container_name: plex
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "32400:32400"
|
||||
volumes:
|
||||
- ./plex/config:/config
|
||||
- /mnt/media:/media:ro # Large media files on separate drive
|
||||
- plex-transcode:/transcode
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PLEX_CLAIM=${PLEX_CLAIM}
|
||||
# Hardware transcoding support
|
||||
# Uncomment ONE of the following options:
|
||||
|
||||
# Option 1: Intel QuickSync (most common)
|
||||
# devices:
|
||||
# - /dev/dri:/dev/dri
|
||||
|
||||
# Option 2: NVIDIA GPU (requires nvidia-container-toolkit installed)
|
||||
# runtime: nvidia
|
||||
# devices:
|
||||
# - /dev/nvidia0:/dev/nvidia0
|
||||
# - /dev/nvidiactl:/dev/nvidiactl
|
||||
# - /dev/nvidia-modeset:/dev/nvidia-modeset
|
||||
# - /dev/nvidia-uvm:/dev/nvidia-uvm
|
||||
# - /dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools
|
||||
# environment:
|
||||
# - NVIDIA_VISIBLE_DEVICES=all
|
||||
# - NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=alternatives"
|
||||
- "homelab.description=Alternative media streaming server to Jellyfin"
|
||||
# Traefik labels - NO Authelia for app access
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.plex.rule=Host(`plex.${DOMAIN}`)"
|
||||
- "traefik.http.routers.plex.entrypoints=websecure"
|
||||
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.plex.loadbalancer.server.port=32400"
|
||||
- "x-dockge.url=https://plex.${DOMAIN}"
|
||||
- "x-dockge.url=https://plex.${DOMAIN}"
|
||||
|
||||
volumes:
|
||||
portainer-data:
|
||||
driver: local
|
||||
authentik-db-data:
|
||||
driver: local
|
||||
authentik-redis-data:
|
||||
driver: local
|
||||
plex-transcode:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
28
docker-compose/core/.env.template
Normal file
28
docker-compose/core/.env.template
Normal file
@@ -0,0 +1,28 @@
|
||||
# Environment Variables Template for Core Services
|
||||
# Copy this file to .env and fill in your values
|
||||
|
||||
# User and Group IDs for file permissions (get with: id -u and id -g)
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
TZ=America/New_York
|
||||
|
||||
SERVER_IP=192.168.1.100
|
||||
SERVER_HOSTNAME=your-server-name
|
||||
|
||||
# Domain & DuckDNS Configuration
|
||||
DUCKDNS_SUBDOMAINS=your-subdomain # Without .duckdns.org
|
||||
DOMAIN=your-subdomain.duckdns.org
|
||||
DUCKDNS_TOKEN=your-duckdns-token-here
|
||||
|
||||
# Default credentials (used by multiple services for easier setup)
|
||||
DEFAULT_USER=admin
|
||||
DEFAULT_PASSWORD=change-this-password
|
||||
|
||||
# Authelia Configuration
|
||||
AUTHELIA_JWT_SECRET=your-jwt-secret-here
|
||||
AUTHELIA_SESSION_SECRET=your-session-secret-here
|
||||
AUTHELIA_STORAGE_ENCRYPTION_KEY=your-encryption-key-here
|
||||
|
||||
# Let's Encrypt Configuration
|
||||
ACME_EMAIL=your-email@example.com
|
||||
171
docker-compose/core/README.md
Normal file
171
docker-compose/core/README.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Core Infrastructure Services
|
||||
|
||||
This directory contains the core infrastructure services that form the foundation of the homelab. These services should always be running and are critical for the operation of other services.
|
||||
|
||||
## Services
|
||||
|
||||
### Traefik (v3)
|
||||
- **Purpose**: Reverse proxy and SSL termination
|
||||
- **Ports**: 80 (HTTP), 443 (HTTPS), 8080 (Dashboard)
|
||||
- **Configuration**: Located in `traefik/config/traefik.yml`
|
||||
- **SSL**: Let's Encrypt with DNS-01 challenge (configurable provider)
|
||||
- **Dashboard**: Available at configured domain
|
||||
|
||||
### Authelia (v4.37.5)
|
||||
- **Purpose**: Single sign-on authentication service
|
||||
- **Port**: 9091 (internal)
|
||||
- **Access**: Configured authentication domain
|
||||
- **Configuration**: Located in `authelia/config/`
|
||||
- **Database**: SQLite database in `authelia/config/db.sqlite3`
|
||||
|
||||
### DuckDNS
|
||||
- **Purpose**: Dynamic DNS service for domain resolution
|
||||
- **Subdomain**: Configurable via environment variables
|
||||
- **Token**: Configured in environment variables
|
||||
|
||||
## ⚠️ Version Pinning & Breaking Changes
|
||||
|
||||
### Authelia Version Pinning
|
||||
**Current Version**: `authelia/authelia:4.37.5`
|
||||
|
||||
**Breaking Changes Identified**:
|
||||
- Authelia v4.39.15+ has breaking configuration changes that are incompatible with the current setup
|
||||
- Database schema changes may require migration or recreation
|
||||
- Configuration file format changes may break existing setups
|
||||
|
||||
**Action Taken**:
|
||||
- Pinned to v4.37.5 which is confirmed working
|
||||
- Database recreated from scratch to ensure compatibility
|
||||
- Configuration files verified and working
|
||||
|
||||
**Upgrade Path**:
|
||||
- Test upgrades in a separate environment first
|
||||
- Backup configuration and database before upgrading
|
||||
- Check Authelia changelog for breaking changes
|
||||
- Consider using Authelia's migration tools if available
|
||||
|
||||
### Traefik Version Pinning
|
||||
**Current Version**: `traefik:v3`
|
||||
|
||||
**Notes**:
|
||||
- Traefik v3 is stable and working with current configuration
|
||||
- Configuration format is compatible
|
||||
- No breaking changes identified in current setup
|
||||
|
||||
## Configuration Requirements
|
||||
|
||||
### File Structure
|
||||
```
|
||||
core/
|
||||
├── docker-compose.yml # Main service definitions
|
||||
├── .env # Environment variables
|
||||
├── authelia/
|
||||
│ └── config/
|
||||
│ ├── configuration.yml # Authelia main config
|
||||
│ ├── users_database.yml # User credentials
|
||||
│ └── db.sqlite3 # SQLite database
|
||||
└── traefik/
|
||||
├── config/
|
||||
│ └── traefik.yml # Traefik static config
|
||||
├── dynamic/ # Dynamic configurations
|
||||
│ ├── routes.yml
|
||||
│ ├── sablier.yml
|
||||
│ └── external-host-*.yml
|
||||
└── letsencrypt/
|
||||
└── acme.json # SSL certificates
|
||||
```
|
||||
|
||||
### Environment Variables (.env)
|
||||
```bash
|
||||
# Required for proper operation
|
||||
DUCKDNS_TOKEN=your_duckdns_token_here
|
||||
DUCKDNS_SUBDOMAINS=your_subdomain
|
||||
DOMAIN=yourdomain.duckdns.org
|
||||
TZ=America/New_York
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
```
|
||||
|
||||
### Network Requirements
|
||||
- Docker network: `traefik-network`
|
||||
- External ports: 80, 443 must be accessible
|
||||
- DNS resolution: Domain must point to server IP
|
||||
|
||||
## Deployment
|
||||
|
||||
### Prerequisites
|
||||
1. Docker and Docker Compose installed
|
||||
2. Ports 80/443 forwarded to server
|
||||
3. DuckDNS account with valid token
|
||||
4. Domain configured in DuckDNS
|
||||
|
||||
### Startup Order
|
||||
1. `duckdns` - For DNS updates
|
||||
2. `traefik` - Reverse proxy
|
||||
3. `authelia` - Authentication service
|
||||
|
||||
### Commands
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up -d
|
||||
|
||||
# Check status
|
||||
docker-compose ps
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f [service-name]
|
||||
|
||||
# Restart specific service
|
||||
docker-compose restart [service-name]
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
1. **Connection Refused**: Check if Traefik config file is in correct location (`traefik/config/traefik.yml`)
|
||||
2. **SSL Certificate Issues**: Verify DuckDNS token and domain configuration
|
||||
3. **Authelia Login Issues**: Check database file exists and configuration is valid
|
||||
4. **Service Not Starting**: Check Docker logs for error messages
|
||||
|
||||
### Backup Strategy
|
||||
- Configuration files are backed up automatically (see backup directories)
|
||||
- Database should be backed up regularly
|
||||
- SSL certificates are stored in `letsencrypt/acme.json`
|
||||
- Use `backup.sh` script for automated backups
|
||||
|
||||
## Security Notes
|
||||
- Authelia provides authentication for protected services
|
||||
- All external traffic goes through Traefik with SSL termination
|
||||
- Internal services communicate via Docker networks
|
||||
- Dashboard access is protected by Authelia middleware
|
||||
|
||||
## Maintenance
|
||||
- Monitor SSL certificate expiration (Let's Encrypt auto-renews)
|
||||
- Keep Authelia version pinned until tested upgrades are available
|
||||
- Regularly backup configuration and database files
|
||||
- Check logs for security issues or errors
|
||||
- Run `./backup.sh` regularly to backup critical files
|
||||
|
||||
## Customization
|
||||
|
||||
### Domain Configuration
|
||||
Update the following files with your domain:
|
||||
- `docker-compose.yml`: Traefik labels and Authelia configuration
|
||||
- `authelia/config/configuration.yml`: Domain settings
|
||||
- `.env`: Domain environment variables
|
||||
|
||||
### SSL Certificate Provider
|
||||
Modify `traefik/config/traefik.yml` to use different DNS providers:
|
||||
```yaml
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
dnsChallenge:
|
||||
provider: cloudflare # or other supported provider
|
||||
```
|
||||
|
||||
### Adding New Services
|
||||
1. Add service definition to `docker-compose.yml`
|
||||
2. Configure Traefik labels for routing
|
||||
3. Add middleware for authentication if needed
|
||||
4. Update network configuration
|
||||
@@ -1,6 +1,6 @@
|
||||
# Authelia Configuration
|
||||
# Authelia Configuration Template
|
||||
# Copy to /opt/stacks/authelia/configuration.yml
|
||||
# IMPORTANT: Replace '${DOMAIN}' with your actual DuckDNS domain
|
||||
# IMPORTANT: Replace environment variable placeholders with your actual values
|
||||
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
@@ -35,7 +35,7 @@ access_control:
|
||||
default_policy: deny
|
||||
|
||||
rules:
|
||||
# Bypass Authelia for Jellyfin (allow app access)
|
||||
# Bypass Authelia for media services (allow app access)
|
||||
- domain: jellyfin.${DOMAIN}
|
||||
policy: bypass
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
###############################################################
|
||||
# Users Database #
|
||||
###############################################################
|
||||
# Template - Replace with your actual user information
|
||||
# Generate password hash with: docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --password 'yourpassword'
|
||||
|
||||
users:
|
||||
kelin:
|
||||
displayname: "Admin User"
|
||||
password: "$argon2id$v=19$m=65536,t=3,p=4$a+3pIrywP/li9wy9J6UkMA$+3THyJiAnS/gNYnLaYtlsRCaYfgnnxsUyGZ4D3xGnUg"
|
||||
email: ${DEFAULT_EMAIL}
|
||||
admin: # Change this username
|
||||
displayname: "Administrator"
|
||||
password: "GENERATE_NEW_PASSWORD_HASH" # Replace with actual hash
|
||||
email: your-email@example.com # Replace with your email
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
###############################################################
|
||||
|
||||
users:
|
||||
kelin:
|
||||
displayname: "Admin User"
|
||||
password: "$argon2id$v=19$m=65536,t=3,p=4$a+3pIrywP/li9wy9J6UkMA$+3THyJiAnS/gNYnLaYtlsRCaYfgnnxsUyGZ4D3xGnUg"
|
||||
${DEFAULT_USER}:
|
||||
displayname: "Administrator"
|
||||
password: "${DEFAULT_PASSWORD_HASH}" # Generate with: docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --password 'yourpassword'
|
||||
email: ${DEFAULT_EMAIL}
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
- users
|
||||
|
||||
48
docker-compose/core/backup.sh
Executable file
48
docker-compose/core/backup.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
# Core Services Backup Script
|
||||
# Run this script to backup critical configuration files and database
|
||||
|
||||
BACKUP_DIR="/opt/stacks/core/backups"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_NAME="core_backup_${TIMESTAMP}"
|
||||
|
||||
echo "Creating backup: ${BACKUP_NAME}"
|
||||
|
||||
# Create backup directory
|
||||
mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}"
|
||||
|
||||
# Backup Authelia configuration and database
|
||||
echo "Backing up Authelia..."
|
||||
cp -r /opt/stacks/core/authelia/config "${BACKUP_DIR}/${BACKUP_NAME}/"
|
||||
|
||||
# Backup Traefik configuration (excluding certificates for security)
|
||||
echo "Backing up Traefik configuration..."
|
||||
mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}/traefik"
|
||||
cp -r /opt/stacks/core/traefik/config "${BACKUP_DIR}/${BACKUP_NAME}/traefik/"
|
||||
cp -r /opt/stacks/core/traefik/dynamic "${BACKUP_DIR}/${BACKUP_NAME}/traefik/"
|
||||
# Note: letsencrypt/acme.json contains private keys - backup separately if needed
|
||||
|
||||
# Backup docker-compose.yml
|
||||
echo "Backing up docker-compose.yml..."
|
||||
cp /opt/stacks/core/docker-compose.yml "${BACKUP_DIR}/${BACKUP_NAME}/"
|
||||
|
||||
# Backup environment file (contains sensitive data - handle carefully)
|
||||
echo "Backing up .env file..."
|
||||
cp /opt/stacks/core/.env "${BACKUP_DIR}/${BACKUP_NAME}/"
|
||||
|
||||
# Create archive
|
||||
echo "Creating compressed archive..."
|
||||
cd "${BACKUP_DIR}"
|
||||
tar -czf "${BACKUP_NAME}.tar.gz" "${BACKUP_NAME}"
|
||||
|
||||
# Cleanup uncompressed backup
|
||||
rm -rf "${BACKUP_NAME}"
|
||||
|
||||
echo "Backup completed: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
|
||||
echo "Backup size: $(du -h "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)"
|
||||
|
||||
# Keep only last 10 backups
|
||||
echo "Cleaning up old backups..."
|
||||
ls -t "${BACKUP_DIR}"/*.tar.gz | tail -n +11 | xargs -r rm -f
|
||||
|
||||
echo "Backup script completed successfully"
|
||||
@@ -15,9 +15,9 @@ services:
|
||||
container_name: duckdns
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS}
|
||||
- TOKEN=${DUCKDNS_TOKEN}
|
||||
volumes:
|
||||
@@ -27,6 +27,8 @@ services:
|
||||
|
||||
traefik:
|
||||
# Reverse proxy and SSL termination - core routing service, must always run
|
||||
# CONFIGURATION REQUIREMENT: traefik.yml MUST be in ./traefik/config/ directory
|
||||
# VOLUME MOUNT: ./traefik/config:/config - config file location is critical
|
||||
image: traefik:v3
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
@@ -62,11 +64,14 @@ services:
|
||||
|
||||
authelia:
|
||||
# Single sign-on authentication service - must always run for user authentication
|
||||
image: authelia/authelia:latest
|
||||
# VERSION PINNING: Pinned to v4.37.5 due to breaking changes in v4.39.15+
|
||||
# BREAKING CHANGES: v4.39.15+ has incompatible configuration and database changes
|
||||
# UPGRADE NOTES: Test in separate environment before upgrading. Backup config and DB.
|
||||
image: authelia/authelia:4.37.5
|
||||
container_name: authelia
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
ports:
|
||||
- "9091:9091"
|
||||
volumes:
|
||||
@@ -115,11 +120,12 @@ services:
|
||||
- SABLIER_DOCKER_API_VERSION=1.51
|
||||
- SABLIER_DOCKER_NETWORK=traefik-network
|
||||
- SABLIER_LOG_LEVEL=debug
|
||||
- DOCKER_HOST=tcp://${SERVER_IP}:2376
|
||||
- DOCKER_TLS_VERIFY=1
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- DOCKER_TLS_VERIFY=0
|
||||
- DOCKER_CERT_PATH=/certs
|
||||
volumes:
|
||||
- ./shared-ca:/certs:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
ports:
|
||||
- 10000:10000
|
||||
labels:
|
||||
|
||||
@@ -27,6 +27,8 @@ services:
|
||||
|
||||
traefik:
|
||||
# Reverse proxy and SSL termination - core routing service, must always run
|
||||
# CONFIGURATION REQUIREMENT: traefik.yml MUST be in ./traefik/config/ directory
|
||||
# VOLUME MOUNT: ./traefik/config:/config - config file location is critical
|
||||
image: traefik:v3
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
@@ -62,7 +64,10 @@ services:
|
||||
|
||||
authelia:
|
||||
# Single sign-on authentication service - must always run for user authentication
|
||||
image: authelia/authelia:latest
|
||||
# VERSION PINNING: Pinned to v4.37.5 due to breaking changes in v4.39.15+
|
||||
# BREAKING CHANGES: v4.39.15+ has incompatible configuration and database changes
|
||||
# UPGRADE NOTES: Test in separate environment before upgrading. Backup config and DB.
|
||||
image: authelia/authelia:4.37.5
|
||||
container_name: authelia
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"letsencrypt": {
|
||||
"Account": {
|
||||
"Email": "kelinfoxy@gmail.com",
|
||||
"Registration": {
|
||||
"body": {
|
||||
"status": "valid"
|
||||
},
|
||||
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2959423246"
|
||||
},
|
||||
"PrivateKey": "MIIJJwIBAAKCAgEAtmlI6xzuaJKm8y8lU2CkLsVEB5QEZx777DDUMH7I3kt2zpIBjWFOxp3u+IppzDqC8ih8+2tzkAzIjF34kb45tgKah+gwTPUg20IoqTyg5/YaN/Otnda7Ioo9CS24k6lZ21DDrReT616BIa45dvtxYld8SES0Qx9x+jDTL8os0y2taMn3bX/0OMIE8jerrkzTYpLZ5PLMxKZFvoDClkfs4wAX4VpLh9oN1H45BqzhFZqsuZ2RZSvt/H91QFJWz38FDS0sRNEX83revbNdXEtJIQs+r45nHXiX6ivvfwtCXeGx2+hluCg/QpESCpCYj/JReQ1r2CCbTsfcpqrtIS1/eoLdal+AhrxGM5OlU6yeyclLHNfcZDIJkM54tr+0bPkweMwdqjoXkXWtEyFYE0Ol1CYQek8wHZLof8YYHwoo/zrLAu05igzSOxcaGRO3Inu1cW3TEvQM7nn2KfnWWPdY+u/Is0H2MqodokbzC9xpmPZlEzrnfGkngtcDtTOSNALUbANbFv4Zu9qBj8VtHUz2AYzkMUF5BKyFf4TSRrELEvXz3dMWpWY1Esjft4XaaeYXUnMCemrzuYPjC+gWyHvfNHXzui0bs5fY914cc4Q318x6JX+R/gKCxUfscuiwDRR9ufIilQCHPDw/hIJtZ9dAHeF66JREwdUQBH2tyBP+hvMCAwEAAQKCAgARbNBS6WIa6jt5ipzpsJcugpijkq+y/CI7p1R1x36/wXy5cfgk/dEtJwQfiPVfVY2RvW1nBRY2ggocYpOutHnF2czSQ8ttZpM7br/8nraOQhOyGZyRseQRghwfhtcVf/199mKi49g1CUOTqJWDuLRVnR7Ztnpz2QqlyEk8TPdoOvpQQs7YjnsRevNHAitrzJn61iVregg2lt2du6Ya/gbyjl05oUsK0Lk2fdJLwXMFAdATMSqk/APRdYmJWfRCARPF9PVAI6tCjo+9lmdKPEThm7XixlsyVQVKEOVhgP1Xg4peg/5Hj8yvOrV6/eIdChxfUHlnXYIIjg4Ve8mIPFTrgS4fv1wwIe0+RcLiimkC0+jTPaAqnMY1xEDU8sisVvB7vU9UevnXIR6XHGkGwsxD1Ga48PW5LvtWHG1YfjfxPEU0cHESsGejgCMPl1WT6UPeOYNmKx1I1gQiOQKixJt4fHXghAPmLBZTPZFrmhyFVSRb/wpVY+J4t61s3fzinqjox8P9xDx6I9bLl/2SI5rQ55a2MrGtRK/0l1zQxTE1U+3qVDD8BV0mbkDrPTtUAvoyHSzAAiwQIIdksSNZzTK7fdDSc/T84WbvSd3dcC6n272g5vfAhOycLEetzdigMc9ht8cCjr16UyHL4Br2adWneAwOxBffTVfVKnuAxshDJQKCAQEAx1idLIRlEGBXSC9x8fwIdsbUtH6y5ajE/ahmQ6L2fV+6A8uvlx/0uhMUkyLIjg30zh0Cnb05Cirzqao7EXSYmMUT6HgctPqNGgk0EvsXLa5NffbhOnPWQNPUKbmEZBf1HdG4K3wOv1/ISQ3fitIVsPrD88/OD3TOafXJLCzeRe8rxnoQlKoztszOwJmE28TMBZTYkvRGQZM6FiqvXzJoJFPeudp+8j0yE78fQPbl1uXNq/p9U5xkYid5PIjturrznoL1fy5KLgxHWrSAJd6JqVvajnch8DdEmsGI9MSLDyRszWHhXp7BeG5tl/+aHHdNxkA4y/38lukCETfORIH3jwKCAQEA6kCTzxHTHVXfxTU4YtcLoAUai94U3wBKf5l9yZfY19P9ITcPijw+daXiYaGLaBUtubMXM+KkjSKq7qx1HNB5hBfbHnSLzt0aAxhOlqfVdRaOi6Fn0tmvOPOLuORjlSVLa4Rng/eRE6yFSjEZ79DTAKYREND2Xxnzfqb573wLro/aFY0IcnZyjm9dO33SF3qBoZPuCoI1yPd+cTGYA7lyKIeNqWemXgCtg/tsxmjADgo9JCVxfc/TtQB8dwHN5GN2pw2jA7MGkCSI43F3QvKlXNEF1OI0jZOxOAphpAAyfWxLUUDsUWmCaDcc7keCFsl+41RqOFVaPewF/SCaybLoXQKCAQAFyp1GXdJR13qxri8xSJE2YjBrzgKEiZKvi+Tssh9XJSDSW2iOi28guM0wOSJ6fg1Or6kTzBuMIBNUKo3sw+ZrCc66QkMTPvQ6fWn14zWZLicyMan5eMQQvha735fpEIkehKlFGiWTicTX2n9UGSZoLeDjhHYIHOyiR3HAxszuWzR6X7F7oDZAaVLYZZ1mhSEoSFrCajZgUVauri7KJTzBUW53F9H4V67MxBC0Ynfq9mIzTOO3OiPwdhUfnRrLAgNx53waZc3h6JlqGTRf5Uc6lGCVIwDpabGkjVrdQZiIqBZBIUba6OHWDd9BOzvO9+haiiMcShS8jahxt51WgDAhAoIBAD+Iuk4sSHUpaGLFd4CfUMDbAYMz/bcqDgqjp9E4hRCsp3gNxgI5Kruf/VF7jiLxs5AtObrR2s2IvJG1ZqIlDQA9tCmDdLPrlfWG7zG/XY6/SnQml9FBR1wL+jZwg23dSqJjq+vIBqouXYxs2tsHaWNAp1pHQrsyf683PIyuuUBkNcMomETrSVDGdaQAES5bBLO9Oo/RFyNltP6gc9l2v7asZUiwGxhd2LH2TF9X49crAcA/A5Qa/RGXiyp/68bpDzJp6W/Ea6BGuHXvvWgEBcOx0YIWxCguCZ/oeOkRQKBx8c+c6zt9gWggopEiBe+GQQsJRzH2PF6VGF66LCFOi+UCggEAFEoujlC54OZHcHnJYT9Jb7JU9K/3F7007g23YPrN4ATE+UPT/6Uiod4BCQ5tTauu6EjofHUjImk1NT9dmc+zCnFexsgfJXLbU83qfRunoDATlueWCRCTzeWMkAEwjReabNQrK7xT0Rk4rGKsH0p0SDmUSP5jnt+uctNSMfLZ/SykihuydGrtQOY/lh87Y4/MX4pY5L03ogleDPAXxWpd+ea+0l8fUz3EX+VtWlTVzSuDFPL5zEFxpZrZeDflR+vxhzCw/Taiyz5/K6kUzaRQxwJq6Wvqv9lgngtfHavauWHFtL2pNs6WySk93M0JVmVpTzItf+bObJTvXuZVt+HbPw==",
|
||||
"KeyType": "4096"
|
||||
},
|
||||
"Certificates": null
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,9 @@ entryPoints:
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: kelinfoxy@gmail.com # Will be replaced by deploy script
|
||||
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
storage: /acme.json
|
||||
email: ${ACME_EMAIL} # Your email for Let's Encrypt notifications
|
||||
caServer: https://acme-v02.api.letsencrypt.org/directory # Use staging for testing
|
||||
storage: /letsencrypt/acme.json
|
||||
# DNS challenge - For wildcard certificates (*.yourdomain.duckdns.org)
|
||||
# Works with DuckDNS - requires DUCKDNS_TOKEN in environment
|
||||
dnsChallenge:
|
||||
|
||||
@@ -32,10 +32,10 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock # For Docker integration do not mount RO
|
||||
- /opt/stacks:/opt/stacks # To discover other stacks
|
||||
environment:
|
||||
- PUID=995 # Must be set to the docker user ID
|
||||
- PGID=995 # Must be set to the docker group ID
|
||||
- PUID=${PUID} # Must be set to the docker user ID
|
||||
- PGID=${PGID} # Must be set to the docker group ID
|
||||
- TZ=${TZ}
|
||||
- HOMEPAGE_ALLOWED_HOSTS=homepage.${DOMAIN}
|
||||
- HOMEPAGE_ALLOWED_HOSTS=${HOMEPAGE_ALLOWED_HOSTS}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -48,14 +48,15 @@ services:
|
||||
# - Routes are configured via external YAML files on the core server
|
||||
# - This prevents conflicts between Docker labels and file provider
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik-network"
|
||||
- "traefik.http.routers.homepage.rule=Host(`homepage.${DOMAIN}`)"
|
||||
- "traefik.http.routers.homepage.entrypoints=websecure"
|
||||
- "traefik.http.routers.homepage.tls=true"
|
||||
- "traefik.http.routers.homepage.middlewares=authelia@docker"
|
||||
- "traefik.http.services.homepage.loadbalancer.server.port=3003"
|
||||
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
|
||||
# Sablier lazy loading (disabled by default - uncomment to enable)
|
||||
# - "sablier.enable=true"
|
||||
# - "sablier.group=${SERVER_HOSTNAME}-homarr"
|
||||
# - "sablier.group=jasper-homarr"
|
||||
# - "sablier.start-on-demand=true"
|
||||
|
||||
# Homarr - Modern dashboard
|
||||
@@ -85,7 +86,7 @@ services:
|
||||
- ./homarr/icons:/app/public/icons
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7575/"]
|
||||
interval: 30s
|
||||
@@ -108,7 +109,7 @@ services:
|
||||
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-homarr"
|
||||
- "sablier.group=jasper-homarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# DOCKGE URL CONFIGURATION
|
||||
@@ -116,9 +117,9 @@ x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://homepage.${DOMAIN}
|
||||
- https://${SERVER_IP}:3003
|
||||
- https://192.168.4.4:3003
|
||||
- https://homarr.${DOMAIN}
|
||||
- https://${SERVER_IP}:7575
|
||||
- https://192.168.4.4:7575
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
|
||||
127
docker-compose/dashboards/docker-compose.yml.template
Normal file
127
docker-compose/dashboards/docker-compose.yml.template
Normal file
@@ -0,0 +1,127 @@
|
||||
# Dashboard Services
|
||||
# Homepage and Homarr for homelab dashboards
|
||||
|
||||
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
|
||||
|
||||
# Service Access URLs:
|
||||
# - Homepage: https://homepage.${DOMAIN}
|
||||
# - Homarr: https://homarr.${DOMAIN}
|
||||
|
||||
services:
|
||||
# Homepage - Default Application Dashboard
|
||||
homepage:
|
||||
image: ghcr.io/gethomepage/homepage:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: homepage
|
||||
restart: unless-stopped # change to 'no' to enable Sablier lazy loading
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3003:3000"
|
||||
volumes:
|
||||
- ./homepage:/app/config
|
||||
- /var/run/docker.sock:/var/run/docker.sock # For Docker integration do not mount RO
|
||||
- /opt/stacks:/opt/stacks # To discover other stacks
|
||||
environment:
|
||||
- PUID=995 # Must be set to the docker user ID
|
||||
- PGID=995 # Must be set to the docker group ID
|
||||
- TZ=${TZ}
|
||||
- HOMEPAGE_ALLOWED_HOSTS=homepage.${DOMAIN}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=dashboard"
|
||||
- "homelab.description=Application dashboard"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# IMPORTANT: On REMOTE SERVERS (where Traefik runs elsewhere):
|
||||
# - COMMENT OUT all traefik.* labels below (don't delete them)
|
||||
# - Routes are configured via external YAML files on the core server
|
||||
# - This prevents conflicts between Docker labels and file provider
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.homepage.rule=Host(`homepage.${DOMAIN}`)"
|
||||
- "traefik.http.routers.homepage.entrypoints=websecure"
|
||||
- "traefik.http.routers.homepage.tls=true"
|
||||
- "traefik.http.routers.homepage.middlewares=authelia@docker"
|
||||
- "traefik.http.services.homepage.loadbalancer.server.port=3003"
|
||||
# Sablier lazy loading (disabled by default - uncomment to enable)
|
||||
# - "sablier.enable=true"
|
||||
# - "sablier.group=${SERVER_HOSTNAME}-homarr"
|
||||
# - "sablier.start-on-demand=true"
|
||||
|
||||
# Homarr - Modern dashboard
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
|
||||
homarr:
|
||||
image: ghcr.io/ajnart/homarr:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: homarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "7575:7575"
|
||||
volumes:
|
||||
- ./homarr/config:/app/config/configs
|
||||
- ./homarr/data:/data
|
||||
- ./homarr/icons:/app/public/icons
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7575/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=dashboard"
|
||||
- "homelab.description=Modern homelab dashboard"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.homarr.rule=Host(`homarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.homarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.homarr.tls=true"
|
||||
- "traefik.http.routers.homarr.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-homarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# DOCKGE URL CONFIGURATION
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://homepage.${DOMAIN}
|
||||
- https://${SERVER_IP}:3003
|
||||
- https://homarr.${DOMAIN}
|
||||
- https://${SERVER_IP}:7575
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -1,86 +0,0 @@
|
||||
# Authelia Configuration
|
||||
# Copy to /opt/stacks/authelia/configuration.yml
|
||||
# IMPORTANT: Replace 'your-domain.duckdns.org' with your actual DuckDNS domain
|
||||
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
port: 9091
|
||||
|
||||
log:
|
||||
level: info
|
||||
|
||||
theme: dark
|
||||
|
||||
jwt_secret: ${AUTHELIA_JWT_SECRET}
|
||||
|
||||
default_redirection_url: https://auth.${DOMAIN}
|
||||
|
||||
totp:
|
||||
issuer: ${DOMAIN}
|
||||
period: 30
|
||||
skew: 1
|
||||
|
||||
authentication_backend:
|
||||
file:
|
||||
path: /config/users_database.yml
|
||||
password:
|
||||
algorithm: argon2id
|
||||
iterations: 1
|
||||
key_length: 32
|
||||
salt_length: 16
|
||||
memory: 1024
|
||||
parallelism: 8
|
||||
|
||||
access_control:
|
||||
default_policy: deny
|
||||
|
||||
rules:
|
||||
# Bypass Authelia for Jellyfin (allow app access)
|
||||
- domain: jellyfin.${DOMAIN}
|
||||
policy: bypass
|
||||
|
||||
# Bypass for Plex (allow app access)
|
||||
- domain: plex.${DOMAIN}
|
||||
policy: bypass
|
||||
|
||||
# Bypass for Home Assistant (has its own auth)
|
||||
- domain: ha.${DOMAIN}
|
||||
policy: bypass
|
||||
|
||||
# Protected: All other services require authentication
|
||||
- domain: "*.${DOMAIN}"
|
||||
policy: one_factor
|
||||
|
||||
# Two-factor for admin services (optional)
|
||||
# - domain:
|
||||
# - "admin.${DOMAIN}"
|
||||
# - "portainer.${DOMAIN}"
|
||||
# policy: two_factor
|
||||
|
||||
session:
|
||||
name: authelia_session
|
||||
secret: ${AUTHELIA_SESSION_SECRET}
|
||||
expiration: 24h # Session expires after 24 hours
|
||||
inactivity: 24h # Session expires after 24 hours of inactivity
|
||||
remember_me_duration: 1M
|
||||
domain: ${DOMAIN}
|
||||
cookies:
|
||||
- name: authelia_session
|
||||
domain: ${DOMAIN}
|
||||
secure: true
|
||||
same_site: lax
|
||||
|
||||
regulation:
|
||||
max_retries: 3
|
||||
find_time: 2m
|
||||
ban_time: 5m
|
||||
|
||||
storage:
|
||||
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
|
||||
local:
|
||||
path: /config/db.sqlite3
|
||||
|
||||
notifier:
|
||||
# File-based notifications (for development/testing)
|
||||
filesystem:
|
||||
filename: /config/notification.txt
|
||||
@@ -1,20 +0,0 @@
|
||||
# Authelia Users Database
|
||||
# Copy to /opt/stacks/authelia/users_database.yml
|
||||
# Generate password hashes with: docker run authelia/authelia:latest authelia crypto hash generate argon2 --password 'yourpassword'
|
||||
|
||||
users:
|
||||
admin:
|
||||
displayname: "Admin User"
|
||||
password: "$argon2id$v=19$m=65536,t=3,p=4$CHANGEME" # Replace with your hashed password
|
||||
email: admin@example.com
|
||||
groups:
|
||||
- admins
|
||||
- users
|
||||
|
||||
# Example: Additional user
|
||||
# user1:
|
||||
# displayname: "User One"
|
||||
# password: "$argon2id$v=19$m=65536,t=3,p=4$CHANGEME"
|
||||
# email: user1@example.com
|
||||
# groups:
|
||||
# - users
|
||||
@@ -13,6 +13,6 @@
|
||||
# host: 192.168.4.5
|
||||
# port: 2375
|
||||
|
||||
#${SERVER_HOSTNAME}:
|
||||
#jasper:
|
||||
# host: 192.168.4.11
|
||||
# port: 2375
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
## no access to the conf directory
|
||||
<IfModule mod_authz_core.c>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
<IfModule !mod_authz_core.c>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</IfModule>
|
||||
@@ -1,10 +0,0 @@
|
||||
# acl.auth.php
|
||||
# <?php exit()?>
|
||||
# Don't modify the lines above
|
||||
#
|
||||
# Access Control Lists
|
||||
#
|
||||
# Auto-generated by install script
|
||||
# Date: Tue, 20 Jan 2026 20:06:48 -0500
|
||||
* @ALL 1
|
||||
* @user 8
|
||||
@@ -1,21 +0,0 @@
|
||||
# acl.auth.php
|
||||
# <?php exit()?>
|
||||
# Don't modify the lines above
|
||||
#
|
||||
# Access Control Lists
|
||||
#
|
||||
# Editing this file by hand shouldn't be necessary. Use the ACL
|
||||
# Manager interface instead.
|
||||
#
|
||||
# If your auth backend allows special char like spaces in groups
|
||||
# or user names you need to urlencode them (only chars <128, leave
|
||||
# UTF-8 multibyte chars as is)
|
||||
#
|
||||
# none 0
|
||||
# read 1
|
||||
# edit 2
|
||||
# create 4
|
||||
# upload 8
|
||||
# delete 16
|
||||
|
||||
* @ALL 8
|
||||
@@ -1,62 +0,0 @@
|
||||
# Acronyms.
|
||||
|
||||
ACL Access Control List
|
||||
AFAICS As far as I can see
|
||||
AFAIK As far as I know
|
||||
AFAIR As far as I remember
|
||||
API Application Programming Interface
|
||||
ASAP As soon as possible
|
||||
ASCII American Standard Code for Information Interchange
|
||||
BTW By the way
|
||||
CMS Content Management System
|
||||
CSS Cascading Style Sheets
|
||||
DNS Domain Name System
|
||||
EOF End of file
|
||||
EOL End of line
|
||||
EOM End of message
|
||||
EOT End of text
|
||||
FAQ Frequently Asked Questions
|
||||
FTP File Transfer Protocol
|
||||
FOSS Free & Open-Source Software
|
||||
FLOSS Free/Libre and Open Source Software
|
||||
FUD Fear, Uncertainty, and Doubt
|
||||
FYI For your information
|
||||
GB Gigabyte
|
||||
GHz Gigahertz
|
||||
GPL GNU General Public License
|
||||
GUI Graphical User Interface
|
||||
HTML HyperText Markup Language
|
||||
IANAL I am not a lawyer (but)
|
||||
IE Internet Explorer
|
||||
IIRC If I remember correctly
|
||||
IMHO In my humble opinion
|
||||
IMO In my opinion
|
||||
IOW In other words
|
||||
IRC Internet Relay Chat
|
||||
IRL In real life
|
||||
KISS Keep it simple stupid
|
||||
LAN Local Area Network
|
||||
LGPL GNU Lesser General Public License
|
||||
LOL Laughing out loud
|
||||
MathML Mathematical Markup Language
|
||||
MB Megabyte
|
||||
MHz Megahertz
|
||||
MSIE Microsoft Internet Explorer
|
||||
OMG Oh my God
|
||||
OS Operating System
|
||||
OSS Open Source Software
|
||||
OTOH On the other hand
|
||||
PITA Pain in the Ass
|
||||
RFC Request for Comments
|
||||
ROTFL Rolling on the floor laughing
|
||||
RTFM Read The Fine Manual
|
||||
spec specification
|
||||
TIA Thanks in advance
|
||||
TL;DR Too long; didn't read
|
||||
TOC Table of Contents
|
||||
URI Uniform Resource Identifier
|
||||
URL Uniform Resource Locator
|
||||
W3C World Wide Web Consortium
|
||||
WTF? What the f***
|
||||
WYSIWYG What You See Is What You Get
|
||||
YMMV Your mileage may vary
|
||||
@@ -1,187 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This is DokuWiki's Main Configuration file
|
||||
*
|
||||
* All the default values are kept here, you should not modify it but use
|
||||
* a local.php file instead to override the settings from here.
|
||||
*
|
||||
* This is a piece of PHP code so PHP syntax applies!
|
||||
*
|
||||
* For help with the configuration and a more detailed explanation of the various options
|
||||
* see https://www.dokuwiki.org/config
|
||||
*/
|
||||
|
||||
|
||||
/* Basic Settings */
|
||||
$conf['title'] = 'DokuWiki'; //what to show in the title
|
||||
$conf['start'] = 'start'; //name of start page
|
||||
$conf['lang'] = 'en'; //your language
|
||||
$conf['template'] = 'dokuwiki'; //see lib/tpl directory
|
||||
$conf['tagline'] = ''; //tagline in header (if template supports it)
|
||||
$conf['sidebar'] = 'sidebar'; //name of sidebar in root namespace (if template supports it)
|
||||
$conf['license'] = 'cc-by-nc-sa'; //see conf/license.php
|
||||
$conf['savedir'] = './data'; //where to store all the files
|
||||
$conf['basedir'] = ''; //absolute dir from serveroot - blank for autodetection
|
||||
$conf['baseurl'] = ''; //URL to server including protocol - blank for autodetect
|
||||
$conf['cookiedir'] = ''; //path to use in cookies - blank for basedir
|
||||
$conf['dmode'] = 0755; //set directory creation mode
|
||||
$conf['fmode'] = 0644; //set file creation mode
|
||||
$conf['allowdebug'] = 0; //allow debug output, enable if needed 0|1
|
||||
|
||||
/* Display Settings */
|
||||
$conf['recent'] = 20; //how many entries to show in recent
|
||||
$conf['recent_days'] = 7; //How many days of recent changes to keep. (days)
|
||||
$conf['breadcrumbs'] = 10; //how many recent visited pages to show
|
||||
$conf['youarehere'] = 0; //show "You are here" navigation? 0|1
|
||||
$conf['fullpath'] = 0; //show full path of the document or relative to datadir only? 0|1
|
||||
$conf['typography'] = 1; //smartquote conversion 0=off, 1=doublequotes, 2=all quotes
|
||||
$conf['dformat'] = '%Y/%m/%d %H:%M'; //dateformat accepted by PHPs strftime() function
|
||||
$conf['signature'] = ' --- //[[@MAIL@|@NAME@]] @DATE@//'; //signature see wiki page for details
|
||||
$conf['showuseras'] = 'loginname'; // 'loginname' users login name
|
||||
// 'username' users full name
|
||||
// 'email' e-mail address (will be obfuscated as per mailguard)
|
||||
// 'email_link' e-mail address as a mailto: link (obfuscated)
|
||||
$conf['toptoclevel'] = 1; //Level starting with and below to include in AutoTOC (max. 5)
|
||||
$conf['tocminheads'] = 3; //Minimum amount of headlines that determines if a TOC is built
|
||||
$conf['maxtoclevel'] = 3; //Up to which level include into AutoTOC (max. 5)
|
||||
$conf['maxseclevel'] = 3; //Up to which level create editable sections (max. 5)
|
||||
$conf['camelcase'] = 0; //Use CamelCase for linking? (I don't like it) 0|1
|
||||
$conf['deaccent'] = 1; //deaccented chars in pagenames (1) or romanize (2) or keep (0)?
|
||||
$conf['useheading'] = 0; //use the first heading in a page as its name
|
||||
$conf['sneaky_index']= 0; //check for namespace read permission in index view (0|1) (1 might cause unexpected behavior)
|
||||
$conf['hidepages'] = ''; //Regexp for pages to be skipped from RSS, Search and Recent Changes
|
||||
|
||||
/* Authentication Settings */
|
||||
$conf['useacl'] = 0; //Use Access Control Lists to restrict access?
|
||||
$conf['autopasswd'] = 1; //autogenerate passwords and email them to user
|
||||
$conf['authtype'] = 'authplain'; //which authentication backend should be used
|
||||
$conf['passcrypt'] = 'bcrypt'; //Used crypt method (smd5,md5,sha1,ssha,crypt,mysql,my411,bcrypt)
|
||||
$conf['defaultgroup']= 'user'; //Default groups new Users are added to
|
||||
$conf['superuser'] = '!!not set!!'; //The admin can be user or @group or comma separated list user1,@group1,user2
|
||||
$conf['manager'] = '!!not set!!'; //The manager can be user or @group or comma separated list user1,@group1,user2
|
||||
$conf['profileconfirm'] = 1; //Require current password to confirm changes to user profile
|
||||
$conf['rememberme'] = 1; //Enable/disable remember me on login
|
||||
$conf['disableactions'] = ''; //comma separated list of actions to disable
|
||||
$conf['auth_security_timeout'] = 900; //time (seconds) auth data is considered valid, set to 0 to recheck on every page view
|
||||
$conf['securecookie'] = 1; //never send HTTPS cookies via HTTP
|
||||
$conf['samesitecookie'] = 'Lax'; //SameSite attribute for cookies (Lax|Strict|None|Empty)
|
||||
$conf['remote'] = 0; //Enable/disable remote interfaces
|
||||
$conf['remoteuser'] = '!!not set!!'; //user/groups that have access to remote interface (comma separated). leave empty to allow all users
|
||||
$conf['remotecors'] = ''; //enable Cross-Origin Resource Sharing (CORS) for the remote interfaces. Asterisk (*) to allow all origins. leave empty to deny.
|
||||
|
||||
/* Antispam Features */
|
||||
$conf['usewordblock']= 1; //block spam based on words? 0|1
|
||||
$conf['relnofollow'] = 1; //use rel="ugc nofollow" for external links?
|
||||
$conf['indexdelay'] = 60*60*24*5; //allow indexing after this time (seconds) default is 5 days
|
||||
$conf['mailguard'] = 'hex'; //obfuscate email addresses against spam harvesters?
|
||||
//valid entries are:
|
||||
// 'visible' - replace @ with [at], . with [dot] and - with [dash]
|
||||
// 'hex' - use hex entities to encode the mail address
|
||||
// 'none' - do not obfuscate addresses
|
||||
$conf['iexssprotect']= 1; // check for JavaScript and HTML in uploaded files 0|1
|
||||
|
||||
/* Editing Settings */
|
||||
$conf['usedraft'] = 1; //automatically save a draft while editing (0|1)
|
||||
$conf['locktime'] = 15*60; //maximum age for lockfiles (defaults to 15 minutes)
|
||||
$conf['cachetime'] = 60*60*24; //maximum age for cachefile in seconds (defaults to a day)
|
||||
|
||||
/* Link Settings */
|
||||
// Set target to use when creating links - leave empty for same window
|
||||
$conf['target']['wiki'] = '';
|
||||
$conf['target']['interwiki'] = '';
|
||||
$conf['target']['extern'] = '';
|
||||
$conf['target']['media'] = '';
|
||||
$conf['target']['windows'] = '';
|
||||
|
||||
/* Media Settings */
|
||||
$conf['mediarevisions'] = 1; //enable/disable media revisions
|
||||
$conf['refcheck'] = 1; //check for references before deleting media files
|
||||
$conf['gdlib'] = 2; //the GDlib version (0, 1 or 2) 2 tries to autodetect
|
||||
$conf['im_convert'] = ''; //path to ImageMagicks convert (will be used instead of GD)
|
||||
$conf['jpg_quality'] = '70'; //quality of compression when scaling jpg images (0-100)
|
||||
$conf['fetchsize'] = 0; //maximum size (bytes) fetch.php may download from extern, disabled by default
|
||||
|
||||
/* Notification Settings */
|
||||
$conf['subscribers'] = 0; //enable change notice subscription support
|
||||
$conf['subscribe_time'] = 24*60*60; //Time after which digests / lists are sent (in sec, default 1 day)
|
||||
//Should be smaller than the time specified in recent_days
|
||||
$conf['notify'] = ''; //send change info to this email (leave blank for nobody)
|
||||
$conf['registernotify'] = ''; //send info about newly registered users to this email (leave blank for nobody)
|
||||
$conf['mailfrom'] = ''; //use this email when sending mails
|
||||
$conf['mailreturnpath'] = ''; //use this email as returnpath for bounce mails
|
||||
$conf['mailprefix'] = ''; //use this as prefix of outgoing mails
|
||||
$conf['htmlmail'] = 1; //send HTML multipart mails
|
||||
$conf['dontlog'] = 'debug'; //logging facilities that should be disabled
|
||||
$conf['logretain'] = 3; //how many days of logs to keep
|
||||
|
||||
/* Syndication Settings */
|
||||
$conf['sitemap'] = 0; //Create a Google sitemap? How often? In days.
|
||||
$conf['rss_type'] = 'rss1'; //type of RSS feed to provide, by default:
|
||||
// 'rss' - RSS 0.91
|
||||
// 'rss1' - RSS 1.0
|
||||
// 'rss2' - RSS 2.0
|
||||
// 'atom' - Atom 0.3
|
||||
// 'atom1' - Atom 1.0
|
||||
$conf['rss_linkto'] = 'diff'; //what page RSS entries link to:
|
||||
// 'diff' - page showing revision differences
|
||||
// 'page' - the revised page itself
|
||||
// 'rev' - page showing all revisions
|
||||
// 'current' - most recent revision of page
|
||||
$conf['rss_content'] = 'abstract'; //what to put in the items by default?
|
||||
// 'abstract' - plain text, first paragraph or so
|
||||
// 'diff' - plain text unified diff wrapped in <pre> tags
|
||||
// 'htmldiff' - diff as HTML table
|
||||
// 'html' - the full page rendered in XHTML
|
||||
$conf['rss_media'] = 'both'; //what should be listed?
|
||||
// 'both' - page and media changes
|
||||
// 'pages' - page changes only
|
||||
// 'media' - media changes only
|
||||
$conf['rss_update'] = 5*60; //Update the RSS feed every n seconds (defaults to 5 minutes)
|
||||
$conf['rss_show_summary'] = 1; //Add revision summary to title? 0|1
|
||||
$conf['rss_show_deleted'] = 1; //Show deleted items 0|1
|
||||
|
||||
/* Advanced Settings */
|
||||
$conf['updatecheck'] = 1; //automatically check for new releases?
|
||||
$conf['userewrite'] = 0; //this makes nice URLs: 0: off 1: .htaccess 2: internal
|
||||
$conf['useslash'] = 0; //use slash instead of colon? only when rewrite is on
|
||||
$conf['sepchar'] = '_'; //word separator character in page names; may be a
|
||||
// letter, a digit, '_', '-', or '.'.
|
||||
$conf['canonical'] = 0; //Should all URLs use full canonical http://... style?
|
||||
$conf['fnencode'] = 'url'; //encode filenames (url|safe|utf-8)
|
||||
$conf['autoplural'] = 0; //try (non)plural form of nonexistent files?
|
||||
$conf['compression'] = 'gz'; //compress old revisions: (0: off) ('gz': gnuzip) ('bz2': bzip)
|
||||
// bz2 generates smaller files, but needs more cpu-power
|
||||
$conf['gzip_output'] = 0; //use gzip content encoding for the output xhtml (if allowed by browser)
|
||||
$conf['compress'] = 1; //Strip whitespaces and comments from Styles and JavaScript? 1|0
|
||||
$conf['cssdatauri'] = 512; //Maximum byte size of small images to embed into CSS, won't work on IE<8
|
||||
$conf['send404'] = 0; //Send an HTTP 404 status for nonexistent pages?
|
||||
$conf['broken_iua'] = 0; //Platform with broken ignore_user_abort (IIS+CGI) 0|1
|
||||
$conf['xsendfile'] = 0; //Use X-Sendfile (1 = lighttpd, 2 = standard)
|
||||
$conf['renderer_xhtml'] = 'xhtml'; //renderer to use for main page generation
|
||||
$conf['readdircache'] = 0; //time cache in second for the readdir operation, 0 to deactivate.
|
||||
$conf['search_nslimit'] = 0; //limit the search to the current X namespaces
|
||||
$conf['search_fragment'] = 'exact'; //specify the default fragment search behavior
|
||||
|
||||
/* Feature Flags */
|
||||
$conf['defer_js'] = 1; // Defer javascript to be executed after the page's HTML has been parsed. Setting will be removed in the next release.
|
||||
$conf['hidewarnings'] = 0; // Hide warnings
|
||||
|
||||
/* Network Settings */
|
||||
$conf['dnslookups'] = 1; //disable to disallow IP to hostname lookups
|
||||
$conf['jquerycdn'] = 0; //use a CDN for delivering jQuery?
|
||||
$conf['trustedproxies'] = array('::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16');
|
||||
// Trusted proxy servers from which to read the X-Forwarded-For header.
|
||||
// Each item in the array may be either an IPv4 or IPv6 address, or
|
||||
// an IPv4 or IPv6 CIDR range (e.g. 10.0.0.0/8).
|
||||
|
||||
$conf['realip'] = false; // Enable reading the X-Real-IP header. Default: false.
|
||||
// Only enable this if your server writes this header, otherwise it may be spoofed.
|
||||
|
||||
|
||||
// Proxy setup - if your Server needs a proxy to access the web set these
|
||||
$conf['proxy']['host'] = '';
|
||||
$conf['proxy']['port'] = '';
|
||||
$conf['proxy']['user'] = '';
|
||||
$conf['proxy']['pass'] = '';
|
||||
$conf['proxy']['ssl'] = 0;
|
||||
$conf['proxy']['except'] = '';
|
||||
@@ -1,22 +0,0 @@
|
||||
# Typography replacements
|
||||
#
|
||||
# Order does matter!
|
||||
#
|
||||
# You can use HTML entities here, but it is not recommended because it may break
|
||||
# non-HTML renderers. Use UTF-8 chars directly instead.
|
||||
|
||||
<-> ↔
|
||||
-> →
|
||||
<- ←
|
||||
<=> ⇔
|
||||
=> ⇒
|
||||
<= ⇐
|
||||
>> »
|
||||
<< «
|
||||
--- —
|
||||
-- –
|
||||
(c) ©
|
||||
(tm) ™
|
||||
(r) ®
|
||||
... …
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# Each URL may contain one of these placeholders
|
||||
# {URL} is replaced by the URL encoded representation of the wikiname
|
||||
# this is the right thing to do in most cases
|
||||
# {NAME} this is replaced by the wikiname as given in the document
|
||||
# only mandatory encoded is done, urlencoding if the link
|
||||
# is an external URL, or encoding as a wikiname if it is an
|
||||
# internal link (begins with a colon)
|
||||
# {SCHEME}
|
||||
# {HOST}
|
||||
# {PORT}
|
||||
# {PATH}
|
||||
# {QUERY} these placeholders will be replaced with the appropriate part
|
||||
# of the link when parsed as a URL
|
||||
# If no placeholder is defined the urlencoded name is appended to the URL
|
||||
|
||||
# To prevent losing your added InterWiki shortcuts after an upgrade,
|
||||
# you should add new ones to interwiki.local.conf
|
||||
|
||||
wp https://en.wikipedia.org/wiki/{NAME}
|
||||
wpfr https://fr.wikipedia.org/wiki/{NAME}
|
||||
wpde https://de.wikipedia.org/wiki/{NAME}
|
||||
wpes https://es.wikipedia.org/wiki/{NAME}
|
||||
wppl https://pl.wikipedia.org/wiki/{NAME}
|
||||
wpjp https://ja.wikipedia.org/wiki/{NAME}
|
||||
wpru https://ru.wikipedia.org/wiki/{NAME}
|
||||
wpmeta https://meta.wikipedia.org/wiki/{NAME}
|
||||
doku https://www.dokuwiki.org/
|
||||
rfc https://tools.ietf.org/html/rfc
|
||||
man http://man.cx/
|
||||
amazon https://www.amazon.com/dp/{URL}?tag=splitbrain-20
|
||||
amazon.de https://www.amazon.de/dp/{URL}?tag=splitbrain-21
|
||||
amazon.uk https://www.amazon.co.uk/dp/{URL}
|
||||
paypal https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=
|
||||
phpfn https://secure.php.net/{NAME}
|
||||
skype skype:{NAME}
|
||||
google https://www.google.com/search?q=
|
||||
google.de https://www.google.de/search?q=
|
||||
go https://www.google.com/search?q={URL}&btnI=lucky
|
||||
user :user:{NAME}
|
||||
|
||||
# To support VoIP/SIP/TEL links
|
||||
callto callto://{NAME}
|
||||
tel tel:{NAME}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This file defines multiple available licenses you can license your
|
||||
* wiki contents under. Do not change this file, but create a
|
||||
* license.local.php instead.
|
||||
*/
|
||||
|
||||
if(empty($LC)) $LC = empty($conf['lang']) ? 'en' : $conf['lang'];
|
||||
|
||||
$license['cc-zero'] = array(
|
||||
'name' => 'CC0 1.0 Universal',
|
||||
'url' => 'https://creativecommons.org/publicdomain/zero/1.0/deed.'.$LC,
|
||||
);
|
||||
$license['publicdomain'] = array(
|
||||
'name' => 'Public Domain',
|
||||
'url' => 'https://creativecommons.org/licenses/publicdomain/deed.'.$LC,
|
||||
);
|
||||
$license['cc-by'] = array(
|
||||
'name' => 'CC Attribution 4.0 International',
|
||||
'url' => 'https://creativecommons.org/licenses/by/4.0/deed.'.$LC,
|
||||
);
|
||||
$license['cc-by-sa'] = array(
|
||||
'name' => 'CC Attribution-Share Alike 4.0 International',
|
||||
'url' => 'https://creativecommons.org/licenses/by-sa/4.0/deed.'.$LC,
|
||||
);
|
||||
$license['gnufdl'] = array(
|
||||
'name' => 'GNU Free Documentation License 1.3',
|
||||
'url' => 'https://www.gnu.org/licenses/fdl-1.3.html',
|
||||
);
|
||||
$license['cc-by-nc'] = array(
|
||||
'name' => 'CC Attribution-Noncommercial 4.0 International',
|
||||
'url' => 'https://creativecommons.org/licenses/by-nc/4.0/deed.'.$LC,
|
||||
);
|
||||
$license['cc-by-nc-sa'] = array(
|
||||
'name' => 'CC Attribution-Noncommercial-Share Alike 4.0 International',
|
||||
'url' => 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.'.$LC,
|
||||
);
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Dokuwiki's Main Configuration File - Local Settings
|
||||
* Auto-generated by install script
|
||||
* Date: Tue, 20 Jan 2026 20:06:48 -0500
|
||||
*/
|
||||
$conf['title'] = 'AI-Homelab';
|
||||
$conf['lang'] = 'en';
|
||||
$conf['license'] = 'cc-by-sa';
|
||||
$conf['useacl'] = 1;
|
||||
$conf['superuser'] = '@admin';
|
||||
$conf['disableactions'] = 'register';
|
||||
$conf['savedir'] = '/app/www/public/data';
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This is an example of how a local.php could look like.
|
||||
* Simply copy the options you want to change from dokuwiki.php
|
||||
* to this file and change them.
|
||||
*
|
||||
* When using the installer, a correct local.php file be generated for
|
||||
* you automatically.
|
||||
*/
|
||||
|
||||
|
||||
//$conf['title'] = 'My Wiki'; //what to show in the title
|
||||
|
||||
//$conf['useacl'] = 1; //Use Access Control Lists to restrict access?
|
||||
//$conf['superuser'] = 'joe';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"display": "standalone"
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This configures which metadata will be editable through
|
||||
* the media manager. Each field of the array is an array with the
|
||||
* following contents:
|
||||
* fieldname - Where data will be saved (EXIF or IPTC field)
|
||||
* label - key to lookup in the $lang var, if not found printed as is
|
||||
* htmltype - 'text', 'textarea' or 'date'
|
||||
* lookups - array additional fields to look up the data (EXIF or IPTC fields)
|
||||
*
|
||||
* The fields are not ordered continuously to make inserting additional items
|
||||
* in between simpler.
|
||||
*
|
||||
* This is a PHP snippet, so PHP syntax applies.
|
||||
*
|
||||
* Note: $fields is not a global variable and will not be available to any
|
||||
* other functions or templates later
|
||||
*
|
||||
* You may extend or overwrite this variable in an optional
|
||||
* conf/mediameta.local.php file
|
||||
*
|
||||
* For a list of available EXIF/IPTC fields refer to
|
||||
* http://www.dokuwiki.org/devel:templates:detail.php
|
||||
*/
|
||||
|
||||
|
||||
$fields = array(
|
||||
10 => array('Iptc.Headline',
|
||||
'img_title',
|
||||
'text'),
|
||||
|
||||
20 => array('',
|
||||
'img_date',
|
||||
'date',
|
||||
array('Date.EarliestTime')),
|
||||
|
||||
30 => array('',
|
||||
'img_fname',
|
||||
'text',
|
||||
array('File.Name')),
|
||||
|
||||
40 => array('Iptc.Caption',
|
||||
'img_caption',
|
||||
'textarea',
|
||||
array('Exif.UserComment',
|
||||
'Exif.TIFFImageDescription',
|
||||
'Exif.TIFFUserComment')),
|
||||
|
||||
50 => array('Iptc.Byline',
|
||||
'img_artist',
|
||||
'text',
|
||||
array('Exif.TIFFArtist',
|
||||
'Exif.Artist',
|
||||
'Iptc.Credit')),
|
||||
|
||||
60 => array('Iptc.CopyrightNotice',
|
||||
'img_copyr',
|
||||
'text',
|
||||
array('Exif.TIFFCopyright',
|
||||
'Exif.Copyright')),
|
||||
|
||||
70 => array('',
|
||||
'img_format',
|
||||
'text',
|
||||
array('File.Format')),
|
||||
|
||||
80 => array('',
|
||||
'img_fsize',
|
||||
'text',
|
||||
array('File.NiceSize')),
|
||||
|
||||
90 => array('',
|
||||
'img_width',
|
||||
'text',
|
||||
array('File.Width')),
|
||||
|
||||
100 => array('',
|
||||
'img_height',
|
||||
'text',
|
||||
array('File.Height')),
|
||||
|
||||
110 => array('',
|
||||
'img_camera',
|
||||
'text',
|
||||
array('Simple.Camera')),
|
||||
|
||||
120 => array('Iptc.Keywords',
|
||||
'img_keywords',
|
||||
'text',
|
||||
array('Exif.Category')),
|
||||
);
|
||||
@@ -1,75 +0,0 @@
|
||||
# Allowed uploadable file extensions and mimetypes are defined here.
|
||||
# To extend this file it is recommended to create a mime.local.conf
|
||||
# file. Mimetypes that should be downloadable and not be opened in the
|
||||
# should be prefixed with a !
|
||||
|
||||
jpg image/jpeg
|
||||
jpeg image/jpeg
|
||||
gif image/gif
|
||||
png image/png
|
||||
webp image/webp
|
||||
ico image/vnd.microsoft.icon
|
||||
|
||||
mp3 audio/mpeg
|
||||
ogg audio/ogg
|
||||
wav audio/wav
|
||||
webm video/webm
|
||||
ogv video/ogg
|
||||
mp4 video/mp4
|
||||
vtt text/vtt
|
||||
|
||||
tgz !application/octet-stream
|
||||
tar !application/x-gtar
|
||||
gz !application/octet-stream
|
||||
bz2 !application/octet-stream
|
||||
zip !application/zip
|
||||
rar !application/rar
|
||||
7z !application/x-7z-compressed
|
||||
|
||||
pdf application/pdf
|
||||
ps !application/postscript
|
||||
|
||||
rpm !application/octet-stream
|
||||
deb !application/octet-stream
|
||||
|
||||
doc !application/msword
|
||||
xls !application/msexcel
|
||||
ppt !application/mspowerpoint
|
||||
rtf !application/msword
|
||||
|
||||
docx !application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
xlsx !application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
pptx !application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
|
||||
sxw !application/soffice
|
||||
sxc !application/soffice
|
||||
sxi !application/soffice
|
||||
sxd !application/soffice
|
||||
|
||||
odc !application/vnd.oasis.opendocument.chart
|
||||
odf !application/vnd.oasis.opendocument.formula
|
||||
odg !application/vnd.oasis.opendocument.graphics
|
||||
odi !application/vnd.oasis.opendocument.image
|
||||
odp !application/vnd.oasis.opendocument.presentation
|
||||
ods !application/vnd.oasis.opendocument.spreadsheet
|
||||
odt !application/vnd.oasis.opendocument.text
|
||||
|
||||
svg image/svg+xml
|
||||
|
||||
# You should enable HTML and Text uploads only for restricted Wikis.
|
||||
# Spammers are known to upload spam pages through unprotected Wikis.
|
||||
# Note: Enabling HTML opens Cross Site Scripting vulnerabilities
|
||||
# through JavaScript. Only enable this with trusted users. You
|
||||
# need to disable the iexssprotect option additionally to
|
||||
# adding the mime type here
|
||||
#html text/html
|
||||
#htm text/html
|
||||
#txt text/plain
|
||||
#conf text/plain
|
||||
#xml text/xml
|
||||
#csv text/csv
|
||||
|
||||
# Also flash may be able to execute arbitrary scripts in the website's
|
||||
# context
|
||||
#swf application/x-shockwave-flash
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This is an example configuration for the mysql auth plugin.
|
||||
*
|
||||
* This SQL statements are optimized for following table structure.
|
||||
* If you use a different one you have to change them accordingly.
|
||||
* See comments of every statement for details.
|
||||
*
|
||||
* TABLE users
|
||||
* uid login pass firstname lastname email
|
||||
*
|
||||
* TABLE groups
|
||||
* gid name
|
||||
*
|
||||
* TABLE usergroup
|
||||
* uid gid
|
||||
*
|
||||
* To use this configuration you have to copy them to local.protected.php
|
||||
* or at least include this file in local.protected.php.
|
||||
*/
|
||||
|
||||
/* Options to configure database access. You need to set up this
|
||||
* options carefully, otherwise you won't be able to access you
|
||||
* database.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['server'] = '';
|
||||
$conf['plugin']['authmysql']['user'] = '';
|
||||
$conf['plugin']['authmysql']['password'] = '';
|
||||
$conf['plugin']['authmysql']['database'] = '';
|
||||
|
||||
/* This option enables debug messages in the mysql plugin. It is
|
||||
* mostly useful for system admins.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['debug'] = 0;
|
||||
|
||||
/* Normally password encryption is done by DokuWiki (recommended) but for
|
||||
* some reasons it might be useful to let the database do the encryption.
|
||||
* Set 'forwardClearPass' to '1' and the cleartext password is forwarded to
|
||||
* the database, otherwise the encrypted one.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['forwardClearPass'] = 0;
|
||||
|
||||
/* Multiple table operations will be protected by locks. This array tells
|
||||
* the plugin which tables to lock. If you use any aliases for table names
|
||||
* these array must also contain these aliases. Any unnamed alias will cause
|
||||
* a warning during operation. See the example below.
|
||||
*/
|
||||
$conf['plugin']['authmysql']['TablesToLock']= array("users", "users AS u","groups", "groups AS g", "usergroup", "usergroup AS ug");
|
||||
|
||||
/***********************************************************************/
|
||||
/* Basic SQL statements for user authentication (required) */
|
||||
/***********************************************************************/
|
||||
|
||||
/* This statement is used to grant or deny access to the wiki. The result
|
||||
* should be a table with exact one line containing at least the password
|
||||
* of the user. If the result table is empty or contains more than one
|
||||
* row, access will be denied.
|
||||
*
|
||||
* The plugin accesses the password as 'pass' so an alias might be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{user} user name
|
||||
* %{pass} encrypted or clear text password (depends on 'encryptPass')
|
||||
* %{dgroup} default group name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['checkPass'] = "SELECT pass
|
||||
FROM usergroup AS ug
|
||||
JOIN users AS u ON u.uid=ug.uid
|
||||
JOIN groups AS g ON g.gid=ug.gid
|
||||
WHERE login='%{user}'
|
||||
AND name='%{dgroup}'";
|
||||
|
||||
/* This statement should return a table with exact one row containing
|
||||
* information about one user. The field needed are:
|
||||
* 'pass' containing the encrypted or clear text password
|
||||
* 'name' the user's full name
|
||||
* 'mail' the user's email address
|
||||
*
|
||||
* Keep in mind that Dokuwiki will access this information through the
|
||||
* names listed above so aliases might be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{user} user name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['getUserInfo'] = "SELECT pass, CONCAT(firstname,' ',lastname) AS name, email AS mail
|
||||
FROM users
|
||||
WHERE login='%{user}'";
|
||||
|
||||
/* This statement is used to get all groups a user is member of. The
|
||||
* result should be a table containing all groups the given user is
|
||||
* member of. The plugin accesses the group name as 'group' so an alias
|
||||
* might be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{user} user name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['getGroups'] = "SELECT name as `group`
|
||||
FROM groups g, users u, usergroup ug
|
||||
WHERE u.uid = ug.uid
|
||||
AND g.gid = ug.gid
|
||||
AND u.login='%{user}'";
|
||||
|
||||
/***********************************************************************/
|
||||
/* Additional minimum SQL statements to use the user manager */
|
||||
/***********************************************************************/
|
||||
|
||||
/* This statement should return a table containing all user login names
|
||||
* that meet certain filter criteria. The filter expressions will be added
|
||||
* case dependent by the plugin. At the end a sort expression will be added.
|
||||
* Important is that this list contains no double entries for a user. Each
|
||||
* user name is only allowed once in the table.
|
||||
*
|
||||
* The login name will be accessed as 'user' to an alias might be necessary.
|
||||
* No patterns will be replaced in this statement but following patters
|
||||
* will be replaced in the filter expressions:
|
||||
* %{user} in FilterLogin user's login name
|
||||
* %{name} in FilterName user's full name
|
||||
* %{email} in FilterEmail user's email address
|
||||
* %{group} in FilterGroup group name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['getUsers'] = "SELECT DISTINCT login AS user
|
||||
FROM users AS u
|
||||
LEFT JOIN usergroup AS ug ON u.uid=ug.uid
|
||||
LEFT JOIN groups AS g ON ug.gid=g.gid";
|
||||
$conf['plugin']['authmysql']['FilterLogin'] = "login LIKE '%{user}'";
|
||||
$conf['plugin']['authmysql']['FilterName'] = "CONCAT(firstname,' ',lastname) LIKE '%{name}'";
|
||||
$conf['plugin']['authmysql']['FilterEmail'] = "email LIKE '%{email}'";
|
||||
$conf['plugin']['authmysql']['FilterGroup'] = "name LIKE '%{group}'";
|
||||
$conf['plugin']['authmysql']['SortOrder'] = "ORDER BY login";
|
||||
|
||||
/***********************************************************************/
|
||||
/* Additional SQL statements to add new users with the user manager */
|
||||
/***********************************************************************/
|
||||
|
||||
/* This statement should add a user to the database. Minimum information
|
||||
* to store are: login name, password, email address and full name.
|
||||
*
|
||||
* Following patterns will be replaced:
|
||||
* %{user} user's login name
|
||||
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
|
||||
* %{email} email address
|
||||
* %{name} user's full name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['addUser'] = "INSERT INTO users
|
||||
(login, pass, email, firstname, lastname)
|
||||
VALUES ('%{user}', '%{pass}', '%{email}',
|
||||
SUBSTRING_INDEX('%{name}',' ', 1),
|
||||
SUBSTRING_INDEX('%{name}',' ', -1))";
|
||||
|
||||
/* This statement should add a group to the database.
|
||||
* Following patterns will be replaced:
|
||||
* %{group} group name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['addGroup'] = "INSERT INTO groups (name)
|
||||
VALUES ('%{group}')";
|
||||
|
||||
/* This statement should connect a user to a group (a user become member
|
||||
* of that group).
|
||||
* Following patterns will be replaced:
|
||||
* %{user} user's login name
|
||||
* %{uid} id of a user dataset
|
||||
* %{group} group name
|
||||
* %{gid} id of a group dataset
|
||||
*/
|
||||
$conf['plugin']['authmysql']['addUserGroup']= "INSERT INTO usergroup (uid, gid)
|
||||
VALUES ('%{uid}', '%{gid}')";
|
||||
|
||||
/* This statement should remove a group fom the database.
|
||||
* Following patterns will be replaced:
|
||||
* %{group} group name
|
||||
* %{gid} id of a group dataset
|
||||
*/
|
||||
$conf['plugin']['authmysql']['delGroup'] = "DELETE FROM groups
|
||||
WHERE gid='%{gid}'";
|
||||
|
||||
/* This statement should return the database index of a given user name.
|
||||
* The plugin will access the index with the name 'id' so an alias might be
|
||||
* necessary.
|
||||
* following patters will be replaced:
|
||||
* %{user} user name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['getUserID'] = "SELECT uid AS id
|
||||
FROM users
|
||||
WHERE login='%{user}'";
|
||||
|
||||
/***********************************************************************/
|
||||
/* Additional SQL statements to delete users with the user manager */
|
||||
/***********************************************************************/
|
||||
|
||||
/* This statement should remove a user fom the database.
|
||||
* Following patterns will be replaced:
|
||||
* %{user} user's login name
|
||||
* %{uid} id of a user dataset
|
||||
*/
|
||||
$conf['plugin']['authmysql']['delUser'] = "DELETE FROM users
|
||||
WHERE uid='%{uid}'";
|
||||
|
||||
/* This statement should remove all connections from a user to any group
|
||||
* (a user quits membership of all groups).
|
||||
* Following patterns will be replaced:
|
||||
* %{uid} id of a user dataset
|
||||
*/
|
||||
$conf['plugin']['authmysql']['delUserRefs'] = "DELETE FROM usergroup
|
||||
WHERE uid='%{uid}'";
|
||||
|
||||
/***********************************************************************/
|
||||
/* Additional SQL statements to modify users with the user manager */
|
||||
/***********************************************************************/
|
||||
|
||||
/* This statements should modify a user entry in the database. The
|
||||
* statements UpdateLogin, UpdatePass, UpdateEmail and UpdateName will be
|
||||
* added to updateUser on demand. Only changed parameters will be used.
|
||||
*
|
||||
* Following patterns will be replaced:
|
||||
* %{user} user's login name
|
||||
* %{pass} password (encrypted or clear text, depends on 'encryptPass')
|
||||
* %{email} email address
|
||||
* %{name} user's full name
|
||||
* %{uid} user id that should be updated
|
||||
*/
|
||||
$conf['plugin']['authmysql']['updateUser'] = "UPDATE users SET";
|
||||
$conf['plugin']['authmysql']['UpdateLogin'] = "login='%{user}'";
|
||||
$conf['plugin']['authmysql']['UpdatePass'] = "pass='%{pass}'";
|
||||
$conf['plugin']['authmysql']['UpdateEmail'] = "email='%{email}'";
|
||||
$conf['plugin']['authmysql']['UpdateName'] = "firstname=SUBSTRING_INDEX('%{name}',' ', 1),
|
||||
lastname=SUBSTRING_INDEX('%{name}',' ', -1)";
|
||||
$conf['plugin']['authmysql']['UpdateTarget']= "WHERE uid=%{uid}";
|
||||
|
||||
/* This statement should remove a single connection from a user to a
|
||||
* group (a user quits membership of that group).
|
||||
*
|
||||
* Following patterns will be replaced:
|
||||
* %{user} user's login name
|
||||
* %{uid} id of a user dataset
|
||||
* %{group} group name
|
||||
* %{gid} id of a group dataset
|
||||
*/
|
||||
$conf['plugin']['authmysql']['delUserGroup']= "DELETE FROM usergroup
|
||||
WHERE uid='%{uid}'
|
||||
AND gid='%{gid}'";
|
||||
|
||||
/* This statement should return the database index of a given group name.
|
||||
* The plugin will access the index with the name 'id' so an alias might
|
||||
* be necessary.
|
||||
*
|
||||
* Following patters will be replaced:
|
||||
* %{group} group name
|
||||
*/
|
||||
$conf['plugin']['authmysql']['getGroupID'] = "SELECT gid AS id
|
||||
FROM groups
|
||||
WHERE name='%{group}'";
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Local plugin enable/disable settings
|
||||
*
|
||||
* Auto-generated by install script
|
||||
* Date: Tue, 20 Jan 2026 20:06:48 -0500
|
||||
*/
|
||||
|
||||
$plugins['authad'] = 0;
|
||||
$plugins['authldap'] = 0;
|
||||
$plugins['authmysql'] = 0;
|
||||
$plugins['authpgsql'] = 0;
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This file configures the default states of available plugins. All settings in
|
||||
* the plugins.*.php files will override those here.
|
||||
*/
|
||||
$plugins['testing'] = 0;
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This file configures the enabled/disabled status of plugins, which are also protected
|
||||
* from changes by the extension manager. These settings will override any local settings.
|
||||
* It is not recommended to change this file, as it is overwritten on DokuWiki upgrades.
|
||||
*/
|
||||
$plugins['acl'] = 1;
|
||||
$plugins['authplain'] = 1;
|
||||
$plugins['extension'] = 1;
|
||||
$plugins['config'] = 1;
|
||||
$plugins['usermanager'] = 1;
|
||||
$plugins['template:dokuwiki'] = 1; // not a plugin, but this should not be uninstalled either
|
||||
@@ -1,11 +0,0 @@
|
||||
#Add URL schemes you want to be recognized as links here
|
||||
|
||||
http
|
||||
https
|
||||
telnet
|
||||
gopher
|
||||
wais
|
||||
ftp
|
||||
ed2k
|
||||
irc
|
||||
ldap
|
||||
@@ -1,28 +0,0 @@
|
||||
# Smileys configured here will be replaced by the
|
||||
# configured images in the smiley directory
|
||||
|
||||
8-) cool.svg
|
||||
8-O eek.svg
|
||||
8-o eek.svg
|
||||
:-( sad.svg
|
||||
:-) smile.svg
|
||||
=) smile2.svg
|
||||
:-/ doubt.svg
|
||||
:-\ doubt2.svg
|
||||
:-? confused.svg
|
||||
:-D biggrin.svg
|
||||
:-P razz.svg
|
||||
:-o surprised.svg
|
||||
:-O surprised.svg
|
||||
:-x silenced.svg
|
||||
:-X silenced.svg
|
||||
:-| neutral.svg
|
||||
;-) wink.svg
|
||||
m( facepalm.svg
|
||||
^_^ fun.svg
|
||||
:?: question.svg
|
||||
:!: exclaim.svg
|
||||
LOL lol.svg
|
||||
FIXME fixme.svg
|
||||
DELETEME deleteme.svg
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# users.auth.php
|
||||
# <?php exit()?>
|
||||
# Don't modify the lines above
|
||||
#
|
||||
# Userfile
|
||||
#
|
||||
# Auto-generated by install script
|
||||
# Date: Tue, 20 Jan 2026 20:06:48 -0500
|
||||
#
|
||||
# Format:
|
||||
# login:passwordhash:Real Name:email:groups,comma,separated
|
||||
|
||||
admin:$2y$10$dX5ryEUsFKXDRNl6DAk5Zem.1KtI8Q45.z0EQ6NLI7HXJjJyx4hqS:Admin:admin@example.com:admin,user
|
||||
@@ -1,10 +0,0 @@
|
||||
# users.auth.php
|
||||
# <?php exit()?>
|
||||
# Don't modify the lines above
|
||||
#
|
||||
# Userfile
|
||||
#
|
||||
# Format:
|
||||
#
|
||||
# login:passwordhash:Real Name:email:groups,comma,separated
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# This blacklist is maintained by the DokuWiki community
|
||||
# patches welcome
|
||||
#
|
||||
https?:\/\/(\S*?)(-side-effects|top|pharm|pill|discount|discount-|deal|price|order|now|best|cheap|cheap-|online|buy|buy-|sale|sell)(\S*?)(cialis|viagra|prazolam|xanax|zanax|soma|vicodin|zenical|xenical|meridia|paxil|prozac|claritin|allegra|lexapro|wellbutrin|zoloft|retin|valium|levitra|phentermine)
|
||||
https?:\/\/(\S*?)(bi\s*sex|gay\s*sex|fetish|incest|penis|\brape\b)
|
||||
zoosex
|
||||
gang\s*bang
|
||||
facials
|
||||
ladyboy
|
||||
\btits\b
|
||||
bolea\.com
|
||||
52crystal
|
||||
baida\.org
|
||||
web-directory\.awardspace\.us
|
||||
korsan-team\.com
|
||||
BUDA TAMAMDIR
|
||||
wow-powerleveling-wow\.com
|
||||
wow gold
|
||||
wow-gold\.dinmo\.cn
|
||||
downgrade-vista\.com
|
||||
downgradetowindowsxp\.com
|
||||
elegantugg\.com
|
||||
classicedhardy\.com
|
||||
research-service\.com
|
||||
https?:\/\/(\S*?)(2-pay-secure|911essay|academia-research|anypapers|applicationessay|bestbuyessay|bestdissertation|bestessay|bestresume|besttermpaper|businessessay|college-paper|customessay|custom-made-paper|custom-writing|degree-?result|dissertationblog|dissertation-service|dissertations?expert|essaybank|essay-?blog|essaycapital|essaylogic|essaymill|essayontime|essaypaper|essays?land|essaytownsucks|essay-?writ|fastessays|freelancercareers|genuinecontent|genuineessay|genuinepaper|goessay|grandresume|killer-content|ma-dissertation|managementessay|masterpaper|mightystudent|needessay|researchedge|researchpaper-blog|resumecvservice|resumesexperts|resumesplanet|rushessay|samedayessay|superiorcontent|superiorpaper|superiorthesis|term-paper|termpaper-blog|term-paper-research|thesisblog|universalresearch|valwriting|vdwriters|wisetranslation|writersassembly|writers\.com\.ph|writers\.ph)
|
||||
flatsinmumbai\.co\.in
|
||||
https?:\/\/(\S*?)penny-?stock
|
||||
mattressreview\.biz
|
||||
(just|simply) (my|a) profile (site|webpage|page)
|
||||
@@ -1,35 +0,0 @@
|
||||
# Dokuwiki - Self-hosted Wiki Platform
|
||||
# Place in /opt/stacks/productivity/dokuwiki/docker-compose.yml
|
||||
|
||||
services:
|
||||
dokuwiki:
|
||||
image: lscr.io/linuxserver/dokuwiki:latest
|
||||
container_name: dokuwiki
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- traefik-network
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Self-hosted wiki platform"
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dokuwiki.rule=Host(`wiki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
|
||||
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
|
||||
- "traefik.http.services.dokuwiki.loadbalancer.server.port=80"
|
||||
- "x-dockge.url=https://wiki.${DOMAIN}"
|
||||
|
||||
volumes:
|
||||
dokuwiki-config:
|
||||
|
||||
networks:
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -1,493 +0,0 @@
|
||||
---
|
||||
# Homepage Bookmarks - Comprehensive EZ-Homelab Resources
|
||||
|
||||
- EZ-Homelab Project:
|
||||
- EZ-Homelab GitHub:
|
||||
- icon: github.png
|
||||
href: https://github.com/kelinfoxy/EZ-Homelab
|
||||
description: EZ-Homelab Repository & Documentation
|
||||
- EZ-Homelab Wiki:
|
||||
- icon: si-readthedocs
|
||||
href: https://github.com/kelinfoxy/EZ-Homelab/wiki
|
||||
description: Comprehensive Documentation Wiki
|
||||
- Homepage Dashboard:
|
||||
- icon: homepage.png
|
||||
href: https://gethomepage.dev
|
||||
description: Homepage Dashboard Documentation
|
||||
|
||||
- Infrastructure & Core Services:
|
||||
- Traefik:
|
||||
- icon: si-traefikproxy
|
||||
href: https://traefik.io
|
||||
description: Traefik Reverse Proxy
|
||||
- icon: github.png
|
||||
href: https://github.com/traefik/traefik
|
||||
description: Traefik GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/_/traefik
|
||||
description: Traefik Docker Image
|
||||
- Authelia:
|
||||
- icon: si-authelia
|
||||
href: https://www.authelia.com
|
||||
description: Authelia SSO Authentication
|
||||
- icon: github.png
|
||||
href: https://github.com/authelia/authelia
|
||||
description: Authelia GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/authelia/authelia
|
||||
description: Authelia Docker Image
|
||||
- DuckDNS:
|
||||
- icon: si-duckduckgo
|
||||
href: https://www.duckdns.org
|
||||
description: Dynamic DNS Service
|
||||
- Docker:
|
||||
- icon: docker.png
|
||||
href: https://www.docker.com
|
||||
description: Docker Official Website
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com
|
||||
description: Docker Hub Registry
|
||||
- icon: si-docker
|
||||
href: https://docs.docker.com
|
||||
description: Docker Documentation
|
||||
- Portainer:
|
||||
- icon: si-portainer
|
||||
href: https://www.portainer.io
|
||||
description: Portainer Container Management
|
||||
- icon: github.png
|
||||
href: https://github.com/portainer/portainer
|
||||
description: Portainer GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/portainer/portainer-ce
|
||||
description: Portainer Docker Image
|
||||
- Pi-hole:
|
||||
- icon: si-raspberrypi
|
||||
href: https://pi-hole.net
|
||||
description: Pi-hole Network-wide Ad Blocking
|
||||
- icon: github.png
|
||||
href: https://github.com/pi-hole/pi-hole
|
||||
description: Pi-hole GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/pihole/pihole
|
||||
description: Pi-hole Docker Image
|
||||
- LinuxServer.io:
|
||||
- icon: si-linux
|
||||
href: https://www.linuxserver.io
|
||||
description: LinuxServer.io Container Images
|
||||
- icon: github.png
|
||||
href: https://github.com/linuxserver
|
||||
description: LinuxServer GitHub Organization
|
||||
|
||||
- Media Services:
|
||||
- Plex:
|
||||
- icon: si-plex
|
||||
href: https://www.plex.tv
|
||||
description: Plex Media Server
|
||||
- icon: github.png
|
||||
href: https://github.com/plexinc/pms-docker
|
||||
description: Plex Docker GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/plexinc/pms-docker
|
||||
description: Plex Docker Image
|
||||
- Jellyfin:
|
||||
- icon: si-jellyfin
|
||||
href: https://jellyfin.org
|
||||
description: Jellyfin Media Server (Open Source)
|
||||
- icon: github.png
|
||||
href: https://github.com/jellyfin/jellyfin
|
||||
description: Jellyfin GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/jellyfin/jellyfin
|
||||
description: Jellyfin Docker Image
|
||||
- Sonarr:
|
||||
- icon: si-sonarr
|
||||
href: https://sonarr.tv
|
||||
description: Sonarr TV Show Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/Sonarr/Sonarr
|
||||
description: Sonarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/sonarr
|
||||
description: Sonarr Docker Image
|
||||
- Radarr:
|
||||
- icon: si-radarr
|
||||
href: https://radarr.video
|
||||
description: Radarr Movie Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/Radarr/Radarr
|
||||
description: Radarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/radarr
|
||||
description: Radarr Docker Image
|
||||
- Prowlarr:
|
||||
- icon: si-prowlarr
|
||||
href: https://prowlarr.com
|
||||
description: Prowlarr Indexer Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/Prowlarr/Prowlarr
|
||||
description: Prowlarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/prowlarr
|
||||
description: Prowlarr Docker Image
|
||||
- qBittorrent:
|
||||
- icon: si-qbittorrent
|
||||
href: https://www.qbittorrent.org
|
||||
description: qBittorrent Torrent Client
|
||||
- icon: github.png
|
||||
href: https://github.com/qbittorrent/qBittorrent
|
||||
description: qBittorrent GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/qbittorrent
|
||||
description: qBittorrent Docker Image
|
||||
- Readarr:
|
||||
- icon: si-readarr
|
||||
href: https://readarr.com
|
||||
description: Readarr Book Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/Readarr/Readarr
|
||||
description: Readarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/readarr
|
||||
description: Readarr Docker Image
|
||||
- Lidarr:
|
||||
- icon: si-lidarr
|
||||
href: https://lidarr.audio
|
||||
description: Lidarr Music Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/Lidarr/Lidarr
|
||||
description: Lidarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/lidarr
|
||||
description: Lidarr Docker Image
|
||||
- Jellyseerr:
|
||||
- icon: si-jellyseerr
|
||||
href: https://jellyseerr.dev
|
||||
description: Jellyseerr Media Requests
|
||||
- icon: github.png
|
||||
href: https://github.com/Fallenbagel/jellyseerr
|
||||
description: Jellyseerr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/fallenbagel/jellyseerr
|
||||
description: Jellyseerr Docker Image
|
||||
- Tdarr:
|
||||
- icon: si-tdarr
|
||||
href: https://tdarr.io
|
||||
description: Tdarr Media Transcoding
|
||||
- icon: github.png
|
||||
href: https://github.com/HaveAGitGat/Tdarr
|
||||
description: Tdarr GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/haveagitgat/tdarr
|
||||
description: Tdarr Docker Image
|
||||
- Unmanic:
|
||||
- icon: si-unmanic
|
||||
href: https://docs.unmanic.app
|
||||
description: Unmanic Media Optimizer
|
||||
- icon: github.png
|
||||
href: https://github.com/Unmanic/unmanic
|
||||
description: Unmanic GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/josh5/unmanic
|
||||
description: Unmanic Docker Image
|
||||
- Calibre-Web:
|
||||
- icon: si-calibre
|
||||
href: https://github.com/janeczku/calibre-web
|
||||
description: Calibre-Web Ebook Reader
|
||||
- icon: github.png
|
||||
href: https://github.com/janeczku/calibre-web
|
||||
description: Calibre-Web GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/calibre-web
|
||||
description: Calibre-Web Docker Image
|
||||
|
||||
- Productivity & Collaboration:
|
||||
- Nextcloud:
|
||||
- icon: si-nextcloud
|
||||
href: https://nextcloud.com
|
||||
description: Nextcloud File Sync & Collaboration
|
||||
- icon: github.png
|
||||
href: https://github.com/nextcloud/server
|
||||
description: Nextcloud GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/nextcloud
|
||||
description: Nextcloud Docker Image
|
||||
- Gitea:
|
||||
- icon: si-gitea
|
||||
href: https://gitea.io
|
||||
description: Gitea Git Service
|
||||
- icon: github.png
|
||||
href: https://github.com/go-gitea/gitea
|
||||
description: Gitea GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/gitea/gitea
|
||||
description: Gitea Docker Image
|
||||
- BookStack:
|
||||
- icon: si-bookstack
|
||||
href: https://www.bookstackapp.com
|
||||
description: BookStack Documentation Platform
|
||||
- icon: github.png
|
||||
href: https://github.com/BookStackApp/BookStack
|
||||
description: BookStack GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/bookstack
|
||||
description: BookStack Docker Image
|
||||
- DokuWiki:
|
||||
- icon: si-dokuwiki
|
||||
href: https://www.dokuwiki.org
|
||||
description: DokuWiki File-based Wiki
|
||||
- icon: github.png
|
||||
href: https://github.com/dokuwiki/dokuwiki
|
||||
description: DokuWiki GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/dokuwiki
|
||||
description: DokuWiki Docker Image
|
||||
- MediaWiki:
|
||||
- icon: si-mediawiki
|
||||
href: https://www.mediawiki.org
|
||||
description: MediaWiki Wiki Platform
|
||||
- icon: github.png
|
||||
href: https://github.com/wikimedia/mediawiki
|
||||
description: MediaWiki GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/mediawiki
|
||||
description: MediaWiki Docker Image
|
||||
- WordPress:
|
||||
- icon: si-wordpress
|
||||
href: https://wordpress.org
|
||||
description: WordPress Blog/CMS Platform
|
||||
- icon: github.png
|
||||
href: https://github.com/WordPress/WordPress
|
||||
description: WordPress GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/wordpress
|
||||
description: WordPress Docker Image
|
||||
- Mealie:
|
||||
- icon: si-mealie
|
||||
href: https://hay-kot.github.io/mealie
|
||||
description: Mealie Recipe Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/hay-kot/mealie
|
||||
description: Mealie GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/hkotel/mealie
|
||||
description: Mealie Docker Image
|
||||
- Form.io:
|
||||
- icon: si-formio
|
||||
href: https://www.form.io
|
||||
description: Form.io Form Builder
|
||||
- icon: github.png
|
||||
href: https://github.com/formio/formio
|
||||
description: Form.io GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/formio/formio-enterprise
|
||||
description: Form.io Docker Image
|
||||
|
||||
- Home Automation:
|
||||
- Home Assistant:
|
||||
- icon: si-homeassistant
|
||||
href: https://www.home-assistant.io
|
||||
description: Home Assistant Smart Home Platform
|
||||
- icon: github.png
|
||||
href: https://github.com/home-assistant/core
|
||||
description: Home Assistant GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/homeassistant
|
||||
description: Home Assistant Docker Image
|
||||
- ESPHome:
|
||||
- icon: si-esphome
|
||||
href: https://esphome.io
|
||||
description: ESPHome ESP32/ESP8266 Firmware
|
||||
- icon: github.png
|
||||
href: https://github.com/esphome/esphome
|
||||
description: ESPHome GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/esphome/esphome
|
||||
description: ESPHome Docker Image
|
||||
- Node-RED:
|
||||
- icon: si-nodered
|
||||
href: https://nodered.org
|
||||
description: Node-RED Flow-based Programming
|
||||
- icon: github.png
|
||||
href: https://github.com/node-red/node-red
|
||||
description: Node-RED GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/nodered/node-red
|
||||
description: Node-RED Docker Image
|
||||
- Zigbee2MQTT:
|
||||
- icon: si-zigbee2mqtt
|
||||
href: https://www.zigbee2mqtt.io
|
||||
description: Zigbee2MQTT Zigbee Bridge
|
||||
- icon: github.png
|
||||
href: https://github.com/Koenkk/zigbee2mqtt
|
||||
description: Zigbee2MQTT GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/koenkk/zigbee2mqtt
|
||||
description: Zigbee2MQTT Docker Image
|
||||
- MotionEye:
|
||||
- icon: si-motioneye
|
||||
href: https://github.com/motioneye-project/motioneye
|
||||
description: MotionEye Video Surveillance
|
||||
- icon: github.png
|
||||
href: https://github.com/motioneye-project/motioneye
|
||||
description: MotionEye GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/motioneye
|
||||
description: MotionEye Docker Image
|
||||
- TasmoAdmin:
|
||||
- icon: si-tasmota
|
||||
href: https://github.com/reloxx13/TasmoAdmin
|
||||
description: TasmoAdmin Tasmota Device Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/reloxx13/TasmoAdmin
|
||||
description: TasmoAdmin GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/raymondmm/tasmoadmin
|
||||
description: TasmoAdmin Docker Image
|
||||
|
||||
- Development & Utilities:
|
||||
- Code Server:
|
||||
- icon: si-visualstudiocode
|
||||
href: https://github.com/coder/code-server
|
||||
description: Code Server (VS Code in Browser)
|
||||
- icon: github.png
|
||||
href: https://github.com/coder/code-server
|
||||
description: Code Server GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/code-server
|
||||
description: Code Server Docker Image
|
||||
- Jupyter Lab:
|
||||
- icon: si-jupyter
|
||||
href: https://jupyter.org
|
||||
description: Jupyter Lab Notebooks
|
||||
- icon: github.png
|
||||
href: https://github.com/jupyterlab/jupyterlab
|
||||
description: Jupyter Lab GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/jupyterlab
|
||||
description: Jupyter Lab Docker Image
|
||||
- Vaultwarden:
|
||||
- icon: si-bitwarden
|
||||
href: https://github.com/dani-garcia/vaultwarden
|
||||
description: Vaultwarden Password Manager
|
||||
- icon: github.png
|
||||
href: https://github.com/dani-garcia/vaultwarden
|
||||
description: Vaultwarden GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/vaultwarden/server
|
||||
description: Vaultwarden Docker Image
|
||||
- Duplicati:
|
||||
- icon: si-duplicati
|
||||
href: https://www.duplicati.com
|
||||
description: Duplicati Backup Solution
|
||||
- icon: github.png
|
||||
href: https://github.com/duplicati/duplicati
|
||||
description: Duplicati GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/duplicati
|
||||
description: Duplicati Docker Image
|
||||
- pgAdmin:
|
||||
- icon: si-postgresql
|
||||
href: https://www.pgadmin.org
|
||||
description: pgAdmin PostgreSQL Management
|
||||
- icon: github.png
|
||||
href: https://github.com/pgadmin-org/pgadmin4
|
||||
description: pgAdmin GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/dpage/pgadmin4
|
||||
description: pgAdmin Docker Image
|
||||
- GitLab CE:
|
||||
- icon: si-gitlab
|
||||
href: https://about.gitlab.com
|
||||
description: GitLab DevOps Platform
|
||||
- icon: github.png
|
||||
href: https://gitlab.com/gitlab-org/gitlab
|
||||
description: GitLab GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/gitlab/gitlab-ce
|
||||
description: GitLab CE Docker Image
|
||||
|
||||
- Monitoring & Observability:
|
||||
- Grafana:
|
||||
- icon: si-grafana
|
||||
href: https://grafana.com
|
||||
description: Grafana Visualization Platform
|
||||
- icon: github.png
|
||||
href: https://github.com/grafana/grafana
|
||||
description: Grafana GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/grafana/grafana
|
||||
description: Grafana Docker Image
|
||||
- Prometheus:
|
||||
- icon: si-prometheus
|
||||
href: https://prometheus.io
|
||||
description: Prometheus Metrics Collection
|
||||
- icon: github.png
|
||||
href: https://github.com/prometheus/prometheus
|
||||
description: Prometheus GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/prom/prometheus
|
||||
description: Prometheus Docker Image
|
||||
- Uptime Kuma:
|
||||
- icon: si-uptimekuma
|
||||
href: https://uptime.kuma.pet
|
||||
description: Uptime Kuma Status Monitoring
|
||||
- icon: github.png
|
||||
href: https://github.com/louislam/uptime-kuma
|
||||
description: Uptime Kuma GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/louislam/uptime-kuma
|
||||
description: Uptime Kuma Docker Image
|
||||
- Glances:
|
||||
- icon: si-glances
|
||||
href: https://nicolargo.github.io/glances
|
||||
description: Glances System Monitoring
|
||||
- icon: github.png
|
||||
href: https://github.com/nicolargo/glances
|
||||
description: Glances GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/linuxserver/glances
|
||||
description: Glances Docker Image
|
||||
- Dozzle:
|
||||
- icon: si-dozzle
|
||||
href: https://dozzle.dev
|
||||
description: Dozzle Docker Log Viewer
|
||||
- icon: github.png
|
||||
href: https://github.com/amir20/dozzle
|
||||
description: Dozzle GitHub
|
||||
- icon: docker.png
|
||||
href: https://hub.docker.com/r/amir20/dozzle
|
||||
description: Dozzle Docker Image
|
||||
|
||||
- External Resources & Communities:
|
||||
- Awesome Docker Compose:
|
||||
- icon: docker.png
|
||||
href: https://awesome-docker-compose.com
|
||||
description: Curated Docker Compose Examples
|
||||
- Servarr Wiki:
|
||||
- icon: si-servarr
|
||||
href: https://wiki.servarr.com
|
||||
description: Servarr Applications Documentation
|
||||
- Docker Compose Documentation:
|
||||
- icon: docker.png
|
||||
href: https://docs.docker.com/compose
|
||||
description: Docker Compose Official Docs
|
||||
- Let's Encrypt:
|
||||
- icon: si-letsencrypt
|
||||
href: https://letsencrypt.org
|
||||
description: Free SSL Certificates
|
||||
- Awesome Selfhosted:
|
||||
- icon: si-awesome
|
||||
href: https://awesome-selfhosted.net
|
||||
description: Self-hosted Software List
|
||||
- Homelab Wiki:
|
||||
- icon: si-wikipedia
|
||||
href: https://homelab.wiki
|
||||
description: Homelab Community Wiki
|
||||
- Reddit r/selfhosted:
|
||||
- icon: si-reddit
|
||||
href: https://reddit.com/r/selfhosted
|
||||
description: Self-hosted Community
|
||||
- Reddit r/homelab:
|
||||
- icon: si-reddit
|
||||
href: https://reddit.com/r/homelab
|
||||
description: Homelab Community
|
||||
@@ -1,31 +0,0 @@
|
||||
.information-widgets {
|
||||
max-width: 1500px;
|
||||
}
|
||||
|
||||
.services-group {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
#services {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.service {
|
||||
height: 70px;
|
||||
max-height: 80px;
|
||||
margin-bottom: 0px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
#services #bookmarks {
|
||||
margin: 0px 0px 0px 20px;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.bookmark-group {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
# For configuration options and examples, please see:
|
||||
# https://gethomepage.dev/configs/docker/
|
||||
|
||||
# my-docker:
|
||||
# host: 127.0.0.1
|
||||
# port: 2375
|
||||
|
||||
# my-docker:
|
||||
# socket: /var/run/docker.sock
|
||||
|
||||
# home-assistant:
|
||||
# host: 192.168.4.5
|
||||
# port: 2375
|
||||
|
||||
#${SERVER_HOSTNAME}:
|
||||
# host: 192.168.4.11
|
||||
# port: 2375
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
# sample kubernetes config
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
# pve:
|
||||
# url: https://proxmox.host.or.ip:8006
|
||||
# token: username@pam!Token ID
|
||||
# secret: secret
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
# For configuration options and examples, please see:
|
||||
# https://gethomepage.dev/configs/settings/
|
||||
|
||||
providers:
|
||||
openweathermap: openweathermapapikey
|
||||
weatherapi: weatherapiapikey
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
# For configuration options and examples, please see:
|
||||
# https://gethomepage.dev/configs/info-widgets/
|
||||
|
||||
- resources:
|
||||
cpu: true
|
||||
memory: true
|
||||
disk: /
|
||||
|
||||
- datetime:
|
||||
text_size: xl
|
||||
format:
|
||||
dateStyle: long
|
||||
timeStyle: short
|
||||
hourCycle: h23
|
||||
|
||||
- greeting:
|
||||
text_size: 4xl
|
||||
text: EZ Homelab
|
||||
@@ -1,46 +0,0 @@
|
||||
# Loki Configuration Template
|
||||
# Copy this file to ./config/loki/loki-config.yml
|
||||
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
grpc_listen_port: 9096
|
||||
|
||||
common:
|
||||
path_prefix: /loki
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
instance_addr: 127.0.0.1
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-10-24
|
||||
store: boltdb-shipper
|
||||
object_store: filesystem
|
||||
schema: v11
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
ruler:
|
||||
alertmanager_url: http://localhost:9093
|
||||
|
||||
# Retention configuration (delete logs older than 30 days)
|
||||
limits_config:
|
||||
retention_period: 720h # 30 days
|
||||
|
||||
# Compactor to delete old data
|
||||
compactor:
|
||||
working_directory: /loki/compactor
|
||||
shared_store: filesystem
|
||||
compaction_interval: 10m
|
||||
retention_enabled: true
|
||||
retention_delete_delay: 2h
|
||||
retention_delete_worker_count: 150
|
||||
@@ -1,49 +0,0 @@
|
||||
# Prometheus Configuration Template
|
||||
# Copy this file to ./config/prometheus/prometheus.yml
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
external_labels:
|
||||
monitor: 'homelab'
|
||||
|
||||
# Alertmanager configuration (optional)
|
||||
# alerting:
|
||||
# alertmanagers:
|
||||
# - static_configs:
|
||||
# - targets:
|
||||
# - alertmanager:9093
|
||||
|
||||
# Load rules once and periodically evaluate them
|
||||
# rule_files:
|
||||
# - "alerts/*.yml"
|
||||
|
||||
# Scrape configurations
|
||||
scrape_configs:
|
||||
# Prometheus itself
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
# Node Exporter - System metrics
|
||||
- job_name: 'node-exporter'
|
||||
static_configs:
|
||||
- targets: ['node-exporter:9100']
|
||||
labels:
|
||||
instance: 'homelab-server'
|
||||
|
||||
# cAdvisor - Container metrics
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
labels:
|
||||
instance: 'homelab-server'
|
||||
|
||||
# Add your own services here
|
||||
# Example: Monitor a service with /metrics endpoint
|
||||
# - job_name: 'my-service'
|
||||
# static_configs:
|
||||
# - targets: ['my-service:8080']
|
||||
# labels:
|
||||
# instance: 'homelab-server'
|
||||
# service: 'my-service'
|
||||
@@ -1,53 +0,0 @@
|
||||
# Promtail Configuration Template
|
||||
# Copy this file to ./config/promtail/promtail-config.yml
|
||||
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://loki:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
# Docker container logs
|
||||
- job_name: docker
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: docker
|
||||
__path__: /var/lib/docker/containers/*/*-json.log
|
||||
|
||||
pipeline_stages:
|
||||
# Parse Docker JSON logs
|
||||
- json:
|
||||
expressions:
|
||||
output: log
|
||||
stream: stream
|
||||
attrs: attrs
|
||||
|
||||
# Extract container name from path
|
||||
- regex:
|
||||
expression: '/var/lib/docker/containers/(?P<container_id>[^/]+)/.*'
|
||||
source: filename
|
||||
|
||||
# Add labels
|
||||
- labels:
|
||||
stream:
|
||||
container_id:
|
||||
|
||||
# Output the log line
|
||||
- output:
|
||||
source: output
|
||||
|
||||
# System logs (optional)
|
||||
# - job_name: system
|
||||
# static_configs:
|
||||
# - targets:
|
||||
# - localhost
|
||||
# labels:
|
||||
# job: varlogs
|
||||
# __path__: /var/log/*.log
|
||||
@@ -1,42 +0,0 @@
|
||||
# Redis Configuration Template
|
||||
# Copy this file to ./config/redis/redis.conf
|
||||
|
||||
# Network
|
||||
bind 0.0.0.0
|
||||
protected-mode yes
|
||||
port 6379
|
||||
|
||||
# General
|
||||
daemonize no
|
||||
supervised no
|
||||
pidfile /var/run/redis_6379.pid
|
||||
loglevel notice
|
||||
logfile ""
|
||||
|
||||
# Persistence - AOF (Append Only File)
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
appendfsync everysec
|
||||
no-appendfsync-on-rewrite no
|
||||
auto-aof-rewrite-percentage 100
|
||||
auto-aof-rewrite-min-size 64mb
|
||||
|
||||
# Persistence - RDB (Snapshotting)
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
stop-writes-on-bgsave-error yes
|
||||
rdbcompression yes
|
||||
rdbchecksum yes
|
||||
dbfilename dump.rdb
|
||||
dir /data
|
||||
|
||||
# Memory Management
|
||||
maxmemory 256mb
|
||||
maxmemory-policy allkeys-lru
|
||||
|
||||
# Security
|
||||
# requirepass yourpassword # Uncomment and set a strong password
|
||||
|
||||
# Limits
|
||||
maxclients 10000
|
||||
@@ -4,253 +4,253 @@
|
||||
- Dashboards:
|
||||
- Homepage:
|
||||
icon: homepage.png
|
||||
href: https://homepage.${DOMAIN}
|
||||
href: https://homepage.kelinreij.duckdns.org
|
||||
description: Hosted on Raspberry Pi
|
||||
|
||||
- Homarr:
|
||||
icon: homarr.png
|
||||
href: https://homarr.${DOMAIN}
|
||||
href: https://homarr.kelinreij.duckdns.org
|
||||
description: Alternative Dashboard
|
||||
|
||||
- Dockge - ${SERVER_HOSTNAME}:
|
||||
- Dockge - jasper:
|
||||
icon: dockge.png
|
||||
href: https://${SERVER_HOSTNAME}.${DOMAIN}
|
||||
href: https://jasper.kelinreij.duckdns.org
|
||||
description: Main Server
|
||||
|
||||
- Dockge - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: dockge.png
|
||||
href: https://${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
href: https://${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
|
||||
description: Raspberry Pi Authentication Server
|
||||
|
||||
- Core:
|
||||
- Traefik:
|
||||
icon: traefik.png
|
||||
href: https://traefik.${DOMAIN}
|
||||
href: https://traefik.kelinreij.duckdns.org
|
||||
description: Reverse Proxy & SSL
|
||||
|
||||
- Authelia:
|
||||
icon: authelia.png
|
||||
href: https://auth.${DOMAIN}
|
||||
href: https://auth.kelinreij.duckdns.org
|
||||
description: Authentication SSO Portal
|
||||
|
||||
- Pi-hole:
|
||||
icon: pi-hole.png
|
||||
href: https://pihole.${DOMAIN}
|
||||
href: https://pihole.kelinreij.duckdns.org
|
||||
description: Network-wide Ad Blocking
|
||||
|
||||
- Monitoring Stack:
|
||||
- Dozzle:
|
||||
icon: dozzle.png
|
||||
href: https://dozzle.${SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${SERVER_HOSTNAME} - Real-time Log Viewer
|
||||
href: https://dozzle.jasper.kelinreij.duckdns.org
|
||||
description: jasper - Real-time Log Viewer
|
||||
|
||||
- Dozzle:
|
||||
icon: dozzle.png
|
||||
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Real-time Log Viewer
|
||||
|
||||
- Glances - ${SERVER_HOSTNAME}:
|
||||
- Glances - jasper:
|
||||
icon: glances.png
|
||||
href: https://glances.${SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${SERVER_HOSTNAME} - System Monitoring
|
||||
href: https://glances.jasper.kelinreij.duckdns.org
|
||||
description: jasper - System Monitoring
|
||||
|
||||
- Glances - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: glances.png
|
||||
href: https://glances.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
href: https://glances.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - System Monitoring
|
||||
|
||||
- Uptime Kuma:
|
||||
icon: uptime-kuma.png
|
||||
href: https://uptime-kuma.${DOMAIN}
|
||||
href: https://uptime-kuma.kelinreij.duckdns.org
|
||||
description: Uptime Monitoring
|
||||
|
||||
- Media:
|
||||
- Jellyfin:
|
||||
icon: jellyfin.png
|
||||
href: https://jellyfin.${DOMAIN}
|
||||
href: https://jellyfin.kelinreij.duckdns.org
|
||||
description: Open Source Media Server
|
||||
|
||||
- Jellyseerr:
|
||||
icon: jellyseerr.png
|
||||
href: https://jellyseerr.${DOMAIN}
|
||||
href: https://jellyseerr.kelinreij.duckdns.org
|
||||
description: Media Request Manager
|
||||
|
||||
- Calibre-Web:
|
||||
icon: calibre-web.png
|
||||
href: https://calibre.${DOMAIN}
|
||||
href: https://calibre.kelinreij.duckdns.org
|
||||
description: Ebook Library
|
||||
|
||||
- Media Management:
|
||||
- Sonarr:
|
||||
icon: sonarr.png
|
||||
href: https://sonarr.${DOMAIN}
|
||||
href: https://sonarr.kelinreij.duckdns.org
|
||||
description: TV Shows Automation
|
||||
|
||||
- Radarr:
|
||||
icon: radarr.png
|
||||
href: https://radarr.${DOMAIN}
|
||||
href: https://radarr.kelinreij.duckdns.org
|
||||
description: Movies Automation
|
||||
|
||||
- Prowlarr:
|
||||
icon: prowlarr.png
|
||||
href: https://prowlarr.${DOMAIN}
|
||||
href: https://prowlarr.kelinreij.duckdns.org
|
||||
description: Indexer Manager
|
||||
|
||||
- Readarr:
|
||||
icon: readarr.png
|
||||
href: https://readarr.${DOMAIN}
|
||||
href: https://readarr.kelinreij.duckdns.org
|
||||
description: Books Automation
|
||||
|
||||
- Lidarr:
|
||||
icon: lidarr.png
|
||||
href: https://lidarr.${DOMAIN}
|
||||
href: https://lidarr.kelinreij.duckdns.org
|
||||
description: Music Automation
|
||||
|
||||
- Mylar3:
|
||||
icon: mylar.png
|
||||
href: https://mylar.${DOMAIN}
|
||||
href: https://mylar.kelinreij.duckdns.org
|
||||
description: Comics Manager
|
||||
|
||||
- Home Automation:
|
||||
- Home Assistant:
|
||||
icon: home-assistant.png
|
||||
href: https://hass.${DOMAIN}
|
||||
href: https://hass.kelinreij.duckdns.org
|
||||
description: Home Automation Platform
|
||||
|
||||
- ESPHome:
|
||||
icon: esphome.png
|
||||
href: https://esphome.${DOMAIN}
|
||||
href: https://esphome.kelinreij.duckdns.org
|
||||
description: ESP Device Manager
|
||||
|
||||
- Node-RED:
|
||||
icon: node-red.png
|
||||
href: https://nodered.${DOMAIN}
|
||||
href: https://nodered.kelinreij.duckdns.org
|
||||
description: Flow-based Automation
|
||||
|
||||
- Zigbee2MQTT:
|
||||
icon: zigbee2mqtt.png
|
||||
href: https://zigbee.${DOMAIN}
|
||||
href: https://zigbee.kelinreij.duckdns.org
|
||||
description: Zigbee Bridge
|
||||
|
||||
- Mosquitto:
|
||||
icon: mosquitto.png
|
||||
href: https://mqtt.${DOMAIN}
|
||||
href: https://mqtt.kelinreij.duckdns.org
|
||||
description: MQTT Broker
|
||||
|
||||
- Productivity:
|
||||
- Nextcloud:
|
||||
icon: nextcloud.png
|
||||
href: https://nextcloud.${DOMAIN}
|
||||
href: https://nextcloud.kelinreij.duckdns.org
|
||||
description: Cloud Storage & Collaboration
|
||||
|
||||
- Gitea:
|
||||
icon: gitea.png
|
||||
href: https://gitea.${DOMAIN}
|
||||
href: https://gitea.kelinreij.duckdns.org
|
||||
description: Git Repository
|
||||
|
||||
- Mealie:
|
||||
icon: mealie.png
|
||||
href: https://mealie.${DOMAIN}
|
||||
href: https://mealie.kelinreij.duckdns.org
|
||||
description: Recipe Manager
|
||||
|
||||
- WordPress:
|
||||
icon: wordpress.png
|
||||
href: https://wordpress.${DOMAIN}
|
||||
href: https://wordpress.kelinreij.duckdns.org
|
||||
description: CMS Platform
|
||||
|
||||
- Wikis:
|
||||
- BookStack:
|
||||
icon: bookstack.png
|
||||
href: https://bookstack.${DOMAIN}
|
||||
href: https://bookstack.kelinreij.duckdns.org
|
||||
description: Wiki Platform
|
||||
|
||||
- DokuWiki:
|
||||
icon: dokuwiki.png
|
||||
href: https://dokuwiki.${DOMAIN}
|
||||
href: https://dokuwiki.kelinreij.duckdns.org
|
||||
description: Simple Wiki
|
||||
|
||||
- Mediawiki:
|
||||
icon: mediawiki.png
|
||||
href: https://mediawiki.${DOMAIN}
|
||||
href: https://mediawiki.kelinreij.duckdns.org
|
||||
description: Collaborative Wiki
|
||||
|
||||
- Development:
|
||||
- VS Code Server:
|
||||
icon: vscode.png
|
||||
href: https://code.${DOMAIN}
|
||||
href: https://code.kelinreij.duckdns.org
|
||||
description: Browser-based IDE
|
||||
|
||||
- Jupyter:
|
||||
icon: jupyter.png
|
||||
href: https://jupyter.${DOMAIN}
|
||||
href: https://jupyter.kelinreij.duckdns.org
|
||||
description: Data Science Notebooks
|
||||
|
||||
- Downloaders:
|
||||
- qBittorrent:
|
||||
icon: qbittorrent.png
|
||||
href: https://qbit.${DOMAIN}
|
||||
href: https://qbit.kelinreij.duckdns.org
|
||||
description: Torrent Client
|
||||
- Transcoders:
|
||||
- Tdarr:
|
||||
icon: tdarr.png
|
||||
href: https://tdarr.${DOMAIN}
|
||||
href: https://tdarr.kelinreij.duckdns.org
|
||||
description: Media Transcoding
|
||||
|
||||
- Unmanic:
|
||||
icon: unmanic.png
|
||||
href: https://unmanic.${DOMAIN}
|
||||
href: https://unmanic.kelinreij.duckdns.org
|
||||
description: Media Transcoder
|
||||
|
||||
- Utilities:
|
||||
- Vaultwarden:
|
||||
icon: vaultwarden.png
|
||||
href: https://vault.${DOMAIN}
|
||||
href: https://vault.kelinreij.duckdns.org
|
||||
description: Password Manager
|
||||
|
||||
- Formio:
|
||||
icon: mdi-form-select
|
||||
href: https://formio.${DOMAIN}
|
||||
href: https://formio.kelinreij.duckdns.org
|
||||
description: Form Builder
|
||||
|
||||
- Backup:
|
||||
- Backrest:
|
||||
icon: mdi-backup-restore
|
||||
href: https://backrest.${DOMAIN}
|
||||
href: https://backrest.kelinreij.duckdns.org
|
||||
description: Backup Solution
|
||||
|
||||
- Duplicati:
|
||||
icon: duplicati.png
|
||||
href: https://duplicati.${DOMAIN}
|
||||
href: https://duplicati.kelinreij.duckdns.org
|
||||
description: Backup Software
|
||||
|
||||
- Metrics:
|
||||
- Grafana:
|
||||
icon: grafana.png
|
||||
href: https://grafana.${DOMAIN}
|
||||
href: https://grafana.kelinreij.duckdns.org
|
||||
description: Metrics Dashboard
|
||||
|
||||
- Prometheus:
|
||||
icon: prometheus.png
|
||||
href: https://prometheus.${DOMAIN}
|
||||
href: https://prometheus.kelinreij.duckdns.org
|
||||
description: Metrics Collection
|
||||
|
||||
- cAdvisor:
|
||||
icon: cadvisor.png
|
||||
href: https://cadvisor.${DOMAIN}
|
||||
href: https://cadvisor.kelinreij.duckdns.org
|
||||
description: Container Metrics
|
||||
|
||||
- Alternatives:
|
||||
- Portainer:
|
||||
icon: portainer.png
|
||||
href: https://portainer.${DOMAIN}
|
||||
href: https://portainer.kelinreij.duckdns.org
|
||||
description: Container Management UI
|
||||
|
||||
- Authentik:
|
||||
icon: authentik.png
|
||||
href: https://authentik.${DOMAIN}
|
||||
href: https://authentik.kelinreij.duckdns.org
|
||||
description: Alternative Auth Provider
|
||||
|
||||
- Plex:
|
||||
icon: plex.png
|
||||
href: https://plex.${DOMAIN}
|
||||
href: https://plex.kelinreij.duckdns.org
|
||||
description: Media Server
|
||||
|
||||
@@ -7,21 +7,11 @@
|
||||
href: https://homepage.${DOMAIN}
|
||||
description: Hosted on Raspberry Pi
|
||||
|
||||
- Homepage - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: homepage.png
|
||||
href: https://homepage.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Application Dashboard
|
||||
|
||||
- Homarr:
|
||||
icon: homarr.png
|
||||
href: https://homarr.${DOMAIN}
|
||||
description: Alternative Dashboard
|
||||
|
||||
- Homarr - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: homarr.png
|
||||
href: https://homarr.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Alternative Dashboard
|
||||
|
||||
- Dockge - ${SERVER_HOSTNAME}:
|
||||
icon: dockge.png
|
||||
href: https://${SERVER_HOSTNAME}.${DOMAIN}
|
||||
@@ -74,21 +64,6 @@
|
||||
href: https://uptime-kuma.${DOMAIN}
|
||||
description: Uptime Monitoring
|
||||
|
||||
- Grafana - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: grafana.png
|
||||
href: https://grafana.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Dashboard
|
||||
|
||||
- Prometheus - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: prometheus.png
|
||||
href: https://prometheus.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Collection
|
||||
|
||||
- Uptime Kuma - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: uptime-kuma.png
|
||||
href: https://status.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Uptime Monitoring
|
||||
|
||||
- Media:
|
||||
- Jellyfin:
|
||||
icon: jellyfin.png
|
||||
@@ -243,21 +218,11 @@
|
||||
href: https://backrest.${DOMAIN}
|
||||
description: Backup Solution
|
||||
|
||||
- Backrest - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: mdi-backup-restore
|
||||
href: https://backrest.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Backup Solution
|
||||
|
||||
- Duplicati:
|
||||
icon: duplicati.png
|
||||
href: https://duplicati.${DOMAIN}
|
||||
description: Backup Software
|
||||
|
||||
- Duplicati - ${REMOTE_SERVER_HOSTNAME}:
|
||||
icon: duplicati.png
|
||||
href: https://duplicati.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
|
||||
description: ${REMOTE_SERVER_HOSTNAME} - Backup Software
|
||||
|
||||
- Metrics:
|
||||
- Grafana:
|
||||
icon: grafana.png
|
||||
@@ -1,19 +0,0 @@
|
||||
http:
|
||||
routers:
|
||||
# Individual Services
|
||||
homeassistant:
|
||||
rule: "Host(`hass.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: homeassistant
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
services:
|
||||
# Individual Services
|
||||
homeassistant:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://${HOMEASSISTANT_IP}:8123"
|
||||
passHostHeader: true
|
||||
@@ -1,795 +0,0 @@
|
||||
http:
|
||||
routers:
|
||||
backrest-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`backrest.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: backrest-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-backrest@file
|
||||
- authelia@docker
|
||||
|
||||
bookstack-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`bookstack.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: bookstack-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-bookstack@file
|
||||
- authelia@docker
|
||||
|
||||
vaultwarden-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`vault.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: vaultwarden-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
# SSO disabled for browser extension and mobile app compatibility
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-vaultwarden@file
|
||||
|
||||
calibre-web-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`calibre.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: calibre-web-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-calibre-web@file
|
||||
- authelia@docker
|
||||
|
||||
code-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`code.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: code-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-code-server@file
|
||||
- authelia@docker
|
||||
|
||||
dockge-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`jarvis.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dockge-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
dockhand-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`dockhand.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dockhand-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
dokuwiki-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`dokuwiki.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dokuwiki-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-dokuwiki@file
|
||||
- authelia@docker
|
||||
|
||||
dozzle-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`dozzle.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dozzle-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-dozzle@file
|
||||
- authelia@docker
|
||||
|
||||
duplicati-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`duplicati.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: duplicati-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-duplicati@file
|
||||
- authelia@docker
|
||||
|
||||
ez-assistant-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`assistant.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
# - sablier-${SERVER_HOSTNAME}-assistant@file
|
||||
- ez-assistant-websocket
|
||||
service: ez-assistant-${SERVER_HOSTNAME}
|
||||
|
||||
formio-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`formio.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: formio-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-formio@file
|
||||
- authelia@docker
|
||||
|
||||
gitea-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`gitea.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: gitea-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-gitea@file
|
||||
- authelia@docker
|
||||
|
||||
glances-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`glances.jarvis.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: glances-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-glances@file
|
||||
- authelia@docker
|
||||
|
||||
homepage-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`homepage.jarvis.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: homepage-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
homarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`homarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: homarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
- sablier-${SERVER_HOSTNAME}-homarr@file
|
||||
|
||||
jellyfin-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`jellyfin.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: jellyfin-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-jellyfin@file
|
||||
# No authelia middleware for media apps
|
||||
|
||||
jupyter-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`jupyter.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: jupyter-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-jupyter@file
|
||||
- authelia@docker
|
||||
|
||||
kopia-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`kopia.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: kopia-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-kopia@file
|
||||
- authelia@docker
|
||||
|
||||
mealie-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`mealie.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: mealie-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-mealie@file
|
||||
- authelia@docker
|
||||
|
||||
motioneye-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`motioneye.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: motioneye-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
mediawiki-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`mediawiki.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: mediawiki-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-mediawiki@file
|
||||
- authelia@docker
|
||||
|
||||
nextcloud-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`nextcloud.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: nextcloud-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-nextcloud@file
|
||||
- authelia@docker
|
||||
|
||||
openkm-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`openkm.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: openkm-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-openkm@file
|
||||
- authelia@docker
|
||||
|
||||
openwebui-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`openwebui.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: openwebui-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-openwebui@file
|
||||
- authelia@docker
|
||||
|
||||
qbittorrent-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`qbit.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: qbittorrent-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
tdarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`tdarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: tdarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
unmanic-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`unmanic.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: unmanic-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-unmanic@file
|
||||
- authelia@docker
|
||||
- authelia@docker
|
||||
|
||||
wordpress-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`wordpress.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: wordpress-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-wordpress@file
|
||||
- authelia@docker
|
||||
|
||||
# Arr Services (no SSO for media apps)
|
||||
|
||||
jellyseerr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`jellyseerr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: jellyseerr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
prowlarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`prowlarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: prowlarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
radarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`radarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: radarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
sonarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`sonarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: sonarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
lidarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`lidarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: lidarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
readarr-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`readarr.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: readarr-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
mylar3-${SERVER_HOSTNAME}:
|
||||
rule: "Host(`mylar3.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: mylar3-${SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- sablier-${SERVER_HOSTNAME}-arr@file
|
||||
- authelia@docker
|
||||
|
||||
# Remote Server Services (${REMOTE_SERVER_HOSTNAME})
|
||||
dockge-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`dockge.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dockge-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
dozzle-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`dozzle.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: dozzle-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
glances-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`glances.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: glances-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
backrest-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`backrest.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: backrest-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
duplicati-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`duplicati.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: duplicati-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
homepage-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`homepage.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: homepage-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
homarr-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`homarr.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: homarr-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
grafana-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`grafana.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: grafana-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
prometheus-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`prometheus.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: prometheus-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
uptime-kuma-${REMOTE_SERVER_HOSTNAME}:
|
||||
rule: "Host(`status.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
entryPoints:
|
||||
- websecure
|
||||
service: uptime-kuma-${REMOTE_SERVER_HOSTNAME}
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- authelia@docker
|
||||
|
||||
# Service Definitions
|
||||
services:
|
||||
backrest-${SERVER_HOSTNAME}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:9898"
|
||||
passHostHeader: true
|
||||
|
||||
vaultwarden-${SERVER_HOSTNAME}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8091"
|
||||
passHostHeader: true
|
||||
|
||||
bookstack-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:6875"
|
||||
passHostHeader: true
|
||||
|
||||
calibre-web-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8083"
|
||||
passHostHeader: true
|
||||
|
||||
code-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8079"
|
||||
passHostHeader: true
|
||||
|
||||
dockge-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:5001"
|
||||
passHostHeader: true
|
||||
|
||||
dockhand-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:3003"
|
||||
passHostHeader: true
|
||||
|
||||
dokuwiki-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8087"
|
||||
passHostHeader: true
|
||||
|
||||
dozzle-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8085"
|
||||
passHostHeader: true
|
||||
|
||||
duplicati-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8200"
|
||||
passHostHeader: true
|
||||
|
||||
ez-assistant-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:18789" # Internal IP of ${SERVER_HOSTNAME} server
|
||||
passHostHeader: true
|
||||
|
||||
formio-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:3002"
|
||||
passHostHeader: true
|
||||
|
||||
gitea-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:3010"
|
||||
passHostHeader: true
|
||||
|
||||
glances-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:61208"
|
||||
passHostHeader: true
|
||||
|
||||
homarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:7575"
|
||||
passHostHeader: true
|
||||
|
||||
homepage-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:3000"
|
||||
passHostHeader: true
|
||||
|
||||
jellyfin-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8096"
|
||||
passHostHeader: true
|
||||
|
||||
jupyter-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8890"
|
||||
passHostHeader: true
|
||||
|
||||
kopia-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:51515"
|
||||
passHostHeader: true
|
||||
|
||||
mealie-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:9000"
|
||||
passHostHeader: true
|
||||
|
||||
mediawiki-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8086"
|
||||
passHostHeader: true
|
||||
|
||||
motioneye-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8081"
|
||||
passHostHeader: true
|
||||
|
||||
nextcloud-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8089"
|
||||
passHostHeader: true
|
||||
|
||||
openkm-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:18080"
|
||||
passHostHeader: true
|
||||
|
||||
openwebui-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:3000"
|
||||
passHostHeader: true
|
||||
|
||||
qbittorrent-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8081"
|
||||
passHostHeader: true
|
||||
|
||||
tdarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8265"
|
||||
passHostHeader: true
|
||||
|
||||
unmanic-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8889"
|
||||
passHostHeader: true
|
||||
|
||||
wordpress-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8088"
|
||||
passHostHeader: true
|
||||
|
||||
# Arr Services
|
||||
|
||||
jellyseerr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:5055"
|
||||
passHostHeader: true
|
||||
|
||||
prowlarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:9696"
|
||||
passHostHeader: true
|
||||
|
||||
radarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:7878"
|
||||
passHostHeader: true
|
||||
|
||||
sonarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8989"
|
||||
passHostHeader: true
|
||||
|
||||
lidarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8686"
|
||||
passHostHeader: true
|
||||
|
||||
readarr-${SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8787"
|
||||
passHostHeader: true
|
||||
|
||||
mylar3-${SERVER_HOSTNAME}:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://${SERVER_IP}:8090"
|
||||
passHostHeader: true
|
||||
|
||||
|
||||
|
||||
|
||||
# Remote Server Service Definitions (${REMOTE_SERVER_HOSTNAME})
|
||||
dockge-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:5001"
|
||||
passHostHeader: true
|
||||
|
||||
dozzle-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:8085"
|
||||
passHostHeader: true
|
||||
|
||||
glances-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:61208"
|
||||
passHostHeader: true
|
||||
|
||||
backrest-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:9898"
|
||||
passHostHeader: true
|
||||
|
||||
duplicati-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:8200"
|
||||
passHostHeader: true
|
||||
|
||||
homepage-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:3000"
|
||||
passHostHeader: true
|
||||
|
||||
homarr-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:7575"
|
||||
passHostHeader: true
|
||||
|
||||
grafana-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:3000"
|
||||
passHostHeader: true
|
||||
|
||||
prometheus-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:9090"
|
||||
passHostHeader: true
|
||||
|
||||
uptime-kuma-${REMOTE_SERVER_HOSTNAME}:
|
||||
loadbalancer:
|
||||
servers:
|
||||
- url: "http://${REMOTE_SERVER_IP}:3001"
|
||||
passHostHeader: true
|
||||
|
||||
# Middleware Definitions
|
||||
middlewares:
|
||||
ez-assistant-websocket:
|
||||
headers:
|
||||
accessControlAllowHeaders:
|
||||
- "Connection"
|
||||
- "Upgrade"
|
||||
accessControlAllowMethods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "OPTIONS"
|
||||
accessControlMaxAge: 86400
|
||||
@@ -1,31 +0,0 @@
|
||||
# Traefik Dynamic Configuration
|
||||
# Copy to /opt/stacks/traefik/dynamic/routes.yml
|
||||
# Add custom routes here that aren't defined via Docker labels
|
||||
|
||||
http:
|
||||
routers:
|
||||
# Example custom route
|
||||
# custom-service:
|
||||
# rule: "Host(`custom.example.com`)"
|
||||
# entryPoints:
|
||||
# - websecure
|
||||
# middlewares:
|
||||
# - authelia@docker
|
||||
# tls:
|
||||
# certResolver: letsencrypt
|
||||
# service: custom-service
|
||||
|
||||
services:
|
||||
# Example custom service
|
||||
# custom-service:
|
||||
# loadBalancer:
|
||||
# servers:
|
||||
# - url: "http://192.168.1.100:8080"
|
||||
|
||||
middlewares:
|
||||
# Additional middlewares can be defined here
|
||||
# Example: Rate limiting
|
||||
# rate-limit:
|
||||
# rateLimit:
|
||||
# average: 100
|
||||
# burst: 50
|
||||
@@ -1,442 +0,0 @@
|
||||
# Session duration set to 5m for testing. Increase to 30m for production.
|
||||
http:
|
||||
middlewares:
|
||||
authelia:
|
||||
forwardauth:
|
||||
address: http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/
|
||||
authResponseHeaders:
|
||||
- X-Secret
|
||||
trustForwardHeader: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-arr:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-arr
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Arr Apps
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-backrest:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-backrest
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Backrest
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-vaultwarden:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-vaultwarden
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Vaultwarden
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-bookstack:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-bookstack
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Bookstack
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-calibre-web:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-calibre-web
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Calibre Web
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-code-server:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-code-server
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Code Server
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-dozzle:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-dozzle
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: dozzle
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-dokuwiki:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-dokuwiki
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: DokuWiki
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-duplicati:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-duplicati
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Duplicati
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-formio:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-formio
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: FormIO
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-gitea:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-gitea
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Gitea
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-glances:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-glances
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Glances
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-homarr:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-homarr
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Homarr
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-jellyfin:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-jellyfin
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Jellyfin
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-jupyter:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-jupyter
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Jupyter
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-komodo:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-komodo
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Komodo
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-kopia:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-kopia
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Kopia
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mealie:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mealie
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Mealie
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-mediawiki:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-mediawiki
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: MediaWiki
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-nextcloud:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-nextcloud
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: NextCloud
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-openkm:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-openkm
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: OpenKM
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-openwebui:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-openwebui
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: OpenWebUI
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-pulse:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-pulse
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Pulse
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-tdarr:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-tdarr
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Tdarr
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-unmanic:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-unmanic
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Unmanic
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${SERVER_HOSTNAME}-wordpress:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${SERVER_HOSTNAME}-wordpress
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: wordpress
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
# Remote Server (${REMOTE_SERVER_HOSTNAME}) Sablier Middlewares
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-dockge:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-dockge
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Dockge (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-dozzle:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-dozzle
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Dozzle (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-glances:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-glances
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Glances (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-backrest:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-backrest
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Backrest (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-duplicati:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-duplicati
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Duplicati (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-homepage:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-homepage
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Homepage (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-homarr:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-homarr
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Homarr (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-grafana:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-grafana
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Grafana (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-prometheus:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-prometheus
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Prometheus (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
|
||||
sablier-${REMOTE_SERVER_HOSTNAME}-uptime-kuma:
|
||||
plugin:
|
||||
sablier:
|
||||
sablierUrl: http://sablier-service:10000
|
||||
group: ${REMOTE_SERVER_HOSTNAME}-uptime-kuma
|
||||
sessionDuration: 5m
|
||||
ignoreUserAgent: curl
|
||||
dynamic:
|
||||
displayName: Uptime Kuma (${REMOTE_SERVER_HOSTNAME})
|
||||
theme: ghost
|
||||
show-details-by-default: true
|
||||
@@ -1,43 +0,0 @@
|
||||
# Traefik Static Configuration
|
||||
# Copy to /opt/stacks/traefik/traefik.yml
|
||||
|
||||
experimental:
|
||||
plugins:
|
||||
sablier:
|
||||
moduleName: github.com/sablierapp/sablier-traefik-plugin
|
||||
version: v1.1.0
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
file:
|
||||
directory: /dynamic
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
websecure:
|
||||
address: ":443"
|
||||
traefik:
|
||||
address: ":8080"
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
dnsChallenge:
|
||||
provider: duckdns
|
||||
email: ${DEFAULT_EMAIL}
|
||||
storage: /letsencrypt/acme.json
|
||||
|
||||
log:
|
||||
level: DEBUG
|
||||
|
||||
accessLog:
|
||||
format: json
|
||||
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
|
||||
ping:
|
||||
manualRouting: true
|
||||
@@ -8,11 +8,11 @@
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Dockge: https://dockge.${DOMAIN}
|
||||
# - Dockge: https://dockge.kelinreij.duckdns.org
|
||||
|
||||
services:
|
||||
# Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer)
|
||||
# Access at: https://dockge.${DOMAIN}
|
||||
# Access at: https://dockge.kelinreij.duckdns.org
|
||||
# Stack management interface should always run for container management
|
||||
dockge:
|
||||
image: louislam/dockge:1
|
||||
@@ -50,7 +50,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dockge.rule=Host(`dockge.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.dockge.entrypoints=websecure"
|
||||
- "traefik.http.routers.dockge.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dockge.middlewares=authelia@docker"
|
||||
|
||||
63
docker-compose/dockge/docker-compose.yml.template
Normal file
63
docker-compose/dockge/docker-compose.yml.template
Normal file
@@ -0,0 +1,63 @@
|
||||
# Dockge Stack
|
||||
# Docker Compose Stack Manager
|
||||
# Place in /opt/dockge/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Dockge: https://dockge.${DOMAIN}
|
||||
|
||||
services:
|
||||
# Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer)
|
||||
# Access at: https://dockge.${DOMAIN}
|
||||
# Stack management interface should always run for container management
|
||||
dockge:
|
||||
image: louislam/dockge:1
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: dockge
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "5001:5001" # Optional: direct access
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /opt/stacks:/opt/stacks # Dockge manages stacks in this directory
|
||||
- ./data:/app/data
|
||||
- /usr/bin/docker:/usr/bin/docker:ro # Mount docker binary for CLI access
|
||||
environment:
|
||||
- DOCKGE_STACKS_DIR=/opt/stacks
|
||||
- DOCKGE_ENABLE_CONSOLE=true
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=Docker Compose stack manager (PRIMARY)"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dockge.entrypoints=websecure"
|
||||
- "traefik.http.routers.dockge.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dockge.middlewares=authelia@docker"
|
||||
- "traefik.http.services.dockge.loadbalancer.server.port=5001"
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -3,15 +3,15 @@
|
||||
# Place in /opt/stacks/homeassistant/docker-compose.yml
|
||||
|
||||
# Service Access URLs:
|
||||
# - Home Assistant: https://ha.${DOMAIN} (configure via Traefik file provider - uses host network)
|
||||
# - ESPHome: https://esphome.${DOMAIN}
|
||||
# - Node-RED: https://nodered.${DOMAIN}
|
||||
# - Home Assistant: https://ha.kelinreij.duckdns.org (configure via Traefik file provider - uses host network)
|
||||
# - ESPHome: https://esphome.kelinreij.duckdns.org
|
||||
# - Node-RED: https://nodered.kelinreij.duckdns.org
|
||||
# - Mosquitto MQTT: mqtt://server-ip:1883 (no web UI)
|
||||
# - Zigbee2MQTT: https://zigbee2mqtt.${DOMAIN} (requires USB adapter)
|
||||
# - Zigbee2MQTT: https://zigbee2mqtt.kelinreij.duckdns.org (requires USB adapter)
|
||||
|
||||
services:
|
||||
# Home Assistant - Home automation platform
|
||||
# Access at: https://ha.${DOMAIN}
|
||||
# Access at: https://ha.kelinreij.duckdns.org
|
||||
# NOTE: No Authelia - HA has its own authentication
|
||||
homeassistant:
|
||||
image: ghcr.io/home-assistant/home-assistant:2024.1
|
||||
@@ -31,7 +31,7 @@ services:
|
||||
- ./homeassistant/config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
privileged: true
|
||||
labels:
|
||||
- "homelab.category=iot"
|
||||
@@ -40,7 +40,7 @@ services:
|
||||
# Use Traefik's file provider or external host routing
|
||||
|
||||
# ESPHome - ESP8266/ESP32 firmware manager
|
||||
# Access at: https://esphome.${DOMAIN}
|
||||
# Access at: https://esphome.kelinreij.duckdns.org
|
||||
esphome:
|
||||
image: ghcr.io/esphome/esphome:latest
|
||||
deploy:
|
||||
@@ -63,7 +63,7 @@ services:
|
||||
- ./esphome/config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
- ESPHOME_DASHBOARD_USE_PING=true
|
||||
privileged: true # For USB device access
|
||||
labels:
|
||||
@@ -76,14 +76,14 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.esphome.rule=Host(`esphome.${DOMAIN}`)"
|
||||
- "traefik.http.routers.esphome.rule=Host(`esphome.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.esphome.entrypoints=websecure"
|
||||
- "traefik.http.routers.esphome.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.esphome.middlewares=authelia@docker"
|
||||
- "traefik.http.services.esphome.loadbalancer.server.port=6052"
|
||||
|
||||
# TasmoAdmin - Tasmota device manager
|
||||
# Access at: https://tasmoadmin.${DOMAIN}
|
||||
# Access at: https://tasmoadmin.kelinreij.duckdns.org
|
||||
tasmoadmin:
|
||||
image: ghcr.io/tasmoadmin/tasmoadmin:latest
|
||||
container_name: tasmoadmin
|
||||
@@ -96,7 +96,7 @@ services:
|
||||
volumes:
|
||||
- /opt/stacks/tasmoadmin/data:/data
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -107,14 +107,14 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.${DOMAIN}`)"
|
||||
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.tasmoadmin.entrypoints=websecure"
|
||||
- "traefik.http.routers.tasmoadmin.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.tasmoadmin.middlewares=authelia@docker"
|
||||
- "traefik.http.services.tasmoadmin.loadbalancer.server.port=80"
|
||||
|
||||
# MotionEye - Video surveillance
|
||||
# Access at: https://motioneye.${DOMAIN}
|
||||
# Access at: https://motioneye.kelinreij.duckdns.org
|
||||
motioneye:
|
||||
image: ccrisan/motioneye:master-amd64
|
||||
container_name: motioneye
|
||||
@@ -128,7 +128,7 @@ services:
|
||||
- ./$(basename $file .yml)/config:/etc/motioneye
|
||||
- /mnt/surveillance:/var/lib/motioneye # Large video files on separate drive
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -139,14 +139,14 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.motioneye.rule=Host(`motioneye.${DOMAIN}`)"
|
||||
- "traefik.http.routers.motioneye.rule=Host(`motioneye.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.motioneye.entrypoints=websecure"
|
||||
- "traefik.http.routers.motioneye.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.motioneye.middlewares=authelia@docker"
|
||||
- "traefik.http.services.motioneye.loadbalancer.server.port=8765"
|
||||
|
||||
# Node-RED - Flow-based automation (Home Assistant addon alternative)
|
||||
# Access at: https://nodered.${DOMAIN}
|
||||
# Access at: https://nodered.kelinreij.duckdns.org
|
||||
nodered:
|
||||
image: nodered/node-red:latest
|
||||
deploy:
|
||||
@@ -168,7 +168,7 @@ services:
|
||||
volumes:
|
||||
- /opt/stacks/nodered/data:/data
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -179,7 +179,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nodered.rule=Host(`nodered.${DOMAIN}`)"
|
||||
- "traefik.http.routers.nodered.rule=Host(`nodered.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.nodered.entrypoints=websecure"
|
||||
- "traefik.http.routers.nodered.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.nodered.middlewares=authelia@docker"
|
||||
@@ -205,7 +205,7 @@ services:
|
||||
- "homelab.description=MQTT message broker"
|
||||
|
||||
# Zigbee2MQTT - Zigbee to MQTT bridge (DISABLED - requires USB adapter)
|
||||
# Access at: https://zigbee2mqtt.${DOMAIN}
|
||||
# Access at: https://zigbee2mqtt.kelinreij.duckdns.org
|
||||
# NOTE: Requires USB Zigbee adapter (e.g., ConBee II, Sonoff ZBDongle)
|
||||
# Uncomment after connecting adapter
|
||||
# zigbee2mqtt:
|
||||
@@ -224,12 +224,12 @@ services:
|
||||
# # Common paths: /dev/ttyACM0, /dev/ttyUSB0, /dev/serial/by-id/...
|
||||
# # Run 'ls -l /dev/serial/by-id/' to find your adapter
|
||||
# environment:
|
||||
# - TZ=${TZ}
|
||||
# - TZ=America/New_York
|
||||
# labels:
|
||||
# - "homelab.category=iot"
|
||||
# - "homelab.description=Zigbee to MQTT bridge"
|
||||
# - "traefik.enable=true"
|
||||
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.${DOMAIN}`)"
|
||||
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.kelinreij.duckdns.org`)"
|
||||
# - "traefik.http.routers.zigbee2mqtt.entrypoints=websecure"
|
||||
# - "traefik.http.routers.zigbee2mqtt.tls.certresolver=letsencrypt"
|
||||
# - "traefik.http.routers.zigbee2mqtt.middlewares=authelia@docker"
|
||||
@@ -244,15 +244,15 @@ networks:
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://ha.${DOMAIN}
|
||||
- http://${SERVER_IP}:8123
|
||||
- https://esphome.${DOMAIN}
|
||||
- http://${SERVER_IP}:6052
|
||||
- https://tasmoadmin.${DOMAIN}
|
||||
- http://${SERVER_IP}:8084
|
||||
- https://motioneye.${DOMAIN}
|
||||
- http://${SERVER_IP}:8765
|
||||
- https://nodered.${DOMAIN}
|
||||
- http://${SERVER_IP}:1880
|
||||
- mqtt://${SERVER_IP}:1883
|
||||
- https://zigbee2mqtt.${DOMAIN}
|
||||
- https://ha.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8123
|
||||
- https://esphome.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:6052
|
||||
- https://tasmoadmin.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8084
|
||||
- https://motioneye.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8765
|
||||
- https://nodered.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:1880
|
||||
- mqtt://192.168.4.4:1883
|
||||
- https://zigbee2mqtt.kelinreij.duckdns.org
|
||||
258
docker-compose/homeassistant/docker-compose.yml.template
Normal file
258
docker-compose/homeassistant/docker-compose.yml.template
Normal file
@@ -0,0 +1,258 @@
|
||||
# Home Assistant and IoT Services
|
||||
# Home automation platform and related tools
|
||||
# Place in /opt/stacks/homeassistant/docker-compose.yml
|
||||
|
||||
# Service Access URLs:
|
||||
# - Home Assistant: https://ha.${DOMAIN} (configure via Traefik file provider - uses host network)
|
||||
# - ESPHome: https://esphome.${DOMAIN}
|
||||
# - Node-RED: https://nodered.${DOMAIN}
|
||||
# - Mosquitto MQTT: mqtt://server-ip:1883 (no web UI)
|
||||
# - Zigbee2MQTT: https://zigbee2mqtt.${DOMAIN} (requires USB adapter)
|
||||
|
||||
services:
|
||||
# Home Assistant - Home automation platform
|
||||
# Access at: https://ha.${DOMAIN}
|
||||
# NOTE: No Authelia - HA has its own authentication
|
||||
homeassistant:
|
||||
image: ghcr.io/home-assistant/home-assistant:2024.1
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.5'
|
||||
memory: 1G
|
||||
pids: 2048
|
||||
reservations:
|
||||
cpus: '0.75'
|
||||
memory: 512M
|
||||
container_name: homeassistant
|
||||
restart: unless-stopped
|
||||
network_mode: host # Required for device discovery
|
||||
volumes:
|
||||
- ./homeassistant/config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
privileged: true
|
||||
labels:
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=Home automation platform"
|
||||
# Note: network_mode: host means Traefik can't proxy this directly
|
||||
# Use Traefik's file provider or external host routing
|
||||
|
||||
# ESPHome - ESP8266/ESP32 firmware manager
|
||||
# Access at: https://esphome.${DOMAIN}
|
||||
esphome:
|
||||
image: ghcr.io/esphome/esphome:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: esphome
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "6052:6052"
|
||||
volumes:
|
||||
- ./esphome/config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- ESPHOME_DASHBOARD_USE_PING=true
|
||||
privileged: true # For USB device access
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=ESP8266/ESP32 firmware manager"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.esphome.rule=Host(`esphome.${DOMAIN}`)"
|
||||
- "traefik.http.routers.esphome.entrypoints=websecure"
|
||||
- "traefik.http.routers.esphome.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.esphome.middlewares=authelia@docker"
|
||||
- "traefik.http.services.esphome.loadbalancer.server.port=6052"
|
||||
|
||||
# TasmoAdmin - Tasmota device manager
|
||||
# Access at: https://tasmoadmin.${DOMAIN}
|
||||
tasmoadmin:
|
||||
image: ghcr.io/tasmoadmin/tasmoadmin:latest
|
||||
container_name: tasmoadmin
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8084:80"
|
||||
volumes:
|
||||
- /opt/stacks/tasmoadmin/data:/data
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=Tasmota device management"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tasmoadmin.rule=Host(`tasmoadmin.${DOMAIN}`)"
|
||||
- "traefik.http.routers.tasmoadmin.entrypoints=websecure"
|
||||
- "traefik.http.routers.tasmoadmin.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.tasmoadmin.middlewares=authelia@docker"
|
||||
- "traefik.http.services.tasmoadmin.loadbalancer.server.port=80"
|
||||
|
||||
# MotionEye - Video surveillance
|
||||
# Access at: https://motioneye.${DOMAIN}
|
||||
motioneye:
|
||||
image: ccrisan/motioneye:master-amd64
|
||||
container_name: motioneye
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8765:8765" # Optional: direct access
|
||||
volumes:
|
||||
- ./$(basename $file .yml)/config:/etc/motioneye
|
||||
- /mnt/surveillance:/var/lib/motioneye # Large video files on separate drive
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=Video surveillance system"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.motioneye.rule=Host(`motioneye.${DOMAIN}`)"
|
||||
- "traefik.http.routers.motioneye.entrypoints=websecure"
|
||||
- "traefik.http.routers.motioneye.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.motioneye.middlewares=authelia@docker"
|
||||
- "traefik.http.services.motioneye.loadbalancer.server.port=8765"
|
||||
|
||||
# Node-RED - Flow-based automation (Home Assistant addon alternative)
|
||||
# Access at: https://nodered.${DOMAIN}
|
||||
nodered:
|
||||
image: nodered/node-red:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: nodered
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "1880:1880"
|
||||
volumes:
|
||||
- /opt/stacks/nodered/data:/data
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=Flow-based automation programming"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nodered.rule=Host(`nodered.${DOMAIN}`)"
|
||||
- "traefik.http.routers.nodered.entrypoints=websecure"
|
||||
- "traefik.http.routers.nodered.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.nodered.middlewares=authelia@docker"
|
||||
- "traefik.http.services.nodered.loadbalancer.server.port=1880"
|
||||
|
||||
# Mosquitto - MQTT broker (Home Assistant addon alternative)
|
||||
# Used by: Home Assistant, ESPHome, Tasmota devices
|
||||
mosquitto:
|
||||
image: eclipse-mosquitto:latest
|
||||
container_name: mosquitto
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
ports:
|
||||
- "1883:1883" # MQTT
|
||||
- "9001:9001" # Websockets
|
||||
volumes:
|
||||
- ./mosquitto/config:/mosquitto/config
|
||||
- ./mosquitto/data:/mosquitto/data
|
||||
- ./mosquitto/log:/mosquitto/log
|
||||
labels:
|
||||
- "homelab.category=iot"
|
||||
- "homelab.description=MQTT message broker"
|
||||
|
||||
# Zigbee2MQTT - Zigbee to MQTT bridge (DISABLED - requires USB adapter)
|
||||
# Access at: https://zigbee2mqtt.${DOMAIN}
|
||||
# NOTE: Requires USB Zigbee adapter (e.g., ConBee II, Sonoff ZBDongle)
|
||||
# Uncomment after connecting adapter
|
||||
# zigbee2mqtt:
|
||||
# image: koenkk/zigbee2mqtt:1.35.1
|
||||
# container_name: zigbee2mqtt
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - homelab-network
|
||||
# - traefik-network
|
||||
# volumes:
|
||||
# - ./zigbee2mqtt/data:/app/data
|
||||
# - /run/udev:/run/udev:ro
|
||||
# # Uncomment and adjust device path after connecting USB adapter:
|
||||
# # devices:
|
||||
# # - /dev/ttyACM0:/dev/ttyACM0 # Adjust based on your adapter
|
||||
# # Common paths: /dev/ttyACM0, /dev/ttyUSB0, /dev/serial/by-id/...
|
||||
# # Run 'ls -l /dev/serial/by-id/' to find your adapter
|
||||
# environment:
|
||||
# - TZ=${TZ}
|
||||
# labels:
|
||||
# - "homelab.category=iot"
|
||||
# - "homelab.description=Zigbee to MQTT bridge"
|
||||
# - "traefik.enable=true"
|
||||
# - "traefik.http.routers.zigbee2mqtt.rule=Host(`zigbee2mqtt.${DOMAIN}`)"
|
||||
# - "traefik.http.routers.zigbee2mqtt.entrypoints=websecure"
|
||||
# - "traefik.http.routers.zigbee2mqtt.tls.certresolver=letsencrypt"
|
||||
# - "traefik.http.routers.zigbee2mqtt.middlewares=authelia@docker"
|
||||
# - "traefik.http.services.zigbee2mqtt.loadbalancer.server.port=8080"
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://ha.${DOMAIN}
|
||||
- http://${SERVER_IP}:8123
|
||||
- https://esphome.${DOMAIN}
|
||||
- http://${SERVER_IP}:6052
|
||||
- https://tasmoadmin.${DOMAIN}
|
||||
- http://${SERVER_IP}:8084
|
||||
- https://motioneye.${DOMAIN}
|
||||
- http://${SERVER_IP}:8765
|
||||
- https://nodered.${DOMAIN}
|
||||
- http://${SERVER_IP}:1880
|
||||
- mqtt://${SERVER_IP}:1883
|
||||
- https://zigbee2mqtt.${DOMAIN}
|
||||
@@ -41,7 +41,7 @@ services:
|
||||
- homelab.description=Docker socket proxy for security
|
||||
|
||||
# Pi-hole - Network-wide ad blocker and DNS server
|
||||
# Access at: https://pihole.${DOMAIN}
|
||||
# Access at: https://pihole.kelinreij.duckdns.org
|
||||
# DNS service must always run for network-wide ad blocking
|
||||
pihole:
|
||||
image: pihole/pihole:2024.01.0
|
||||
@@ -66,9 +66,9 @@ services:
|
||||
- ./pihole/etc-pihole:/etc/pihole
|
||||
- ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
- WEBPASSWORD=${PIHOLE_PASSWORD}
|
||||
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
|
||||
- FTLCONF_LOCAL_IPV4=192.168.4.4
|
||||
dns:
|
||||
- 127.0.0.1
|
||||
- 1.1.1.1
|
||||
@@ -86,7 +86,7 @@ services:
|
||||
# - Routes are configured via external YAML files on the core server
|
||||
# - This prevents conflicts between Docker labels and file provider
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
|
||||
- "traefik.http.routers.pihole.rule=Host(`pihole.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.pihole.entrypoints=websecure"
|
||||
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.pihole.middlewares=authelia@docker"
|
||||
@@ -115,7 +115,7 @@ services:
|
||||
- "homelab.description=Automatic Docker container updates"
|
||||
|
||||
# Dozzle - Real-time Docker log viewer
|
||||
# Access at: https://dozzle.${DOMAIN}
|
||||
# Access at: https://dozzle.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
@@ -155,7 +155,7 @@ services:
|
||||
- "homelab.description=Real-time Docker log viewer"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.dozzle.rule=Host(`dozzle.${SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dozzle.rule=Host(`dozzle.jasper.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.dozzle.entrypoints=websecure"
|
||||
- "traefik.http.routers.dozzle.tls=true"
|
||||
- "traefik.http.routers.dozzle.middlewares=authelia@docker"
|
||||
@@ -163,11 +163,11 @@ services:
|
||||
- "traefik.http.services.dozzle.loadbalancer.server.port=8085"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-dozzle"
|
||||
- "sablier.group=jasper-dozzle"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Glances - System monitoring
|
||||
# Access at: https://glances.${DOMAIN}
|
||||
# Access at: https://glances.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
|
||||
glances:
|
||||
image: nicolargo/glances:latest-full
|
||||
@@ -207,7 +207,7 @@ services:
|
||||
- "homelab.description=System and Docker monitoring"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.glances.rule=Host(`glances.${SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.glances.rule=Host(`glances.jasper.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.glances.entrypoints=websecure"
|
||||
- "traefik.http.routers.glances.tls=true"
|
||||
- "traefik.http.routers.glances.middlewares=authelia@docker"
|
||||
@@ -215,11 +215,11 @@ services:
|
||||
- "traefik.http.services.glances.loadbalancer.server.port=61208"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-glances"
|
||||
- "sablier.group=jasper-glances"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Code Server - VS Code in browser
|
||||
# Access at: https://code.${DOMAIN}
|
||||
# Access at: https://code.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
|
||||
code-server:
|
||||
image: lscr.io/linuxserver/code-server:latest
|
||||
@@ -244,9 +244,9 @@ services:
|
||||
- /opt/stacks:/opt/stacks # Access to all stacks
|
||||
- /mnt:/mnt:ro # Read-only access to data
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- PASSWORD=${CODE_SERVER_PASSWORD}
|
||||
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD}
|
||||
healthcheck:
|
||||
@@ -263,7 +263,7 @@ services:
|
||||
- "homelab.description=VS Code in browser"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.code-server.rule=Host(`code.${DOMAIN}`)"
|
||||
- "traefik.http.routers.code-server.rule=Host(`code.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.code-server.entrypoints=websecure"
|
||||
- "traefik.http.routers.code-server.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.code-server.middlewares=authelia@docker"
|
||||
@@ -271,21 +271,21 @@ services:
|
||||
- "traefik.http.services.code-server.loadbalancer.server.port=8443"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-code-server"
|
||||
- "sablier.group=jasper-code-server"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://pihole.${DOMAIN}
|
||||
- https://${SERVER_IP}:53
|
||||
- https://dozzle.${DOMAIN}
|
||||
- https://${SERVER_IP}:8085
|
||||
- https://glances.${DOMAIN}
|
||||
- https://${SERVER_IP}:61208
|
||||
- https://code.${DOMAIN}
|
||||
- https://${SERVER_IP}:8079
|
||||
- http://${SERVER_IP}:2375 # Docker Proxy
|
||||
- http://${SERVER_IP}:19999 # Netdata
|
||||
- https://pihole.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:53
|
||||
- https://dozzle.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8085
|
||||
- https://glances.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:61208
|
||||
- https://code.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8079
|
||||
- http://192.168.4.4:2375 # Docker Proxy
|
||||
- http://192.168.4.4:19999 # Netdata
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
|
||||
294
docker-compose/infrastructure/docker-compose.yml.template
Normal file
294
docker-compose/infrastructure/docker-compose.yml.template
Normal file
@@ -0,0 +1,294 @@
|
||||
# Infrastructure Services
|
||||
# Core services that other services depend on
|
||||
# Place in /opt/stacks/infrastructure/docker-compose.yml
|
||||
|
||||
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
dockerproxy:
|
||||
# Docker socket proxy for security - provides safe Docker API access, must always run
|
||||
# REQUIREMENTS FOR SABLIER INTEGRATION:
|
||||
# 1. Docker daemon must be configured to listen on TCP port 2375 (not just unix socket)
|
||||
# 2. Firewall must allow access to port 2375 from Sablier service
|
||||
# 3. Docker daemon config should include: "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
|
||||
# 4. For security, consider restricting access to specific IP ranges or using TLS
|
||||
# 5. dockerproxy runs for additional security but doesn't expose port 2375 (handled by Docker daemon)
|
||||
image: tecnativa/docker-socket-proxy:latest
|
||||
container_name: dockerproxy
|
||||
privileged: true
|
||||
restart: unless-stopped
|
||||
# Note: Port 2375 is handled directly by Docker daemon for Sablier access
|
||||
# dockerproxy provides additional security features but doesn't expose the port
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- CONTAINERS=1
|
||||
- SERVICES=1
|
||||
- TASKS=1
|
||||
- NETWORKS=1
|
||||
- NODES=1
|
||||
- EXEC=1
|
||||
- IMAGES=1
|
||||
- VOLUMES=1
|
||||
- SWARM=1
|
||||
labels:
|
||||
- homelab.category=infrastructure
|
||||
- homelab.description=Docker socket proxy for security
|
||||
|
||||
# Pi-hole - Network-wide ad blocker and DNS server
|
||||
# Access at: https://pihole.${DOMAIN}
|
||||
# DNS service must always run for network-wide ad blocking
|
||||
pihole:
|
||||
image: pihole/pihole:2024.01.0
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
pids: 256
|
||||
reservations:
|
||||
cpus: '0.10'
|
||||
memory: 64M
|
||||
container_name: pihole
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "53:53/tcp" # DNS TCP
|
||||
- "53:53/udp" # DNS UDP
|
||||
volumes:
|
||||
- ./pihole/etc-pihole:/etc/pihole
|
||||
- ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- WEBPASSWORD=${PIHOLE_PASSWORD}
|
||||
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
|
||||
dns:
|
||||
- 127.0.0.1
|
||||
- 1.1.1.1
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=Network-wide ad blocking and DNS"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# IMPORTANT: On REMOTE SERVERS (where Traefik runs elsewhere):
|
||||
# - COMMENT OUT all traefik.* labels below (don't delete them)
|
||||
# - Routes are configured via external YAML files on the core server
|
||||
# - This prevents conflicts between Docker labels and file provider
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
|
||||
- "traefik.http.routers.pihole.entrypoints=websecure"
|
||||
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.pihole.middlewares=authelia@docker"
|
||||
- "traefik.http.services.pihole.loadbalancer.server.port=80"
|
||||
|
||||
# Watchtower - Automatic container updates
|
||||
# Monitors and updates Docker containers to latest versions
|
||||
# Runs daily at 4 AM
|
||||
watchtower:
|
||||
image: containrrr/watchtower:latest
|
||||
container_name: watchtower
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- DOCKER_API_VERSION=1.52
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- WATCHTOWER_INCLUDE_RESTARTING=true
|
||||
- WATCHTOWER_SCHEDULE=0 0 4 * * * # 4 AM daily
|
||||
- WATCHTOWER_NOTIFICATIONS=shoutrrr
|
||||
- WATCHTOWER_NOTIFICATION_URL=${WATCHTOWER_NOTIFICATION_URL}
|
||||
labels:
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=Automatic Docker container updates"
|
||||
|
||||
# Dozzle - Real-time Docker log viewer
|
||||
# Access at: https://dozzle.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: dozzle
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8085:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- DOZZLE_LEVEL=info
|
||||
- DOZZLE_TAILSIZE=300
|
||||
- DOZZLE_FILTER=status=running
|
||||
healthcheck:
|
||||
test: ["CMD", "/dozzle", "healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=Real-time Docker log viewer"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.dozzle.rule=Host(`dozzle.${SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dozzle.entrypoints=websecure"
|
||||
- "traefik.http.routers.dozzle.tls=true"
|
||||
- "traefik.http.routers.dozzle.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.dozzle.loadbalancer.server.port=8085"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-dozzle"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Glances - System monitoring
|
||||
# Access at: https://glances.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
|
||||
glances:
|
||||
image: nicolargo/glances:latest-full
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: glances
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "61208:61208"
|
||||
pid: host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./glances/config:/glances/conf
|
||||
environment:
|
||||
- GLANCES_OPT=-w
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:61208/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=System and Docker monitoring"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.glances.rule=Host(`glances.${SERVER_HOSTNAME}.${DOMAIN}`)"
|
||||
- "traefik.http.routers.glances.entrypoints=websecure"
|
||||
- "traefik.http.routers.glances.tls=true"
|
||||
- "traefik.http.routers.glances.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.glances.loadbalancer.server.port=61208"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-glances"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Code Server - VS Code in browser
|
||||
# Access at: https://code.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 30min inactivity
|
||||
code-server:
|
||||
image: lscr.io/linuxserver/code-server:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.5'
|
||||
memory: 1G
|
||||
pids: 2048
|
||||
reservations:
|
||||
cpus: '0.75'
|
||||
memory: 512M
|
||||
container_name: code-server
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8079:8443"
|
||||
volumes:
|
||||
- ./code-server/config:/config
|
||||
- /opt/stacks:/opt/stacks # Access to all stacks
|
||||
- /mnt:/mnt:ro # Read-only access to data
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PASSWORD=${CODE_SERVER_PASSWORD}
|
||||
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8443/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=infrastructure"
|
||||
- "homelab.description=VS Code in browser"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.code-server.rule=Host(`code.${DOMAIN}`)"
|
||||
- "traefik.http.routers.code-server.entrypoints=websecure"
|
||||
- "traefik.http.routers.code-server.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.code-server.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.code-server.loadbalancer.server.port=8443"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-code-server"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://pihole.${DOMAIN}
|
||||
- https://${SERVER_IP}:53
|
||||
- https://dozzle.${DOMAIN}
|
||||
- https://${SERVER_IP}:8085
|
||||
- https://glances.${DOMAIN}
|
||||
- https://${SERVER_IP}:61208
|
||||
- https://code.${DOMAIN}
|
||||
- https://${SERVER_IP}:8079
|
||||
- http://${SERVER_IP}:2375 # Docker Proxy
|
||||
- http://${SERVER_IP}:19999 # Netdata
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -24,9 +24,9 @@ services:
|
||||
- /mnt/media:/media
|
||||
- /mnt/downloads:/downloads # Large downloads on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8989/"]
|
||||
interval: 30s
|
||||
@@ -44,13 +44,13 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.sonarr.rule=Host(`sonarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.sonarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.sonarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.sonarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Radarr - Movie automation
|
||||
@@ -69,9 +69,9 @@ services:
|
||||
- /mnt/media:/media
|
||||
- /mnt/downloads:/downloads # Large downloads on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7878/"]
|
||||
interval: 30s
|
||||
@@ -89,13 +89,13 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.radarr.rule=Host(`radarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.radarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.radarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.radarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Prowlarr - Indexer manager
|
||||
@@ -112,9 +112,9 @@ services:
|
||||
volumes:
|
||||
- ./prowlarr/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9696/"]
|
||||
interval: 30s
|
||||
@@ -132,17 +132,17 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.prowlarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.prowlarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.prowlarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.prowlarr.loadbalancer.server.port=9696"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Readarr - Ebook and audiobook management
|
||||
# Access at: https://readarr.${DOMAIN}
|
||||
# Access at: https://readarr.kelinreij.duckdns.org
|
||||
readarr:
|
||||
image: linuxserver/readarr:0.4.19-nightly
|
||||
container_name: readarr
|
||||
@@ -157,9 +157,9 @@ services:
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -171,17 +171,17 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.readarr.rule=Host(`readarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.readarr.rule=Host(`readarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.readarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.readarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.readarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.readarr.loadbalancer.server.port=8787"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Lidarr - Music collection manager
|
||||
# Access at: https://lidarr.${DOMAIN}
|
||||
# Access at: https://lidarr.kelinreij.duckdns.org
|
||||
lidarr:
|
||||
image: linuxserver/lidarr:2.0.7
|
||||
container_name: lidarr
|
||||
@@ -196,9 +196,9 @@ services:
|
||||
- /mnt/media/music:/music
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -210,17 +210,17 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.lidarr.rule=Host(`lidarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.lidarr.rule=Host(`lidarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.lidarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.lidarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.lidarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.lidarr.loadbalancer.server.port=8686"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Lazy Librarian - Book manager
|
||||
# Access at: https://lazylibrarian.${DOMAIN}
|
||||
# Access at: https://lazylibrarian.kelinreij.duckdns.org
|
||||
lazylibrarian:
|
||||
image: linuxserver/lazylibrarian:latest
|
||||
container_name: lazylibrarian
|
||||
@@ -235,9 +235,9 @@ services:
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
@@ -250,17 +250,17 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.${DOMAIN}`)"
|
||||
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.lazylibrarian.entrypoints=websecure"
|
||||
- "traefik.http.routers.lazylibrarian.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.lazylibrarian.middlewares=authelia@docker"
|
||||
- "traefik.http.services.lazylibrarian.loadbalancer.server.port=5299"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Mylar3 - Comic book manager
|
||||
# Access at: https://mylar.${DOMAIN}
|
||||
# Access at: https://mylar.kelinreij.duckdns.org
|
||||
mylar3:
|
||||
image: linuxserver/mylar3:latest
|
||||
container_name: mylar3
|
||||
@@ -275,9 +275,9 @@ services:
|
||||
- /mnt/media/comics:/comics
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -289,17 +289,17 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mylar.rule=Host(`mylar.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mylar.rule=Host(`mylar.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.mylar.entrypoints=websecure"
|
||||
- "traefik.http.routers.mylar.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mylar.middlewares=authelia@docker"
|
||||
- "traefik.http.services.mylar.loadbalancer.server.port=8090"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Jellyseerr - Request management for Jellyfin/Plex
|
||||
# Access at: https://jellyseerr.${DOMAIN}
|
||||
# Access at: https://jellyseerr.kelinreij.duckdns.org
|
||||
jellyseerr:
|
||||
image: fallenbagel/jellyseerr:latest
|
||||
container_name: jellyseerr
|
||||
@@ -313,7 +313,7 @@ services:
|
||||
- ./jellyseerr/config:/app/config
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5055/"]
|
||||
interval: 30s
|
||||
@@ -331,13 +331,13 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.jellyseerr.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.jellyseerr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.jellyseerr.loadbalancer.server.port=5055"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# FlareSolverr - Cloudflare bypass for Prowlarr
|
||||
@@ -350,32 +350,32 @@ services:
|
||||
- homelab-network
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
- homelab.category=media
|
||||
- homelab.description=Cloudflare bypass for indexers
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.group=jasper-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://sonarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8989
|
||||
- https://radarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:7878
|
||||
- https://prowlarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:9696
|
||||
- https://readarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8787
|
||||
- https://lidarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8686
|
||||
- https://lazylibrarian.${DOMAIN}
|
||||
- http://${SERVER_IP}:5299
|
||||
- https://mylar.${DOMAIN}
|
||||
- http://${SERVER_IP}:8090
|
||||
- https://jellyseerr.${DOMAIN}
|
||||
- http://${SERVER_IP}:5055
|
||||
- https://sonarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8989
|
||||
- https://radarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:7878
|
||||
- https://prowlarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:9696
|
||||
- https://readarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8787
|
||||
- https://lidarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8686
|
||||
- https://lazylibrarian.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:5299
|
||||
- https://mylar.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8090
|
||||
- https://jellyseerr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:5055
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
|
||||
384
docker-compose/media-management/docker-compose.yml.template
Normal file
384
docker-compose/media-management/docker-compose.yml.template
Normal file
@@ -0,0 +1,384 @@
|
||||
# Media Management Services
|
||||
# Content automation and library management (*arr apps, transcoders, etc.)
|
||||
# Place in /opt/stacks/media-management/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
# Sonarr - TV show automation
|
||||
# Access at: https://sonarr.yourdomain.duckdns.org
|
||||
sonarr:
|
||||
image: linuxserver/sonarr:4.0.0
|
||||
container_name: sonarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8989:8989"
|
||||
volumes:
|
||||
- ./sonarr/config:/config
|
||||
- /mnt/media:/media
|
||||
- /mnt/downloads:/downloads # Large downloads on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8989/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=TV show management and automation"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.sonarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.sonarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.sonarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Radarr - Movie automation
|
||||
# Access at: https://radarr.yourdomain.duckdns.org
|
||||
radarr:
|
||||
image: linuxserver/radarr:5.2.6
|
||||
container_name: radarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "7878:7878"
|
||||
volumes:
|
||||
- ./radarr/config:/config
|
||||
- /mnt/media:/media
|
||||
- /mnt/downloads:/downloads # Large downloads on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7878/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Movie management and automation"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.radarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.radarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.radarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Prowlarr - Indexer manager
|
||||
# Access at: https://prowlarr.yourdomain.duckdns.org
|
||||
prowlarr:
|
||||
image: linuxserver/prowlarr:1.11.4
|
||||
container_name: prowlarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9696:9696"
|
||||
volumes:
|
||||
- ./prowlarr/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9696/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Indexer manager for Sonarr/Radarr"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.prowlarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.prowlarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.prowlarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.prowlarr.loadbalancer.server.port=9696"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Readarr - Ebook and audiobook management
|
||||
# Access at: https://readarr.${DOMAIN}
|
||||
readarr:
|
||||
image: linuxserver/readarr:0.4.19-nightly
|
||||
container_name: readarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8787:8787"
|
||||
volumes:
|
||||
- ./readarr/config:/config
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Ebook and audiobook management"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.readarr.rule=Host(`readarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.readarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.readarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.readarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.readarr.loadbalancer.server.port=8787"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Lidarr - Music collection manager
|
||||
# Access at: https://lidarr.${DOMAIN}
|
||||
lidarr:
|
||||
image: linuxserver/lidarr:2.0.7
|
||||
container_name: lidarr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8686:8686"
|
||||
volumes:
|
||||
- ./lidarr/config:/config
|
||||
- /mnt/media/music:/music
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Music collection manager"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.lidarr.rule=Host(`lidarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.lidarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.lidarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.lidarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.lidarr.loadbalancer.server.port=8686"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Lazy Librarian - Book manager
|
||||
# Access at: https://lazylibrarian.${DOMAIN}
|
||||
lazylibrarian:
|
||||
image: linuxserver/lazylibrarian:latest
|
||||
container_name: lazylibrarian
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "5299:5299"
|
||||
volumes:
|
||||
- ./lazylibrarian/config:/config
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Book download automation"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.${DOMAIN}`)"
|
||||
- "traefik.http.routers.lazylibrarian.entrypoints=websecure"
|
||||
- "traefik.http.routers.lazylibrarian.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.lazylibrarian.middlewares=authelia@docker"
|
||||
- "traefik.http.services.lazylibrarian.loadbalancer.server.port=5299"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Mylar3 - Comic book manager
|
||||
# Access at: https://mylar.${DOMAIN}
|
||||
mylar3:
|
||||
image: linuxserver/mylar3:latest
|
||||
container_name: mylar3
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8090:8090"
|
||||
volumes:
|
||||
- ./mylar3/config:/config
|
||||
- /mnt/media/comics:/comics
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Comic book collection manager"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mylar.rule=Host(`mylar.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mylar.entrypoints=websecure"
|
||||
- "traefik.http.routers.mylar.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mylar.middlewares=authelia@docker"
|
||||
- "traefik.http.services.mylar.loadbalancer.server.port=8090"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Jellyseerr - Request management for Jellyfin/Plex
|
||||
# Access at: https://jellyseerr.${DOMAIN}
|
||||
jellyseerr:
|
||||
image: fallenbagel/jellyseerr:latest
|
||||
container_name: jellyseerr
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "5055:5055"
|
||||
volumes:
|
||||
- ./jellyseerr/config:/app/config
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5055/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Media request management"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jellyseerr.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.jellyseerr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.jellyseerr.loadbalancer.server.port=5055"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# FlareSolverr - Cloudflare bypass for Prowlarr
|
||||
# No web UI - used by Prowlarr
|
||||
flaresolverr:
|
||||
image: flaresolverr/flaresolverr:latest
|
||||
container_name: flaresolverr
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
environment:
|
||||
- LOG_LEVEL=info
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
- homelab.category=media
|
||||
- homelab.description=Cloudflare bypass for indexers
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-arr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://sonarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8989
|
||||
- https://radarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:7878
|
||||
- https://prowlarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:9696
|
||||
- https://readarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8787
|
||||
- https://lidarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8686
|
||||
- https://lazylibrarian.${DOMAIN}
|
||||
- http://${SERVER_IP}:5299
|
||||
- https://mylar.${DOMAIN}
|
||||
- http://${SERVER_IP}:8090
|
||||
- https://jellyseerr.${DOMAIN}
|
||||
- http://${SERVER_IP}:5055
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -10,9 +10,9 @@
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Jellyfin: https://jellyfin.${DOMAIN} (no SSO - app access)
|
||||
# - Plex: https://plex.${DOMAIN} (no SSO - app access)
|
||||
# - qBittorrent: https://qbit.${DOMAIN} (routed through Gluetun VPN)
|
||||
# - Jellyfin: https://jellyfin.kelinreij.duckdns.org (no SSO - app access)
|
||||
# - Plex: https://plex.kelinreij.duckdns.org (no SSO - app access)
|
||||
# - qBittorrent: https://qbit.kelinreij.duckdns.org (routed through Gluetun VPN)
|
||||
|
||||
services:
|
||||
# Jellyfin - Open-source media streaming server
|
||||
@@ -42,9 +42,9 @@ services:
|
||||
- ./jellyfin/cache:/cache
|
||||
- /mnt/media:/media:ro # Large media files on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8096/"]
|
||||
interval: 30s
|
||||
@@ -62,7 +62,7 @@ services:
|
||||
- "homelab.description=Open-source media streaming server"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.jellyfin.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyfin.tls=true"
|
||||
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
|
||||
@@ -70,12 +70,12 @@ services:
|
||||
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-jellyfin"
|
||||
- "sablier.group=jasper-jellyfin"
|
||||
- "sablier.start-on-demand=true"
|
||||
- "sablier.theme=hacker-terminal"
|
||||
|
||||
# Calibre-Web - Ebook reader and server
|
||||
# Access at: https://calibre.${DOMAIN}
|
||||
# Access at: https://calibre.kelinreij.duckdns.org
|
||||
calibre-web:
|
||||
image: lscr.io/linuxserver/calibre-web:latest
|
||||
deploy:
|
||||
@@ -98,9 +98,9 @@ services:
|
||||
- ./calibre-web/config:/config
|
||||
- /mnt/media/books:/books
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- DOCKER_MODS=linuxserver/mods:universal-calibre
|
||||
# TRAEFIK CONFIGURATION
|
||||
labels:
|
||||
@@ -110,7 +110,7 @@ services:
|
||||
- "homelab.description=Ebook reader and library management"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.calibre.rule=Host(`calibre.${DOMAIN}`)"
|
||||
- "traefik.http.routers.calibre.rule=Host(`calibre.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.calibre.entrypoints=websecure"
|
||||
- "traefik.http.routers.calibre.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.calibre.middlewares=authelia@docker"
|
||||
@@ -118,7 +118,7 @@ services:
|
||||
- "traefik.http.services.calibre.loadbalancer.server.port=8083"
|
||||
# Sablier configuration (disabled by default)
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-calibre-web"
|
||||
- "sablier.group=jasper-calibre-web"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# ==========================================
|
||||
@@ -127,10 +127,10 @@ services:
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://jellyfin.${DOMAIN}
|
||||
- http://${SERVER_IP}:8096
|
||||
- https://calibre.${DOMAIN}
|
||||
- http://${SERVER_IP}:8083
|
||||
- https://jellyfin.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8096
|
||||
- https://calibre.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8083
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
|
||||
139
docker-compose/media/docker-compose.yml.template
Normal file
139
docker-compose/media/docker-compose.yml.template
Normal file
@@ -0,0 +1,139 @@
|
||||
# Media Services
|
||||
# Default Services for media management and streaming
|
||||
# Place in /opt/stacks/media/docker-compose.yml
|
||||
|
||||
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Jellyfin: https://jellyfin.${DOMAIN} (no SSO - app access)
|
||||
# - Plex: https://plex.${DOMAIN} (no SSO - app access)
|
||||
# - qBittorrent: https://qbit.${DOMAIN} (routed through Gluetun VPN)
|
||||
|
||||
services:
|
||||
# Jellyfin - Open-source media streaming server
|
||||
# Access at: https://jellyfin.yourdomain.duckdns.org
|
||||
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:10.8.13
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 2G
|
||||
pids: 2048
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 1G
|
||||
container_name: jellyfin
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8096:8096"
|
||||
volumes:
|
||||
- ./jellyfin/config:/config
|
||||
- ./jellyfin/cache:/cache
|
||||
- /mnt/media:/media:ro # Large media files on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8096/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
# Uncomment for hardware transcoding
|
||||
# devices:
|
||||
# - /dev/dri:/dev/dri
|
||||
# TRAEFIK CONFIGURATION
|
||||
labels:
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Open-source media streaming server"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jellyfin.entrypoints=websecure"
|
||||
- "traefik.http.routers.jellyfin.tls=true"
|
||||
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
|
||||
# Service configuration
|
||||
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-jellyfin"
|
||||
- "sablier.start-on-demand=true"
|
||||
- "sablier.theme=hacker-terminal"
|
||||
|
||||
# Calibre-Web - Ebook reader and server
|
||||
# Access at: https://calibre.${DOMAIN}
|
||||
calibre-web:
|
||||
image: lscr.io/linuxserver/calibre-web:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: calibre-web
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8083:8083"
|
||||
volumes:
|
||||
- ./calibre-web/config:/config
|
||||
- /mnt/media/books:/books
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- DOCKER_MODS=linuxserver/mods:universal-calibre
|
||||
# TRAEFIK CONFIGURATION
|
||||
labels:
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Ebook reader and library management"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.calibre.rule=Host(`calibre.${DOMAIN}`)"
|
||||
- "traefik.http.routers.calibre.entrypoints=websecure"
|
||||
- "traefik.http.routers.calibre.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.calibre.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.calibre.loadbalancer.server.port=8083"
|
||||
# Sablier configuration (disabled by default)
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-calibre-web"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# ==========================================
|
||||
# DOCKGE URL CONFIGURATION
|
||||
# ==========================================
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://jellyfin.${DOMAIN}
|
||||
- http://${SERVER_IP}:8096
|
||||
- https://calibre.${DOMAIN}
|
||||
- http://${SERVER_IP}:8083
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
@@ -8,18 +8,18 @@
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Prometheus: http://${SERVER_IP}:9090 (or configure Traefik)
|
||||
# - Grafana: http://${SERVER_IP}:3000 (or configure Traefik)
|
||||
# - Uptime Kuma: https://status.${DOMAIN}
|
||||
# - Node Exporter: http://${SERVER_IP}:9100/metrics
|
||||
# - cAdvisor: http://${SERVER_IP}:8082
|
||||
# - Loki: http://${SERVER_IP}:3100
|
||||
# - Prometheus: http://192.168.4.4:9090 (or configure Traefik)
|
||||
# - Grafana: http://192.168.4.4:3000 (or configure Traefik)
|
||||
# - Uptime Kuma: https://status.kelinreij.duckdns.org
|
||||
# - Node Exporter: http://192.168.4.4:9100/metrics
|
||||
# - cAdvisor: http://192.168.4.4:8082
|
||||
# - Loki: http://192.168.4.4:3100
|
||||
# NOTE: Prometheus, Grafana, Loki use ports because they need to be accessible to other services
|
||||
# Add Traefik labels if you want https://prometheus.${DOMAIN} access
|
||||
# Add Traefik labels if you want https://prometheus.kelinreij.duckdns.org access
|
||||
|
||||
services:
|
||||
# Prometheus - Metrics collection and storage
|
||||
# Access at: http://${SERVER_IP}:9090
|
||||
# Access at: http://192.168.4.4:9090
|
||||
prometheus:
|
||||
image: prom/prometheus:v2.48.1
|
||||
deploy:
|
||||
@@ -58,7 +58,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
||||
- "traefik.http.routers.prometheus.tls=true"
|
||||
- "traefik.http.routers.prometheus.tls.certresolver=letsencrypt"
|
||||
@@ -66,7 +66,7 @@ services:
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
|
||||
# Grafana - Metrics visualization
|
||||
# Access at: http://${SERVER_IP}:3000
|
||||
# Access at: http://192.168.4.4:3000
|
||||
# Default credentials: admin / admin (change on first login)
|
||||
grafana:
|
||||
image: grafana/grafana:10.2.3
|
||||
@@ -92,9 +92,9 @@ services:
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_SERVER_ROOT_URL=https://grafana.${DOMAIN}
|
||||
- GF_SERVER_ROOT_URL=https://grafana.kelinreij.duckdns.org
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel
|
||||
user: "${PUID}:${PGID}"
|
||||
user: "1000:1000"
|
||||
depends_on:
|
||||
- prometheus
|
||||
labels:
|
||||
@@ -107,7 +107,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
|
||||
@@ -115,7 +115,7 @@ services:
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
|
||||
# Node Exporter - Host metrics exporter
|
||||
# Metrics at: http://${SERVER_IP}:9100/metrics
|
||||
# Metrics at: http://192.168.4.4:9100/metrics
|
||||
node-exporter:
|
||||
image: prom/node-exporter:v1.7.0
|
||||
container_name: node-exporter
|
||||
@@ -138,7 +138,7 @@ services:
|
||||
- "homelab.description=Hardware and OS metrics exporter"
|
||||
|
||||
# cAdvisor - Container metrics exporter
|
||||
# Access at: http://${SERVER_IP}:8082
|
||||
# Access at: http://192.168.4.4:8082
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:v0.47.2
|
||||
container_name: cadvisor
|
||||
@@ -167,7 +167,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.${DOMAIN}`)"
|
||||
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.cadvisor.entrypoints=websecure"
|
||||
- "traefik.http.routers.cadvisor.tls=true"
|
||||
- "traefik.http.routers.cadvisor.tls.certresolver=letsencrypt"
|
||||
@@ -175,7 +175,7 @@ services:
|
||||
- "traefik.http.services.cadvisor.loadbalancer.server.port=8080"
|
||||
|
||||
# Uptime Kuma - Uptime monitoring
|
||||
# Access at: https://uptime-kuma.${DOMAIN}
|
||||
# Access at: https://uptime-kuma.kelinreij.duckdns.org
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:1
|
||||
deploy:
|
||||
@@ -207,7 +207,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.${DOMAIN}`)"
|
||||
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
|
||||
- "traefik.http.routers.uptime-kuma.tls=true"
|
||||
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
|
||||
@@ -215,7 +215,7 @@ services:
|
||||
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
|
||||
|
||||
# Loki - Log aggregation
|
||||
# Access at: http://${SERVER_IP}:3100
|
||||
# Access at: http://192.168.4.4:3100
|
||||
loki:
|
||||
image: grafana/loki:2.9.3
|
||||
deploy:
|
||||
@@ -248,7 +248,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.loki.rule=Host(`loki.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.loki.entrypoints=websecure"
|
||||
- "traefik.http.routers.loki.tls=true"
|
||||
- "traefik.http.routers.loki.tls.certresolver=letsencrypt"
|
||||
@@ -293,9 +293,9 @@ networks:
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- http://${SERVER_IP}:9090
|
||||
- http://${SERVER_IP}:3000
|
||||
- https://uptime-kuma.${DOMAIN}
|
||||
- http://${SERVER_IP}:9100/metrics
|
||||
- http://${SERVER_IP}:8082
|
||||
- http://${SERVER_IP}:3100
|
||||
- http://192.168.4.4:9090
|
||||
- http://192.168.4.4:3000
|
||||
- https://uptime-kuma.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:9100/metrics
|
||||
- http://192.168.4.4:8082
|
||||
- http://192.168.4.4:3100
|
||||
|
||||
301
docker-compose/monitoring/docker-compose.yml.template
Normal file
301
docker-compose/monitoring/docker-compose.yml.template
Normal file
@@ -0,0 +1,301 @@
|
||||
# Monitoring and Observability Services
|
||||
# Services for monitoring your homelab infrastructure
|
||||
# Place in /opt/stacks/monitoring/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
# Service Access URLs:
|
||||
# - Prometheus: http://${SERVER_IP}:9090 (or configure Traefik)
|
||||
# - Grafana: http://${SERVER_IP}:3000 (or configure Traefik)
|
||||
# - Uptime Kuma: https://status.${DOMAIN}
|
||||
# - Node Exporter: http://${SERVER_IP}:9100/metrics
|
||||
# - cAdvisor: http://${SERVER_IP}:8082
|
||||
# - Loki: http://${SERVER_IP}:3100
|
||||
# NOTE: Prometheus, Grafana, Loki use ports because they need to be accessible to other services
|
||||
# Add Traefik labels if you want https://prometheus.${DOMAIN} access
|
||||
|
||||
services:
|
||||
# Prometheus - Metrics collection and storage
|
||||
# Access at: http://${SERVER_IP}:9090
|
||||
prometheus:
|
||||
image: prom/prometheus:v2.48.1
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.75'
|
||||
memory: 512M
|
||||
pids: 1024
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./config/prometheus:/etc/prometheus
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Metrics collection and time-series database"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)"
|
||||
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
||||
- "traefik.http.routers.prometheus.tls=true"
|
||||
- "traefik.http.routers.prometheus.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.prometheus.middlewares=authelia@docker"
|
||||
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
||||
|
||||
# Grafana - Metrics visualization
|
||||
# Access at: http://${SERVER_IP}:3000
|
||||
# Default credentials: admin / admin (change on first login)
|
||||
grafana:
|
||||
image: grafana/grafana:10.2.3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
- ./config/grafana/provisioning:/etc/grafana/provisioning
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_SERVER_ROOT_URL=https://grafana.${DOMAIN}
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel
|
||||
user: "${PUID}:${PGID}"
|
||||
depends_on:
|
||||
- prometheus
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Metrics visualization and dashboards"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)"
|
||||
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.grafana.middlewares=authelia@docker"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
|
||||
# Node Exporter - Host metrics exporter
|
||||
# Metrics at: http://${SERVER_IP}:9100/metrics
|
||||
node-exporter:
|
||||
image: prom/node-exporter:v1.7.0
|
||||
container_name: node-exporter
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
ports:
|
||||
- "9100:9100"
|
||||
volumes:
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /:/rootfs:ro
|
||||
command:
|
||||
- '--path.procfs=/host/proc'
|
||||
- '--path.rootfs=/rootfs'
|
||||
- '--path.sysfs=/host/sys'
|
||||
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
|
||||
labels:
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Hardware and OS metrics exporter"
|
||||
|
||||
# cAdvisor - Container metrics exporter
|
||||
# Access at: http://${SERVER_IP}:8082
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:v0.47.2
|
||||
container_name: cadvisor
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8082:8080"
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:ro
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker:/var/lib/docker:ro
|
||||
- /dev/disk:/dev/disk:ro
|
||||
privileged: true
|
||||
devices:
|
||||
- /dev/kmsg
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Container metrics and performance monitoring"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.cadvisor.rule=Host(`cadvisor.${DOMAIN}`)"
|
||||
- "traefik.http.routers.cadvisor.entrypoints=websecure"
|
||||
- "traefik.http.routers.cadvisor.tls=true"
|
||||
- "traefik.http.routers.cadvisor.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.cadvisor.middlewares=authelia@docker"
|
||||
- "traefik.http.services.cadvisor.loadbalancer.server.port=8080"
|
||||
|
||||
# Uptime Kuma - Uptime monitoring
|
||||
# Access at: https://uptime-kuma.${DOMAIN}
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:1
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: uptime-kuma
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3001:3001"
|
||||
volumes:
|
||||
- uptime-kuma-data:/app/data
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Service uptime monitoring and alerts"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.${DOMAIN}`)"
|
||||
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
|
||||
- "traefik.http.routers.uptime-kuma.tls=true"
|
||||
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.uptime-kuma.middlewares=authelia@docker"
|
||||
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
|
||||
|
||||
# Loki - Log aggregation
|
||||
# Access at: http://${SERVER_IP}:3100
|
||||
loki:
|
||||
image: grafana/loki:2.9.3
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.75'
|
||||
memory: 512M
|
||||
pids: 1024
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3100:3100"
|
||||
volumes:
|
||||
- ./config/loki:/etc/loki
|
||||
- loki-data:/loki
|
||||
command: -config.file=/etc/loki/loki-config.yml
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Log aggregation system"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.loki.entrypoints=websecure"
|
||||
- "traefik.http.routers.loki.tls=true"
|
||||
- "traefik.http.routers.loki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.loki.middlewares=authelia@docker"
|
||||
- "traefik.http.services.loki.loadbalancer.server.port=3100"
|
||||
|
||||
# Promtail - Log shipper for Loki
|
||||
# Ships Docker container logs to Loki
|
||||
promtail:
|
||||
image: grafana/promtail:2.9.3
|
||||
container_name: promtail
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- ./config/promtail:/etc/promtail
|
||||
- /var/log:/var/log:ro
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
command: -config.file=/etc/promtail/promtail-config.yml
|
||||
depends_on:
|
||||
- loki
|
||||
labels:
|
||||
- "homelab.category=monitoring"
|
||||
- "homelab.description=Log collector for Loki"
|
||||
|
||||
volumes:
|
||||
prometheus-data:
|
||||
driver: local
|
||||
grafana-data:
|
||||
driver: local
|
||||
uptime-kuma-data:
|
||||
driver: local
|
||||
loki-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- http://${SERVER_IP}:9090
|
||||
- http://${SERVER_IP}:3000
|
||||
- https://uptime-kuma.${DOMAIN}
|
||||
- http://${SERVER_IP}:9100/metrics
|
||||
- http://${SERVER_IP}:8082
|
||||
- http://${SERVER_IP}:3100
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
services:
|
||||
# Nextcloud - File sync and collaboration
|
||||
# Access at: https://nextcloud.${DOMAIN}
|
||||
# Access at: https://nextcloud.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
nextcloud:
|
||||
image: nextcloud:28
|
||||
@@ -40,10 +40,10 @@ services:
|
||||
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
|
||||
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN}
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.kelinreij.duckdns.org
|
||||
- TRUSTED_PROXIES=172.18.0.0/16
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- OVERWRITEHOST=nextcloud.${DOMAIN}
|
||||
- OVERWRITEHOST=nextcloud.kelinreij.duckdns.org
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
|
||||
interval: 30s
|
||||
@@ -60,7 +60,7 @@ services:
|
||||
- "homelab.description=File sync and collaboration"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)"
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.nextcloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.nextcloud.middlewares=authelia@docker"
|
||||
@@ -68,7 +68,7 @@ services:
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=8089"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-nextcloud"
|
||||
- "sablier.group=jasper-nextcloud"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
nextcloud-db:
|
||||
@@ -90,7 +90,7 @@ services:
|
||||
- "homelab.description=Nextcloud database"
|
||||
|
||||
# Mealie - Recipe manager
|
||||
# Access at: https://mealie.${DOMAIN}
|
||||
# Access at: https://mealie.kelinreij.duckdns.org
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:latest
|
||||
container_name: mealie
|
||||
@@ -103,10 +103,10 @@ services:
|
||||
volumes:
|
||||
- ./mealie/data:/app/data
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- BASE_URL=https://mealie.${DOMAIN}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- BASE_URL=https://mealie.kelinreij.duckdns.org
|
||||
- DB_ENGINE=sqlite
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
@@ -116,7 +116,7 @@ services:
|
||||
- "homelab.description=Recipe manager and meal planner"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mealie.rule=Host(`mealie.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.mealie.entrypoints=websecure"
|
||||
- "traefik.http.routers.mealie.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mealie.middlewares=authelia@docker"
|
||||
@@ -124,11 +124,11 @@ services:
|
||||
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-mealie"
|
||||
- "sablier.group=jasper-mealie"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# WordPress - Blog/website platform
|
||||
# Access at: https://blog.${DOMAIN}
|
||||
# Access at: https://blog.kelinreij.duckdns.org
|
||||
wordpress:
|
||||
image: wordpress:latest
|
||||
container_name: wordpress
|
||||
@@ -161,7 +161,7 @@ services:
|
||||
- "homelab.description=Blog and website platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.wordpress.rule=Host(`wordpress.${DOMAIN}`)"
|
||||
- "traefik.http.routers.wordpress.rule=Host(`wordpress.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.wordpress.entrypoints=websecure"
|
||||
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.wordpress.middlewares=authelia@docker"
|
||||
@@ -169,7 +169,7 @@ services:
|
||||
- "traefik.http.services.wordpress.loadbalancer.server.port=8088"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-wordpress"
|
||||
- "sablier.group=jasper-wordpress"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
wordpress-db:
|
||||
@@ -190,7 +190,7 @@ services:
|
||||
- "homelab.description=WordPress database"
|
||||
|
||||
# Gitea - Self-hosted Git service
|
||||
# Access at: https://git.${DOMAIN}
|
||||
# Access at: https://git.kelinreij.duckdns.org
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
deploy:
|
||||
@@ -214,8 +214,8 @@ services:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- USER_UID=${PUID}
|
||||
- USER_GID=${PGID}
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
@@ -237,7 +237,7 @@ services:
|
||||
- "homelab.description=Self-hosted Git service"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
|
||||
- "traefik.http.routers.gitea.rule=Host(`gitea.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.gitea.middlewares=authelia@docker"
|
||||
@@ -245,7 +245,7 @@ services:
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3010"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-gitea"
|
||||
- "sablier.group=jasper-gitea"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
gitea-db:
|
||||
@@ -266,7 +266,7 @@ services:
|
||||
|
||||
|
||||
# Jupyter Lab - Interactive computing notebooks
|
||||
# Access at: https://jupyter.${DOMAIN}
|
||||
# Access at: https://jupyter.kelinreij.duckdns.org
|
||||
# Token displayed in logs on first start
|
||||
jupyter:
|
||||
image: jupyter/scipy-notebook:latest
|
||||
@@ -302,14 +302,14 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jupyter.rule=Host(`jupyter.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jupyter.rule=Host(`jupyter.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.jupyter.entrypoints=websecure"
|
||||
- "traefik.http.routers.jupyter.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.jupyter.middlewares=authelia@docker"
|
||||
- "traefik.http.services.jupyter.loadbalancer.server.port=8890"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-jupyter"
|
||||
- "sablier.group=jasper-jupyter"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
volumes:
|
||||
@@ -326,13 +326,13 @@ networks:
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://nextcloud.${DOMAIN}
|
||||
- https://${SERVER_IP}:8089
|
||||
- https://mealie.${DOMAIN}
|
||||
- https://${SERVER_IP}:9000
|
||||
- https://wordpress.${DOMAIN}
|
||||
- https://${SERVER_IP}:8088
|
||||
- https://gitea.${DOMAIN}
|
||||
- https://${SERVER_IP}:3010
|
||||
- https://jupyter.${DOMAIN}
|
||||
- https://${SERVER_IP}:8890
|
||||
- https://nextcloud.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8089
|
||||
- https://mealie.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:9000
|
||||
- https://wordpress.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8088
|
||||
- https://gitea.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:3010
|
||||
- https://jupyter.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8890
|
||||
|
||||
338
docker-compose/productivity/docker-compose.yml.template
Normal file
338
docker-compose/productivity/docker-compose.yml.template
Normal file
@@ -0,0 +1,338 @@
|
||||
# Productivity and Content Management Services
|
||||
# Place in /opt/stacks/productivity/docker-compose.yml
|
||||
|
||||
# SABLIER SESSION DURATION: Set to 5m for testing. Increase to 30m for production in config-templates/traefik/dynamic/sablier.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
# Nextcloud - File sync and collaboration
|
||||
# Access at: https://nextcloud.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
nextcloud:
|
||||
image: nextcloud:28
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.5'
|
||||
memory: 1G
|
||||
pids: 2048
|
||||
reservations:
|
||||
cpus: '0.75'
|
||||
memory: 512M
|
||||
container_name: nextcloud
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8089:80"
|
||||
volumes:
|
||||
- ./nextcloud/html:/var/www/html
|
||||
- /mnt/nextcloud-data:/var/www/html/data # Large data on separate drive
|
||||
environment:
|
||||
- MYSQL_HOST=nextcloud-db
|
||||
- MYSQL_DATABASE=nextcloud
|
||||
- MYSQL_USER=nextcloud
|
||||
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
|
||||
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN}
|
||||
- TRUSTED_PROXIES=172.18.0.0/16
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- OVERWRITEHOST=nextcloud.${DOMAIN}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=File sync and collaboration"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)"
|
||||
- "traefik.http.routers.nextcloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.nextcloud.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=8089"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-nextcloud"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
nextcloud-db:
|
||||
image: mariadb:10.11
|
||||
container_name: nextcloud-db
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- nextcloud-db-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${NEXTCLOUD_DB_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=nextcloud
|
||||
- MYSQL_USER=nextcloud
|
||||
- MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
|
||||
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Nextcloud database"
|
||||
|
||||
# Mealie - Recipe manager
|
||||
# Access at: https://mealie.${DOMAIN}
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:latest
|
||||
container_name: mealie
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- ./mealie/data:/app/data
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- BASE_URL=https://mealie.${DOMAIN}
|
||||
- DB_ENGINE=sqlite
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Recipe manager and meal planner"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mealie.entrypoints=websecure"
|
||||
- "traefik.http.routers.mealie.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mealie.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-mealie"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# WordPress - Blog/website platform
|
||||
# Access at: https://blog.${DOMAIN}
|
||||
wordpress:
|
||||
image: wordpress:latest
|
||||
container_name: wordpress
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8088:80"
|
||||
volumes:
|
||||
- ./wordpress/html:/var/www/html
|
||||
environment:
|
||||
- WORDPRESS_DB_HOST=wordpress-db
|
||||
- WORDPRESS_DB_USER=wordpress
|
||||
- WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
|
||||
- WORDPRESS_DB_NAME=wordpress
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- wordpress-db
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Blog and website platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.wordpress.rule=Host(`wordpress.${DOMAIN}`)"
|
||||
- "traefik.http.routers.wordpress.entrypoints=websecure"
|
||||
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.wordpress.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.wordpress.loadbalancer.server.port=8088"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-wordpress"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
wordpress-db:
|
||||
image: mariadb:10.11
|
||||
container_name: wordpress-db
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- wordpress-db-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${WORDPRESS_DB_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=wordpress
|
||||
- MYSQL_USER=wordpress
|
||||
- MYSQL_PASSWORD=${WORDPRESS_DB_PASSWORD}
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=WordPress database"
|
||||
|
||||
# Gitea - Self-hosted Git service
|
||||
# Access at: https://git.${DOMAIN}
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
pids: 512
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
container_name: gitea
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3010:3000"
|
||||
volumes:
|
||||
- ./gitea/data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- USER_UID=${PUID}
|
||||
- USER_GID=${PGID}
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- gitea-db
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Self-hosted Git service"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
|
||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.gitea.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3010"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-gitea"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
gitea-db:
|
||||
image: postgres:14-alpine
|
||||
container_name: gitea-db
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- gitea-db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=gitea
|
||||
- POSTGRES_PASSWORD=${GITEA_DB_PASSWORD}
|
||||
- POSTGRES_DB=gitea
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Gitea database"
|
||||
|
||||
|
||||
# Jupyter Lab - Interactive computing notebooks
|
||||
# Access at: https://jupyter.${DOMAIN}
|
||||
# Token displayed in logs on first start
|
||||
jupyter:
|
||||
image: jupyter/scipy-notebook:latest
|
||||
container_name: jupyter
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8890:8888"
|
||||
volumes:
|
||||
- ./config/jupyter:/home/jovyan/work
|
||||
environment:
|
||||
- JUPYTER_ENABLE_LAB=yes
|
||||
- GRANT_SUDO=yes
|
||||
user: root
|
||||
command: start-notebook.sh --NotebookApp.token='${JUPYTER_TOKEN}'
|
||||
# Uncomment for GPU support (NVIDIA, requires nvidia-container-toolkit)
|
||||
# runtime: nvidia
|
||||
# devices:
|
||||
# - /dev/nvidia0:/dev/nvidia0
|
||||
# - /dev/nvidiactl:/dev/nvidiactl
|
||||
# Add these to environment above:
|
||||
# - NVIDIA_VISIBLE_DEVICES=all
|
||||
# - NVIDIA_DRIVER_CAPABILITIES=compute,utility
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Jupyter Lab for data science and ML"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jupyter.rule=Host(`jupyter.${DOMAIN}`)"
|
||||
- "traefik.http.routers.jupyter.entrypoints=websecure"
|
||||
- "traefik.http.routers.jupyter.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.jupyter.middlewares=authelia@docker"
|
||||
- "traefik.http.services.jupyter.loadbalancer.server.port=8890"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-jupyter"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
volumes:
|
||||
nextcloud-db-data:
|
||||
wordpress-db-data:
|
||||
gitea-db-data:
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://nextcloud.${DOMAIN}
|
||||
- https://${SERVER_IP}:8089
|
||||
- https://mealie.${DOMAIN}
|
||||
- https://${SERVER_IP}:9000
|
||||
- https://wordpress.${DOMAIN}
|
||||
- https://${SERVER_IP}:8088
|
||||
- https://gitea.${DOMAIN}
|
||||
- https://${SERVER_IP}:3010
|
||||
- https://jupyter.${DOMAIN}
|
||||
- https://${SERVER_IP}:8890
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
# Tdarr Server - Distributed transcoding server
|
||||
# Access at: https://tdarr.${DOMAIN}
|
||||
# Access at: https://tdarr.kelinreij.duckdns.org
|
||||
tdarr-server:
|
||||
image: ghcr.io/haveagitgat/tdarr:latest
|
||||
container_name: tdarr-server
|
||||
@@ -18,9 +18,9 @@ services:
|
||||
- /mnt/media:/media
|
||||
- /mnt/tdarr-transcode:/temp # Transcode cache on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- serverIP=0.0.0.0
|
||||
- serverPort=8266
|
||||
- webUIPort=8265
|
||||
@@ -35,13 +35,13 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tdarr.rule=Host(`tdarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.tdarr.rule=Host(`tdarr.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.tdarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.tdarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.tdarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.tdarr.loadbalancer.server.port=8265"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
|
||||
- "sablier.group=jasper-tdarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Tdarr Node - Transcoding worker
|
||||
@@ -58,9 +58,9 @@ services:
|
||||
- /mnt/media:/media
|
||||
- /mnt/tdarr-transcode:/temp
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- nodeID=MainNode
|
||||
- nodeIP=0.0.0.0
|
||||
- nodePort=8267
|
||||
@@ -70,11 +70,11 @@ services:
|
||||
- homelab.category=media
|
||||
- homelab.description=Tdarr transcoding worker node
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
|
||||
- "sablier.group=jasper-tdarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Unmanic - Another transcoding option
|
||||
# Access at: https://unmanic.${DOMAIN}
|
||||
# Access at: https://unmanic.kelinreij.duckdns.org
|
||||
unmanic:
|
||||
image: josh5/unmanic:latest
|
||||
container_name: unmanic
|
||||
@@ -89,9 +89,9 @@ services:
|
||||
- /mnt/media:/library
|
||||
- /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
@@ -103,13 +103,13 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.unmanic.rule=Host(`unmanic.${DOMAIN}`)"
|
||||
- "traefik.http.routers.unmanic.rule=Host(`unmanic.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.unmanic.entrypoints=websecure"
|
||||
- "traefik.http.routers.unmanic.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.unmanic.middlewares=authelia@docker"
|
||||
- "traefik.http.services.unmanic.loadbalancer.server.port=8889"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-unmanic"
|
||||
- "sablier.group=jasper-unmanic"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
networks:
|
||||
@@ -120,7 +120,7 @@ networks:
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://tdarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8265
|
||||
- https://unmanic.${DOMAIN}
|
||||
- http://${SERVER_IP}:8888
|
||||
- https://tdarr.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8265
|
||||
- https://unmanic.kelinreij.duckdns.org
|
||||
- http://192.168.4.4:8888
|
||||
126
docker-compose/transcoders/docker-compose.yml.template
Normal file
126
docker-compose/transcoders/docker-compose.yml.template
Normal file
@@ -0,0 +1,126 @@
|
||||
services:
|
||||
# Tdarr Server - Distributed transcoding server
|
||||
# Access at: https://tdarr.${DOMAIN}
|
||||
tdarr-server:
|
||||
image: ghcr.io/haveagitgat/tdarr:latest
|
||||
container_name: tdarr-server
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- 8265:8265 # Web UI port
|
||||
- 8266:8266 # Server port
|
||||
volumes:
|
||||
- ./tdarr/server:/app/server
|
||||
- ./tdarr/configs:/app/configs
|
||||
- ./tdarr/logs:/app/logs
|
||||
- /mnt/media:/media
|
||||
- /mnt/tdarr-transcode:/temp # Transcode cache on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- serverIP=0.0.0.0
|
||||
- serverPort=8266
|
||||
- webUIPort=8265
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Distributed transcoding server"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.tdarr.rule=Host(`tdarr.${DOMAIN}`)"
|
||||
- "traefik.http.routers.tdarr.entrypoints=websecure"
|
||||
- "traefik.http.routers.tdarr.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.tdarr.middlewares=authelia@docker"
|
||||
- "traefik.http.services.tdarr.loadbalancer.server.port=8265"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Tdarr Node - Transcoding worker
|
||||
# No web UI - controlled by server
|
||||
tdarr-node:
|
||||
image: ghcr.io/haveagitgat/tdarr_node:latest
|
||||
container_name: tdarr-node
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- ./tdarr/configs:/app/configs
|
||||
- ./tdarr/logs:/app/logs
|
||||
- /mnt/media:/media
|
||||
- /mnt/tdarr-transcode:/temp
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- nodeID=MainNode
|
||||
- nodeIP=0.0.0.0
|
||||
- nodePort=8267
|
||||
- serverIP=tdarr-server
|
||||
- serverPort=8266
|
||||
labels:
|
||||
- homelab.category=media
|
||||
- homelab.description=Tdarr transcoding worker node
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-tdarr"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Unmanic - Another transcoding option
|
||||
# Access at: https://unmanic.${DOMAIN}
|
||||
unmanic:
|
||||
image: josh5/unmanic:latest
|
||||
container_name: unmanic
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8889:8888"
|
||||
volumes:
|
||||
- ./unmanic/config:/config
|
||||
- /mnt/media:/library
|
||||
- /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=media"
|
||||
- "homelab.description=Library optimization and transcoding"
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.unmanic.rule=Host(`unmanic.${DOMAIN}`)"
|
||||
- "traefik.http.routers.unmanic.entrypoints=websecure"
|
||||
- "traefik.http.routers.unmanic.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.unmanic.middlewares=authelia@docker"
|
||||
- "traefik.http.services.unmanic.loadbalancer.server.port=8889"
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-unmanic"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://tdarr.${DOMAIN}
|
||||
- http://${SERVER_IP}:8265
|
||||
- https://unmanic.${DOMAIN}
|
||||
- http://${SERVER_IP}:8888
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
services:
|
||||
# Backrest - Backup solution for restic
|
||||
# Access at: https://backrest.${DOMAIN}
|
||||
# Access at: https://backrest.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
backrest:
|
||||
image: garethgeorge/backrest:latest
|
||||
@@ -28,7 +28,7 @@ services:
|
||||
environment:
|
||||
- BACKREST_DATA=/data
|
||||
- BACKREST_CONFIG=/config/config.json
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9898/"]
|
||||
interval: 30s
|
||||
@@ -43,7 +43,7 @@ services:
|
||||
- "homelab.description=Backup management with restic"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.backrest.rule=Host(`backrest.${DOMAIN}`)"
|
||||
- "traefik.http.routers.backrest.rule=Host(`backrest.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.backrest.entrypoints=websecure"
|
||||
- "traefik.http.routers.backrest.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.backrest.middlewares=authelia@docker"
|
||||
@@ -51,11 +51,11 @@ services:
|
||||
- "traefik.http.services.backrest.loadbalancer.server.port=9898"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-backrest"
|
||||
- "sablier.group=jasper-backrest"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Duplicati - Backup solution
|
||||
# Access at: https://duplicati.${DOMAIN}
|
||||
# Access at: https://duplicati.kelinreij.duckdns.org
|
||||
duplicati:
|
||||
image: lscr.io/linuxserver/duplicati:2.0.7
|
||||
container_name: duplicati
|
||||
@@ -71,9 +71,9 @@ services:
|
||||
- /mnt:/source/mnt:ro
|
||||
- /mnt/backups:/backups
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8200/"]
|
||||
interval: 30s
|
||||
@@ -88,7 +88,7 @@ services:
|
||||
- "homelab.description=Backup software with encryption"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.duplicati.rule=Host(`duplicati.${DOMAIN}`)"
|
||||
- "traefik.http.routers.duplicati.rule=Host(`duplicati.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.duplicati.entrypoints=websecure"
|
||||
- "traefik.http.routers.duplicati.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.duplicati.middlewares=authelia@docker"
|
||||
@@ -96,7 +96,7 @@ services:
|
||||
- "traefik.http.services.duplicati.loadbalancer.server.port=8200"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-duplicati"
|
||||
- "sablier.group=jasper-duplicati"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Form.io - Form builder
|
||||
@@ -132,7 +132,7 @@ services:
|
||||
# Traefik labels
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.formio.rule=Host(`forms.${DOMAIN}`)"
|
||||
- "traefik.http.routers.formio.rule=Host(`forms.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.formio.entrypoints=websecure"
|
||||
- "traefik.http.routers.formio.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.formio.middlewares=authelia@docker"
|
||||
@@ -140,7 +140,7 @@ services:
|
||||
- "traefik.http.services.formio.loadbalancer.server.port=3001"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-formio"
|
||||
- "sablier.group=jasper-formio"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
formio-mongo:
|
||||
@@ -154,7 +154,7 @@ services:
|
||||
- "homelab.description=Form.io database"
|
||||
|
||||
# Bitwarden (Vaultwarden) - Password manager
|
||||
# Access at: https://vault.${DOMAIN}
|
||||
# Access at: https://vault.kelinreij.duckdns.org
|
||||
# Note: SSO disabled for browser extension and mobile app compatibility
|
||||
|
||||
vaultwarden:
|
||||
@@ -169,7 +169,7 @@ services:
|
||||
volumes:
|
||||
- ./vaultwarden/data:/data
|
||||
environment:
|
||||
- DOMAIN=https://vault.${DOMAIN}
|
||||
- DOMAIN=https://vault.kelinreij.duckdns.org
|
||||
- SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED}
|
||||
- INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED}
|
||||
- ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN}
|
||||
@@ -196,7 +196,7 @@ services:
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.vaultwarden.rule=Host(`vault.${DOMAIN}`)"
|
||||
- "traefik.http.routers.vaultwarden.rule=Host(`vault.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
|
||||
- "traefik.http.routers.vaultwarden.tls=true"
|
||||
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
|
||||
@@ -205,7 +205,7 @@ services:
|
||||
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-vaultwarden"
|
||||
- "sablier.group=jasper-vaultwarden"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Authelia Redis - Session storage for Authelia
|
||||
@@ -236,11 +236,11 @@ networks:
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://backrest.${DOMAIN}
|
||||
- https://${SERVER_IP}:9898
|
||||
- https://duplicati.${DOMAIN}
|
||||
- https://${SERVER_IP}:8200
|
||||
- https://forms.${DOMAIN}
|
||||
- https://${SERVER_IP}:3002
|
||||
- https://vault.${DOMAIN}
|
||||
- https://${SERVER_IP}:8091
|
||||
- https://backrest.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:9898
|
||||
- https://duplicati.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8200
|
||||
- https://forms.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:3002
|
||||
- https://vault.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8091
|
||||
246
docker-compose/utilities/docker-compose.yml.template
Normal file
246
docker-compose/utilities/docker-compose.yml.template
Normal file
@@ -0,0 +1,246 @@
|
||||
# Backup and Utility Services
|
||||
# Place in /opt/stacks/utilities/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
# Backrest - Backup solution for restic
|
||||
# Access at: https://backrest.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
backrest:
|
||||
image: garethgeorge/backrest:latest
|
||||
container_name: backrest
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "9898:9898"
|
||||
volumes:
|
||||
- ./backrest/data:/data
|
||||
- ./backrest/config:/config
|
||||
- /opt/stacks:/opt/stacks:ro # Backup source
|
||||
- /mnt:/mnt:ro # Backup additional drives
|
||||
- backrest-cache:/cache
|
||||
environment:
|
||||
- BACKREST_DATA=/data
|
||||
- BACKREST_CONFIG=/config/config.json
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9898/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=utilities"
|
||||
- "homelab.description=Backup management with restic"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.backrest.rule=Host(`backrest.${DOMAIN}`)"
|
||||
- "traefik.http.routers.backrest.entrypoints=websecure"
|
||||
- "traefik.http.routers.backrest.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.backrest.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.backrest.loadbalancer.server.port=9898"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-backrest"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Duplicati - Backup solution
|
||||
# Access at: https://duplicati.${DOMAIN}
|
||||
duplicati:
|
||||
image: lscr.io/linuxserver/duplicati:2.0.7
|
||||
container_name: duplicati
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8200:8200"
|
||||
volumes:
|
||||
- ./duplicati/config:/config
|
||||
- /opt/stacks:/source/stacks:ro
|
||||
- /mnt:/source/mnt:ro
|
||||
- /mnt/backups:/backups
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8200/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=utilities"
|
||||
- "homelab.description=Backup software with encryption"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.duplicati.rule=Host(`duplicati.${DOMAIN}`)"
|
||||
- "traefik.http.routers.duplicati.entrypoints=websecure"
|
||||
- "traefik.http.routers.duplicati.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.duplicati.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.duplicati.loadbalancer.server.port=8200"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-duplicati"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Form.io - Form builder
|
||||
# Uncomment and configure if formio/formio image becomes available
|
||||
formio:
|
||||
image: calipseo/formio:latest
|
||||
container_name: formio
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "3002:3001"
|
||||
environment:
|
||||
- MONGO=mongodb://formio-mongo:27017/formio
|
||||
- JWT_SECRET=${FORMIO_JWT_SECRET}
|
||||
- DB_SECRET=${FORMIO_DB_SECRET}
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3001/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- formio-mongo
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=utilities"
|
||||
- "homelab.description=Form builder platform"
|
||||
# Traefik labels
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.formio.rule=Host(`forms.${DOMAIN}`)"
|
||||
- "traefik.http.routers.formio.entrypoints=websecure"
|
||||
- "traefik.http.routers.formio.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.formio.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.formio.loadbalancer.server.port=3001"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-formio"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
formio-mongo:
|
||||
image: mongo:4.4
|
||||
container_name: formio-mongo
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- homelab-network
|
||||
labels:
|
||||
- "homelab.category=utilities"
|
||||
- "homelab.description=Form.io database"
|
||||
|
||||
# Bitwarden (Vaultwarden) - Password manager
|
||||
# Access at: https://vault.${DOMAIN}
|
||||
# Note: SSO disabled for browser extension and mobile app compatibility
|
||||
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:1.30.1
|
||||
container_name: vaultwarden
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8091:80"
|
||||
volumes:
|
||||
- ./vaultwarden/data:/data
|
||||
environment:
|
||||
- DOMAIN=https://vault.${DOMAIN}
|
||||
- SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED}
|
||||
- INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED}
|
||||
- ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN}
|
||||
# SMTP disabled - uncomment and configure to enable email
|
||||
# - SMTP_HOST=${SMTP_HOST}
|
||||
# - SMTP_FROM=${SMTP_FROM}
|
||||
# - SMTP_PORT=${SMTP_PORT}
|
||||
# - SMTP_SECURITY=${SMTP_SECURITY}
|
||||
# - SMTP_USERNAME=${SMTP_USERNAME}
|
||||
# - SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# ==========================================
|
||||
# Service metadata
|
||||
- "homelab.category=utilities"
|
||||
- "homelab.description=Self-hosted password manager (Bitwarden)"
|
||||
# Traefik reverse proxy (comment/uncomment to disable/enable)
|
||||
# If Traefik is on a remote server: these labels are NOT USED;
|
||||
# configure external yml files in /traefik/dynamic folder instead.
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.vaultwarden.rule=Host(`vault.${DOMAIN}`)"
|
||||
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
|
||||
- "traefik.http.routers.vaultwarden.tls=true"
|
||||
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
|
||||
# SSO disabled for browser extension and mobile app compatibility
|
||||
# - "traefik.http.routers.vaultwarden.middlewares=authelia@docker"
|
||||
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-vaultwarden"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# Authelia Redis - Session storage for Authelia
|
||||
# No web UI - backend service
|
||||
# authelia-redis:
|
||||
# image: redis:7-alpine
|
||||
# container_name: authelia-redis
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - homelab-network
|
||||
# volumes:
|
||||
# - authelia-redis-data:/data
|
||||
# command: redis-server --save 60 1 --loglevel warning
|
||||
# labels:
|
||||
# - homelab.category=utilities
|
||||
# - homelab.description=Session storage for Authelia
|
||||
|
||||
volumes:
|
||||
backrest-cache: null
|
||||
formio-mongo-data: null
|
||||
authelia-redis-data: null
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://backrest.${DOMAIN}
|
||||
- https://${SERVER_IP}:9898
|
||||
- https://duplicati.${DOMAIN}
|
||||
- https://${SERVER_IP}:8200
|
||||
- https://forms.${DOMAIN}
|
||||
- https://${SERVER_IP}:3002
|
||||
- https://vault.${DOMAIN}
|
||||
- https://${SERVER_IP}:8091
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
- OPENVPN_USER=${SURFSHARK_USERNAME}
|
||||
- OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
|
||||
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES}
|
||||
- TZ=${TZ}
|
||||
- TZ=America/New_York
|
||||
# TRAEFIK CONFIGURATION
|
||||
labels:
|
||||
# Service metadata
|
||||
@@ -46,7 +46,7 @@ services:
|
||||
- "homelab.description=VPN client for secure downloads"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.${DOMAIN}`)"
|
||||
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
|
||||
- "traefik.http.routers.qbittorrent.tls=true"
|
||||
- "traefik.http.routers.qbittorrent.middlewares=authelia@docker"
|
||||
@@ -54,7 +54,7 @@ services:
|
||||
- "traefik.http.services.qbittorrent.loadbalancer.server.port=8081"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-qbittorrent"
|
||||
- "sablier.group=jasper-qbittorrent"
|
||||
- "sablier.sessionDuration=1h"
|
||||
|
||||
# qBittorrent - Torrent client
|
||||
@@ -77,9 +77,9 @@ services:
|
||||
- ./qbittorrent/config:/config
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- WEBUI_PORT=8080
|
||||
depends_on:
|
||||
- gluetun
|
||||
@@ -92,5 +92,5 @@ networks:
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://qbit.${DOMAIN}
|
||||
- https://${SERVER_IP}:8081
|
||||
- https://qbit.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8081
|
||||
96
docker-compose/vpn/docker-compose.yml.template
Normal file
96
docker-compose/vpn/docker-compose.yml.template
Normal file
@@ -0,0 +1,96 @@
|
||||
# VPN Stack
|
||||
# VPN client and VPN-routed download clients
|
||||
# Place in /opt/stacks/vpn/docker-compose.yml
|
||||
|
||||
# RESTART POLICY GUIDE:
|
||||
# - unless-stopped: Core infrastructure services that should always run
|
||||
# - no: Services with Sablier lazy loading (start on-demand)
|
||||
# - See individual service comments for specific reasoning
|
||||
|
||||
services:
|
||||
# Gluetun - VPN client (Surfshark)
|
||||
# Routes download clients through VPN for security
|
||||
# VPN service should always run to maintain secure connections
|
||||
gluetun:
|
||||
image: qmcgaw/gluetun:latest
|
||||
container_name: gluetun
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8888:8888/tcp" # HTTP proxy
|
||||
- "8388:8388/tcp" # Shadowsocks
|
||||
- "8388:8388/udp" # Shadowsocks
|
||||
- "8081:8080" # qBittorrent web UI
|
||||
- "6881:6881" # qBittorrent
|
||||
- "6881:6881/udp" # qBittorrent
|
||||
volumes:
|
||||
- ./gluetun:/gluetun
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=surfshark
|
||||
- VPN_TYPE=openvpn
|
||||
- OPENVPN_USER=${SURFSHARK_USERNAME}
|
||||
- OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
|
||||
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES}
|
||||
- TZ=${TZ}
|
||||
# TRAEFIK CONFIGURATION
|
||||
labels:
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=downloaders"
|
||||
- "homelab.description=VPN client for secure downloads"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.${DOMAIN}`)"
|
||||
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
|
||||
- "traefik.http.routers.qbittorrent.tls=true"
|
||||
- "traefik.http.routers.qbittorrent.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.qbittorrent.loadbalancer.server.port=8081"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-qbittorrent"
|
||||
- "sablier.sessionDuration=1h"
|
||||
|
||||
# qBittorrent - Torrent client
|
||||
# Routes through Gluetun VPN
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
pids: 1024
|
||||
reservations:
|
||||
cpus: '0.50'
|
||||
memory: 256M
|
||||
container_name: qbittorrent
|
||||
restart: unless-stopped
|
||||
network_mode: "service:gluetun" # Routes through VPN in same compose file
|
||||
volumes:
|
||||
- ./qbittorrent/config:/config
|
||||
- /mnt/downloads:/downloads
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- WEBUI_PORT=8080
|
||||
depends_on:
|
||||
- gluetun
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
- https://qbit.${DOMAIN}
|
||||
- https://${SERVER_IP}:8081
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
# DokuWiki - Wiki without database
|
||||
# Access at: https://wiki.${DOMAIN}
|
||||
# Access at: https://wiki.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
dokuwiki:
|
||||
image: lscr.io/linuxserver/dokuwiki:latest
|
||||
@@ -14,9 +14,9 @@ services:
|
||||
volumes:
|
||||
- ./dokuwiki/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- "homelab.description=File-based wiki"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
|
||||
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
|
||||
@@ -33,11 +33,11 @@ services:
|
||||
- "traefik.http.services.dokuwiki.loadbalancer.server.port=8087"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-dokuwiki"
|
||||
- "sablier.group=jasper-dokuwiki"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# BookStack - Documentation platform
|
||||
# Access at: https://docs.${DOMAIN}
|
||||
# Access at: https://docs.kelinreij.duckdns.org
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
bookstack:
|
||||
image: lscr.io/linuxserver/bookstack:latest
|
||||
@@ -51,9 +51,9 @@ services:
|
||||
volumes:
|
||||
- ./bookstack/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- APP_URL=https://bookstack.${DOMAIN}
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- APP_URL=https://bookstack.kelinreij.duckdns.org
|
||||
- DB_HOST=bookstack-db
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=bookstack
|
||||
@@ -76,7 +76,7 @@ services:
|
||||
- "homelab.description=Documentation and wiki platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.bookstack.rule=Host(`bookstack.${DOMAIN}`)"
|
||||
- "traefik.http.routers.bookstack.rule=Host(`bookstack.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.bookstack.entrypoints=websecure"
|
||||
- "traefik.http.routers.bookstack.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.bookstack.middlewares=authelia@docker"
|
||||
@@ -84,7 +84,7 @@ services:
|
||||
- "traefik.http.services.bookstack.loadbalancer.server.port=6875"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-bookstack"
|
||||
- "sablier.group=jasper-bookstack"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
bookstack-db:
|
||||
@@ -105,7 +105,7 @@ services:
|
||||
- "homelab.description=BookStack database"
|
||||
|
||||
# MediaWiki - Wiki platform
|
||||
# Access at: https://mediawiki.${DOMAIN}
|
||||
# Access at: https://mediawiki.kelinreij.duckdns.org
|
||||
mediawiki:
|
||||
image: mediawiki:latest
|
||||
container_name: mediawiki
|
||||
@@ -139,7 +139,7 @@ services:
|
||||
- "homelab.description=MediaWiki platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.kelinreij.duckdns.org`)"
|
||||
- "traefik.http.routers.mediawiki.entrypoints=websecure"
|
||||
- "traefik.http.routers.mediawiki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mediawiki.middlewares=authelia@docker"
|
||||
@@ -147,7 +147,7 @@ services:
|
||||
- "traefik.http.services.mediawiki.loadbalancer.server.port=8086"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-mediawiki"
|
||||
- "sablier.group=jasper-mediawiki"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
mediawiki-db:
|
||||
@@ -180,9 +180,9 @@ networks:
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://bookstack.${DOMAIN}
|
||||
- https://${SERVER_IP}:6875
|
||||
- https://dokuwiki.${DOMAIN}
|
||||
- https://${SERVER_IP}:8087
|
||||
- https://mediawiki.${DOMAIN}
|
||||
- https://${SERVER_IP}:8086
|
||||
- https://bookstack.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:6875
|
||||
- https://dokuwiki.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8087
|
||||
- https://mediawiki.kelinreij.duckdns.org
|
||||
- https://192.168.4.4:8086
|
||||
|
||||
188
docker-compose/wikis/docker-compose.yml.template
Normal file
188
docker-compose/wikis/docker-compose.yml.template
Normal file
@@ -0,0 +1,188 @@
|
||||
services:
|
||||
# DokuWiki - Wiki without database
|
||||
# Access at: https://wiki.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
dokuwiki:
|
||||
image: lscr.io/linuxserver/dokuwiki:latest
|
||||
container_name: dokuwiki
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8087:80"
|
||||
volumes:
|
||||
- ./dokuwiki/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=${TZ}
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=File-based wiki"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
|
||||
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.dokuwiki.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.dokuwiki.loadbalancer.server.port=8087"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-dokuwiki"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
# BookStack - Documentation platform
|
||||
# Access at: https://docs.${DOMAIN}
|
||||
# Uses Sablier lazy loading - starts on-demand, stops after 5min inactivity
|
||||
bookstack:
|
||||
image: lscr.io/linuxserver/bookstack:latest
|
||||
container_name: bookstack
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "6875:80"
|
||||
volumes:
|
||||
- ./bookstack/config:/config
|
||||
environment:
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- APP_URL=https://bookstack.${DOMAIN}
|
||||
- DB_HOST=bookstack-db
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=bookstack
|
||||
- DB_USERNAME=bookstack
|
||||
- DB_PASSWORD=${BOOKSTACK_DB_PASSWORD}
|
||||
- APP_KEY=base64:NsYD8+8MAvtBhK8xw9p8pxQDy4x8aOQi/78M3CsseAw=
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- bookstack-db
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=Documentation and wiki platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.bookstack.rule=Host(`bookstack.${DOMAIN}`)"
|
||||
- "traefik.http.routers.bookstack.entrypoints=websecure"
|
||||
- "traefik.http.routers.bookstack.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.bookstack.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.bookstack.loadbalancer.server.port=6875"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-bookstack"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
bookstack-db:
|
||||
image: mariadb:10.11
|
||||
container_name: bookstack-db
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- bookstack-db-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${BOOKSTACK_DB_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=bookstack
|
||||
- MYSQL_USER=bookstack
|
||||
- MYSQL_PASSWORD=${BOOKSTACK_DB_PASSWORD}
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=BookStack database"
|
||||
|
||||
# MediaWiki - Wiki platform
|
||||
# Access at: https://mediawiki.${DOMAIN}
|
||||
mediawiki:
|
||||
image: mediawiki:latest
|
||||
container_name: mediawiki
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
- traefik-network
|
||||
ports:
|
||||
- "8086:80"
|
||||
volumes:
|
||||
- ./mediawiki/images:/var/www/html/images
|
||||
- ./mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php
|
||||
environment:
|
||||
- MEDIAWIKI_DB_HOST=mediawiki-db
|
||||
- MEDIAWIKI_DB_NAME=mediawiki
|
||||
- MEDIAWIKI_DB_USER=mediawiki
|
||||
- MEDIAWIKI_DB_PASSWORD=${MEDIAWIKI_DB_PASSWORD}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
depends_on:
|
||||
- mediawiki-db
|
||||
labels:
|
||||
# TRAEFIK CONFIGURATION
|
||||
# Service metadata
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=MediaWiki platform"
|
||||
- "traefik.enable=true"
|
||||
# Router configuration
|
||||
- "traefik.http.routers.mediawiki.rule=Host(`mediawiki.${DOMAIN}`)"
|
||||
- "traefik.http.routers.mediawiki.entrypoints=websecure"
|
||||
- "traefik.http.routers.mediawiki.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.mediawiki.middlewares=authelia@docker"
|
||||
# Service configuration
|
||||
- "traefik.http.services.mediawiki.loadbalancer.server.port=8086"
|
||||
# Sablier configuration
|
||||
- "sablier.enable=true"
|
||||
- "sablier.group=${SERVER_HOSTNAME}-mediawiki"
|
||||
- "sablier.start-on-demand=true"
|
||||
|
||||
mediawiki-db:
|
||||
image: mariadb:10.11
|
||||
container_name: mediawiki-db
|
||||
restart: no
|
||||
networks:
|
||||
- homelab-network
|
||||
volumes:
|
||||
- mediawiki-db-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${MEDIAWIKI_DB_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=mediawiki
|
||||
- MYSQL_USER=mediawiki
|
||||
- MYSQL_PASSWORD=${MEDIAWIKI_DB_PASSWORD}
|
||||
labels:
|
||||
- "homelab.category=productivity"
|
||||
- "homelab.description=MediaWiki database"
|
||||
|
||||
volumes:
|
||||
bookstack-db-data:
|
||||
mediawiki-db-data:
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
external: true
|
||||
traefik-network:
|
||||
external: true
|
||||
|
||||
x-dockge:
|
||||
urls:
|
||||
# Proxied URLs (through Traefik)
|
||||
- https://bookstack.${DOMAIN}
|
||||
- https://${SERVER_IP}:6875
|
||||
- https://dokuwiki.${DOMAIN}
|
||||
- https://${SERVER_IP}:8087
|
||||
- https://mediawiki.${DOMAIN}
|
||||
- https://${SERVER_IP}:8086
|
||||
Reference in New Issue
Block a user