Merge pull request #1 from kelinfoxy/copilot/add-ai-chat-agent

Add AI-powered Docker service management for VS Code with 60+ homelab services, unified core stack, automated setup and deployment scripts, and modular documentation
This commit is contained in:
Kelin
2026-01-12 01:18:27 -05:00
committed by GitHub
37 changed files with 8403 additions and 1 deletions

194
.env.example Normal file
View File

@@ -0,0 +1,194 @@
# Environment Variables Template
# Copy this file to .env and fill in your values
# NEVER commit .env to git!
# User and Group IDs (get with: id -u and id -g)
PUID=1000
PGID=1000
# Timezone (list: timedatectl list-timezones)
TZ=America/New_York
# Server IP address
SERVER_IP=192.168.1.100
# Domain Configuration
DOMAIN=yourdomain.duckdns.org # Your DuckDNS domain
# Directory Paths
USERDIR=/opt/stacks
MEDIADIR=/mnt/media # Large media files on separate drive
DOWNLOADDIR=/mnt/downloads # Downloads on separate drive
PROJECTDIR=/home/username/projects
# DuckDNS Configuration
DUCKDNS_TOKEN=your-duckdns-token
DUCKDNS_SUBDOMAINS=yourdomain # Without .duckdns.org
# Let's Encrypt / ACME
ACME_EMAIL=your-email@example.com
# Authelia Secrets (generate with: openssl rand -hex 64)
AUTHELIA_JWT_SECRET=your-jwt-secret-here-64-chars
AUTHELIA_SESSION_SECRET=your-session-secret-here-64-chars
AUTHELIA_STORAGE_ENCRYPTION_KEY=your-encryption-key-here-64-chars
# SMTP for Authelia Notifications (optional)
SMTP_USERNAME=your-email@example.com
SMTP_PASSWORD=your-smtp-password
# Authentik SSO (optional - alternative to Authelia with web UI)
# Generate secrets with: openssl rand -hex 50
AUTHENTIK_SECRET_KEY=your-authentik-secret-key-here-100-chars
AUTHENTIK_DB_USER=authentik
AUTHENTIK_DB_PASSWORD=changeme-authentik-db-password
AUTHENTIK_DB_NAME=authentik
# VPN Configuration (Surfshark)
# Get WireGuard details from Surfshark dashboard
SURFSHARK_PRIVATE_KEY=your-wireguard-private-key
SURFSHARK_ADDRESSES=10.14.0.2/16
VPN_COUNTRY=Netherlands # Preferred VPN server location
# Alternative: OpenVPN credentials (if not using WireGuard)
# SURFSHARK_USERNAME=your-surfshark-username
# SURFSHARK_PASSWORD=your-surfshark-password
# Media Services
PLEX_CLAIM=claim-xxxxxxxxxx
# Monitoring & Dashboards
GRAFANA_ADMIN_PASSWORD=changeme
# Development Tools
CODE_SERVER_PASSWORD=changeme
CODE_SERVER_SUDO_PASSWORD=changeme
# Databases - General
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changeme
POSTGRES_DB=homelab
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=changeme
# Infrastructure
PIHOLE_PASSWORD=changeme
WATCHTOWER_NOTIFICATION_URL=
# Productivity Services - Nextcloud
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=changeme
NEXTCLOUD_DB_PASSWORD=changeme
NEXTCLOUD_DB_ROOT_PASSWORD=changeme
# Productivity Services - Gitea
GITEA_DB_PASSWORD=changeme
# Productivity Services - WordPress
WORDPRESS_DB_PASSWORD=changeme
WORDPRESS_DB_ROOT_PASSWORD=changeme
# Productivity Services - BookStack
BOOKSTACK_DB_PASSWORD=changeme
BOOKSTACK_DB_ROOT_PASSWORD=changeme
# Productivity Services - MediaWiki
MEDIAWIKI_DB_PASSWORD=changeme
MEDIAWIKI_DB_ROOT_PASSWORD=changeme
# Utilities - Form.io
FORMIO_JWT_SECRET=changeme
FORMIO_DB_SECRET=changeme
# Development - Jupyter
JUPYTER_TOKEN=changeme
# Cloudflare API (optional, for DNS challenge)
# CF_DNS_API_TOKEN=your-cloudflare-api-token
# qBittorrent
QBITTORRENT_USER=admin
QBITTORRENT_PASS=changeme
# Homepage Dashboard - API Keys and Tokens
# Generate these from each service's settings page
HOMEPAGE_VAR_DOMAIN=${DOMAIN}
HOMEPAGE_VAR_SERVER_IP=${SERVER_IP}
HOMEPAGE_VAR_PORTAINER_KEY=your-portainer-api-key
HOMEPAGE_VAR_PIHOLE_KEY=your-pihole-api-key
HOMEPAGE_VAR_PLEX_KEY=your-plex-token
HOMEPAGE_VAR_JELLYFIN_KEY=your-jellyfin-api-key
HOMEPAGE_VAR_SONARR_KEY=your-sonarr-api-key
HOMEPAGE_VAR_RADARR_KEY=your-radarr-api-key
HOMEPAGE_VAR_LIDARR_KEY=your-lidarr-api-key
HOMEPAGE_VAR_READARR_KEY=your-readarr-api-key
HOMEPAGE_VAR_PROWLARR_KEY=your-prowlarr-api-key
HOMEPAGE_VAR_JELLYSEERR_KEY=your-jellyseerr-api-key
HOMEPAGE_VAR_QBITTORRENT_USER=${QBITTORRENT_USER}
HOMEPAGE_VAR_QBITTORRENT_PASS=${QBITTORRENT_PASS}
HOMEPAGE_VAR_HA_KEY=your-home-assistant-long-lived-token
HOMEPAGE_VAR_NEXTCLOUD_USER=${NEXTCLOUD_ADMIN_USER}
HOMEPAGE_VAR_NEXTCLOUD_PASS=${NEXTCLOUD_ADMIN_PASSWORD}
HOMEPAGE_VAR_GRAFANA_USER=admin
HOMEPAGE_VAR_GRAFANA_PASS=${GRAFANA_ADMIN_PASSWORD}
HOMEPAGE_VAR_BOOKSTACK_KEY=your-bookstack-api-token
HOMEPAGE_VAR_UPTIMEKUMA_SLUG=your-uptime-kuma-slug
HOMEPAGE_VAR_OPENWEATHER_KEY=your-openweather-api-key
HOMEPAGE_VAR_WEATHERAPI_KEY=your-weatherapi-key
HOMEPAGE_VAR_UNIFI_USER=your-unifi-username
HOMEPAGE_VAR_UNIFI_PASS=your-unifi-password
# Add your own variables below
# Get WireGuard details from Surfshark dashboard
SURFSHARK_PRIVATE_KEY=your-wireguard-private-key
SURFSHARK_ADDRESSES=10.14.0.2/16
VPN_COUNTRY=Netherlands # Preferred VPN server location
# Alternative: OpenVPN credentials (if not using WireGuard)
# SURFSHARK_USERNAME=your-surfshark-username
# SURFSHARK_PASSWORD=your-surfshark-password
# Plex Configuration
PLEX_CLAIM=claim-xxxxxxxxxx
# Monitoring Passwords
GRAFANA_ADMIN_PASSWORD=changeme
# Code Server Passwords
CODE_SERVER_PASSWORD=changeme
CODE_SERVER_SUDO_PASSWORD=changeme
# Database Credentials
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changeme
POSTGRES_DB=homelab
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=changeme
# Jupyter Token
JUPYTER_TOKEN=changeme
# Pi-hole
PIHOLE_PASSWORD=changeme
# Bitwarden (Vaultwarden) Password Manager
# Admin token: openssl rand -base64 48
BITWARDEN_ADMIN_TOKEN=changeme-bitwarden-admin-token
BITWARDEN_SIGNUPS_ALLOWED=true # Set to false after creating accounts
BITWARDEN_INVITATIONS_ALLOWED=true
SMTP_HOST=smtp.gmail.com
SMTP_FROM=bitwarden@yourdomain.com
SMTP_PORT=587
SMTP_SECURITY=starttls
# SMTP_USERNAME and SMTP_PASSWORD defined above
# Watchtower Notifications (optional)
# WATCHTOWER_NOTIFICATION_URL=
# Cloudflare API (optional, for DNS challenge)
# CF_DNS_API_TOKEN=your-cloudflare-api-token
# Add your own variables below

530
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,530 @@
# AI Homelab Management Assistant
You are an AI assistant specialized in managing Docker-based homelab infrastructure using Dockge. Your role is to help users create, modify, and manage Docker services while maintaining consistency across the entire server stack.
## Core Principles
### 1. Dockge and Docker Compose First
- **ALWAYS** use Docker Compose stacks for persistent services
- Store all compose files in `/opt/stacks/stack-name/` directories
- Only use `docker run` for temporary containers (e.g., testing nvidia-container-toolkit functionality)
- Maintain all services in organized docker-compose.yml files within their stack folders
### 2. File Structure and Storage
- **Base Path**: All stacks are stored in `/opt/stacks/`
- **Bind Mounts**: Default to `/opt/stacks/stack-name/` for configuration files
- **Large Data**: Suggest using separate mounted drives for:
- Media files (movies, TV shows, music) - typically `/mnt/media`
- Downloads - typically `/mnt/downloads`
- Database data files that grow large
- Backup storage
- Any data that may exceed 50GB or grow continuously
- **Named Volumes**: Use Docker named volumes for smaller application data
### 3. Consistency is Key
- Keep consistent naming conventions across all compose files
- Use the same network naming patterns
- Maintain uniform volume mount structures
- Apply consistent environment variable patterns
- **Prefer LinuxServer.io images** when available (they support PUID/PGID for proper file permissions)
### 4. Stack-Aware Changes
- Before making changes, consider the impact on the entire server stack
- Check for service dependencies (networks, volumes, other services)
- Ensure changes don't break existing integrations
- Validate that port assignments don't conflict
### 5. Automated Configuration Management
- Configure all services via configuration files, not web UIs
- Traefik routes configured via Docker labels
- Authelia rules configured via YAML files
- Enable AI to manage and update configurations automatically
- Maintain homelab functionality through code, not manual UI clicks
### 6. Security-First Approach
- **All services start with SSO protection enabled by default**
- Only Plex and Jellyfin bypass SSO (for app/device compatibility)
- Users should explicitly remove SSO when ready to expose a service
- Comment out (don't remove) Authelia middleware when disabling SSO
- Prioritize security over convenience - expose services gradually
## Creating a New Docker Service
When creating a new service, follow these steps:
1. **Assess the Stack**
- Review existing services and their configurations
- Check for available ports
- Identify shared networks and volumes
- Note any dependent services
2. **Choose the Right Location**
- Place related services in the same compose file
- Use separate compose files for different functional areas (e.g., monitoring, media, development)
- Keep the file structure organized by category
3. **Service Definition Template**
```yaml
services:
service-name:
image: image:tag # Always pin versions for stability
container_name: service-name # Use descriptive, consistent names
restart: unless-stopped # Standard restart policy
networks:
- homelab-network # Use shared networks
ports:
- "host_port:container_port" # Document port purpose (if not using Traefik)
volumes:
- /opt/stacks/stack-name/config:/config # Config in stack directory
- service-data:/data # Named volumes for persistent data
# For large data, use separate mount:
# - /mnt/media:/media # Large media files on separate drive
environment:
- PUID=1000 # Standard user/group IDs
- PGID=1000
- TZ=America/New_York # Consistent timezone
labels:
- "homelab.category=category-name" # For organization
- "homelab.description=Service description"
# Traefik labels (if using Traefik):
# - "traefik.enable=true"
# - "traefik.http.routers.service-name.rule=Host(`service.domain.com`)"
# - "traefik.http.routers.service-name.entrypoints=websecure"
# - "traefik.http.routers.service-name.tls.certresolver=letsencrypt"
# Authelia middleware (ENABLED BY DEFAULT for security-first approach):
# - "traefik.http.routers.service-name.middlewares=authelia@docker"
# ONLY bypass SSO for Plex, Jellyfin, or services requiring direct app access
volumes:
service-data:
driver: local
networks:
homelab-network:
external: true # Or define once in main compose
```
4. **Configuration Best Practices**
- Pin image versions (avoid `:latest` in production)
- Use environment variables for configuration
- Store sensitive data in `.env` files (never commit these!)
- Use named volumes for data that should persist
- Bind mount config directories for easy access
5. **Documentation**
- Add comments explaining non-obvious configurations
- Document port mappings and their purposes
- Note any special requirements or dependencies
## Editing an Existing Service
When modifying a service:
1. **Review Current Configuration**
- Read the entire service definition
- Check for dependencies (links, depends_on, networks)
- Note any volumes or data that might be affected
2. **Plan the Change**
- Identify what needs to change
- Consider backward compatibility
- Plan for data migration if needed
3. **Make Minimal Changes**
- Change only what's necessary
- Maintain existing patterns and conventions
- Keep the same structure unless there's a good reason to change it
4. **Validate the Change**
- Check YAML syntax
- Verify port availability
- Ensure network connectivity
- Test the service starts correctly
5. **Update Documentation**
- Update comments if behavior changes
- Revise README files if user interaction changes
## Common Operations
### Testing a New Image
```bash
# Use docker run for quick tests, then convert to compose
docker run --rm -it \
--name test-container \
image:tag \
command
```
### Checking NVIDIA GPU Access
```bash
# Temporary test container for GPU
docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi
```
### Deploying a Stack
```bash
# Start all services in a compose file
docker compose -f docker-compose.yml up -d
# Start specific services
docker compose -f docker-compose.yml up -d service-name
```
### Updating a Service
```bash
# Pull latest image (if version updated)
docker compose -f docker-compose.yml pull service-name
# Recreate the service
docker compose -f docker-compose.yml up -d service-name
```
### Checking Logs
```bash
# View logs for a service
docker compose -f docker-compose.yml logs -f service-name
```
## Network Management
### Standard Network Setup
- Use a shared bridge network for inter-service communication
- Name it consistently (e.g., `homelab-network`)
- Define it once in a main compose file or create it manually
### Network Isolation
- Use separate networks for different security zones
- Keep databases on internal networks only
- Expose only necessary services to external networks
## Volume Management
### Volume Strategy
- **Named volumes**: For data that should persist but doesn't need direct access
- **Bind mounts**: For configs you want to edit directly
- **tmpfs**: For temporary data that should not persist
### Backup Considerations
- Keep important data in well-defined volumes
- Document backup procedures for each service
- Use consistent paths for easier backup automation
## Environment Variables
### Standard Variables
```yaml
environment:
- PUID=1000 # User ID for file permissions
- PGID=1000 # Group ID for file permissions
- TZ=America/New_York # Timezone
- UMASK=022 # File creation mask
```
### Sensitive Data
- Store secrets in `.env` files
- Reference them in compose: `${VARIABLE_NAME}`
- Never commit `.env` files to git
- Provide `.env.example` templates
## Troubleshooting
### Service Won't Start
1. Check logs: `docker compose logs service-name`
2. Verify configuration syntax
3. Check for port conflicts
4. Verify volume mounts exist
5. Check network connectivity
### Permission Issues
1. Verify PUID/PGID match host user
2. Check directory permissions
3. Verify volume ownership
### Network Issues
1. Verify network exists: `docker network ls`
2. Check if services are on same network
3. Use service names for DNS resolution
4. Check firewall rules
## File Organization
```
/opt/stacks/
├── core/ # Core infrastructure (deploy FIRST)
│ ├── docker-compose.yml # DuckDNS, Traefik, Authelia, Gluetun
│ ├── duckdns/ # DuckDNS config
│ ├── traefik/
│ │ ├── traefik.yml # Traefik static config
│ │ ├── dynamic/ # Dynamic configuration
│ │ │ └── routes.yml # Route definitions
│ │ └── acme.json # Let's Encrypt certificates
│ ├── authelia/
│ │ ├── configuration.yml # Authelia config
│ │ └── users_database.yml # User definitions
│ ├── gluetun/ # VPN config
│ └── .env # Core secrets
├── infrastructure/
│ ├── docker-compose.yml # Dockge, Portainer, Pi-hole, etc.
│ ├── config/
│ └── .env
├── dashboards/
│ ├── docker-compose.yml # Homepage, Homarr
│ ├── config/
│ └── .env
├── media/
│ ├── docker-compose.yml # Plex, Jellyfin, Sonarr, Radarr, etc.
│ ├── config/
│ └── .env
└── [other stacks...]
```
## Core Infrastructure Stack
The `core` stack (located at `/opt/stacks/core/docker-compose.yml`) contains the four essential services that must be deployed **FIRST**:
1. **DuckDNS** - Dynamic DNS updater for Let's Encrypt
2. **Traefik** - Reverse proxy with automatic SSL certificates
3. **Authelia** - SSO authentication for all services
4. **Gluetun** - VPN client (Surfshark WireGuard) for secure downloads
**Why combined in one stack?**
- These services depend on each other
- Simplifies initial deployment (one command)
- Easier to manage core infrastructure together
- Reduces network configuration complexity
- All core services in `/opt/stacks/core/` directory
**Deployment:**
```bash
# From within the directory
cd /opt/stacks/core/
docker compose up -d
# Or from anywhere with full path
docker compose -f /opt/stacks/core/docker-compose.yml up -d
```
All other stacks depend on the core stack being deployed first.
**Note:** The separate `authelia.yml`, `duckdns.yml`, `gluetun.yml`, and `traefik.yml` files have been removed to eliminate redundancy. All these services are now in the unified `core.yml` stack.
## Toggling SSO (Authelia) On/Off
You can easily enable or disable SSO protection for any service by modifying its Traefik labels.
### To Enable SSO
Add the Authelia middleware label:
```yaml
labels:
- "traefik.http.routers.servicename.middlewares=authelia@docker"
```
### To Disable SSO
Remove or comment out the middleware label:
```yaml
labels:
# - "traefik.http.routers.servicename.middlewares=authelia@docker"
```
**Common Use Cases:**
- **Development**: Enable SSO to protect services during testing
- **Production**: Disable SSO for services needing direct app/API access (Plex, Jellyfin)
- **Quick Toggle**: AI can modify these labels when you ask to enable/disable SSO
After changes, redeploy:
```bash
docker compose up -d
```
## VPN Integration with Gluetun
### When to Use VPN
- Download clients (qBittorrent, SABnzbd, etc.)
- Services that need to hide their origin IP
- Services accessing geo-restricted content
### Gluetun Configuration
- **Default VPN**: Surfshark
- Services connect through Gluetun's network namespace
- Use `network_mode: "service:gluetun"` for VPN routing
- Access via Gluetun's ports: map ports in Gluetun service
**Example:**
```yaml
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
cap_add:
- NET_ADMIN
environment:
- VPN_SERVICE_PROVIDER=surfshark
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${SURFSHARK_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${SURFSHARK_ADDRESSES}
- SERVER_COUNTRIES=Netherlands
ports:
- 8080:8080 # qBittorrent web UI
- 6881:6881 # qBittorrent ports
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
network_mode: "service:gluetun" # Route through VPN
depends_on:
- gluetun
volumes:
- /opt/stacks/qbittorrent/config:/config
- /mnt/downloads:/downloads
```
## SSO with Authelia
### Authentication Strategy
- **Protected Services**: Most web UIs (require SSO login)
- **Bypass Services**: Apps that need direct access (Jellyfin, Plex, mobile apps)
- **API Endpoints**: Configure bypass rules for API access
### Authelia Configuration
- Users defined in `users_database.yml`
- Access rules in `configuration.yml`
- Integrate with Traefik via middleware
### Services Requiring Authelia
- Monitoring dashboards (Grafana, Prometheus, etc.)
- Admin panels (Portainer, etc.)
- Download clients web UIs
- Development tools
- Any service with sensitive data
### Services Bypassing Authelia
- Jellyfin (for app access - Roku, Fire TV, mobile apps)
- Plex (for app access)
- Home Assistant (has its own auth)
- Services with API-only access
- Public-facing services (if any)
**Example Traefik Labels with Authelia:**
```yaml
labels:
- "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" # SSO enabled
```
**Example Bypassing Authelia (Jellyfin):**
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
# No authelia middleware - direct access for apps
```
## Traefik Reverse Proxy
### Why Traefik Instead of Nginx Proxy Manager
- **File-based configuration**: AI can modify YAML files
- **Docker label integration**: Automatic service discovery
- **No web UI dependency**: Fully automated management
- **Let's Encrypt automation**: Automatic SSL certificate management
- **Dynamic configuration**: Changes without restarts
### Traefik Configuration Pattern
1. **Static config** (`traefik.yml`): Core settings, entry points, certificate resolvers
2. **Dynamic config** (Docker labels): Per-service routing rules
3. **File provider**: Additional route definitions in `dynamic/` directory
### Managing Routes via AI
- Traefik routes defined in Docker labels
- AI can read compose files and add/modify labels
- Automatic service discovery when containers start
- Update routes by modifying compose files and redeploying
**Example Service with Traefik:**
```yaml
services:
service-name:
image: service:latest
container_name: service-name
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.service-name.rule=Host(`service.${DOMAIN}`)"
- "traefik.http.routers.service-name.entrypoints=websecure"
- "traefik.http.routers.service-name.tls.certresolver=letsencrypt"
- "traefik.http.routers.service-name.middlewares=authelia@docker"
- "traefik.http.services.service-name.loadbalancer.server.port=8080"
```
## DuckDNS for Dynamic DNS
### Purpose
- Provides dynamic DNS for home IP addresses
- Integrates with Let's Encrypt for SSL certificates
- Updates automatically when IP changes
### Configuration
- Single container updates your domain periodically
- Works with Traefik's Let's Encrypt resolver
- Set up once and forget
## Automated Homelab Management
### AI's Role in Maintenance
1. **Service Addition**: Create compose files with proper Traefik labels
2. **Route Management**: Update labels to modify proxy routes
3. **SSL Certificates**: Traefik handles automatically via Let's Encrypt
4. **SSO Configuration**: Add/remove authelia middleware as needed
5. **VPN Routing**: Configure services to use Gluetun when required
6. **Monitoring**: Ensure all services are properly configured
### Configuration Files AI Can Manage
- `docker-compose.yml` files for all stacks
- `traefik/dynamic/routes.yml` for custom routes
- `authelia/configuration.yml` for access rules
- Environment variables in `.env` files
- Service-specific config files in `/opt/stacks/stack-name/config/`
### What AI Should Monitor
- Port conflicts
- Network connectivity
- Certificate expiration (Traefik handles renewal)
- Service health
- VPN connection status
- Authentication bypass requirements
## Safety Checks
Before deploying any changes:
- [ ] YAML syntax is valid
- [ ] Ports don't conflict with existing services
- [ ] Networks exist or are defined
- [ ] Volume paths are correct (use /opt/stacks/ or /mnt/ for large data)
- [ ] Environment variables are set
- [ ] No secrets in compose files
- [ ] Service dependencies are met
- [ ] Backup of current configuration exists
- [ ] Traefik labels are correct for routing
- [ ] Authelia middleware applied appropriately
- [ ] VPN routing configured if needed
## Remember
- **Think before you act**: Consider the entire stack
- **Be consistent**: Follow established patterns
- **Use /opt/stacks/**: All compose files go in stack directories
- **Large data on /mnt/**: Media and downloads go on separate drives
- **Configure via files**: Traefik labels, Authelia YAML, not web UIs
- **Document everything**: Future you will thank you
- **Test safely**: Use temporary containers first
- **Back up first**: Always have a rollback plan
- **Security matters**: Use Authelia SSO, keep secrets in .env files
- **VPN when needed**: Route download clients through Gluetun
When a user asks you to create or modify a Docker service, follow these guidelines carefully, ask clarifying questions if needed, and always prioritize the stability, security, and consistency of the entire homelab infrastructure.

76
.gitignore vendored Normal file
View File

@@ -0,0 +1,76 @@
# Environment variables and secrets
.env
*.env
!.env.example
# Config directories with sensitive data
config/*/secrets/
config/*/*.key
config/*/*.pem
config/*/*.crt
config/*/db/
# Backup files
*.backup
*.bak
backups/
# OS files
.DS_Store
Thumbs.db
*.swp
*.swo
*~
# Editor files
.vscode/
.idea/
*.sublime-*
# Logs
*.log
logs/
# Temporary files
tmp/
temp/
*.tmp
# Docker volumes (if locally mounted)
volumes/
# Documentation builds
docs/_build/
docs/.doctrees/
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
# Node
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Database files
*.sqlite
*.db
# Certificates and keys
*.pem
*.key
*.crt
*.cer
*.p12
*.pfx
# Monitoring data (if stored locally)
prometheus-data/
grafana-data/
loki-data/

688
README.md
View File

@@ -1,2 +1,688 @@
# AI-Homelab
AI Powered Homelab administration
AI-Powered Homelab Administration with GitHub Copilot
## Overview
This repository provides a comprehensive, production-ready homelab infrastructure using Docker Compose with Dockge, featuring 40+ pre-configured services. Integrated AI assistance through GitHub Copilot helps you create, modify, and manage Docker services while maintaining consistency across your entire server stack.
The infrastructure uses Traefik for reverse proxy with automatic SSL, Authelia for Single Sign-On, Gluetun for VPN routing, and DuckDNS for dynamic DNS - all managed through file-based configurations that the AI can modify.
## Features
- **AI-Powered Management**: GitHub Copilot integration with specialized instructions for Docker service management
- **Dockge Structure**: All stacks organized in `/opt/stacks/` for easy management via Dockge
- **40+ Pre-configured Services**: Production-ready compose files across infrastructure, media, home automation, productivity, and monitoring
- **Traefik Reverse Proxy**: Automatic HTTPS with Let's Encrypt via file-based configuration (no web UI needed)
- **Authelia SSO**: Single Sign-On protection for all admin interfaces with smart bypass rules for media apps
- **Gluetun VPN**: Surfshark WireGuard integration for secure downloads
- **Homepage Dashboard**: AI-configurable dashboard with Docker integration and service widgets
- **External Host Proxying**: Proxy external services (Raspberry Pi, routers, NAS) through Traefik
- **Stack-Aware Changes**: AI considers the entire infrastructure when making changes
- **Comprehensive Documentation**: Detailed guidelines including proxying external hosts
- **File-Based Configuration**: Everything managed via YAML files - no web UI dependencies
## Quick Start
### Prerequisites
- Docker Engine 24.0+ installed
- Docker Compose V2
- Git
- VS Code with GitHub Copilot extension (for AI assistance)
- A domain from DuckDNS (free)
- Surfshark VPN account (optional, for VPN features)
- Sufficient disk space: 120GB+ system drive (NVMe or SSD highly recommended), 2TB+ for media & additional disks for services like Nextcloud that require lots of space
### Quick Setup (Dockge Structure)
1. **Clone the repository:**
```bash
# Note: Replace 'kelinfoxy' with your username if you forked this repository
git clone https://github.com/kelinfoxy/AI-Homelab.git
cd AI-Homelab
```
2. **(Optional) Run first-run setup script:**
**For fresh Debian installations only**, this automated script will:
- Update system and install Docker Engine + Compose V2
- Configure user groups (sudo, docker) and SSH access
- Detect NVIDIA GPU and provide driver installation guidance
- Create directory structure and Docker networks
```bash
sudo ./scripts/setup-homelab.sh
```
After completion, log out and log back in for group changes to take effect.
**Skip this step if Docker is already installed and configured.**
3. **Create and configure environment file:**
```bash
cp .env.example .env
nano .env # Edit with your domain, API keys, and passwords
```
**Required variables:**
- `DOMAIN` - Your DuckDNS domain (e.g., yourhomelab.duckdns.org)
- `DUCKDNS_TOKEN` - Token from DuckDNS.org
- `TZ` - Your timezone (e.g., America/New_York)
- Authelia user credentials
- API keys for services you plan to use
4. **Run deployment script:**
This automated script will:
- Create required directories
- Verify Docker networks exist
- Deploy core infrastructure (DuckDNS, Traefik, Authelia, Gluetun)
- Deploy infrastructure stack with Dockge
- Wait for Dockge to be ready
- Automatically open Dockge in your browser
```bash
./scripts/deploy-homelab.sh
```
The script will automatically open `https://dockge.yourdomain.duckdns.org` when ready.
**Manual deployment alternative:**
```bash
# Deploy core stack
mkdir -p /opt/stacks/core
cp docker-compose/core.yml /opt/stacks/core/docker-compose.yml
cp -r config-templates/traefik /opt/stacks/core/
cp -r config-templates/authelia /opt/stacks/core/
cp .env /opt/stacks/core/
cd /opt/stacks/core && docker compose up -d
# Deploy infrastructure stack
mkdir -p /opt/stacks/infrastructure
cp docker-compose/infrastructure.yml /opt/stacks/infrastructure/docker-compose.yml
cp .env /opt/stacks/infrastructure/
cd /opt/stacks/infrastructure && docker compose up -d
# Manually open: https://dockge.yourdomain.duckdns.org
```
5. **Deploy additional stacks through Dockge:**
Log in to Dockge with your Authelia credentials and deploy additional stacks:
- `dashboards.yml` - Homepage and Homarr dashboards
- `media.yml` - Plex, Jellyfin, Sonarr, Radarr, Prowlarr, qBittorrent
- `media-extended.yml` - Readarr, Lidarr, Lazy Librarian, Mylar3, Calibre-Web
- `homeassistant.yml` - Home Assistant, ESPHome, Node-RED, and accessories
- `productivity.yml` - Nextcloud, Gitea, WordPress, wikis
- `monitoring.yml` - Grafana, Prometheus, Loki
- `utilities.yml` - Backups, code editors, password manager
## Repository Structure
```
AI-Homelab/
├── .github/
│ └── copilot-instructions.md # AI assistant guidelines (Dockge, Traefik, Authelia aware)
├── docker-compose/
│ ├── traefik.yml # Reverse proxy (deploy first)
│ ├── authelia.yml # SSO authentication
│ ├── duckdns.yml # Dynamic DNS
│ ├── gluetun.yml # VPN client (Surfshark) + qBittorrent
│ ├── infrastructure.yml # Dockge, Portainer, Pi-hole, Watchtower, Dozzle, Glances
│ ├── dashboards.yml # Homepage, Homarr
│ ├── media.yml # Plex, Jellyfin, Sonarr, Radarr, Prowlarr
│ ├── media-extended.yml # Readarr, Lidarr, Lazy Librarian, Mylar3, Calibre-Web,
│ │ # Jellyseerr, FlareSolverr, Tdarr, Unmanic
│ ├── homeassistant.yml # Home Assistant, ESPHome, TasmoAdmin, Node-RED,
│ │ # Mosquitto, Zigbee2MQTT, MotionEye
│ ├── productivity.yml # Nextcloud, Mealie, WordPress, Gitea, DokuWiki,
│ │ # BookStack, MediaWiki (all with databases)
│ ├── utilities.yml # Backrest, Duplicati, Uptime Kuma, Code Server,
│ │ # Form.io, Authelia-Redis
│ ├── monitoring.yml # Prometheus, Grafana, Loki, Promtail, cAdvisor
│ ├── development.yml # GitLab, PostgreSQL, Redis, pgAdmin, Jupyter
│ └── README-dockge.md # Dockge deployment guide
├── config-templates/
│ ├── traefik/ # Traefik static and dynamic configs
│ ├── authelia/ # Authelia config and user database
│ ├── homepage/ # Homepage dashboard configs (with widgets)
│ ├── prometheus/ # Prometheus scrape configs
│ ├── loki/ # Loki log aggregation config
│ └── ... # Other service templates
├── docs/
│ ├── docker-guidelines.md # Comprehensive Docker guidelines
│ ├── getting-started.md # Step-by-step setup guide
│ ├── quick-reference.md # Command reference
│ └── proxying-external-hosts.md # Guide for proxying Raspberry Pi, routers, etc.
├── .env.example # Environment variable template (40+ vars)
├── .gitignore # Git ignore patterns
└── README.md # This file
```
## Using the AI Assistant
### In VS Code
1. **Install GitHub Copilot** extension in VS Code
2. **Open this repository** in VS Code
3. **Start Copilot Chat** and ask questions like:
- "Help me add a new media service to my homelab"
- "Configure Traefik routing for my new service"
- "Add Authelia SSO protection to this service"
- "How do I proxy my Raspberry Pi through Traefik?"
- "Create a Homepage widget for this service"
- "Route this download client through Gluetun VPN"
The AI assistant automatically follows the guidelines in `.github/copilot-instructions.md` to:
- Use `/opt/stacks/` directory structure (Dockge compatible)
- Configure Traefik labels for automatic routing
- Apply Authelia middleware where appropriate
- Suggest `/mnt/` for large data storage
- Add services to Homepage dashboard with widgets
- Maintain consistency with existing services
- Consider the entire stack when making changes
### Example Interactions
**Adding a new service:**
```
You: "Add Tautulli to monitor my Plex server"
Copilot: [Creates compose configuration with]:
- /opt/stacks/tautulli/ directory structure
- Traefik labels for HTTPS access
- Authelia middleware for SSO protection
- Homepage dashboard entry with widget
- Connection to existing Plex service
```
**Proxying external service:**
```
You: "Proxy my Raspberry Pi Home Assistant through Traefik"
Copilot: [Creates Traefik route configuration]:
- File in /opt/stacks/traefik/dynamic/
- HTTPS with Let's Encrypt
- Authelia bypass (HA has its own auth)
- WebSocket support
- Homepage dashboard entry
```
**Configuring VPN routing:**
```
You: "Route SABnzbd through the VPN"
Copilot: [Updates compose to use Gluetun]:
- network_mode: "service:gluetun"
- Exposes ports through Gluetun
- Maintains Traefik routing
- Updates documentation
```
## Available Service Stacks
### Core Infrastructure (Required)
#### 1. Traefik (`traefik.yml`)
**Reverse proxy with automatic SSL** - Deploy first!
- Automatic HTTPS via Let's Encrypt
- File-based and Docker label routing
- HTTP to HTTPS redirect
- Dashboard at `https://traefik.${DOMAIN}`
#### 2. Authelia (`authelia.yml`)
**Single Sign-On authentication**
- TOTP 2FA support
- LDAP/file-based user database
- Smart bypass rules for media apps
- Login at `https://auth.${DOMAIN}`
#### 3. DuckDNS (`duckdns.yml`)
**Dynamic DNS updater**
- Automatic IP updates
- Integrates with Let's Encrypt
- No web UI - runs silently
#### 4. Gluetun (`gluetun.yml`)
**VPN client (Surfshark WireGuard)**
- Includes qBittorrent
- Download via `https://qbit.${DOMAIN}`
- Easy to route other services through VPN
### Infrastructure Tools (`infrastructure.yml`)
- **Dockge**: Docker Compose stack manager (PRIMARY) - `https://dockge.${DOMAIN}`
- **Portainer**: Docker management UI (secondary) - `https://portainer.${DOMAIN}`
- **Pi-hole**: Network-wide ad blocking - `https://pihole.${DOMAIN}`
- **Watchtower**: Automatic container updates
- **Dozzle**: Real-time Docker logs - `https://dozzle.${DOMAIN}`
- **Glances**: System monitoring - `https://glances.${DOMAIN}`
- **Docker Proxy**: Secure Docker socket access
### Dashboards (`dashboards.yml`)
- **Homepage**: AI-configurable dashboard with widgets - `https://home.${DOMAIN}`
- Docker integration (container status)
- Service widgets (Sonarr, Radarr, Plex, Jellyfin, etc.)
- 11 organized categories
- **Homarr**: Modern alternative dashboard - `https://homarr.${DOMAIN}`
### Media Services (`media.yml`)
- **Plex**: Media streaming server - `https://plex.${DOMAIN}` (no SSO - app access)
- **Jellyfin**: Open-source media server - `https://jellyfin.${DOMAIN}` (no SSO - app access)
- **Sonarr**: TV show automation - `https://sonarr.${DOMAIN}`
- **Radarr**: Movie automation - `https://radarr.${DOMAIN}`
- **Prowlarr**: Indexer manager - `https://prowlarr.${DOMAIN}`
- **qBittorrent**: Torrent client (via VPN) - See gluetun.yml
### Extended Media (`media-extended.yml`)
- **Readarr**: Ebook/audiobook management - `https://readarr.${DOMAIN}`
- **Lidarr**: Music collection manager - `https://lidarr.${DOMAIN}`
- **Lazy Librarian**: Book download automation - `https://lazylibrarian.${DOMAIN}`
- **Mylar3**: Comic book manager - `https://mylar.${DOMAIN}`
- **Calibre-Web**: Ebook reader and server - `https://calibre.${DOMAIN}`
- **Jellyseerr**: Media request management - `https://jellyseerr.${DOMAIN}` (no SSO)
- **FlareSolverr**: Cloudflare bypass (no UI)
- **Tdarr**: Distributed transcoding - `https://tdarr.${DOMAIN}`
- **Unmanic**: Library optimizer - `https://unmanic.${DOMAIN}`
### Home Automation (`homeassistant.yml`)
- **Home Assistant**: Home automation hub - `https://ha.${DOMAIN}` (uses host network)
- **ESPHome**: ESP device manager - `https://esphome.${DOMAIN}`
- **TasmoAdmin**: Tasmota device manager - `https://tasmoadmin.${DOMAIN}`
- **Node-RED**: Flow automation - `https://nodered.${DOMAIN}`
- **Mosquitto**: MQTT broker (no UI)
- **Zigbee2MQTT**: Zigbee bridge - `https://zigbee2mqtt.${DOMAIN}`
- **MotionEye**: Video surveillance - `https://motioneye.${DOMAIN}`
### Productivity (`productivity.yml`)
- **Nextcloud**: File sync & collaboration - `https://nextcloud.${DOMAIN}`
- Includes MariaDB database
- **Mealie**: Recipe manager - `https://mealie.${DOMAIN}` (no SSO)
- **WordPress**: Blog platform - `https://blog.${DOMAIN}` (no SSO - public)
- Includes MariaDB database
- **Gitea**: Self-hosted Git - `https://git.${DOMAIN}`
- Includes PostgreSQL database
- **DokuWiki**: File-based wiki - `https://wiki.${DOMAIN}`
- **BookStack**: Documentation platform - `https://docs.${DOMAIN}`
- Includes MariaDB database
- **MediaWiki**: Wiki platform - `https://mediawiki.${DOMAIN}`
- Includes MariaDB database
### Utilities (`utilities.yml`)
- **Backrest**: Backup manager (restic) - `https://backrest.${DOMAIN}`
- **Duplicati**: Backup software - `https://duplicati.${DOMAIN}`
- **Uptime Kuma**: Status monitoring - `https://status.${DOMAIN}` (no SSO - public)
- **Code Server**: VS Code in browser - `https://code.${DOMAIN}`
- **Form.io**: Form builder - `https://forms.${DOMAIN}`
- Includes MongoDB database
- **Authelia-Redis**: Session storage (no UI)
### Monitoring (`monitoring.yml`)
- **Prometheus**: Metrics collection - `https://prometheus.${DOMAIN}`
- **Grafana**: Metrics visualization - `https://grafana.${DOMAIN}`
- **Loki**: Log aggregation
- **Promtail**: Log shipping
- **Node Exporter**: Host metrics
- **cAdvisor**: Container metrics
### Development (`development.yml`)
- **GitLab CE**: Git with CI/CD - `https://gitlab.${DOMAIN}`
- **PostgreSQL**: SQL database
- **Redis**: In-memory store
- **pgAdmin**: PostgreSQL UI - `https://pgadmin.${DOMAIN}`
- **Jupyter Lab**: Interactive notebooks - `https://jupyter.${DOMAIN}`
## Common Operations
### Managing Stacks via Dockge
Access Dockge at `https://dockge.${DOMAIN}` to:
- View all stacks and their status
- Start/stop/restart stacks
- Edit compose files directly
- View logs
- Deploy new stacks
### Command Line Operations
#### Starting Services (Dockge Structure)
```bash
# Start entire stack
cd /opt/stacks/media
docker compose up -d
# Start specific services
cd /opt/stacks/media
docker compose up -d sonarr radarr
# Start with rebuild
cd /opt/stacks/infrastructure
docker compose up -d --build
```
#### Stopping Services
```bash
# Stop entire stack
cd /opt/stacks/media
docker compose down
# Stop but keep volumes
cd /opt/stacks/media
docker compose stop
# Stop specific service
cd /opt/stacks/media
docker compose stop plex
```
#### Viewing Logs
```bash
# Follow logs for entire stack
cd /opt/stacks/media
docker compose logs -f
# Follow logs for specific service
cd /opt/stacks/media
docker compose logs -f plex
# View last 100 lines
cd /opt/stacks/media
docker compose logs --tail=100 plex
# Or use Dozzle web UI at https://dozzle.${DOMAIN}
```
#### Updating Services
```bash
# Pull latest images
cd /opt/stacks/media
docker compose pull
# Update specific service
cd /opt/stacks/media
docker compose pull plex
docker compose up -d plex
# Or enable Watchtower for automatic updates
```
### Testing with Docker Run
Use `docker run` only for temporary testing:
```bash
# Test NVIDIA GPU support
docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi
# Test a new image
docker run --rm -it alpine:latest /bin/sh
# Test VPN connection through Gluetun
docker run --rm --network container:gluetun curlimages/curl ifconfig.me
```
## Network Architecture
Services connect to multiple networks for organization and security:
- **traefik-network**: For Traefik to reach services (external)
- **homelab-network**: Main network for inter-service communication (external)
- **media-network**: Isolated network for media stack (external)
- **monitoring-network**: Network for observability stack (created per stack)
- **database-network**: Isolated networks for database services (created per stack)
- **dockerproxy-network**: Secure Docker socket access (created in infrastructure)
### Creating Required Networks
```bash
# Create external networks (do this once)
docker network create traefik-network
docker network create homelab-network
docker network create media-network
# Stack-specific networks are created automatically by compose files
```
### Traefik Routing
All services accessed via Traefik with automatic HTTPS:
- Pattern: `https://service.yourdomain.duckdns.org`
- Configured via Docker labels on each service
- SSL certificates automatically managed
- No port exposure needed (except Traefik 80/443)
## Documentation
### Comprehensive Guides
- **[Docker Guidelines](docs/docker-guidelines.md)**: Complete guide to Docker service management with Dockge
- **[Getting Started](docs/getting-started.md)**: Step-by-step setup walkthrough
- **[Quick Reference](docs/quick-reference.md)**: Command reference and troubleshooting
- **[Dockge Deployment](docker-compose/README-dockge.md)**: Dockge-specific deployment guide
- **[Proxying External Hosts](docs/proxying-external-hosts.md)**: Guide for proxying Raspberry Pi, routers, NAS via Traefik
- **[Copilot Instructions](.github/copilot-instructions.md)**: AI assistant guidelines (Traefik, Authelia, Dockge aware)
### Key Principles
1. **Dockge Structure**: All stacks in `/opt/stacks/stack-name/`
2. **Docker Compose First**: Always use compose for persistent services
3. **Docker Run for Testing**: Only use `docker run` for temporary containers
4. **File-Based Configuration**: Traefik labels and Authelia YAML (AI-manageable)
5. **Traefik for All**: Every service routed through Traefik with automatic SSL
6. **Smart SSO**: Authelia protects admin interfaces, bypasses media apps for device access
7. **VPN When Needed**: Route download clients through Gluetun
8. **Large Data Separate**: Use `/mnt/` for media, downloads, large databases
9. **Stack Awareness**: Consider dependencies and interactions
10. **Security**: Keep secrets in `.env` files, never commit them
## Configuration Management
### Environment Variables
All services use variables from `.env` in each stack directory:
- `PUID`/`PGID`: User/group IDs for file permissions
- `TZ`: Timezone for all services
- `DOMAIN`: Your DuckDNS domain (e.g., yourdomain.duckdns.org)
- `SERVER_IP`: Your server's IP address
- Service-specific credentials and API keys
- Homepage widget API keys (40+ variables)
See `.env.example` for complete list.
### Storage Strategy
**Small Data** (configs, databases < 10GB): `/opt/stacks/stack-name/`
```yaml
volumes:
- /opt/stacks/sonarr/config:/config
```
**Large Data** (media, downloads, backups): `/mnt/`
```yaml
volumes:
- /mnt/media:/media
- /mnt/downloads:/downloads
- /mnt/backups:/backups
```
The AI will suggest when to use `/mnt/` based on expected data size.
### Configuration Files
Service configurations stored in stack directories:
```
/opt/stacks/
├── traefik/
│ ├── docker-compose.yml
│ ├── traefik.yml # Static config
│ ├── dynamic/ # Dynamic routes
│ │ └── routes.yml
│ └── acme.json # SSL certificates
├── authelia/
│ ├── docker-compose.yml
│ ├── configuration.yml # Authelia settings
│ └── users_database.yml # User accounts
├── homepage/
│ ├── docker-compose.yml
│ └── config/
│ ├── services.yaml # Service definitions
│ ├── docker.yaml # Docker integration
│ ├── settings.yaml # Dashboard settings
│ └── widgets.yaml # Homepage widgets
└── ...
```
Templates available in `config-templates/` directory.
## Security Best Practices
1. **Pin Image Versions**: Never use `:latest` in production
2. **Use Environment Variables**: Store secrets in `.env` (gitignored)
3. **Run as Non-Root**: Set PUID/PGID to match your user
4. **Limit Exposure**: Bind ports to localhost when possible
5. **Regular Updates**: Keep images updated via Watchtower
6. **Scan Images**: Use `docker scan` to check for vulnerabilities
## Troubleshooting
### Service Won't Start
1. Check logs: `docker compose -f file.yml logs service-name`
2. Validate config: `docker compose -f file.yml config`
3. Check port conflicts: `sudo netstat -tlnp | grep PORT`
4. Verify network exists: `docker network ls`
### Permission Issues
1. Check PUID/PGID match your user: `id -u` and `id -g`
2. Fix ownership: `sudo chown -R 1000:1000 ./config/service-name`
### Network Issues
1. Verify network exists: `docker network inspect homelab-network`
2. Test connectivity: `docker compose exec service1 ping service2`
### Getting Help
- Review the [Docker Guidelines](docs/docker-guidelines.md)
- Ask GitHub Copilot in VS Code
- Check service-specific documentation
- Review Docker logs for error messages
## Backup Strategy
### What to Backup
1. **Docker Compose files** (version controlled in git)
2. **Config directories**: `./config/*`
3. **Named volumes**: `docker volume ls`
4. **Environment file**: `.env` (securely, not in git)
### Backup Named Volumes
```bash
# Backup a volume
docker run --rm \
-v volume-name:/data \
-v $(pwd)/backups:/backup \
busybox tar czf /backup/volume-backup.tar.gz /data
```
### Restore Named Volumes
```bash
# Restore a volume
docker run --rm \
-v volume-name:/data \
-v $(pwd)/backups:/backup \
busybox tar xzf /backup/volume-backup.tar.gz -C /
```
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Follow existing patterns and conventions
4. Test your changes
5. Submit a pull request
## License
This project is provided as-is for personal homelab use.
## Acknowledgments
- Docker and Docker Compose communities
- LinuxServer.io for excellent container images
- GitHub Copilot for AI assistance capabilities
- All the open-source projects used in example compose files
## Getting Started Checklist
- [ ] Install Docker and Docker Compose V2
- [ ] Sign up for DuckDNS (free) and get your domain
- [ ] Get Surfshark VPN credentials (optional, for VPN features)
- [ ] Clone this repository
- [ ] Copy `.env.example` to `.env` and configure all values
- [ ] Create `/opt/stacks` directory: `sudo mkdir -p /opt/stacks && sudo chown $USER:$USER /opt/stacks`
- [ ] Create Docker networks: `docker network create traefik-network homelab-network media-network`
- [ ] Deploy DuckDNS stack
- [ ] Deploy Traefik stack (with config templates)
- [ ] Deploy Authelia stack (with config templates)
- [ ] Deploy infrastructure stack (Dockge)
- [ ] Access Dockge at `https://dockge.${DOMAIN}` and deploy remaining stacks
- [ ] Configure Homepage dashboard (copy templates to /opt/stacks/homepage/config/)
- [ ] Install VS Code with GitHub Copilot extension
- [ ] Open repository in VS Code and start using AI assistance
## Proxying External Hosts
You can proxy services running on other devices (Raspberry Pi, routers, NAS) through Traefik:
**Example: Raspberry Pi Home Assistant**
```yaml
# In /opt/stacks/traefik/dynamic/external.yml
http:
routers:
ha-pi:
rule: "Host(`ha.yourdomain.duckdns.org`)"
entryPoints:
- websecure
service: ha-pi
tls:
certResolver: letsencrypt
services:
ha-pi:
loadBalancer:
servers:
- url: "http://192.168.1.50:8123"
```
See [docs/proxying-external-hosts.md](docs/proxying-external-hosts.md) for complete guide including:
- Three methods (file provider, Docker labels, hybrid)
- Authelia bypass configuration
- WebSocket support
- Examples for routers, NAS, cameras, Proxmox
## Support
For issues, questions, or suggestions:
- Open an issue on GitHub
- Consult the comprehensive [documentation](docs/docker-guidelines.md)
- Use GitHub Copilot in VS Code for real-time assistance

196
config-templates/README.md Normal file
View File

@@ -0,0 +1,196 @@
# Configuration Templates
This directory contains example configuration files for various services. These templates provide sensible defaults and are ready to use with minimal modifications.
## Usage
1. **Create your config directory** (if it doesn't exist):
```bash
mkdir -p config/service-name
```
2. **Copy the template** to your config directory:
```bash
cp config-templates/service-name/* config/service-name/
```
3. **Edit the configuration** as needed for your environment
4. **Start the service** using Docker Compose
## Available Templates
### Prometheus (`prometheus/prometheus.yml`)
Metrics collection and monitoring system configuration.
**Features:**
- Pre-configured to scrape Node Exporter and cAdvisor
- 15-second scrape interval
- Ready for additional service monitoring
**Setup:**
```bash
mkdir -p config/prometheus
cp config-templates/prometheus/prometheus.yml config/prometheus/
docker compose -f docker-compose/monitoring.yml up -d prometheus
```
### Loki (`loki/loki-config.yml`)
Log aggregation system configuration.
**Features:**
- Filesystem-based storage
- 30-day log retention
- Automatic log compaction
- Pre-configured for Promtail
**Setup:**
```bash
mkdir -p config/loki
cp config-templates/loki/loki-config.yml config/loki/
docker compose -f docker-compose/monitoring.yml up -d loki
```
### Promtail (`promtail/promtail-config.yml`)
Log shipper for Loki.
**Features:**
- Automatically ships Docker container logs
- Parses Docker JSON format
- Extracts container IDs and names
- Optional system log collection
**Setup:**
```bash
mkdir -p config/promtail
cp config-templates/promtail/promtail-config.yml config/promtail/
docker compose -f docker-compose/monitoring.yml up -d promtail
```
### Redis (`redis/redis.conf`)
In-memory data store configuration.
**Features:**
- Both AOF and RDB persistence enabled
- 256MB memory limit with LRU eviction
- Sensible defaults for homelab use
- Security options (password protection available)
**Setup:**
```bash
mkdir -p config/redis
cp config-templates/redis/redis.conf config/redis/
# Optional: Edit redis.conf to set a password
docker compose -f docker-compose/development.yml up -d redis
```
## Customization Tips
### Prometheus
- Add more scrape targets to monitor additional services
- Adjust `scrape_interval` based on your needs (lower = more frequent, more data)
- Configure alerting by uncommenting the alertmanager section
### Loki
- Adjust `retention_period` to keep logs longer or shorter
- Change storage from filesystem to S3 for better scalability
- Configure multiple tenants if needed
### Promtail
- Add more scrape configs for system logs, application logs, etc.
- Customize pipeline stages to extract more labels
- Filter logs based on patterns
### Redis
- Set `maxmemory` based on your available RAM
- Choose appropriate `maxmemory-policy` for your use case
- Enable password protection by uncommenting `requirepass`
## Service-Specific Notes
### Services That Don't Need Config Templates
Many services work perfectly with just environment variables and don't require separate config files:
- **Plex, Jellyfin**: Configure via web UI
- **Sonarr, Radarr, Prowlarr**: Configure via web UI
- **Portainer**: Configure via web UI
- **Grafana**: Can use provisioning or web UI
- **Most LinuxServer.io images**: Configured via environment variables
### Services That Benefit from Config Files
- **Prometheus**: Requires `prometheus.yml` for scrape configuration
- **Loki**: Requires config for storage and retention
- **Promtail**: Requires config for log sources
- **Redis**: Benefits from custom config for persistence and security
- **Nginx**: Needs config for proxy rules (use Nginx Proxy Manager UI instead)
## Best Practices
1. **Version Control**: Keep your config templates in git
2. **Secrets**: Never commit passwords or API keys
3. **Comments**: Add comments explaining custom settings
4. **Backups**: Backup config directories regularly
5. **Testing**: Test config changes in a separate environment first
## Creating New Templates
When creating templates for other services:
1. Start with the official documentation
2. Use sensible defaults for homelab use
3. Add comments explaining important settings
4. Include examples for common customizations
5. Test the template before committing
## Getting Help
- Check the official documentation for each service
- Ask GitHub Copilot in VS Code for configuration help
- Review the [Docker Guidelines](../docs/docker-guidelines.md)
- Consult service-specific community forums
## Example: Full Monitoring Stack Setup
```bash
# Create all config directories
mkdir -p config/{prometheus,loki,promtail,grafana}
# Copy templates
cp config-templates/prometheus/prometheus.yml config/prometheus/
cp config-templates/loki/loki-config.yml config/loki/
cp config-templates/promtail/promtail-config.yml config/promtail/
# Start the monitoring stack
docker compose -f docker-compose/monitoring.yml up -d
# Access services
# Prometheus: http://server-ip:9090
# Grafana: http://server-ip:3000
# Loki: http://server-ip:3100
```
## Troubleshooting
### Config file not found
Ensure you copied the template to the correct location referenced in the docker-compose file.
### Permission errors
Fix ownership:
```bash
sudo chown -R 1000:1000 config/service-name
```
### Syntax errors
Validate YAML files:
```bash
# For YAML files
python3 -c "import yaml; yaml.safe_load(open('config/service/config.yml'))"
```
### Service won't start
Check logs for configuration errors:
```bash
docker compose -f docker-compose/file.yml logs service-name
```

View File

@@ -0,0 +1,93 @@
# Authelia Configuration
# Copy to /opt/stacks/authelia/configuration.yml
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: 1h
inactivity: 5m
remember_me_duration: 1M
domain: ${DOMAIN}
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 testing)
filesystem:
filename: /config/notification.txt
# SMTP notifications (recommended for production)
# smtp:
# host: smtp.gmail.com
# port: 587
# username: ${SMTP_USERNAME}
# password: ${AUTHELIA_NOTIFIER_SMTP_PASSWORD}
# sender: authelia@${DOMAIN}
# identifier: localhost
# subject: "[Authelia] {title}"
# startup_check_address: test@authelia.com
# disable_require_tls: false
# disable_html_emails: false

View File

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

View File

@@ -0,0 +1,13 @@
# Homepage Configuration - Docker Integration
# Copy to /opt/stacks/homepage/config/docker.yaml
# Enables auto-discovery of containers and status monitoring
---
# Docker socket (via proxy for security)
my-docker:
socket: /var/run/docker.sock
# Or use Docker socket proxy (recommended for production)
# my-docker:
# host: dockerproxy
# port: 2375

View File

@@ -0,0 +1,373 @@
# Homepage Configuration - Services
# Copy to /opt/stacks/homepage/config/services.yaml
# This file is AI-configurable - Homepage will auto-discover services via Docker labels
---
# Infrastructure Services
- Infrastructure:
- Dockge:
icon: dockge.png
href: https://dockge.{{HOMEPAGE_VAR_DOMAIN}}
description: Docker Compose Stack Manager (PRIMARY)
container: dockge
widget:
type: dockge
url: http://dockge:5001
- Traefik:
icon: traefik.png
href: https://traefik.{{HOMEPAGE_VAR_DOMAIN}}
description: Reverse Proxy & SSL
container: traefik
widget:
type: traefik
url: http://traefik:8080
- Authelia:
icon: authelia.png
href: https://auth.{{HOMEPAGE_VAR_DOMAIN}}
description: Single Sign-On
container: authelia
widget:
type: authelia
url: http://authelia:9091
- Portainer:
icon: portainer.png
href: https://portainer.{{HOMEPAGE_VAR_DOMAIN}}
description: Docker Management (Secondary)
container: portainer
widget:
type: portainer
url: http://portainer:9000
env: 1
key: {{HOMEPAGE_VAR_PORTAINER_KEY}}
- Pi-hole:
icon: pi-hole.png
href: https://pihole.{{HOMEPAGE_VAR_DOMAIN}}
description: Network-wide Ad Blocking
container: pihole
widget:
type: pihole
url: http://pihole
key: {{HOMEPAGE_VAR_PIHOLE_KEY}}
- Dozzle:
icon: dozzle.png
href: https://dozzle.{{HOMEPAGE_VAR_DOMAIN}}
description: Real-time Docker Logs
container: dozzle
- Glances:
icon: glances.png
href: https://glances.{{HOMEPAGE_VAR_DOMAIN}}
description: System Monitoring
container: glances
widget:
type: glances
url: http://glances:61208
metric: cpu
# Dashboards
- Dashboards:
- Homarr:
icon: homarr.png
href: https://homarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Alternative Dashboard
container: homarr
- Uptime Kuma:
icon: uptime-kuma.png
href: https://status.{{HOMEPAGE_VAR_DOMAIN}}
description: Uptime Monitoring
container: uptime-kuma
widget:
type: uptimekuma
url: http://uptime-kuma:3001
slug: {{HOMEPAGE_VAR_UPTIMEKUMA_SLUG}}
# Media - Streaming
- Media Streaming:
- Plex:
icon: plex.png
href: https://plex.{{HOMEPAGE_VAR_DOMAIN}}
description: Media Server
container: plex
widget:
type: plex
url: http://plex:32400
key: {{HOMEPAGE_VAR_PLEX_KEY}}
- Jellyfin:
icon: jellyfin.png
href: https://jellyfin.{{HOMEPAGE_VAR_DOMAIN}}
description: Open Source Media Server
container: jellyfin
widget:
type: jellyfin
url: http://jellyfin:8096
key: {{HOMEPAGE_VAR_JELLYFIN_KEY}}
- Jellyseerr:
icon: jellyseerr.png
href: https://jellyseerr.{{HOMEPAGE_VAR_DOMAIN}}
description: Media Requests
container: jellyseerr
widget:
type: jellyseerr
url: http://jellyseerr:5055
key: {{HOMEPAGE_VAR_JELLYSEERR_KEY}}
# Media - Management
- Media Management:
- Sonarr:
icon: sonarr.png
href: https://sonarr.{{HOMEPAGE_VAR_DOMAIN}}
description: TV Show Management
container: sonarr
widget:
type: sonarr
url: http://sonarr:8989
key: {{HOMEPAGE_VAR_SONARR_KEY}}
- Radarr:
icon: radarr.png
href: https://radarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Movie Management
container: radarr
widget:
type: radarr
url: http://radarr:7878
key: {{HOMEPAGE_VAR_RADARR_KEY}}
- Lidarr:
icon: lidarr.png
href: https://lidarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Music Management
container: lidarr
widget:
type: lidarr
url: http://lidarr:8686
key: {{HOMEPAGE_VAR_LIDARR_KEY}}
- Readarr:
icon: readarr.png
href: https://readarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Book Management
container: readarr
widget:
type: readarr
url: http://readarr:8787
key: {{HOMEPAGE_VAR_READARR_KEY}}
- Prowlarr:
icon: prowlarr.png
href: https://prowlarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Indexer Manager
container: prowlarr
widget:
type: prowlarr
url: http://prowlarr:9696
key: {{HOMEPAGE_VAR_PROWLARR_KEY}}
# Downloads
- Downloads:
- qBittorrent:
icon: qbittorrent.png
href: https://qbit.{{HOMEPAGE_VAR_DOMAIN}}
description: Torrent Client (via VPN)
container: qbittorrent
widget:
type: qbittorrent
url: http://gluetun:8080
username: {{HOMEPAGE_VAR_QBITTORRENT_USER}}
password: {{HOMEPAGE_VAR_QBITTORRENT_PASS}}
- Gluetun:
icon: gluetun.png
href: http://gluetun:8000
description: VPN Client (Surfshark)
container: gluetun
# Books & Comics
- Books & Comics:
- Calibre-Web:
icon: calibre-web.png
href: https://calibre.{{HOMEPAGE_VAR_DOMAIN}}
description: Ebook Library
container: calibre-web
- Lazy Librarian:
icon: lazylibrarian.png
href: https://lazylibrarian.{{HOMEPAGE_VAR_DOMAIN}}
description: Book Manager
container: lazylibrarian
- Mylar3:
icon: mylar3.png
href: https://mylar.{{HOMEPAGE_VAR_DOMAIN}}
description: Comic Book Manager
container: mylar3
# Transcoding
- Transcoding:
- Tdarr:
icon: tdarr.png
href: https://tdarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Distributed Transcoding
container: tdarr-server
widget:
type: tdarr
url: http://tdarr-server:8265
- Unmanic:
icon: unmanic.png
href: https://unmanic.{{HOMEPAGE_VAR_DOMAIN}}
description: Library Optimizer
container: unmanic
# Home Automation
- Home Automation:
- Home Assistant:
icon: home-assistant.png
href: https://ha.{{HOMEPAGE_VAR_DOMAIN}}
description: Home Automation Hub
# Note: Uses host network, configure manually
widget:
type: homeassistant
url: http://{{HOMEPAGE_VAR_SERVER_IP}}:8123
key: {{HOMEPAGE_VAR_HA_KEY}}
- ESPHome:
icon: esphome.png
href: https://esphome.{{HOMEPAGE_VAR_DOMAIN}}
description: ESP Device Manager
container: esphome
- Node-RED:
icon: node-red.png
href: https://nodered.{{HOMEPAGE_VAR_DOMAIN}}
description: Flow Automation
container: nodered
- TasmoAdmin:
icon: tasmota.png
href: https://tasmoadmin.{{HOMEPAGE_VAR_DOMAIN}}
description: Tasmota Device Manager
container: tasmoadmin
- Zigbee2MQTT:
icon: zigbee2mqtt.png
href: https://zigbee2mqtt.{{HOMEPAGE_VAR_DOMAIN}}
description: Zigbee Bridge
container: zigbee2mqtt
- MotionEye:
icon: motioneye.png
href: https://motioneye.{{HOMEPAGE_VAR_DOMAIN}}
description: Video Surveillance
container: motioneye
# Productivity
- Productivity:
- Nextcloud:
icon: nextcloud.png
href: https://nextcloud.{{HOMEPAGE_VAR_DOMAIN}}
description: File Sync & Share
container: nextcloud
widget:
type: nextcloud
url: http://nextcloud
username: {{HOMEPAGE_VAR_NEXTCLOUD_USER}}
password: {{HOMEPAGE_VAR_NEXTCLOUD_PASS}}
- Mealie:
icon: mealie.png
href: https://mealie.{{HOMEPAGE_VAR_DOMAIN}}
description: Recipe Manager
container: mealie
- Gitea:
icon: gitea.png
href: https://git.{{HOMEPAGE_VAR_DOMAIN}}
description: Git Service
container: gitea
- Code Server:
icon: vscode.png
href: https://code.{{HOMEPAGE_VAR_DOMAIN}}
description: VS Code in Browser
container: code-server
# Documentation
- Documentation:
- BookStack:
icon: bookstack.png
href: https://docs.{{HOMEPAGE_VAR_DOMAIN}}
description: Documentation Platform
container: bookstack
widget:
type: bookstack
url: http://bookstack
key: {{HOMEPAGE_VAR_BOOKSTACK_KEY}}
- DokuWiki:
icon: dokuwiki.png
href: https://wiki.{{HOMEPAGE_VAR_DOMAIN}}
description: File-based Wiki
container: dokuwiki
- MediaWiki:
icon: mediawiki.png
href: https://mediawiki.{{HOMEPAGE_VAR_DOMAIN}}
description: Wiki Platform
container: mediawiki
- WordPress:
icon: wordpress.png
href: https://blog.{{HOMEPAGE_VAR_DOMAIN}}
description: Blog Platform
container: wordpress
# Backups & Monitoring
- Backups & Tools:
- Backrest:
icon: backrest.png
href: https://backrest.{{HOMEPAGE_VAR_DOMAIN}}
description: Backup Manager (Restic)
container: backrest
- Duplicati:
icon: duplicati.png
href: https://duplicati.{{HOMEPAGE_VAR_DOMAIN}}
description: Backup Software
container: duplicati
# Monitoring Stack
- Monitoring:
- Grafana:
icon: grafana.png
href: https://grafana.{{HOMEPAGE_VAR_DOMAIN}}
description: Metrics Visualization
container: grafana
widget:
type: grafana
url: http://grafana:3000
username: {{HOMEPAGE_VAR_GRAFANA_USER}}
password: {{HOMEPAGE_VAR_GRAFANA_PASS}}
- Prometheus:
icon: prometheus.png
href: https://prometheus.{{HOMEPAGE_VAR_DOMAIN}}
description: Metrics Collection
container: prometheus
widget:
type: prometheus
url: http://prometheus:9090
- Uptime Kuma:
icon: uptime-kuma.png
href: https://status.{{HOMEPAGE_VAR_DOMAIN}}
description: Status Page
container: uptime-kuma

View File

@@ -0,0 +1,63 @@
# Homepage Configuration - Settings
# Copy to /opt/stacks/homepage/config/settings.yaml
---
title: Homelab Dashboard
background: https://images.unsplash.com/photo-1558591710-4b4a1ae0f04d
backgroundOpacity: 0.2
theme: dark
color: slate
headerStyle: boxed
hideVersion: true
hideErrors: false
showStats: true
target: _self # Open links in same tab
# Layout configuration
layout:
Infrastructure:
style: row
columns: 4
Dashboards:
style: row
columns: 2
Media Streaming:
style: row
columns: 3
Media Management:
style: row
columns: 4
Downloads:
style: row
columns: 2
Books & Comics:
style: row
columns: 3
Home Automation:
style: row
columns: 4
Productivity:
style: row
columns: 4
Documentation:
style: row
columns: 4
Backups & Tools:
style: row
columns: 2
Monitoring:
style: row
columns: 3
# Quick search
quicklaunch:
searchDescriptions: true
hideInternetSearch: false
showSearchSuggestions: true
# Providers for additional functionality
providers:
longhorn:
url: http://longhorn:9500
openweathermap: {{HOMEPAGE_VAR_OPENWEATHER_KEY}}
weatherapi: {{HOMEPAGE_VAR_WEATHERAPI_KEY}}

View File

@@ -0,0 +1,49 @@
# Homepage Configuration - Widgets
# Copy to /opt/stacks/homepage/config/widgets.yaml
# Displays system resources and other information
---
- logo:
icon: https://avatars.githubusercontent.com/u/... # Your logo here
- search:
provider: google
target: _blank
- datetime:
text_size: xl
format:
dateStyle: long
timeStyle: short
hourCycle: h23
- resources:
label: System
cpu: true
memory: true
disk: /
cputemp: true
uptime: true
units: metric
- resources:
label: Storage
disk: /mnt/media
expanded: true
- resources:
label: Downloads
disk: /mnt/downloads
expanded: true
- openmeteo:
label: Weather
latitude: 40.7128
longitude: -74.0060
units: metric
cache: 5
- unifi_console:
url: http://unifi:8443
username: {{HOMEPAGE_VAR_UNIFI_USER}}
password: {{HOMEPAGE_VAR_UNIFI_PASS}}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,58 @@
# Traefik Static Configuration
# Copy to /opt/stacks/traefik/traefik.yml
global:
checkNewVersion: true
sendAnonymousUsage: false
api:
dashboard: true
insecure: false # Dashboard accessible via Traefik route with Authelia
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: ${ACME_EMAIL}
storage: /acme.json
# Use HTTP challenge (port 80 must be accessible)
httpChallenge:
entryPoint: web
# Or use DNS challenge (requires API token):
# dnsChallenge:
# provider: duckdns
# resolvers:
# - "1.1.1.1:53"
# - "8.8.8.8:53"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false # Only expose services with traefik.enable=true
network: traefik-network
file:
directory: /dynamic
watch: true
log:
level: INFO # DEBUG, INFO, WARN, ERROR
filePath: /var/log/traefik/traefik.log
accessLog:
filePath: /var/log/traefik/access.log
bufferingSize: 100

View File

@@ -0,0 +1,324 @@
# Docker Compose Stacks - Dockge Structure
This directory contains Docker Compose files designed for use with Dockge. Each stack should be placed in `/opt/stacks/stack-name/` on your server.
## Structure
```
/opt/stacks/
├── traefik/
│ ├── docker-compose.yml # Copy from traefik.yml
│ ├── traefik.yml # Static configuration
│ ├── dynamic/ # Dynamic routes
│ ├── acme.json # SSL certificates (chmod 600)
│ └── .env
├── authelia/
│ ├── docker-compose.yml # Copy from authelia.yml
│ ├── configuration.yml # Authelia config
│ ├── users_database.yml # User definitions
│ └── .env
├── duckdns/
│ ├── docker-compose.yml # Copy from duckdns.yml
│ └── .env
├── gluetun/
│ ├── docker-compose.yml # Copy from gluetun.yml (includes qBittorrent)
│ └── .env
├── infrastructure/
│ ├── docker-compose.yml # Copy from infrastructure.yml
│ └── .env
├── media/
│ ├── docker-compose.yml # Copy from media.yml
│ └── .env
├── monitoring/
│ ├── docker-compose.yml # Copy from monitoring.yml
│ └── .env
└── development/
├── docker-compose.yml # Copy from development.yml
└── .env
```
## Core Infrastructure Stacks
### 1. Traefik (REQUIRED - Deploy First)
**File**: `traefik.yml`
**Location**: `/opt/stacks/traefik/`
Reverse proxy with automatic SSL certificates via Let's Encrypt.
**Features**:
- Automatic HTTPS with Let's Encrypt
- Docker service discovery via labels
- File-based configuration for AI management
- HTTP to HTTPS redirect
**Setup**:
```bash
mkdir -p /opt/stacks/traefik/dynamic
cd /opt/stacks/traefik
# Copy traefik.yml to docker-compose.yml
# Copy config templates from config-templates/traefik/
# Create acme.json and set permissions
touch acme.json && chmod 600 acme.json
# Edit .env with your domain and email
docker compose up -d
```
### 2. Authelia (REQUIRED - Deploy Second)
**File**: `authelia.yml`
**Location**: `/opt/stacks/authelia/`
Single Sign-On (SSO) authentication for all services.
**Features**:
- Protects services with authentication
- Bypass rules for apps (Jellyfin, Plex)
- Integrates with Traefik via middleware
- TOTP 2FA support
**Setup**:
```bash
mkdir -p /opt/stacks/authelia
cd /opt/stacks/authelia
# Copy authelia.yml to docker-compose.yml
# Copy config templates from config-templates/authelia/
# Generate secrets: openssl rand -hex 64
# Edit configuration.yml and users_database.yml
# Hash password: docker run authelia/authelia:latest authelia crypto hash generate argon2 --password 'yourpassword'
docker compose up -d
```
### 3. DuckDNS (RECOMMENDED)
**File**: `duckdns.yml`
**Location**: `/opt/stacks/duckdns/`
Dynamic DNS updater for your domain.
**Setup**:
```bash
mkdir -p /opt/stacks/duckdns
cd /opt/stacks/duckdns
# Copy duckdns.yml to docker-compose.yml
# Add DUCKDNS_TOKEN and DUCKDNS_SUBDOMAINS to .env
docker compose up -d
```
### 4. Gluetun VPN (REQUIRED for torrenting)
**File**: `gluetun.yml`
**Location**: `/opt/stacks/gluetun/`
VPN client (Surfshark) for routing download clients securely.
**Includes**: qBittorrent configured to route through VPN
**Setup**:
```bash
mkdir -p /opt/stacks/gluetun
mkdir -p /opt/stacks/qbittorrent
cd /opt/stacks/gluetun
# Copy gluetun.yml to docker-compose.yml
# Add Surfshark WireGuard credentials to .env
# Get WireGuard config from Surfshark dashboard
docker compose up -d
```
## Application Stacks
### Infrastructure
**File**: `infrastructure.yml`
**Location**: `/opt/stacks/infrastructure/`
- Pi-hole: Network-wide ad blocking
- Portainer: Docker management UI
- Watchtower: Automatic container updates
### Media
**File**: `media.yml`
**Location**: `/opt/stacks/media/`
- Plex: Media streaming (NO Authelia - app access)
- Jellyfin: Open-source streaming (NO Authelia - app access)
- Sonarr: TV show automation (WITH Authelia)
- Radarr: Movie automation (WITH Authelia)
- Prowlarr: Indexer manager (WITH Authelia)
**Note**: qBittorrent is in gluetun.yml (VPN routing)
### Monitoring
**File**: `monitoring.yml`
**Location**: `/opt/stacks/monitoring/`
- Prometheus: Metrics collection
- Grafana: Visualization
- Node Exporter: System metrics
- cAdvisor: Container metrics
- Uptime Kuma: Service monitoring
- Loki: Log aggregation
- Promtail: Log shipping
### Development
**File**: `development.yml`
**Location**: `/opt/stacks/development/`
- Code Server: VS Code in browser
- GitLab: Git repository manager
- PostgreSQL: Database
- Redis: In-memory store
- pgAdmin: Database UI
- Jupyter Lab: Data science notebooks
- Node-RED: Automation
## Networks
Create these networks before deploying stacks:
```bash
docker network create traefik-network
docker network create homelab-network
```
## Environment Variables
Each stack needs a `.env` file. Use `/home/runner/work/AI-Homelab/AI-Homelab/.env.example` as a template.
**Required variables**:
- `DOMAIN`: Your DuckDNS domain (e.g., `yourdomain.duckdns.org`)
- `DUCKDNS_TOKEN`: Your DuckDNS token
- `ACME_EMAIL`: Email for Let's Encrypt
- `AUTHELIA_JWT_SECRET`: Generate with `openssl rand -hex 64`
- `AUTHELIA_SESSION_SECRET`: Generate with `openssl rand -hex 64`
- `AUTHELIA_STORAGE_ENCRYPTION_KEY`: Generate with `openssl rand -hex 64`
- `SURFSHARK_PRIVATE_KEY`: From Surfshark WireGuard config
- `SURFSHARK_ADDRESSES`: From Surfshark WireGuard config
## Deployment Order
1. **Create networks**:
```bash
docker network create traefik-network
docker network create homelab-network
```
2. **Deploy Traefik** (reverse proxy):
```bash
cd /opt/stacks/traefik
docker compose up -d
```
3. **Deploy Authelia** (SSO):
```bash
cd /opt/stacks/authelia
docker compose up -d
```
4. **Deploy DuckDNS** (optional but recommended):
```bash
cd /opt/stacks/duckdns
docker compose up -d
```
5. **Deploy Gluetun** (VPN for downloads):
```bash
cd /opt/stacks/gluetun
docker compose up -d
```
6. **Deploy other stacks** as needed:
```bash
cd /opt/stacks/infrastructure
docker compose up -d
cd /opt/stacks/media
docker compose up -d
```
## Accessing Services
All services are accessible via your domain:
- **With Authelia (SSO required)**:
- `https://traefik.yourdomain.duckdns.org` - Traefik dashboard
- `https://portainer.yourdomain.duckdns.org` - Portainer
- `https://sonarr.yourdomain.duckdns.org` - Sonarr
- `https://radarr.yourdomain.duckdns.org` - Radarr
- `https://prowlarr.yourdomain.duckdns.org` - Prowlarr
- `https://qbit.yourdomain.duckdns.org` - qBittorrent
- `https://grafana.yourdomain.duckdns.org` - Grafana
- And more...
- **Without Authelia (direct app access)**:
- `https://plex.yourdomain.duckdns.org` - Plex
- `https://jellyfin.yourdomain.duckdns.org` - Jellyfin
- **Authentication page**:
- `https://auth.yourdomain.duckdns.org` - Authelia login
## AI Management
The AI assistant (GitHub Copilot) can:
1. **Add new services**: Creates compose files with proper Traefik labels and Authelia middleware
2. **Modify routes**: Updates Docker labels to change proxy routing
3. **Manage SSO**: Adds or removes Authelia middleware as needed
4. **Configure VPN**: Sets up services to route through Gluetun
5. **Update configurations**: Modifies config files in `/opt/stacks/*/config/`
All configuration is file-based, allowing the AI to manage everything without web UI dependencies.
## Storage Strategy
- **Config files**: `/opt/stacks/stack-name/config/` (on system drive)
- **Small data**: Docker named volumes
- **Large data**:
- Media: `/mnt/media` (separate drive)
- Downloads: `/mnt/downloads` (separate drive)
- Backups: `/mnt/backups` (separate drive)
## Troubleshooting
### Service won't start
```bash
cd /opt/stacks/stack-name
docker compose logs -f
```
### Check Traefik routing
```bash
docker logs traefik
# Or visit: https://traefik.yourdomain.duckdns.org
```
### Test VPN connection
```bash
docker exec gluetun sh -c "curl ifconfig.me"
# Should show VPN IP, not your home IP
```
### Authelia issues
```bash
cd /opt/stacks/authelia
docker compose logs -f authelia
# Check configuration.yml for syntax errors
```
## Backup Important Files
Regular backups of:
- `/opt/stacks/` (all compose files and configs)
- `/opt/stacks/traefik/acme.json` (SSL certificates)
- `/opt/stacks/authelia/users_database.yml` (user accounts)
- Environment files (`.env` - store securely, not in git!)
## Security Notes
1. **Secrets**: Never commit `.env` files or `acme.json` to git
2. **Authelia**: Use strong passwords, hash them properly
3. **VPN**: Always route download clients through Gluetun
4. **Updates**: Watchtower keeps containers updated automatically
5. **Firewall**: Only expose ports 80 and 443 to the internet
## Getting Help
- Check the main [README.md](../README.md)
- Review [Docker Guidelines](../docs/docker-guidelines.md)
- Use GitHub Copilot in VS Code for AI assistance
- Check service-specific logs

228
docker-compose/README.md Normal file
View File

@@ -0,0 +1,228 @@
# Docker Compose Stacks
This directory contains Docker Compose files for managing your homelab services. Each file is organized by functional area to maintain clarity and organization.
## Structure
```
docker-compose/
├── infrastructure.yml # Core services (reverse proxy, DNS, etc.)
├── media.yml # Media server services (Plex, Jellyfin, etc.)
├── monitoring.yml # Observability stack (Prometheus, Grafana, etc.)
├── development.yml # Development tools and services
└── README.md # This file
```
## Usage
### Starting Services
Start all services in a compose file:
```bash
docker compose -f docker-compose/infrastructure.yml up -d
```
Start a specific service:
```bash
docker compose -f docker-compose/media.yml up -d plex
```
Start multiple compose files together:
```bash
docker compose -f docker-compose/infrastructure.yml -f docker-compose/media.yml up -d
```
### Stopping Services
Stop all services in a compose file:
```bash
docker compose -f docker-compose/infrastructure.yml down
```
Stop a specific service:
```bash
docker compose -f docker-compose/media.yml stop plex
```
### Viewing Status
Check running services:
```bash
docker compose -f docker-compose/media.yml ps
```
View logs:
```bash
docker compose -f docker-compose/media.yml logs -f plex
```
### Updating Services
Pull latest images:
```bash
docker compose -f docker-compose/media.yml pull
```
Update a specific service:
```bash
docker compose -f docker-compose/media.yml pull plex
docker compose -f docker-compose/media.yml up -d plex
```
## Networks
All services connect to a shared bridge network called `homelab-network`. Create it once:
```bash
docker network create homelab-network
```
Some services may use additional networks for security isolation:
- `monitoring-network` - For monitoring stack
- `database-network` - For database isolation
- `media-network` - For media services
Create them as needed:
```bash
docker network create monitoring-network
docker network create database-network
docker network create media-network
```
## Environment Variables
Create a `.env` file in the root of your homelab directory with common variables:
```bash
# .env
PUID=1000
PGID=1000
TZ=America/New_York
USERDIR=/home/username/homelab
DATADIR=/mnt/data
```
Never commit `.env` files to git! Use `.env.example` as a template instead.
## Best Practices
1. **Pin Versions**: Always specify image versions (e.g., `nginx:1.25.3` not `nginx:latest`)
2. **Use Labels**: Add labels for organization and documentation
3. **Health Checks**: Define health checks for critical services
4. **Resource Limits**: Set memory and CPU limits for resource-intensive services
5. **Logging**: Configure log rotation to prevent disk space issues
6. **Restart Policies**: Use `unless-stopped` for most services
7. **Comments**: Document non-obvious configurations
## Template
When creating a new service, use this template:
```yaml
services:
service-name:
image: vendor/image:version
container_name: service-name
restart: unless-stopped
networks:
- homelab-network
ports:
- "host_port:container_port"
volumes:
- ./config/service-name:/config
- service-data:/data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:port/health"]
interval: 30s
timeout: 10s
retries: 3
labels:
- "homelab.category=category"
- "homelab.description=Service description"
volumes:
service-data:
driver: local
networks:
homelab-network:
external: true
```
## Troubleshooting
### Service won't start
1. Check logs: `docker compose -f file.yml logs service-name`
2. Validate config: `docker compose -f file.yml config`
3. Check for port conflicts: `sudo netstat -tlnp | grep PORT`
4. Verify volumes exist and have correct permissions
### Permission errors
1. Ensure PUID and PGID match your user: `id -u` and `id -g`
2. Fix directory ownership: `sudo chown -R 1000:1000 ./config/service-name`
### Network issues
1. Verify network exists: `docker network ls`
2. Check service is connected: `docker network inspect homelab-network`
3. Test connectivity: `docker compose exec service1 ping service2`
## Migration from Docker Run
If you have services running via `docker run`, migrate them to compose:
1. Get current configuration:
```bash
docker inspect container-name > container-config.json
```
2. Convert to compose format (extract image, ports, volumes, environment)
3. Test the compose configuration
4. Stop old container:
```bash
docker stop container-name
docker rm container-name
```
5. Start with compose:
```bash
docker compose -f file.yml up -d
```
## Backup Strategy
Regular backups are essential:
```bash
# Backup compose files (already in git)
git add docker-compose/*.yml
git commit -m "Update compose configurations"
# Backup volumes
docker run --rm \
-v volume-name:/data \
-v $(pwd)/backups:/backup \
busybox tar czf /backup/volume-name-$(date +%Y%m%d).tar.gz /data
# Backup config directories
tar czf backups/config-$(date +%Y%m%d).tar.gz config/
```
## Getting Help
- Check the [Docker Guidelines](../docs/docker-guidelines.md) for detailed documentation
- Review the [GitHub Copilot Instructions](../.github/copilot-instructions.md) for AI assistance
- Consult service-specific documentation in `config/service-name/README.md`
## Examples
See the example compose files in this directory:
- `infrastructure.yml` - Essential services like reverse proxy
- `media.yml` - Media server stack
- `monitoring.yml` - Observability and monitoring
- `development.yml` - Development environments and tools

137
docker-compose/core.yml Normal file
View File

@@ -0,0 +1,137 @@
# Core Infrastructure Stack
# Essential services required for the homelab to function
# Deploy this stack FIRST before any other services
# Place in /opt/stacks/core/docker-compose.yml
services:
# DuckDNS - Dynamic DNS updater
# Updates your public IP automatically for Let's Encrypt SSL
duckdns:
image: lscr.io/linuxserver/duckdns:latest
container_name: duckdns
restart: unless-stopped
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS} # Your subdomain(s), comma separated
- TOKEN=${DUCKDNS_TOKEN} # Your DuckDNS token
- UPDATE_IP=ipv4 # or ipv6, or both
volumes:
- /opt/stacks/core/duckdns:/config
labels:
- "homelab.category=infrastructure"
- "homelab.description=Dynamic DNS updater"
# Traefik - Reverse proxy with automatic SSL
# Routes all traffic and manages Let's Encrypt certificates
traefik:
image: traefik:v2.11
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-network
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Dashboard (protected with Authelia)
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- /opt/stacks/core/traefik/traefik.yml:/traefik.yml:ro
- /opt/stacks/core/traefik/dynamic:/dynamic:ro
- /opt/stacks/core/traefik/acme.json:/acme.json
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN} # If using Cloudflare DNS challenge
- DUCKDNS_TOKEN=${DUCKDNS_TOKEN} # If using DuckDNS
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.middlewares=authelia@docker"
- "traefik.http.routers.traefik.service=api@internal"
# Global HTTP to HTTPS redirect
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
depends_on:
- duckdns
# Authelia - SSO authentication
# Protects all admin services with single sign-on
authelia:
image: authelia/authelia:4.37
container_name: authelia
restart: unless-stopped
networks:
- traefik-network
volumes:
- /opt/stacks/core/authelia/configuration.yml:/config/configuration.yml:ro
- /opt/stacks/core/authelia/users_database.yml:/config/users_database.yml
- authelia-data:/config
environment:
- TZ=${TZ}
- AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
- AUTHELIA_NOTIFIER_SMTP_PASSWORD=${SMTP_PASSWORD} # If using email notifications
labels:
- "traefik.enable=true"
- "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)"
- "traefik.http.routers.authelia.entrypoints=websecure"
- "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
# Authelia middleware for other services
- "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}"
- "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
depends_on:
- traefik
# Gluetun - VPN client (Surfshark WireGuard)
# Routes download clients through VPN for security
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
- "8080:8080" # qBittorrent web UI
- "6881:6881" # qBittorrent
- "6881:6881/udp" # qBittorrent
volumes:
- /opt/stacks/core/gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=surfshark
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${SURFSHARK_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${SURFSHARK_ADDRESSES}
- SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES:-Netherlands}
- TZ=${TZ}
labels:
- "homelab.category=infrastructure"
- "homelab.description=VPN client for secure downloads"
volumes:
authelia-data:
driver: local
networks:
traefik-network:
external: true
homelab-network:
external: true

View File

@@ -0,0 +1,66 @@
# Dashboard Services
# Homepage and Homarr for homelab dashboards
# Place in /opt/stacks/dashboards/docker-compose.yml
services:
# Homepage - Application dashboard (AI-configurable via YAML)
# Access at: https://home.${DOMAIN}
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- dockerproxy-network
volumes:
- /opt/stacks/homepage/config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro # For Docker integration
- /opt/stacks:/opt/stacks:ro # To discover other stacks
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=dashboard"
- "homelab.description=Application dashboard (AI-configurable)"
- "traefik.enable=true"
- "traefik.http.routers.homepage.rule=Host(`home.${DOMAIN}`)"
- "traefik.http.routers.homepage.entrypoints=websecure"
- "traefik.http.routers.homepage.tls.certresolver=letsencrypt"
- "traefik.http.routers.homepage.middlewares=authelia@docker"
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
# Homarr - Modern dashboard
# Access at: https://homarr.${DOMAIN}
homarr:
image: ghcr.io/ajnart/homarr:latest
container_name: homarr
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/homarr/configs:/app/data/configs
- /opt/stacks/homarr/data:/data
- /opt/stacks/homarr/icons:/app/public/icons
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=${TZ}
labels:
- "homelab.category=dashboard"
- "homelab.description=Modern homelab dashboard"
- "traefik.enable=true"
- "traefik.http.routers.homarr.rule=Host(`homarr.${DOMAIN}`)"
- "traefik.http.routers.homarr.entrypoints=websecure"
- "traefik.http.routers.homarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.homarr.middlewares=authelia@docker"
- "traefik.http.services.homarr.loadbalancer.server.port=7575"
networks:
homelab-network:
external: true
traefik-network:
external: true
dockerproxy-network:
external: true

View File

@@ -0,0 +1,191 @@
# Development Services
# Tools and services for development work
services:
# Code Server - VS Code in the browser
# Access at: http://server-ip:8443
code-server:
image: lscr.io/linuxserver/code-server:4.20.0
container_name: code-server
restart: unless-stopped
networks:
- homelab-network
ports:
- "8443:8443"
volumes:
- ./config/code-server:/config
- ${PROJECTDIR:-/home/user/projects}:/projects
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
- PASSWORD=${CODE_SERVER_PASSWORD:-changeme}
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD:-changeme}
labels:
- "homelab.category=development"
- "homelab.description=VS Code in browser for remote development"
# GitLab CE - Self-hosted Git repository manager
# Access at: http://server-ip:8929
# Note: Requires significant resources (4GB+ RAM recommended)
gitlab:
image: gitlab/gitlab-ce:16.7.0-ce.0
container_name: gitlab
restart: unless-stopped
networks:
- homelab-network
ports:
- "8929:80" # Web UI
- "2222:22" # SSH
volumes:
- ./config/gitlab/config:/etc/gitlab
- gitlab-logs:/var/log/gitlab
- gitlab-data:/var/opt/gitlab
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://${SERVER_IP}:8929'
gitlab_rails['gitlab_shell_ssh_port'] = 2222
gitlab_rails['time_zone'] = '${TZ:-America/New_York}'
shm_size: '256m'
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
labels:
- "homelab.category=development"
- "homelab.description=Self-hosted Git repository manager"
# PostgreSQL - Database for development
# Access at: localhost:5432 from other containers
postgres:
image: postgres:16.1-alpine
container_name: postgres-dev
restart: unless-stopped
networks:
- database-network
- homelab-network
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./config/postgres/init:/docker-entrypoint-initdb.d
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-changeme}
- POSTGRES_DB=${POSTGRES_DB:-homelab}
- PGDATA=/var/lib/postgresql/data/pgdata
labels:
- "homelab.category=development"
- "homelab.description=PostgreSQL database for development"
# Redis - In-memory data store
# Access at: localhost:6379 from other containers
redis:
image: redis:7.2.3-alpine
container_name: redis-dev
restart: unless-stopped
networks:
- database-network
- homelab-network
ports:
- "6379:6379"
volumes:
- redis-data:/data
- ./config/redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf --appendonly yes
labels:
- "homelab.category=development"
- "homelab.description=Redis in-memory data store"
# pgAdmin - PostgreSQL management UI
# Access at: http://server-ip:5050
pgadmin:
image: dpage/pgadmin4:8.2
container_name: pgadmin
restart: unless-stopped
networks:
- database-network
- homelab-network
ports:
- "5050:80"
volumes:
- pgadmin-data:/var/lib/pgadmin
environment:
- PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL:-admin@example.com}
- PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD:-changeme}
- PGADMIN_CONFIG_SERVER_MODE=False
depends_on:
- postgres
labels:
- "homelab.category=development"
- "homelab.description=PostgreSQL administration UI"
# Jupyter Lab - Interactive computing notebooks
# Access at: http://server-ip:8888
# Token displayed in logs on first start
jupyter:
image: jupyter/scipy-notebook:2023-12-25
container_name: jupyter
restart: unless-stopped
networks:
- homelab-network
ports:
- "8888: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:-changeme}'
# 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:
- "homelab.category=development"
- "homelab.description=Jupyter Lab for data science and ML"
# Node-RED - Visual programming for automation
# Access at: http://server-ip:1880
nodered:
image: nodered/node-red:3.1.3
container_name: nodered
restart: unless-stopped
networks:
- homelab-network
ports:
- "1880:1880"
volumes:
- nodered-data:/data
environment:
- TZ=${TZ:-America/New_York}
labels:
- "homelab.category=development"
- "homelab.description=Visual automation and workflow tool"
volumes:
gitlab-logs:
driver: local
gitlab-data:
driver: local
postgres-data:
driver: local
redis-data:
driver: local
pgadmin-data:
driver: local
nodered-data:
driver: local
networks:
database-network:
driver: bridge
homelab-network:
external: true

View File

@@ -0,0 +1,173 @@
# Home Assistant and IoT Services
# Home automation platform and related tools
# Place in /opt/stacks/homeassistant/docker-compose.yml
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
container_name: homeassistant
restart: unless-stopped
network_mode: host # Required for device discovery
volumes:
- /opt/stacks/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
container_name: esphome
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/esphome/config:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=${TZ}
- ESPHOME_DASHBOARD_USE_PING=true
privileged: true # For USB device access
labels:
- "homelab.category=iot"
- "homelab.description=ESP8266/ESP32 firmware manager"
- "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
volumes:
- /opt/stacks/tasmoadmin/data:/data
environment:
- TZ=${TZ}
labels:
- "homelab.category=iot"
- "homelab.description=Tasmota device management"
- "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:
- /opt/stacks/motioneye/config:/etc/motioneye
- /mnt/surveillance:/var/lib/motioneye # Large video files on separate drive
environment:
- TZ=${TZ}
labels:
- "homelab.category=iot"
- "homelab.description=Video surveillance system"
- "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
container_name: nodered
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/nodered/data:/data
environment:
- TZ=${TZ}
labels:
- "homelab.category=iot"
- "homelab.description=Flow-based automation programming"
- "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:
- /opt/stacks/mosquitto/config:/mosquitto/config
- /opt/stacks/mosquitto/data:/mosquitto/data
- /opt/stacks/mosquitto/log:/mosquitto/log
labels:
- "homelab.category=iot"
- "homelab.description=MQTT message broker"
# Zigbee2MQTT - Zigbee to MQTT bridge (Home Assistant addon alternative)
# Access at: https://zigbee2mqtt.${DOMAIN}
zigbee2mqtt:
image: koenkk/zigbee2mqtt:latest
container_name: zigbee2mqtt
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/zigbee2mqtt/data:/app/data
- /run/udev:/run/udev:ro
devices:
- /dev/ttyACM0:/dev/ttyACM0 # Zigbee adapter - adjust as needed
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

View File

@@ -0,0 +1,302 @@
# Infrastructure Services
# Core services that other services depend on
# Place in /opt/stacks/infrastructure/docker-compose.yml
# NOTE: Traefik, Authelia, DuckDNS, and Gluetun have their own separate stacks
# See /opt/stacks/traefik/, /opt/stacks/authelia/, etc.
services:
# Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer)
# Access at: https://dockge.${DOMAIN}
dockge:
image: louislam/dockge:1
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
- /opt/dockge/data:/app/data
environment:
- DOCKGE_STACKS_DIR=/opt/stacks
labels:
- "homelab.category=infrastructure"
- "homelab.description=Docker Compose stack manager (PRIMARY)"
- "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"
# Portainer - Docker management UI (SECONDARY - use Dockge instead)
# Access at: https://portainer.${DOMAIN}
portainer:
image: portainer/portainer-ce:2.19.4
container_name: portainer
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer-data:/data
security_opt:
- no-new-privileges:true
labels:
- "homelab.category=infrastructure"
- "homelab.description=Docker container management UI (SECONDARY)"
- "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"
# Pi-hole - Network-wide ad blocker and DNS server
# Access at: https://pihole.${DOMAIN}
pihole:
image: pihole/pihole:2024.01.0
container_name: pihole
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "53:53/tcp" # DNS TCP
- "53:53/udp" # DNS UDP
volumes:
- /opt/stacks/pihole/etc-pihole:/etc/pihole
- /opt/stacks/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
environment:
- TZ=${TZ:-America/New_York}
- WEBPASSWORD=${PIHOLE_PASSWORD:-changeme}
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
dns:
- 127.0.0.1
- 1.1.1.1
cap_add:
- NET_ADMIN
labels:
- "homelab.category=infrastructure"
- "homelab.description=Network-wide ad blocking and DNS"
- "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
# Runs silently in background, no UI
watchtower:
image: containrrr/watchtower:1.7.1
container_name: watchtower
restart: unless-stopped
networks:
- homelab-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- 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}
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- DOZZLE_LEVEL=info
- DOZZLE_TAILSIZE=300
- DOZZLE_FILTER=status=running
labels:
- "homelab.category=infrastructure"
- "homelab.description=Real-time Docker log viewer"
- "traefik.enable=true"
- "traefik.http.routers.dozzle.rule=Host(`dozzle.${DOMAIN}`)"
- "traefik.http.routers.dozzle.entrypoints=websecure"
- "traefik.http.routers.dozzle.tls.certresolver=letsencrypt"
- "traefik.http.routers.dozzle.middlewares=authelia@docker"
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
# Docker Proxy - Socket proxy for security
# Used by services that need Docker socket access
dockerproxy:
image: tecnativa/docker-socket-proxy:latest
container_name: dockerproxy
restart: unless-stopped
networks:
- dockerproxy-network
ports:
- "127.0.0.1:2375:2375"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CONTAINERS=1
- SERVICES=1
- TASKS=1
- NETWORKS=1
- NODES=1
labels:
- "homelab.category=infrastructure"
- "homelab.description=Docker socket proxy for security"
# Glances - System monitoring
# Access at: https://glances.${DOMAIN}
glances:
image: nicolargo/glances:latest-full
container_name: glances
restart: unless-stopped
networks:
- homelab-network
- traefik-network
pid: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /opt/stacks/glances/config:/glances/conf
environment:
- GLANCES_OPT=-w
labels:
- "homelab.category=infrastructure"
- "homelab.description=System and Docker monitoring"
- "traefik.enable=true"
- "traefik.http.routers.glances.rule=Host(`glances.${DOMAIN}`)"
- "traefik.http.routers.glances.entrypoints=websecure"
- "traefik.http.routers.glances.tls.certresolver=letsencrypt"
- "traefik.http.routers.glances.middlewares=authelia@docker"
- "traefik.http.services.glances.loadbalancer.server.port=61208"
# 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
authentik-server:
image: ghcr.io/goauthentik/server:2024.2.0
container_name: authentik-server
restart: unless-stopped
command: server
networks:
- homelab-network
- traefik-network
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}
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME:-authentik}
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
labels:
- "homelab.category=infrastructure"
- "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
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}
- AUTHENTIK_POSTGRESQL__NAME=${AUTHENTIK_DB_NAME:-authentik}
- AUTHENTIK_POSTGRESQL__PASSWORD=${AUTHENTIK_DB_PASSWORD}
- AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY}
- AUTHENTIK_ERROR_REPORTING__ENABLED=false
labels:
- "homelab.category=infrastructure"
- "homelab.description=Authentik background worker"
depends_on:
- authentik-db
- authentik-redis
# Authentik Database - PostgreSQL
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:-authentik}
- POSTGRES_PASSWORD=${AUTHENTIK_DB_PASSWORD}
- POSTGRES_DB=${AUTHENTIK_DB_NAME:-authentik}
labels:
- "homelab.category=infrastructure"
- "homelab.description=Authentik database"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_DB_USER:-authentik}"]
interval: 10s
timeout: 5s
retries: 5
# Authentik Redis - Cache and message queue
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:
- "homelab.category=infrastructure"
- "homelab.description=Authentik cache and messaging"
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 10s
timeout: 3s
retries: 5
volumes:
portainer-data:
driver: local
authentik-db-data:
driver: local
authentik-redis-data:
driver: local
networks:
homelab-network:
external: true
traefik-network:
external: true
dockerproxy-network:
driver: bridge

View File

@@ -0,0 +1,282 @@
# Extended Media Services
# Additional media management tools
# Place in /opt/stacks/media-extended/docker-compose.yml
services:
# Readarr - Ebook and audiobook management
# Access at: https://readarr.${DOMAIN}
readarr:
image: lscr.io/linuxserver/readarr:develop
container_name: readarr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/readarr/config:/config
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Ebook and audiobook management"
- "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"
# Lidarr - Music collection manager
# Access at: https://lidarr.${DOMAIN}
lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/lidarr/config:/config
- /mnt/media/music:/music
- /mnt/downloads:/downloads
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Music collection manager"
- "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"
# Lazy Librarian - Book manager
# Access at: https://lazylibrarian.${DOMAIN}
lazylibrarian:
image: lscr.io/linuxserver/lazylibrarian:latest
container_name: lazylibrarian
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/lazylibrarian/config:/config
- /mnt/media/books:/books
- /mnt/downloads:/downloads
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg
labels:
- "homelab.category=media"
- "homelab.description=Book download automation"
- "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"
# Mylar3 - Comic book manager
# Access at: https://mylar.${DOMAIN}
mylar3:
image: lscr.io/linuxserver/mylar3:latest
container_name: mylar3
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/mylar3/config:/config
- /mnt/media/comics:/comics
- /mnt/downloads:/downloads
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Comic book collection manager"
- "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"
# Calibre-Web - Ebook reader and server
# Access at: https://calibre.${DOMAIN}
calibre-web:
image: lscr.io/linuxserver/calibre-web:latest
container_name: calibre-web
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/calibre-web/config:/config
- /mnt/media/books:/books
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- DOCKER_MODS=linuxserver/mods:universal-calibre
labels:
- "homelab.category=media"
- "homelab.description=Ebook reader and library management"
- "traefik.enable=true"
- "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"
- "traefik.http.services.calibre.loadbalancer.server.port=8083"
# Jellyseerr - Request management for Jellyfin/Plex
# Access at: https://jellyseerr.${DOMAIN}
jellyseerr:
image: fallenbagel/jellyseerr:latest
container_name: jellyseerr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/jellyseerr/config:/app/config
environment:
- LOG_LEVEL=info
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Media request management"
- "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"
# FlareSolverr - Cloudflare bypass for Prowlarr
# No web UI - used by Prowlarr
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
networks:
- media-network
environment:
- LOG_LEVEL=info
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Cloudflare bypass for indexers"
# Tdarr Server - Distributed transcoding server
# Access at: https://tdarr.${DOMAIN}
tdarr-server:
image: ghcr.io/haveagitgat/tdarr:latest
container_name: tdarr-server
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
ports:
- "8266:8266" # Server port
volumes:
- /opt/stacks/tdarr/server:/app/server
- /opt/stacks/tdarr/configs:/app/configs
- /opt/stacks/tdarr/logs:/app/logs
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp # Transcode cache on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- serverIP=0.0.0.0
- serverPort=8266
- webUIPort=8265
labels:
- "homelab.category=media"
- "homelab.description=Distributed transcoding server"
- "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"
# 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:
- media-network
volumes:
- /opt/stacks/tdarr/configs:/app/configs
- /opt/stacks/tdarr/logs:/app/logs
- /mnt/media:/media
- /mnt/tdarr-transcode:/temp
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- 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"
# Unmanic - Another transcoding option
# Access at: https://unmanic.${DOMAIN}
unmanic:
image: josh5/unmanic:latest
container_name: unmanic
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/unmanic/config:/config
- /mnt/media:/library
- /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=media"
- "homelab.description=Library optimization and transcoding"
- "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=8888"
networks:
media-network:
external: true
homelab-network:
external: true
traefik-network:
external: true

188
docker-compose/media.yml Normal file
View File

@@ -0,0 +1,188 @@
# Media Services
# Services for media management and streaming
# Place in /opt/stacks/media/docker-compose.yml
# NOTE: qBittorrent is configured to use Gluetun VPN (see gluetun.yml)
services:
# Plex Media Server - Media streaming platform
# Access at: https://plex.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
plex:
image: plexinc/pms-docker:1.40.0.7998-f68041501
container_name: plex
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/plex/config:/config
- /mnt/media:/media:ro # Large media files on separate drive
- plex-transcode:/transcode
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
- 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:
- "homelab.category=media"
- "homelab.description=Plex media streaming server"
# 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"
# Jellyfin - Free alternative to Plex
# Access at: https://jellyfin.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
jellyfin:
image: jellyfin/jellyfin:10.8.13
container_name: jellyfin
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/jellyfin/config:/config
- /opt/stacks/jellyfin/cache:/cache
- /mnt/media:/media:ro # Large media files on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
# Uncomment for hardware transcoding
# devices:
# - /dev/dri:/dev/dri
labels:
- "homelab.category=media"
- "homelab.description=Open-source media streaming server"
# Traefik labels - NO Authelia for app access
- "traefik.enable=true"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
# Sonarr - TV show automation
# Access at: https://sonarr.yourdomain.duckdns.org
sonarr:
image: lscr.io/linuxserver/sonarr:4.0.0
container_name: sonarr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/sonarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
labels:
- "homelab.category=media"
- "homelab.description=TV show management and automation"
# Traefik labels with Authelia
- "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"
# Radarr - Movie automation
# Access at: https://radarr.yourdomain.duckdns.org
radarr:
image: lscr.io/linuxserver/radarr:5.2.6
container_name: radarr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/radarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
labels:
- "homelab.category=media"
- "homelab.description=Movie management and automation"
# Traefik labels with Authelia
- "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"
# Prowlarr - Indexer manager
# Access at: https://prowlarr.yourdomain.duckdns.org
prowlarr:
image: lscr.io/linuxserver/prowlarr:1.11.4
container_name: prowlarr
restart: unless-stopped
networks:
- media-network
- homelab-network
- traefik-network
volumes:
- /opt/stacks/prowlarr/config:/config
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
labels:
- "homelab.category=media"
- "homelab.description=Indexer manager for Sonarr/Radarr"
# Traefik labels with Authelia
- "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"
# qBittorrent - Torrent client
# Access at: https://qbit.yourdomain.duckdns.org
# Routes through Gluetun VPN - configure in gluetun.yml
# NOTE: This is a placeholder. Configure qBittorrent in gluetun.yml with network_mode: "service:gluetun"
# See gluetun.yml for the actual qBittorrent configuration
volumes:
plex-transcode:
driver: local
networks:
media-network:
driver: bridge
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -0,0 +1,181 @@
# Monitoring and Observability Services
# Services for monitoring your homelab infrastructure
services:
# Prometheus - Metrics collection and storage
# Access at: http://server-ip:9090
prometheus:
image: prom/prometheus:v2.48.1
container_name: prometheus
restart: unless-stopped
networks:
- monitoring-network
- homelab-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'
user: "${PUID:-1000}:${PGID:-1000}"
labels:
- "homelab.category=monitoring"
- "homelab.description=Metrics collection and time-series database"
# Grafana - Metrics visualization
# Access at: http://server-ip:3000
# Default credentials: admin / admin (change on first login)
grafana:
image: grafana/grafana:10.2.3
container_name: grafana
restart: unless-stopped
networks:
- monitoring-network
- homelab-network
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
- ./config/grafana/provisioning:/etc/grafana/provisioning
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin}
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_ROOT_URL=http://${SERVER_IP}:3000
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel
user: "${PUID:-1000}:${PGID:-1000}"
depends_on:
- prometheus
labels:
- "homelab.category=monitoring"
- "homelab.description=Metrics visualization and dashboards"
# 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:
- monitoring-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:
- monitoring-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:
- "homelab.category=monitoring"
- "homelab.description=Container metrics and performance monitoring"
# Uptime Kuma - Uptime monitoring
# Access at: https://status.${DOMAIN}
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
networks:
- monitoring-network
- homelab-network
- traefik-network
volumes:
- uptime-kuma-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
labels:
- "homelab.category=monitoring"
- "homelab.description=Service uptime monitoring and alerts"
- "traefik.enable=true"
- "traefik.http.routers.uptime-kuma.rule=Host(`status.${DOMAIN}`)"
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
- "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
container_name: loki
restart: unless-stopped
networks:
- monitoring-network
ports:
- "3100:3100"
volumes:
- ./config/loki:/etc/loki
- loki-data:/loki
command: -config.file=/etc/loki/loki-config.yml
user: "${PUID:-1000}:${PGID:-1000}"
labels:
- "homelab.category=monitoring"
- "homelab.description=Log aggregation system"
# 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:
- monitoring-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:
monitoring-network:
driver: bridge
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -0,0 +1,324 @@
# Productivity and Content Management Services
# Place in /opt/stacks/productivity/docker-compose.yml
services:
# Nextcloud - File sync and collaboration
# Access at: https://nextcloud.${DOMAIN}
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- nextcloud-network
volumes:
- /opt/stacks/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:-admin}
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=${DOMAIN}
- TRUSTED_PROXIES=172.18.0.0/16
- OVERWRITEPROTOCOL=https
depends_on:
- nextcloud-db
labels:
- "homelab.category=productivity"
- "homelab.description=File sync and collaboration"
- "traefik.enable=true"
- "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"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
nextcloud-db:
image: mariadb:10.11
container_name: nextcloud-db
restart: unless-stopped
networks:
- nextcloud-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: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/mealie/data:/app/data
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- BASE_URL=https://mealie.${DOMAIN}
- DB_ENGINE=sqlite
labels:
- "homelab.category=productivity"
- "homelab.description=Recipe manager and meal planner"
- "traefik.enable=true"
- "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)"
- "traefik.http.routers.mealie.entrypoints=websecure"
- "traefik.http.routers.mealie.tls.certresolver=letsencrypt"
- "traefik.http.services.mealie.loadbalancer.server.port=9000"
# No Authelia - family members should access easily
# WordPress - Blog/website platform
# Access at: https://blog.${DOMAIN}
wordpress:
image: wordpress:latest
container_name: wordpress
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- wordpress-network
volumes:
- /opt/stacks/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
depends_on:
- wordpress-db
labels:
- "homelab.category=productivity"
- "homelab.description=Blog and website platform"
- "traefik.enable=true"
- "traefik.http.routers.wordpress.rule=Host(`blog.${DOMAIN}`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
# No Authelia - public blog
wordpress-db:
image: mariadb:10.11
container_name: wordpress-db
restart: unless-stopped
networks:
- wordpress-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
container_name: gitea
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- gitea-network
volumes:
- /opt/stacks/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
- USER_UID=${PUID:-1000}
- USER_GID=${PGID:-1000}
- 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}
depends_on:
- gitea-db
labels:
- "homelab.category=productivity"
- "homelab.description=Self-hosted Git service"
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`git.${DOMAIN}`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.routers.gitea.middlewares=authelia@docker"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
gitea-db:
image: postgres:14-alpine
container_name: gitea-db
restart: unless-stopped
networks:
- gitea-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"
# DokuWiki - Wiki without database
# Access at: https://wiki.${DOMAIN}
dokuwiki:
image: lscr.io/linuxserver/dokuwiki:latest
container_name: dokuwiki
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/dokuwiki/config:/config
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=productivity"
- "homelab.description=File-based wiki"
- "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"
# BookStack - Documentation platform
# Access at: https://docs.${DOMAIN}
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- bookstack-network
volumes:
- /opt/stacks/bookstack/config:/config
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- APP_URL=https://docs.${DOMAIN}
- DB_HOST=bookstack-db
- DB_PORT=3306
- DB_DATABASE=bookstack
- DB_USERNAME=bookstack
- DB_PASSWORD=${BOOKSTACK_DB_PASSWORD}
depends_on:
- bookstack-db
labels:
- "homelab.category=productivity"
- "homelab.description=Documentation and wiki platform"
- "traefik.enable=true"
- "traefik.http.routers.bookstack.rule=Host(`docs.${DOMAIN}`)"
- "traefik.http.routers.bookstack.entrypoints=websecure"
- "traefik.http.routers.bookstack.tls.certresolver=letsencrypt"
- "traefik.http.routers.bookstack.middlewares=authelia@docker"
- "traefik.http.services.bookstack.loadbalancer.server.port=80"
bookstack-db:
image: mariadb:10.11
container_name: bookstack-db
restart: unless-stopped
networks:
- bookstack-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: unless-stopped
networks:
- homelab-network
- traefik-network
- mediawiki-network
volumes:
- /opt/stacks/mediawiki/images:/var/www/html/images
- /opt/stacks/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}
depends_on:
- mediawiki-db
labels:
- "homelab.category=productivity"
- "homelab.description=MediaWiki platform"
- "traefik.enable=true"
- "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"
- "traefik.http.services.mediawiki.loadbalancer.server.port=80"
mediawiki-db:
image: mariadb:10.11
container_name: mediawiki-db
restart: unless-stopped
networks:
- mediawiki-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:
nextcloud-db-data:
wordpress-db-data:
gitea-db-data:
bookstack-db-data:
mediawiki-db-data:
networks:
homelab-network:
external: true
traefik-network:
external: true
nextcloud-network:
driver: bridge
wordpress-network:
driver: bridge
gitea-network:
driver: bridge
bookstack-network:
driver: bridge
mediawiki-network:
driver: bridge

View File

@@ -0,0 +1,189 @@
# Backup and Utility Services
# Place in /opt/stacks/utilities/docker-compose.yml
services:
# Backrest - Backup solution for restic
# Access at: https://backrest.${DOMAIN}
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/backrest/data:/data
- /opt/stacks/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}
labels:
- "homelab.category=utilities"
- "homelab.description=Backup management with restic"
- "traefik.enable=true"
- "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"
- "traefik.http.services.backrest.loadbalancer.server.port=9898"
# Duplicati - Backup solution
# Access at: https://duplicati.${DOMAIN}
duplicati:
image: lscr.io/linuxserver/duplicati:latest
container_name: duplicati
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/duplicati/config:/config
- /opt/stacks:/source/stacks:ro
- /mnt:/source/mnt:ro
- /mnt/backups:/backups
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
labels:
- "homelab.category=utilities"
- "homelab.description=Backup software with encryption"
- "traefik.enable=true"
- "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"
- "traefik.http.services.duplicati.loadbalancer.server.port=8200"
# Code Server - VS Code in browser
# Access at: https://code.${DOMAIN}
code-server:
image: lscr.io/linuxserver/code-server:latest
container_name: code-server
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/code-server/config:/config
- /opt/stacks:/opt/stacks # Access to all stacks
- /mnt:/mnt:ro # Read-only access to data
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- PASSWORD=${CODE_SERVER_PASSWORD}
- SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD}
labels:
- "homelab.category=utilities"
- "homelab.description=VS Code in browser"
- "traefik.enable=true"
- "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"
- "traefik.http.services.code-server.loadbalancer.server.port=8443"
# Form.io - Form builder (if needed)
# Access at: https://forms.${DOMAIN}
formio:
image: formio/formio:latest
container_name: formio
restart: unless-stopped
networks:
- homelab-network
- traefik-network
- formio-network
environment:
- MONGO_URL=mongodb://formio-mongo:27017/formio
- JWT_SECRET=${FORMIO_JWT_SECRET}
- DB_SECRET=${FORMIO_DB_SECRET}
depends_on:
- formio-mongo
labels:
- "homelab.category=utilities"
- "homelab.description=Form builder platform"
- "traefik.enable=true"
- "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"
- "traefik.http.services.formio.loadbalancer.server.port=3000"
formio-mongo:
image: mongo:6
container_name: formio-mongo
restart: unless-stopped
networks:
- formio-network
volumes:
- formio-mongo-data:/data/db
labels:
- "homelab.category=utilities"
- "homelab.description=Form.io database"
# Bitwarden (Vaultwarden) - Password manager
# Access at: https://bitwarden.${DOMAIN}
# Note: SSO disabled for browser extension and mobile app compatibility
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- homelab-network
- traefik-network
volumes:
- /opt/stacks/vaultwarden/data:/data
environment:
- DOMAIN=https://bitwarden.${DOMAIN}
- SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED:-true}
- INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED:-true}
- ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN}
- SMTP_HOST=${SMTP_HOST}
- SMTP_FROM=${SMTP_FROM}
- SMTP_PORT=${SMTP_PORT:-587}
- SMTP_SECURITY=${SMTP_SECURITY:-starttls}
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
labels:
- "homelab.category=utilities"
- "homelab.description=Self-hosted password manager (Bitwarden)"
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`bitwarden.${DOMAIN}`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "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"
# Authelia Redis - Session storage for Authelia
# No web UI - backend service
authelia-redis:
image: redis: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:
formio-mongo-data:
authelia-redis-data:
networks:
homelab-network:
external: true
traefik-network:
external: true
formio-network:
driver: bridge

1002
docs/docker-guidelines.md Normal file

File diff suppressed because it is too large Load Diff

420
docs/getting-started.md Normal file
View File

@@ -0,0 +1,420 @@
# Getting Started Guide
This guide will walk you through setting up your AI-powered homelab with Dockge, Traefik, Authelia, and 40+ services from scratch.
## Prerequisites
Before you begin, ensure you have:
- [ ] A Linux server (Ubuntu 22.04+ recommended)
- [ ] Docker Engine 24.0+ installed
- [ ] Docker Compose V2 installed
- [ ] Git installed
- [ ] At least 8GB RAM (16GB+ recommended)
- [ ] Sufficient disk space: 120GB+ system drive (NVMe or SSD highly recommended), 2TB+ for media & additional disks for services like Nextcloud that require lots of space
- [ ] Static IP address for your server (or DHCP reservation)
- [ ] DuckDNS account (free) with a domain
- [ ] Surfshark VPN account (optional, for VPN features)
- [ ] VS Code with GitHub Copilot extension (for AI assistance)
## Step 1: Verify Docker Installation
```bash
# Check Docker version
docker --version
# Should show: Docker version 24.0.0 or higher
# Check Docker Compose version
docker compose version
# Should show: Docker Compose version v2.x.x
# Test Docker works
docker run --rm hello-world
# Should download and run successfully
```
## Step 2: Clone the Repository
```bash
# Navigate to your home directory
cd ~
# Clone the repository
# Note: Replace 'kelinfoxy' with your username if you forked this repository
git clone https://github.com/kelinfoxy/AI-Homelab.git
# Enter the directory
cd AI-Homelab
```
## Step 3: Sign Up for DuckDNS
1. Go to https://www.duckdns.org/
2. Sign in with your preferred method
3. Create a domain (e.g., `myhomelab`)
4. Copy your token - you'll need it for `.env`
5. Your domain will be: `myhomelab.duckdns.org`
## Step 4: Configure Environment Variables
```bash
# Copy the example environment file
cp .env.example .env
# Get your user and group IDs
id -u # This is your PUID
id -g # This is your PGID
# Edit the .env file
nano .env
```
**Critical values to update in `.env`:**
```bash
# Your user/group IDs
PUID=1000 # Replace with your user ID
PGID=1000 # Replace with your group ID
# Your timezone (find yours: timedatectl list-timezones)
TZ=America/New_York
# Your server's IP address
SERVER_IP=192.168.1.100 # Replace with your actual IP
# DuckDNS Configuration
DOMAIN=myhomelab.duckdns.org # Your DuckDNS domain
DUCKDNS_TOKEN=your-duckdns-token-here
DUCKDNS_SUBDOMAINS=myhomelab # Without .duckdns.org
# Let's Encrypt Email
ACME_EMAIL=your-email@example.com
# Authelia Secrets (generate with: openssl rand -hex 64)
AUTHELIA_JWT_SECRET=$(openssl rand -hex 64)
AUTHELIA_SESSION_SECRET=$(openssl rand -hex 64)
AUTHELIA_STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 64)
# Surfshark VPN (if using)
SURFSHARK_PRIVATE_KEY=your-wireguard-private-key
SURFSHARK_ADDRESSES=10.14.0.2/16
# Set secure passwords for all services
PIHOLE_PASSWORD=your-secure-password
GRAFANA_ADMIN_PASSWORD=your-secure-password
CODE_SERVER_PASSWORD=your-secure-password
# ... (see .env.example for complete list)
```
**Save and exit** (Ctrl+X, Y, Enter in nano)
## Step 5: Create Dockge Directory Structure
```bash
# Create main stacks directory
sudo mkdir -p /opt/stacks
sudo chown -R $USER:$USER /opt/stacks
# Create mount points for large data (adjust as needed)
sudo mkdir -p /mnt/media/{movies,tv,music,books,photos}
sudo mkdir -p /mnt/downloads/{complete,incomplete}
sudo mkdir -p /mnt/backups
sudo chown -R $USER:$USER /mnt/media /mnt/downloads /mnt/backups
```
## Step 6: Create Docker Networks
```bash
# Create required external networks
docker network create traefik-network
docker network create homelab-network
docker network create media-network
docker network create dockerproxy-network
# Verify networks were created
docker network ls | grep -E "traefik|homelab|media|dockerproxy"
```
## Step 7: Deploy Core Infrastructure Stack
The **core** stack contains all essential services that must be deployed first: DuckDNS, Traefik, Authelia, and Gluetun.
```bash
# Create core stack directory
mkdir -p /opt/stacks/core/{duckdns,traefik/dynamic,authelia,gluetun}
# Copy the core compose file
cp ~/AI-Homelab/docker-compose/core.yml /opt/stacks/core/docker-compose.yml
# Copy configuration templates
cp ~/AI-Homelab/config-templates/traefik/traefik.yml /opt/stacks/core/traefik/
cp ~/AI-Homelab/config-templates/traefik/dynamic/*.yml /opt/stacks/core/traefik/dynamic/
cp ~/AI-Homelab/config-templates/authelia/*.yml /opt/stacks/core/authelia/
# Create acme.json for SSL certificates
touch /opt/stacks/core/traefik/acme.json
chmod 600 /opt/stacks/core/traefik/acme.json
# Generate password hash for Authelia user
docker run --rm authelia/authelia:4.37 authelia crypto hash generate argon2 --password 'yourpassword'
# Copy the output hash
# Edit users_database.yml with your username and password hash
cd /opt/stacks/core/authelia
nano users_database.yml
# Replace the password hash with your generated one
# Example:
# users:
# admin:
# displayname: "Admin User"
# password: "$argon2id$v=19$m=65536..." # Your generated hash
# email: admin@example.com
# groups:
# - admins
# Copy .env file to core stack
cp ~/AI-Homelab/.env /opt/stacks/core/.env
# Deploy the entire core stack - use either method:
# Method 1: From within directory
cd /opt/stacks/core
docker compose up -d
# Method 2: From anywhere with full path
docker compose -f /opt/stacks/core/docker-compose.yml up -d
# Check logs to ensure everything is running
docker compose logs -f
# You should see:
# - DuckDNS updating your IP
# - Traefik starting and acquiring SSL certificates
# - Authelia initializing
# - Gluetun connecting to VPN
```
**Verify Core Services:**
- Traefik dashboard: `https://traefik.yourdomain.duckdns.org` (login with Authelia)
- Authelia login: `https://auth.yourdomain.duckdns.org`
- All services should have valid SSL certificates
**Troubleshooting:**
- If Traefik can't get certificates, check DuckDNS is updating your IP
- If Authelia won't start, check your password hash and configuration.yml
- If Gluetun fails, verify your Surfshark credentials in .env
## Step 8: Deploy Infrastructure Services (Dockge)
```bash
# Create stack directory
mkdir -p /opt/stacks/infrastructure
# Copy compose file
cp ~/AI-Homelab/docker-compose/infrastructure.yml /opt/stacks/infrastructure/docker-compose.yml
# Create necessary subdirectories
mkdir -p /opt/dockge/data
mkdir -p /opt/stacks/pihole/{etc-pihole,etc-dnsmasq.d}
mkdir -p /opt/stacks/glances/config
# Copy .env
cp ~/AI-Homelab/.env /opt/stacks/infrastructure/.env
# Deploy Dockge first
cd /opt/stacks/infrastructure
docker compose up -d dockge
# Access Dockge at https://dockge.yourdomain.duckdns.org (login with Authelia)
# Deploy remaining infrastructure services
docker compose up -d
```
## Step 9: Deploy Dashboards (Homepage & Homarr)
```bash
# Create stack directory
mkdir -p /opt/stacks/dashboards/{homepage,homarr}
# Copy compose file
cp ~/AI-Homelab/docker-compose/dashboards.yml /opt/stacks/dashboards/docker-compose.yml
# Copy Homepage configuration templates
cp ~/AI-Homelab/config-templates/homepage/* /opt/stacks/dashboards/homepage/
# Copy .env
cp ~/AI-Homelab/.env /opt/stacks/dashboards/.env
# Deploy
cd /opt/stacks/dashboards
docker compose up -d
# Access Homepage at https://home.yourdomain.duckdns.org (login with Authelia)
# Access Homarr at https://homarr.yourdomain.duckdns.org (login with Authelia)
```
## Step 10: Deploy Additional Stacks
Now use Dockge UI at `https://dockge.yourdomain.duckdns.org` to deploy additional stacks, or continue with command line:
### 8.1 Gluetun + qBittorrent (VPN)
```bash
mkdir -p /opt/stacks/gluetun
cp ~/AI-Homelab/docker-compose/gluetun.yml /opt/stacks/gluetun/docker-compose.yml
cp ~/AI-Homelab/.env /opt/stacks/gluetun/.env
cd /opt/stacks/gluetun
docker compose up -d
# Test VPN
docker exec gluetun curl ifconfig.me
# Should show VPN IP
```
### 8.2 Homepage Dashboard
```bash
mkdir -p /opt/stacks/homepage/config
cp ~/AI-Homelab/docker-compose/dashboards.yml /opt/stacks/homepage/docker-compose.yml
cp ~/AI-Homelab/config-templates/homepage/* /opt/stacks/homepage/config/
cp ~/AI-Homelab/.env /opt/stacks/homepage/.env
cd /opt/stacks/homepage
docker compose up -d homepage
# Access at https://home.yourdomain.duckdns.org
```
### 8.3 Media Stack
```bash
mkdir -p /opt/stacks/media
cp ~/AI-Homelab/docker-compose/media.yml /opt/stacks/media/docker-compose.yml
cp ~/AI-Homelab/.env /opt/stacks/media/.env
cd /opt/stacks/media
docker compose up -d
```
### 8.4 Additional Stacks
Deploy as needed:
- `media-extended.yml``/opt/stacks/media-extended/`
- `homeassistant.yml``/opt/stacks/homeassistant/`
- `productivity.yml``/opt/stacks/productivity/`
- `utilities.yml``/opt/stacks/utilities/`
- `monitoring.yml``/opt/stacks/monitoring/`
- `development.yml``/opt/stacks/development/`
## Step 9: Configure Homepage Widgets
Get API keys from each service and add to Homepage config:
```bash
cd /opt/stacks/homepage/config
nano services.yaml
# Get API keys:
# - Sonarr/Radarr/etc: Settings → General → API Key
# - Plex: https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/
# - Jellyfin: Dashboard → API Keys
# Add to .env:
nano /opt/stacks/homepage/.env
# HOMEPAGE_VAR_SONARR_KEY=...
# HOMEPAGE_VAR_RADARR_KEY=...
# etc.
# Restart Homepage
cd /opt/stacks/homepage
docker compose restart
```
## Step 10: Install VS Code and GitHub Copilot
```bash
# Install VS Code (if not already installed)
# Download from https://code.visualstudio.com/
# Install GitHub Copilot extension
# In VS Code: Extensions → Search "GitHub Copilot" → Install
# Open the repository
code ~/AI-Homelab
# Start using AI assistance!
```
## Next Steps
1. Explore Dockge at `https://dockge.yourdomain.duckdns.org`
2. Check Homepage dashboard at `https://home.yourdomain.duckdns.org`
3. Configure services through their web UIs
4. Set up Authelia users in `/opt/stacks/authelia/users_database.yml`
5. Configure Homepage widgets with API keys
6. Use VS Code with Copilot to ask questions and make changes
7. Review [proxying-external-hosts.md](proxying-external-hosts.md) to proxy your Raspberry Pi
## Troubleshooting
### Can't access services via HTTPS
Check Traefik logs:
```bash
cd /opt/stacks/traefik
docker compose logs -f
```
Verify DNS is resolving:
```bash
nslookup dockge.yourdomain.duckdns.org
```
Check certificate generation:
```bash
docker exec traefik cat /acme.json
```
### Authelia login not working
Check Authelia logs:
```bash
cd /opt/stacks/authelia
docker compose logs -f
```
Verify password hash in `users_database.yml`
### Service not accessible
1. Check Traefik dashboard: `https://traefik.yourdomain.duckdns.org`
2. Verify service has correct Traefik labels
3. Check service is on `traefik-network`
4. Review service logs
### Port forwarding
Ensure your router forwards ports 80 and 443 to your server IP.
## Security Checklist
- [ ] All passwords in `.env` are strong and unique
- [ ] Authelia 2FA is enabled for admin accounts
- [ ] `.env` file permissions are 600 (`chmod 600 .env`)
- [ ] acme.json permissions are 600
- [ ] Firewall is configured (only 80, 443 open to internet)
- [ ] Pi-hole is configured as your DNS server
- [ ] Watchtower is monitoring for updates
- [ ] Backrest/Duplicati configured for backups
## Congratulations!
Your AI-powered homelab is now running with:
- ✅ Automatic HTTPS via Traefik + Let's Encrypt
- ✅ SSO protection via Authelia
- ✅ 40+ services ready to deploy
- ✅ Dashboard with service widgets
- ✅ AI assistance via GitHub Copilot
- ✅ Centralized management via Dockge
Continue exploring with VS Code and Copilot to add more services, customize configurations, and proxy external devices!

View File

@@ -0,0 +1,379 @@
# Proxying External Hosts with Traefik and Authelia
This guide explains how to use Traefik and Authelia to proxy external services (like a Raspberry Pi running Home Assistant) through your domain with HTTPS and optional SSO protection.
## Overview
Traefik can proxy services that aren't running in Docker, such as:
- Home Assistant on a Raspberry Pi
- Other physical servers on your network
- Services running on different machines
- Any HTTP/HTTPS service accessible via IP:PORT
## Method 1: Using Traefik File Provider (Recommended)
### Step 1: Create External Service Configuration
Create a file in `/opt/stacks/traefik/dynamic/external-hosts.yml`:
```yaml
http:
routers:
# Home Assistant on Raspberry Pi
homeassistant-external:
rule: "Host(`ha.yourdomain.duckdns.org`)"
entryPoints:
- websecure
service: homeassistant-external
tls:
certResolver: letsencrypt
# Uncomment to add Authelia protection:
# middlewares:
# - authelia@docker
services:
homeassistant-external:
loadBalancer:
servers:
- url: "http://192.168.1.50:8123" # Replace with your Pi's IP and port
passHostHeader: true
middlewares:
# Optional: Add headers for WebSocket support
homeassistant-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
customResponseHeaders:
X-Frame-Options: "SAMEORIGIN"
```
### Step 2: Reload Traefik
Traefik watches the `/opt/stacks/traefik/dynamic/` directory automatically and reloads configurations:
```bash
# Verify configuration is loaded
docker logs traefik | grep external-hosts
# If needed, restart Traefik
cd /opt/stacks/traefik
docker compose restart
```
### Step 3: Test Access
Visit `https://ha.yourdomain.duckdns.org` - Traefik will:
1. Accept the HTTPS connection
2. Proxy the request to `http://192.168.1.50:8123`
3. Return the response with proper SSL
4. (Optionally) Require Authelia login if middleware is configured
## Method 2: Using Docker Labels (Dummy Container)
If you prefer managing routes via Docker labels (so the AI can modify them), create a dummy container:
### Create a Label Container
In `/opt/stacks/external-proxies/docker-compose.yml`:
```yaml
services:
# Dummy container for Raspberry Pi Home Assistant
homeassistant-proxy-labels:
image: alpine:latest
container_name: homeassistant-proxy-labels
command: tail -f /dev/null # Keep container running
restart: unless-stopped
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.ha-external.rule=Host(`ha.${DOMAIN}`)"
- "traefik.http.routers.ha-external.entrypoints=websecure"
- "traefik.http.routers.ha-external.tls.certresolver=letsencrypt"
# Point to external service
- "traefik.http.services.ha-external.loadbalancer.server.url=http://192.168.1.50:8123"
# Optional: Add Authelia (usually not for HA)
# - "traefik.http.routers.ha-external.middlewares=authelia@docker"
networks:
traefik-network:
external: true
```
Deploy:
```bash
cd /opt/stacks/external-proxies
docker compose up -d
```
## Method 3: Hybrid Approach (File + Docker Discovery)
Combine both methods for maximum flexibility:
- Use file provider for static external hosts
- Use Docker labels for frequently changing services
- AI can manage both!
## Common External Services to Proxy
### Home Assistant (Raspberry Pi)
```yaml
homeassistant-pi:
rule: "Host(`ha.yourdomain.duckdns.org`)"
service: http://192.168.1.50:8123
# No Authelia - HA has its own auth
```
### Router/Firewall Admin Panel
```yaml
router-admin:
rule: "Host(`router.yourdomain.duckdns.org`)"
service: http://192.168.1.1:80
middlewares:
- authelia@docker # Add SSO protection
```
### Proxmox Server
```yaml
proxmox:
rule: "Host(`proxmox.yourdomain.duckdns.org`)"
service: https://192.168.1.100:8006
middlewares:
- authelia@docker
# Note: Use https:// if backend uses HTTPS
```
### TrueNAS/FreeNAS
```yaml
truenas:
rule: "Host(`nas.yourdomain.duckdns.org`)"
service: http://192.168.1.200:80
middlewares:
- authelia@docker
```
### Security Camera NVR
```yaml
nvr:
rule: "Host(`cameras.yourdomain.duckdns.org`)"
service: http://192.168.1.10:80
middlewares:
- authelia@docker # Definitely protect cameras!
```
## Advanced Configuration
### WebSocket Support
Some services (like Home Assistant) need WebSocket support:
```yaml
http:
middlewares:
websocket-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
Connection: "upgrade"
Upgrade: "websocket"
routers:
homeassistant-external:
middlewares:
- websocket-headers
```
### HTTPS Backend
If your external service already uses HTTPS:
```yaml
http:
services:
https-backend:
loadBalancer:
servers:
- url: "https://192.168.1.50:8123"
serversTransport: insecureTransport
serversTransports:
insecureTransport:
insecureSkipVerify: true # Only if using self-signed cert
```
### IP Whitelist
Restrict access to specific IPs:
```yaml
http:
middlewares:
local-only:
ipWhiteList:
sourceRange:
- "192.168.1.0/24"
- "10.0.0.0/8"
routers:
sensitive-service:
middlewares:
- local-only
- authelia@docker
```
## Authelia Bypass Rules
Configure Authelia to bypass authentication for specific external hosts.
Edit `/opt/stacks/authelia/configuration.yml`:
```yaml
access_control:
rules:
# Bypass for Home Assistant (app access)
- domain: ha.yourdomain.duckdns.org
policy: bypass
# Require auth for router admin
- domain: router.yourdomain.duckdns.org
policy: one_factor
# Two-factor for critical services
- domain: proxmox.yourdomain.duckdns.org
policy: two_factor
```
## DNS Configuration
Ensure your DuckDNS domain points to your public IP:
1. DuckDNS container automatically updates your IP
2. Port forward 80 and 443 to your Traefik server
3. All subdomains (`*.yourdomain.duckdns.org`) point to same IP
4. Traefik routes based on Host header
## Troubleshooting
### Check Traefik Routing
```bash
# View active routes
docker logs traefik | grep "Creating router"
# Check if external host route is loaded
docker logs traefik | grep homeassistant
# View Traefik dashboard
# Visit: https://traefik.yourdomain.duckdns.org
```
### Test Without SSL
```bash
# Temporarily test direct connection
curl -H "Host: ha.yourdomain.duckdns.org" http://localhost/
```
### Check Authelia Logs
```bash
cd /opt/stacks/authelia
docker compose logs -f authelia
```
### Verify External Service
```bash
# Test that external service is reachable
curl http://192.168.1.50:8123
```
## AI Management
The AI can manage external host proxying by:
1. **Reading existing configurations**: Parse `/opt/stacks/traefik/dynamic/*.yml`
2. **Adding new routes**: Create/update YAML files in dynamic directory
3. **Modifying Docker labels**: Update dummy container labels
4. **Configuring Authelia rules**: Edit `configuration.yml` for bypass/require auth
5. **Testing connectivity**: Suggest verification steps
Example AI prompt:
> "Add proxying for my Unifi Controller at 192.168.1.5:8443 with Authelia protection"
AI will:
1. Create route configuration file
2. Add HTTPS backend support (Unifi uses HTTPS)
3. Configure Authelia middleware
4. Add to Homepage dashboard
5. Provide testing instructions
## Security Best Practices
1. **Always use Authelia** for admin interfaces (routers, NAS, etc.)
2. **Bypass Authelia** only for services with their own auth (HA, Plex)
3. **Use IP whitelist** for highly sensitive services
4. **Enable two-factor** for critical infrastructure
5. **Monitor access logs** in Traefik and Authelia
6. **Keep services updated** - Traefik, Authelia, and external services
## Example: Complete External Host Setup
Let's proxy a Raspberry Pi Home Assistant:
1. **Traefik configuration** (`/opt/stacks/traefik/dynamic/raspberry-pi.yml`):
```yaml
http:
routers:
ha-pi:
rule: "Host(`ha.yourdomain.duckdns.org`)"
entryPoints:
- websecure
service: ha-pi
tls:
certResolver: letsencrypt
middlewares:
- ha-headers
services:
ha-pi:
loadBalancer:
servers:
- url: "http://192.168.1.50:8123"
middlewares:
ha-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
```
2. **Authelia bypass** (in `/opt/stacks/authelia/configuration.yml`):
```yaml
access_control:
rules:
- domain: ha.yourdomain.duckdns.org
policy: bypass
```
3. **Homepage entry** (in `/opt/stacks/homepage/config/services.yaml`):
```yaml
- Home Automation:
- Home Assistant (Pi):
icon: home-assistant.png
href: https://ha.yourdomain.duckdns.org
description: HA on Raspberry Pi
ping: 192.168.1.50
widget:
type: homeassistant
url: http://192.168.1.50:8123
key: your-long-lived-token
```
4. **Test**:
```bash
# Reload Traefik (automatic, but verify)
docker logs traefik | grep ha-pi
# Visit
https://ha.yourdomain.duckdns.org
```
Done! Your Raspberry Pi Home Assistant is now accessible via your domain with HTTPS. 🎉

434
docs/quick-reference.md Normal file
View File

@@ -0,0 +1,434 @@
# Quick Reference Guide
## Common Commands
**Note**: Replace `infrastructure.yml` with your compose file name:
- `infrastructure.yml` - Core services
- `media.yml` - Media stack
- `monitoring.yml` - Monitoring services
- `development.yml` - Development tools
### Service Management
```bash
# Start all services in a compose file (from stack directory)
cd /opt/stacks/stack-name/
docker compose up -d
# Start all services (from anywhere, using full path)
docker compose -f /opt/stacks/stack-name/docker-compose.yml up -d
# Start specific service (from stack directory)
cd /opt/stacks/stack-name/
docker compose up -d service-name
# Start specific service (from anywhere)
docker compose -f /opt/stacks/stack-name/docker-compose.yml up -d service-name
# Stop all services (from stack directory)
cd /opt/stacks/stack-name/
docker compose down
# Stop all services (from anywhere)
docker compose -f /opt/stacks/stack-name/docker-compose.yml down
# Stop specific service (from stack directory)
cd /opt/stacks/stack-name/
docker compose stop service-name
# Stop specific service (from anywhere)
docker compose -f /opt/stacks/stack-name/docker-compose.yml stop service-name
# Restart service (from stack directory)
cd /opt/stacks/stack-name/
docker compose restart service-name
# Restart service (from anywhere)
docker compose -f /opt/stacks/stack-name/docker-compose.yml restart service-name
# Remove service and volumes (from stack directory)
cd /opt/stacks/stack-name/
docker compose down -v
# Remove service and volumes (from anywhere)
docker compose -f /opt/stacks/stack-name/docker-compose.yml down -v
```
**Note:** There's more than one way to manage containers - use whichever is most convenient:
- Navigate to `/opt/stacks/stack-name/` and use short commands
- Use full paths with `-f` flag from anywhere in the system
### Monitoring
```bash
# View logs
docker compose -f docker-compose/file.yml logs -f service-name
# Check service status
docker compose -f docker-compose/file.yml ps
# View resource usage
docker stats
# Inspect service
docker inspect container-name
```
### Updates
```bash
# Pull latest images
docker compose -f docker-compose/file.yml pull
# Pull and update specific service
docker compose -f docker-compose/file.yml pull service-name
docker compose -f docker-compose/file.yml up -d service-name
```
### Network Management
```bash
# List networks
docker network ls
# Inspect network
docker network inspect homelab-network
# Create network
docker network create network-name
# Remove network
docker network rm network-name
```
### Volume Management
```bash
# List volumes
docker volume ls
# Inspect volume
docker volume inspect volume-name
# Remove volume
docker volume rm volume-name
# Backup volume
docker run --rm -v volume-name:/data -v $(pwd)/backups:/backup \
busybox tar czf /backup/backup.tar.gz /data
# Restore volume
docker run --rm -v volume-name:/data -v $(pwd)/backups:/backup \
busybox tar xzf /backup/backup.tar.gz -C /
```
### System Maintenance
```bash
# View disk usage
docker system df
# Clean up unused resources
docker system prune
# Clean up everything (careful!)
docker system prune -a --volumes
# Remove unused images
docker image prune
# Remove unused volumes
docker volume prune
# Remove unused networks
docker network prune
```
## Port Reference
### Infrastructure Services
- **80**: Nginx Proxy Manager (HTTP)
- **443**: Nginx Proxy Manager (HTTPS)
- **81**: Nginx Proxy Manager (Admin)
- **53**: Pi-hole (DNS)
- **8080**: Pi-hole (Web UI)
- **9000**: Portainer
- **9443**: Portainer (HTTPS)
### Media Services
- **32400**: Plex
- **8096**: Jellyfin
- **8989**: Sonarr
- **7878**: Radarr
- **9696**: Prowlarr
- **8081**: qBittorrent
### Monitoring Services
- **9090**: Prometheus
- **3000**: Grafana
- **9100**: Node Exporter
- **8082**: cAdvisor
- **3001**: Uptime Kuma
- **3100**: Loki
### Development Services
- **8443**: Code Server
- **8929**: GitLab
- **2222**: GitLab SSH
- **5432**: PostgreSQL
- **6379**: Redis
- **5050**: pgAdmin
- **8888**: Jupyter Lab
- **1880**: Node-RED
## Environment Variables Quick Reference
```bash
# User/Group
PUID=1000 # Your user ID (get with: id -u)
PGID=1000 # Your group ID (get with: id -g)
# General
TZ=America/New_York # Your timezone
SERVER_IP=192.168.1.100 # Server IP address
# Paths
USERDIR=/home/username/homelab
MEDIADIR=/mnt/media
DOWNLOADDIR=/mnt/downloads
PROJECTDIR=/home/username/projects
```
## Network Setup
```bash
# Create all networks at once
docker network create homelab-network
docker network create media-network
docker network create monitoring-network
docker network create database-network
```
## Service URLs
After starting services, access them at:
```
Infrastructure:
http://SERVER_IP:81 - Nginx Proxy Manager
http://SERVER_IP:8080 - Pi-hole
http://SERVER_IP:9000 - Portainer
Media:
http://SERVER_IP:32400/web - Plex
http://SERVER_IP:8096 - Jellyfin
http://SERVER_IP:8989 - Sonarr
http://SERVER_IP:7878 - Radarr
http://SERVER_IP:9696 - Prowlarr
http://SERVER_IP:8081 - qBittorrent
Monitoring:
http://SERVER_IP:9090 - Prometheus
http://SERVER_IP:3000 - Grafana
http://SERVER_IP:3001 - Uptime Kuma
Development:
http://SERVER_IP:8443 - Code Server
http://SERVER_IP:8929 - GitLab
http://SERVER_IP:5050 - pgAdmin
http://SERVER_IP:8888 - Jupyter Lab
http://SERVER_IP:1880 - Node-RED
```
## Troubleshooting Quick Fixes
### Service won't start
```bash
# 1. Check logs
docker compose -f docker-compose/file.yml logs service-name
# 2. Validate configuration
docker compose -f docker-compose/file.yml config
# 3. Check what's using the port
sudo netstat -tlnp | grep PORT_NUMBER
```
### Permission errors
```bash
# Check your IDs
id -u # Should match PUID in .env
id -g # Should match PGID in .env
# Fix ownership
sudo chown -R 1000:1000 ./config/service-name
```
### Network issues
```bash
# Check network exists
docker network inspect homelab-network
# Recreate network
docker network rm homelab-network
docker network create homelab-network
docker compose -f docker-compose/file.yml up -d
```
### Container keeps restarting
```bash
# Watch logs in real-time
docker compose -f docker-compose/file.yml logs -f service-name
# Check resource usage
docker stats container-name
# Inspect container
docker inspect container-name | less
```
## Testing GPU Support (NVIDIA)
```bash
# Test if nvidia-container-toolkit works
docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi
# If successful, you should see your GPU info
```
## Backup Commands
```bash
# Backup all config directories
tar czf backup-config-$(date +%Y%m%d).tar.gz config/
# Backup a specific volume
docker run --rm \
-v volume-name:/data \
-v $(pwd)/backups:/backup \
busybox tar czf /backup/volume-name-$(date +%Y%m%d).tar.gz /data
# Backup .env file (store securely!)
cp .env .env.backup
```
## Health Checks
```bash
# Check all container health status
docker ps --format "table {{.Names}}\t{{.Status}}"
# Check specific service health
docker inspect --format='{{json .State.Health}}' container-name | jq
```
## Resource Limits
Add to service definition if needed:
```yaml
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '0.5'
memory: 1G
```
## Common Patterns
### Add a new service
1. Choose the appropriate compose file
2. Add service definition following existing patterns
3. Use environment variables from .env
4. Connect to homelab-network
5. Pin specific image version
6. Add labels for organization
7. Test: `docker compose -f file.yml config`
8. Deploy: `docker compose -f file.yml up -d service-name`
### Update a service version
1. Edit compose file with new version
2. Pull new image: `docker compose -f file.yml pull service-name`
3. Recreate: `docker compose -f file.yml up -d service-name`
4. Check logs: `docker compose -f file.yml logs -f service-name`
### Remove a service
1. Stop service: `docker compose -f file.yml stop service-name`
2. Remove service: `docker compose -f file.yml rm service-name`
3. Remove from compose file
4. Optional: Remove volumes: `docker volume rm volume-name`
5. Optional: Remove config: `rm -rf config/service-name`
## AI Assistant Usage in VS Code
### Ask for help:
- "Add Jellyfin to my media stack"
- "Configure GPU for Plex"
- "Create monitoring dashboard setup"
- "Help me troubleshoot port conflicts"
- "Generate a compose file for Home Assistant"
### The AI will:
- Check existing services
- Follow naming conventions
- Avoid port conflicts
- Use proper network configuration
- Include health checks
- Add documentation comments
- Suggest related services
## Quick Deployment
### Minimal setup
```bash
# 1. Clone and configure
# Note: Replace 'kelinfoxy' with your username if you forked this repository
git clone https://github.com/kelinfoxy/AI-Homelab.git
cd AI-Homelab
cp .env.example .env
nano .env # Edit values
# 2. Create network
docker network create homelab-network
# 3. Start Portainer (for container management)
docker compose -f docker-compose/infrastructure.yml up -d portainer
# 4. Access at http://SERVER_IP:9000
```
### Full stack deployment
```bash
# After minimal setup, deploy everything:
docker compose -f docker-compose/infrastructure.yml up -d
docker compose -f docker-compose/media.yml up -d
docker compose -f docker-compose/monitoring.yml up -d
docker compose -f docker-compose/development.yml up -d
```
## Maintenance Schedule
### Daily (automated)
- Watchtower checks for updates at 4 AM
### Weekly
- Review logs for each stack:
```bash
docker compose -f docker-compose/infrastructure.yml logs --tail=100
docker compose -f docker-compose/media.yml logs --tail=100
docker compose -f docker-compose/monitoring.yml logs --tail=100
```
- Check disk space: `docker system df`
### Monthly
- Update pinned versions in compose files
- Backup volumes and configs
- Review security updates
### Quarterly
- Full system audit
- Documentation review
- Performance optimization

356
docs/services-reference.md Normal file
View File

@@ -0,0 +1,356 @@
# Complete Services Reference
This document provides a comprehensive overview of all 60+ pre-configured services available in the AI-Homelab repository.
## Services Overview
| Stack | Services | SSO | Storage | Access URLs |
|-------|----------|-----|---------|-------------|
| **📦 core** (4) | **Deploy First** | | | |
| ├─ DuckDNS | Dynamic DNS updater | - | /opt/stacks/core/duckdns | No UI |
| ├─ Traefik | Reverse proxy + SSL | ✓ | /opt/stacks/core/traefik | traefik.${DOMAIN} |
| ├─ Authelia | SSO authentication | - | /opt/stacks/core/authelia | auth.${DOMAIN} |
| └─ Gluetun | VPN (Surfshark) | - | /opt/stacks/core/gluetun | No UI |
| **🔧 infrastructure** (12) | | | | |
| ├─ Dockge | Stack manager (PRIMARY) | ✓ | /opt/stacks/infrastructure | dockge.${DOMAIN} |
| ├─ Portainer | Container management | ✓ | /opt/stacks/infrastructure | portainer.${DOMAIN} |
| ├─ Authentik Server | SSO with web UI | ✓ | /opt/stacks/authentik | authentik.${DOMAIN} |
| │ ├─ authentik-worker | Background tasks | - | /opt/stacks/authentik | No UI |
| │ ├─ authentik-db | PostgreSQL | - | /opt/stacks/authentik | No UI |
| │ └─ authentik-redis | Cache/messaging | - | /opt/stacks/authentik | No UI |
| ├─ Pi-hole | DNS + Ad blocking | ✓ | /opt/stacks/infrastructure | pihole.${DOMAIN} |
| ├─ Watchtower | Auto container updates | - | /opt/stacks/infrastructure | No UI |
| ├─ Dozzle | Docker log viewer | ✓ | /opt/stacks/infrastructure | dozzle.${DOMAIN} |
| ├─ Glances | System monitoring | ✓ | /opt/stacks/infrastructure | glances.${DOMAIN} |
| └─ Docker Proxy | Secure socket access | - | /opt/stacks/infrastructure | No UI |
| **📊 dashboards** (2) | | | | |
| ├─ Homepage | App dashboard (AI cfg) | ✓ | /opt/stacks/dashboards | home.${DOMAIN} |
| └─ Homarr | Modern dashboard | ✓ | /opt/stacks/dashboards | homarr.${DOMAIN} |
| **🎬 media** (6) | | | | |
| ├─ Plex | Media server | ✗ | /mnt/media, /mnt/transcode | plex.${DOMAIN} |
| ├─ Jellyfin | Media server (OSS) | ✗ | /mnt/media, /mnt/transcode | jellyfin.${DOMAIN} |
| ├─ Sonarr | TV automation | ✓ | /opt/stacks/media, /mnt/media | sonarr.${DOMAIN} |
| ├─ Radarr | Movie automation | ✓ | /opt/stacks/media, /mnt/media | radarr.${DOMAIN} |
| ├─ Prowlarr | Indexer manager | ✓ | /opt/stacks/media | prowlarr.${DOMAIN} |
| └─ qBittorrent | Torrent (via VPN) | ✓ | /mnt/downloads | qbit.${DOMAIN} |
| **📚 media-extended** (10) | | | | |
| ├─ Readarr | Ebooks/Audiobooks | ✓ | /opt/stacks/media-ext, /mnt/media | readarr.${DOMAIN} |
| ├─ Lidarr | Music manager | ✓ | /opt/stacks/media-ext, /mnt/media | lidarr.${DOMAIN} |
| ├─ Lazy Librarian | Book automation | ✓ | /opt/stacks/media-ext, /mnt/media | lazylibrarian.${DOMAIN} |
| ├─ Mylar3 | Comic manager | ✓ | /opt/stacks/media-ext, /mnt/media | mylar.${DOMAIN} |
| ├─ Calibre-Web | Ebook reader | ✓ | /opt/stacks/media-ext, /mnt/media | calibre.${DOMAIN} |
| ├─ Jellyseerr | Media requests | ✓ | /opt/stacks/media-ext | jellyseerr.${DOMAIN} |
| ├─ FlareSolverr | Cloudflare bypass | - | /opt/stacks/media-ext | No UI |
| ├─ Tdarr Server | Transcoding server | ✓ | /opt/stacks/media-ext, /mnt/transcode | tdarr.${DOMAIN} |
| ├─ Tdarr Node | Transcoding worker | - | /mnt/transcode-cache | No UI |
| └─ Unmanic | Library optimizer | ✓ | /opt/stacks/media-ext, /mnt/transcode | unmanic.${DOMAIN} |
| **🏠 homeassistant** (7) | | | | |
| ├─ Home Assistant | HA platform | ✗ | /opt/stacks/homeassistant | ha.${DOMAIN} |
| ├─ ESPHome | ESP firmware mgr | ✓ | /opt/stacks/homeassistant | esphome.${DOMAIN} |
| ├─ TasmoAdmin | Tasmota device mgr | ✓ | /opt/stacks/homeassistant | tasmoadmin.${DOMAIN} |
| ├─ Node-RED | Automation flows | ✓ | /opt/stacks/homeassistant | nodered.${DOMAIN} |
| ├─ Mosquitto | MQTT broker | - | /opt/stacks/homeassistant | Ports 1883, 9001 |
| ├─ Zigbee2MQTT | Zigbee bridge | ✓ | /opt/stacks/homeassistant | zigbee2mqtt.${DOMAIN} |
| └─ MotionEye | Video surveillance | ✓ | /opt/stacks/homeassistant, /mnt/surveillance | motioneye.${DOMAIN} |
| **💼 productivity** (8 + 6 DBs) | | | | |
| ├─ Nextcloud | File sync platform | ✓ | /opt/stacks/productivity, /mnt/nextcloud | nextcloud.${DOMAIN} |
| │ └─ nextcloud-db | MariaDB | - | /opt/stacks/productivity | No UI |
| ├─ Mealie | Recipe manager | ✗ | /opt/stacks/productivity | mealie.${DOMAIN} |
| ├─ WordPress | Blog platform | ✗ | /opt/stacks/productivity | blog.${DOMAIN} |
| │ └─ wordpress-db | MariaDB | - | /opt/stacks/productivity | No UI |
| ├─ Gitea | Git service | ✓ | /opt/stacks/productivity, /mnt/git | git.${DOMAIN} |
| │ └─ gitea-db | PostgreSQL | - | /opt/stacks/productivity | No UI |
| ├─ DokuWiki | File-based wiki | ✓ | /opt/stacks/productivity | wiki.${DOMAIN} |
| ├─ BookStack | Documentation | ✓ | /opt/stacks/productivity | docs.${DOMAIN} |
| │ └─ bookstack-db | MariaDB | - | /opt/stacks/productivity | No UI |
| ├─ MediaWiki | Wiki platform | ✓ | /opt/stacks/productivity | mediawiki.${DOMAIN} |
| │ └─ mediawiki-db | MariaDB | - | /opt/stacks/productivity | No UI |
| └─ Form.io | Form builder | ✓ | /opt/stacks/productivity | forms.${DOMAIN} |
| └─ formio-mongo | MongoDB | - | /opt/stacks/productivity | No UI |
| **🛠️ utilities** (7) | | | | |
| ├─ Vaultwarden | Password manager | ✗ | /opt/stacks/utilities | bitwarden.${DOMAIN} |
| ├─ Backrest | Backup (restic) | ✓ | /opt/stacks/utilities, /mnt/backups | backrest.${DOMAIN} |
| ├─ Duplicati | Encrypted backups | ✓ | /opt/stacks/utilities, /mnt/backups | duplicati.${DOMAIN} |
| ├─ Code Server | VS Code in browser | ✓ | /opt/stacks/utilities | code.${DOMAIN} |
| ├─ Form.io | Form platform | ✓ | /opt/stacks/utilities | forms.${DOMAIN} |
| │ └─ formio-mongo | MongoDB | - | /opt/stacks/utilities | No UI |
| └─ Authelia-Redis | Session storage | - | /opt/stacks/utilities | No UI |
| **📈 monitoring** (8) | | | | |
| ├─ Prometheus | Metrics collection | ✓ | /opt/stacks/monitoring | prometheus.${DOMAIN} |
| ├─ Grafana | Visualization | ✓ | /opt/stacks/monitoring | grafana.${DOMAIN} |
| ├─ Loki | Log aggregation | - | /opt/stacks/monitoring | Via Grafana |
| ├─ Promtail | Log shipper | - | /opt/stacks/monitoring | No UI |
| ├─ Node Exporter | Host metrics | - | /opt/stacks/monitoring | No UI |
| ├─ cAdvisor | Container metrics | - | /opt/stacks/monitoring | Internal :8080 |
| └─ Uptime Kuma | Uptime monitoring | ✓ | /opt/stacks/monitoring | status.${DOMAIN} |
| **👨‍💻 development** (6) | | | | |
| ├─ GitLab CE | Git + CI/CD | ✓ | /opt/stacks/development, /mnt/git | gitlab.${DOMAIN} |
| ├─ PostgreSQL | SQL database | - | /opt/stacks/development | Port 5432 |
| ├─ Redis | In-memory store | - | /opt/stacks/development | Port 6379 |
| ├─ pgAdmin | PostgreSQL UI | ✓ | /opt/stacks/development | pgadmin.${DOMAIN} |
| ├─ Jupyter Lab | Notebooks | ✓ | /opt/stacks/development | jupyter.${DOMAIN} |
| └─ Code Server | VS Code | ✓ | /opt/stacks/development | code.${DOMAIN} |
**Legend:** ✓ = Protected by SSO | ✗ = Bypasses SSO | - = No web UI
## Quick Deployment Order
1. **Create Networks** (one-time setup)
```bash
docker network create traefik-network
docker network create homelab-network
docker network create dockerproxy-network
```
2. **Deploy Core Stack** (required first)
```bash
cd /opt/stacks/core/
docker compose up -d
```
3. **Deploy Infrastructure**
```bash
cd /opt/stacks/infrastructure/
docker compose up -d
```
4. **Deploy Dashboards**
```bash
cd /opt/stacks/dashboards/
docker compose up -d
```
5. **Deploy Additional Stacks** (as needed)
- Media: `/opt/stacks/media/`
- Extended Media: `/opt/stacks/media-extended/`
- Home Automation: `/opt/stacks/homeassistant/`
- Productivity: `/opt/stacks/productivity/`
- Utilities: `/opt/stacks/utilities/`
- Monitoring: `/opt/stacks/monitoring/`
- Development: `/opt/stacks/development/`
## Toggling SSO (Authelia) On/Off
You can easily enable or disable SSO protection for any service by modifying its Traefik labels in the docker-compose.yml file.
### To Enable SSO on a Service
Add the Authelia middleware to the service's Traefik labels:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.servicename.rule=Host(`servicename.${DOMAIN}`)"
- "traefik.http.routers.servicename.entrypoints=websecure"
- "traefik.http.routers.servicename.tls.certresolver=letsencrypt"
- "traefik.http.routers.servicename.middlewares=authelia@docker" # ← Add this line
- "traefik.http.services.servicename.loadbalancer.server.port=8080"
```
### To Disable SSO on a Service
Comment out (don't remove) the middleware line:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.servicename.rule=Host(`servicename.${DOMAIN}`)"
- "traefik.http.routers.servicename.entrypoints=websecure"
- "traefik.http.routers.servicename.tls.certresolver=letsencrypt"
# - "traefik.http.routers.servicename.middlewares=authelia@docker" # ← Commented out (not removed)
- "traefik.http.services.servicename.loadbalancer.server.port=8080"
```
After making changes, redeploy the service:
```bash
# From inside the stack directory
cd /opt/stacks/stack-name/
docker compose up -d
# Or from anywhere, using the full path
docker compose -f /opt/stacks/stack-name/docker-compose.yml up -d
```
**Stopping a Service:**
```bash
# From inside the stack directory
cd /opt/stacks/stack-name/
docker compose down
# Or from anywhere, using the full path
docker compose -f /opt/stacks/stack-name/docker-compose.yml down
```
**Use Cases for Development/Production:**
- **Security First**: All services start with SSO enabled by default for maximum security
- **Development**: Keep SSO enabled to protect services during testing
- **Production**: Disable SSO only for services needing direct app/API access (Plex, Jellyfin)
- **Gradual Exposure**: Comment out SSO only when ready to expose a service
- **Quick Toggle**: AI assistant can modify these labels automatically when you ask
## Authelia Customization
### Available Customization Options
**1. Branding and Appearance**
Edit `/opt/stacks/core/authelia/configuration.yml`:
```yaml
# Custom logo and branding
theme: dark # Options: light, dark, grey, auto
# No built-in web UI for configuration
# All settings managed via YAML files
```
**2. User Management**
Users are managed in `/opt/stacks/core/authelia/users_database.yml`:
```yaml
users:
username:
displayname: "Display Name"
password: "$argon2id$v=19$m=65536..." # Generated with authelia hash-password
email: user@example.com
groups:
- admins
- users
```
Generate password hash:
```bash
docker run --rm authelia/authelia:4.37 authelia hash-password 'yourpassword'
```
**3. Access Control Rules**
Customize who can access what in `configuration.yml`:
```yaml
access_control:
default_policy: deny
rules:
# Public services (no auth)
- domain:
- "jellyfin.yourdomain.com"
- "plex.yourdomain.com"
policy: bypass
# Admin only services
- domain:
- "dockge.yourdomain.com"
- "portainer.yourdomain.com"
policy: two_factor
subject:
- "group:admins"
# All authenticated users
- domain: "*.yourdomain.com"
policy: one_factor
```
**4. Two-Factor Authentication (2FA)**
- TOTP (Time-based One-Time Password) via apps like Google Authenticator, Authy
- Configure in `configuration.yml` under `totp:` section
- Per-user enrollment via Authelia UI at `https://auth.${DOMAIN}`
**5. Session Management**
Edit `configuration.yml`:
```yaml
session:
name: authelia_session
expiration: 1h # How long before re-login required
inactivity: 5m # Timeout after inactivity
remember_me_duration: 1M # "Remember me" checkbox duration
```
**6. Notification Settings**
Email notifications for password resets, 2FA enrollment:
```yaml
notifier:
smtp:
host: smtp.gmail.com
port: 587
username: your-email@gmail.com
password: app-password
sender: authelia@yourdomain.com
```
### No Web UI for Configuration
⚠️ **Important**: Authelia does **not** have a configuration web UI. All configuration is done via YAML files:
- `/opt/stacks/core/authelia/configuration.yml` - Main settings
- `/opt/stacks/core/authelia/users_database.yml` - User accounts
This is **by design** and makes Authelia perfect for AI management and security-first approach:
- AI can read and modify YAML files
- Version control friendly
- No UI clicks required
- Infrastructure as code
- Secure by default
**Web UI Available For:**
- Login page: `https://auth.${DOMAIN}`
- User profile: Change password, enroll 2FA
- Device enrollment: Manage trusted devices
**Alternative with Web UI: Authentik**
If you need a web UI for user management, Authentik is included in the infrastructure stack:
- **Authentik**: Full-featured SSO with web UI for user/group management
- Access at: `https://authentik.${DOMAIN}`
- Includes PostgreSQL database and Redis cache
- More complex but offers GUI-based configuration
- Deploy only if you need web-based user management
**Other Alternatives:**
- **Keycloak**: Enterprise-grade SSO with web UI
- **Authelia + LDAP**: Use LDAP with web management (phpLDAPadmin, etc.)
### Quick Configuration with AI
Since all Authelia configuration is file-based, you can use the AI assistant to:
- Add/remove users
- Modify access rules
- Change session settings
- Update branding
- Enable/disable features
Just ask: "Add a new user to Authelia" or "Change session timeout to 2 hours"
## Storage Recommendations
| Data Type | Recommended Location | Reason |
|-----------|---------------------|--------|
| Configuration files | `/opt/stacks/stack-name/` | Easy access, version control |
| Small databases (< 10GB) | `/opt/stacks/stack-name/db/` | Manageable on system drive |
| Media files (movies, TV, music) | `/mnt/media/` | Large, continuous growth |
| Downloads | `/mnt/downloads/` | Temporary, high throughput |
| Backups | `/mnt/backups/` | Large, separate from system |
| Surveillance footage | `/mnt/surveillance/` | Continuous recording |
| Large databases (> 10GB) | `/mnt/databases/` | Growth over time |
| Transcoding cache | `/mnt/transcode-cache/` | High I/O, large temporary files |
| Git repositories | `/mnt/git/` | Can grow large |
| Nextcloud data | `/mnt/nextcloud/` | User files, photos |
## Configuration Templates
All configuration templates are available in `config-templates/`:
- `traefik/` - Static and dynamic Traefik configuration
- `authelia/` - Complete Authelia setup with user database
- `homepage/` - Dashboard services, widgets, and Docker integration
- `prometheus/` - Metrics scrape configurations
- `loki/` - Log aggregation settings
- `promtail/` - Log shipping configuration
- `redis/` - Redis server configuration
## Additional Resources
- **Getting Started**: See [docs/getting-started.md](getting-started.md) for detailed deployment
- **Docker Guidelines**: See [docs/docker-guidelines.md](docker-guidelines.md) for management patterns
- **Quick Reference**: See [docs/quick-reference.md](quick-reference.md) for common commands
- **Proxying External Hosts**: See [docs/proxying-external-hosts.md](proxying-external-hosts.md) for Raspberry Pi, NAS, etc.
- **AI Assistant**: Use GitHub Copilot in VS Code with `.github/copilot-instructions.md` for intelligent homelab management

188
scripts/README.md Normal file
View File

@@ -0,0 +1,188 @@
# AI-Homelab Setup Scripts
This directory contains two scripts for automated AI-Homelab deployment:
1. **setup-homelab.sh** - System preparation (optional, for fresh installations)
2. **deploy-homelab.sh** - Core infrastructure deployment
## setup-homelab.sh
Automated first-run setup script for preparing a fresh Debian installation for AI-Homelab deployment. **This is optional** - skip if Docker is already installed and configured.
### What It Does
1. **System Update** - Updates all system packages
2. **Install Dependencies** - Installs required packages (curl, git, etc.)
3. **Install Docker** - Adds Docker repository and installs Docker Engine with Compose V2
4. **Configure User Groups** - Adds user to sudo and docker groups
5. **Configure SSH** - Enables and starts SSH server for remote access
6. **Detect NVIDIA GPU** - Checks for NVIDIA graphics card and provides manual driver installation instructions
7. **Create Directories** - Sets up `/opt/stacks`, `/opt/dockge`, `/mnt/media`, `/mnt/downloads`
8. **Create Docker Networks** - Creates homelab-network, traefik-network, and media-network
### Usage
```bash
# Download the repository
git clone https://github.com/kelinfoxy/AI-Homelab.git
cd AI-Homelab
# Make the script executable (if needed)
chmod +x scripts/setup-homelab.sh
# Run with sudo
sudo ./scripts/setup-homelab.sh
```
### After Running
1. Log out and log back in for group changes to take effect
2. Edit `.env` file with your configuration
3. Run `deploy-homelab.sh` to deploy core infrastructure and Dockge
### NVIDIA GPU Support
If an NVIDIA GPU is detected, the script will provide instructions for manual driver installation:
1. Identify your GPU model from the output
2. Visit https://www.nvidia.com/Download/index.aspx
3. Download the official driver for your GPU
4. Run the installer: `sudo bash NVIDIA-Linux-x86_64-XXX.XX.run`
5. Install container toolkit:
```bash
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
This manual approach avoids driver conflicts that often occur with automated installation methods.
### Requirements
- Fresh Debian installation (Debian 11 or 12)
- Root access (via sudo)
- Internet connection
### Tested On
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
### Notes
- The script is idempotent - safe to run multiple times
- Creates directories with proper ownership
- Configures Docker networks automatically
- SSH is enabled for remote management
- NVIDIA driver installation requires manual intervention for reliability
---
## deploy-homelab.sh
Automated deployment script that deploys the core infrastructure and Dockge. Run this after editing your `.env` file.
### What It Does
1. **Validate Prerequisites** - Checks for Docker, .env file, and proper configuration
2. **Create Directories** - Sets up `/opt/stacks/core` and `/opt/stacks/infrastructure`
3. **Create Docker Networks** - Ensures homelab-network, traefik-network, and media-network exist
4. **Deploy Core Stack** - Deploys DuckDNS, Traefik, Authelia, and Gluetun
5. **Deploy Infrastructure Stack** - Deploys Dockge, Portainer, Pi-hole, and monitoring tools
6. **Wait for Dockge** - Waits for Dockge web UI to become accessible
7. **Open Browser** - Automatically opens Dockge in your default browser
### Usage
```bash
# From the AI-Homelab directory
cd AI-Homelab
# Ensure .env is configured
cp .env.example .env
nano .env # Edit with your values
# Make the script executable (if needed)
chmod +x scripts/deploy-homelab.sh
# Run WITHOUT sudo (run as your regular user)
./scripts/deploy-homelab.sh
```
### After Running
The script will automatically open `https://dockge.yourdomain.duckdns.org` in your browser when Dockge is ready.
1. Log in to Dockge using your Authelia credentials (configured in `/opt/stacks/core/authelia/users_database.yml`)
2. Deploy additional stacks through Dockge's web UI:
- `dashboards.yml` - Homepage and Homarr
- `media.yml` - Plex, Jellyfin, Sonarr, Radarr, etc.
- `media-extended.yml` - Readarr, Lidarr, etc.
- `homeassistant.yml` - Home Assistant and accessories
- `productivity.yml` - Nextcloud, Gitea, wikis
- `monitoring.yml` - Grafana, Prometheus
- `utilities.yml` - Backups, password manager
### Requirements
- Docker and Docker Compose installed
- `.env` file configured with your domain and credentials
- User must be in docker group (handled by setup-homelab.sh)
### Browser Detection
The script will attempt to open Dockge using:
- `xdg-open` (default on most Linux desktops)
- `gnome-open` (GNOME desktop)
- `firefox` or `google-chrome` (direct browser launch)
If no browser is detected, it will display the URL for manual access.
### Manual Deployment Alternative
If you prefer to deploy manually instead of using the script:
```bash
# Deploy core stack
mkdir -p /opt/stacks/core
cp docker-compose/core.yml /opt/stacks/core/docker-compose.yml
cp -r config-templates/traefik /opt/stacks/core/
cp -r config-templates/authelia /opt/stacks/core/
cp .env /opt/stacks/core/
cd /opt/stacks/core && docker compose up -d
# Deploy infrastructure stack
mkdir -p /opt/stacks/infrastructure
cp docker-compose/infrastructure.yml /opt/stacks/infrastructure/docker-compose.yml
cp .env /opt/stacks/infrastructure/
cd /opt/stacks/infrastructure && docker compose up -d
# Manually open: https://dockge.yourdomain.duckdns.org
```
### Troubleshooting
**Script says "Docker daemon is not running":**
- Run: `sudo systemctl start docker`
- Or log out and back in if you just added yourself to docker group
**Script says ".env file not found":**
- Run: `cp .env.example .env` and edit with your values
**Dockge doesn't open automatically:**
- The script will display the URL to open manually
- Wait a minute for services to fully start
- Check logs: `docker compose -f /opt/stacks/infrastructure/docker-compose.yml logs dockge`
**Traefik SSL certificate errors:**
- Initial certificate generation can take a few minutes
- Check DuckDNS token is correct in .env
- Verify your domain is accessible from the internet
### Notes
- Run as regular user (NOT with sudo)
- Validates .env configuration before deployment
- Waits up to 60 seconds for Dockge to become ready
- Automatically copies .env to stack directories
- Safe to run multiple times (idempotent)

239
scripts/deploy-homelab.sh Executable file
View File

@@ -0,0 +1,239 @@
#!/bin/bash
# AI-Homelab Deployment Script
# This script deploys the core infrastructure and Dockge
# Run after: 1) setup-homelab.sh and 2) editing .env file
# Run as: ./deploy-homelab.sh
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Log functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if running as root
if [ "$EUID" -eq 0 ]; then
log_error "Please do NOT run this script as root or with sudo"
log_info "Run as: ./deploy-homelab.sh"
exit 1
fi
# Get script directory (AI-Homelab/scripts)
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
log_info "AI-Homelab Deployment Script"
echo ""
# Check if .env file exists
if [ ! -f "$REPO_DIR/.env" ]; then
log_error ".env file not found!"
log_info "Please create and configure your .env file first:"
echo " cd $REPO_DIR"
echo " cp .env.example .env"
echo " nano .env"
exit 1
fi
# Check if Docker is installed and running
if ! command -v docker &> /dev/null; then
log_error "Docker is not installed. Please run setup-homelab.sh first."
exit 1
fi
if ! docker info &> /dev/null; then
log_error "Docker daemon is not running or you don't have permission."
log_info "Try: sudo systemctl start docker"
log_info "Or log out and log back in for group changes to take effect"
exit 1
fi
log_success "Docker is available and running"
echo ""
# Load environment variables for domain check
source "$REPO_DIR/.env"
if [ -z "$DOMAIN" ]; then
log_error "DOMAIN is not set in .env file"
log_info "Please edit .env and set your DuckDNS domain"
exit 1
fi
log_info "Using domain: $DOMAIN"
echo ""
# Step 1: Create required directories
log_info "Step 1/5: Creating required directories..."
mkdir -p /opt/stacks/core
mkdir -p /opt/stacks/infrastructure
mkdir -p /opt/dockge/data
log_success "Directories created"
echo ""
# Step 2: Create Docker networks (if they don't exist)
log_info "Step 2/5: Creating Docker networks..."
docker network create homelab-network 2>/dev/null && log_success "Created homelab-network" || log_info "homelab-network already exists"
docker network create traefik-network 2>/dev/null && log_success "Created traefik-network" || log_info "traefik-network already exists"
docker network create media-network 2>/dev/null && log_success "Created media-network" || log_info "media-network already exists"
echo ""
# Step 3: Deploy core infrastructure (DuckDNS, Traefik, Authelia, Gluetun)
log_info "Step 3/5: Deploying core infrastructure stack..."
log_info " - DuckDNS (Dynamic DNS)"
log_info " - Traefik (Reverse Proxy with SSL)"
log_info " - Authelia (Single Sign-On)"
log_info " - Gluetun (VPN Client)"
echo ""
# Copy core stack files
cp "$REPO_DIR/docker-compose/core.yml" /opt/stacks/core/docker-compose.yml
cp -r "$REPO_DIR/config-templates/traefik" /opt/stacks/core/
cp -r "$REPO_DIR/config-templates/authelia" /opt/stacks/core/
cp "$REPO_DIR/.env" /opt/stacks/core/.env
# Deploy core stack
cd /opt/stacks/core
docker compose up -d
log_success "Core infrastructure deployed"
echo ""
# Wait for Traefik to be ready
log_info "Waiting for Traefik to initialize..."
sleep 10
# Check if Traefik is healthy
if docker ps | grep -q "traefik.*Up"; then
log_success "Traefik is running"
else
log_warning "Traefik container check inconclusive, continuing..."
fi
echo ""
# Step 4: Deploy infrastructure stack (Dockge and monitoring tools)
log_info "Step 4/5: Deploying infrastructure stack..."
log_info " - Dockge (Docker Compose Manager)"
log_info " - Portainer (Alternative Docker UI)"
log_info " - Pi-hole (DNS Ad Blocker)"
log_info " - Watchtower (Container Updates)"
log_info " - Dozzle (Log Viewer)"
log_info " - Glances (System Monitor)"
log_info " - Docker Proxy (Security)"
echo ""
# Copy infrastructure stack
cp "$REPO_DIR/docker-compose/infrastructure.yml" /opt/stacks/infrastructure/docker-compose.yml
cp "$REPO_DIR/.env" /opt/stacks/infrastructure/.env
# Deploy infrastructure stack
cd /opt/stacks/infrastructure
docker compose up -d
log_success "Infrastructure stack deployed"
echo ""
# Step 5: Wait for Dockge to be ready and open browser
log_info "Step 5/5: Waiting for Dockge web UI to be ready..."
DOCKGE_URL="https://dockge.${DOMAIN}"
MAX_WAIT=60 # Maximum wait time in seconds
WAITED=0
# Function to check if Dockge is accessible
check_dockge() {
# Try to connect to Dockge (ignore SSL cert warnings for self-signed during startup)
curl -k -s -o /dev/null -w "%{http_code}" "$DOCKGE_URL" 2>/dev/null
}
# Wait for Dockge to respond
while [ $WAITED -lt $MAX_WAIT ]; do
HTTP_CODE=$(check_dockge)
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "401" ]; then
log_success "Dockge web UI is ready!"
break
fi
echo -n "."
sleep 2
WAITED=$((WAITED + 2))
done
echo ""
echo ""
if [ $WAITED -ge $MAX_WAIT ]; then
log_warning "Dockge did not respond within ${MAX_WAIT} seconds"
log_info "It may still be starting up. Check manually at: $DOCKGE_URL"
else
# Try to open browser
log_info "Opening Dockge in your browser..."
# Detect and use available browser
if command -v xdg-open &> /dev/null; then
xdg-open "$DOCKGE_URL" &> /dev/null &
log_success "Browser opened"
elif command -v gnome-open &> /dev/null; then
gnome-open "$DOCKGE_URL" &> /dev/null &
log_success "Browser opened"
elif command -v firefox &> /dev/null; then
firefox "$DOCKGE_URL" &> /dev/null &
log_success "Browser opened"
elif command -v google-chrome &> /dev/null; then
google-chrome "$DOCKGE_URL" &> /dev/null &
log_success "Browser opened"
else
log_warning "No browser detected. Please manually open: $DOCKGE_URL"
fi
fi
echo ""
echo "=========================================="
log_success "Deployment completed successfully!"
echo "=========================================="
echo ""
log_info "Access your services:"
echo ""
echo " 🚀 Dockge: $DOCKGE_URL"
echo " 🔒 Authelia: https://auth.${DOMAIN}"
echo " 🔀 Traefik: https://traefik.${DOMAIN}"
echo ""
log_info "Next steps:"
echo ""
echo " 1. Log in to Dockge using your Authelia credentials"
echo " (configured in /opt/stacks/core/authelia/users_database.yml)"
echo ""
echo " 2. Deploy additional stacks through Dockge's web UI:"
echo " - dashboards.yml (Homepage, Homarr)"
echo " - media.yml (Plex, Jellyfin, Sonarr, Radarr, etc.)"
echo " - media-extended.yml (Readarr, Lidarr, etc.)"
echo " - homeassistant.yml (Home Assistant and accessories)"
echo " - productivity.yml (Nextcloud, Gitea, wikis)"
echo " - monitoring.yml (Grafana, Prometheus, etc.)"
echo " - utilities.yml (Backups, code editors, etc.)"
echo ""
echo " 3. Configure services via the AI assistant in VS Code"
echo ""
echo "=========================================="
echo ""
log_info "For documentation, see: $REPO_DIR/docs/"
log_info "For troubleshooting, see: $REPO_DIR/docs/quick-reference.md"
echo ""

227
scripts/setup-homelab.sh Executable file
View File

@@ -0,0 +1,227 @@
#!/bin/bash
# AI-Homelab First-Run Setup Script
# This script prepares a fresh Debian installation for homelab deployment
# Run as: sudo ./setup-homelab.sh
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Log functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use: sudo ./setup-homelab.sh)"
exit 1
fi
# Get the actual user who invoked sudo
ACTUAL_USER="${SUDO_USER:-$USER}"
if [ "$ACTUAL_USER" = "root" ]; then
log_error "Please run this script with sudo, not as root user"
exit 1
fi
log_info "Setting up AI-Homelab for user: $ACTUAL_USER"
echo ""
# Step 1: System Update
log_info "Step 1/8: Updating system packages..."
apt-get update && apt-get upgrade -y
log_success "System updated successfully"
echo ""
# Step 2: Install Required Packages
log_info "Step 2/8: Installing required packages..."
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release \
software-properties-common \
git \
openssh-server \
sudo \
pciutils \
net-tools
log_success "Required packages installed"
echo ""
# Step 3: Install Docker
log_info "Step 3/8: Installing Docker..."
if command -v docker &> /dev/null; then
log_warning "Docker is already installed ($(docker --version))"
else
# Add Docker's official GPG key
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update and install Docker
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
log_success "Docker installed successfully ($(docker --version))"
fi
echo ""
# Step 4: Configure User Groups
log_info "Step 4/8: Configuring user groups..."
# Add user to sudo group if not already
if groups "$ACTUAL_USER" | grep -q '\bsudo\b'; then
log_warning "User $ACTUAL_USER is already in sudo group"
else
usermod -aG sudo "$ACTUAL_USER"
log_success "User $ACTUAL_USER added to sudo group"
fi
# Add user to docker group
if groups "$ACTUAL_USER" | grep -q '\bdocker\b'; then
log_warning "User $ACTUAL_USER is already in docker group"
else
usermod -aG docker "$ACTUAL_USER"
log_success "User $ACTUAL_USER added to docker group"
fi
echo ""
# Step 5: Configure SSH
log_info "Step 5/8: Configuring SSH server..."
systemctl enable ssh
systemctl start ssh
# Check if SSH is running
if systemctl is-active --quiet ssh; then
SSH_PORT=$(grep "^Port" /etc/ssh/sshd_config | awk '{print $2}')
SSH_PORT=${SSH_PORT:-22}
log_success "SSH server is running on port $SSH_PORT"
else
log_warning "SSH server failed to start, check configuration"
fi
echo ""
# Step 6: Detect and Install NVIDIA Drivers (if applicable)
log_info "Step 6/8: Checking for NVIDIA GPU..."
# Detect NVIDIA GPU
if lspci | grep -i nvidia > /dev/null; then
log_info "NVIDIA GPU detected:"
lspci | grep -i nvidia
echo ""
log_warning "NVIDIA GPU found, but driver installation requires manual intervention."
log_info "For best results, please follow these steps manually:"
echo ""
echo " 1. Identify your GPU model from the output above"
echo " 2. Visit: https://www.nvidia.com/Download/index.aspx"
echo " 3. Download the official driver for your GPU"
echo " 4. Run the downloaded installer (example): sudo bash NVIDIA-Linux-x86_64-XXX.XX.run"
echo ""
log_info "After installing NVIDIA drivers, run:"
echo " sudo apt-get install -y nvidia-container-toolkit"
echo " sudo nvidia-ctk runtime configure --runtime=docker"
echo " sudo systemctl restart docker"
echo ""
log_warning "Skipping automatic NVIDIA driver installation to avoid conflicts"
echo ""
else
log_info "No NVIDIA GPU detected, skipping driver installation"
echo ""
fi
# Step 7: Create Directory Structure
log_info "Step 7/8: Creating directory structure..."
mkdir -p /opt/stacks
mkdir -p /opt/dockge/data
mkdir -p /mnt/media
mkdir -p /mnt/downloads
# Set ownership
chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks
chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/dockge
chown -R "$ACTUAL_USER:$ACTUAL_USER" /mnt/media
chown -R "$ACTUAL_USER:$ACTUAL_USER" /mnt/downloads
log_success "Directory structure created"
echo ""
# Step 8: Create Docker Networks
log_info "Step 8/8: Creating Docker networks..."
su - "$ACTUAL_USER" -c "docker network create homelab-network 2>/dev/null || true"
su - "$ACTUAL_USER" -c "docker network create traefik-network 2>/dev/null || true"
su - "$ACTUAL_USER" -c "docker network create media-network 2>/dev/null || true"
log_success "Docker networks created"
echo ""
# Final Summary
echo ""
echo "=========================================="
log_success "AI-Homelab setup completed successfully!"
echo "=========================================="
echo ""
log_info "Next steps:"
echo ""
echo " 1. Log out and log back in for group changes to take effect"
echo " (or run: newgrp docker)"
echo ""
echo " 2. Navigate to your AI-Homelab repository:"
echo " cd ~/AI-Homelab"
echo ""
echo " 3. Edit the .env file with your configuration:"
echo " cp .env.example .env"
echo " nano .env"
echo ""
echo " 4. Deploy the core infrastructure stack:"
echo " mkdir -p /opt/stacks/core"
echo " cp docker-compose/core.yml /opt/stacks/core/docker-compose.yml"
echo " cp -r config-templates/traefik /opt/stacks/core/"
echo " cp -r config-templates/authelia /opt/stacks/core/"
echo " cd /opt/stacks/core && docker compose up -d"
echo ""
echo " 5. Deploy the infrastructure stack (includes Dockge):"
echo " mkdir -p /opt/stacks/infrastructure"
echo " cp docker-compose/infrastructure.yml /opt/stacks/infrastructure/docker-compose.yml"
echo " cd /opt/stacks/infrastructure && docker compose up -d"
echo ""
echo " 6. Access Dockge at: https://dockge.yourdomain.duckdns.org"
echo " (Use your configured domain and Authelia credentials)"
echo ""
echo "=========================================="
if lspci | grep -i nvidia > /dev/null; then
echo ""
log_warning "REMINDER: Manual NVIDIA driver installation required"
echo " See instructions above in Step 6"
echo "=========================================="
fi
echo ""
log_info "Setup complete! Please log out and log back in."