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:
194
.env.example
Normal file
194
.env.example
Normal 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
530
.github/copilot-instructions.md
vendored
Normal 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
76
.gitignore
vendored
Normal 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
688
README.md
@@ -1,2 +1,688 @@
|
|||||||
# AI-Homelab
|
# 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
196
config-templates/README.md
Normal 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
|
||||||
|
```
|
||||||
93
config-templates/authelia/configuration.yml
Normal file
93
config-templates/authelia/configuration.yml
Normal 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
|
||||||
20
config-templates/authelia/users_database.yml
Normal file
20
config-templates/authelia/users_database.yml
Normal 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
|
||||||
13
config-templates/homepage/docker.yaml
Normal file
13
config-templates/homepage/docker.yaml
Normal 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
|
||||||
373
config-templates/homepage/services.yaml
Normal file
373
config-templates/homepage/services.yaml
Normal 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
|
||||||
63
config-templates/homepage/settings.yaml
Normal file
63
config-templates/homepage/settings.yaml
Normal 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}}
|
||||||
49
config-templates/homepage/widgets.yaml
Normal file
49
config-templates/homepage/widgets.yaml
Normal 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}}
|
||||||
46
config-templates/loki/loki-config.yml
Normal file
46
config-templates/loki/loki-config.yml
Normal 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
|
||||||
49
config-templates/prometheus/prometheus.yml
Normal file
49
config-templates/prometheus/prometheus.yml
Normal 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'
|
||||||
53
config-templates/promtail/promtail-config.yml
Normal file
53
config-templates/promtail/promtail-config.yml
Normal 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
|
||||||
42
config-templates/redis/redis.conf
Normal file
42
config-templates/redis/redis.conf
Normal 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
|
||||||
31
config-templates/traefik/dynamic/routes.yml
Normal file
31
config-templates/traefik/dynamic/routes.yml
Normal 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
|
||||||
58
config-templates/traefik/traefik.yml
Normal file
58
config-templates/traefik/traefik.yml
Normal 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
|
||||||
324
docker-compose/README-dockge.md
Normal file
324
docker-compose/README-dockge.md
Normal 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
228
docker-compose/README.md
Normal 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
137
docker-compose/core.yml
Normal 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
|
||||||
66
docker-compose/dashboards.yml
Normal file
66
docker-compose/dashboards.yml
Normal 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
|
||||||
191
docker-compose/development.yml
Normal file
191
docker-compose/development.yml
Normal 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
|
||||||
173
docker-compose/homeassistant.yml
Normal file
173
docker-compose/homeassistant.yml
Normal 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
|
||||||
302
docker-compose/infrastructure.yml
Normal file
302
docker-compose/infrastructure.yml
Normal 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
|
||||||
282
docker-compose/media-extended.yml
Normal file
282
docker-compose/media-extended.yml
Normal 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
188
docker-compose/media.yml
Normal 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
|
||||||
181
docker-compose/monitoring.yml
Normal file
181
docker-compose/monitoring.yml
Normal 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
|
||||||
324
docker-compose/productivity.yml
Normal file
324
docker-compose/productivity.yml
Normal 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
|
||||||
189
docker-compose/utilities.yml
Normal file
189
docker-compose/utilities.yml
Normal 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
1002
docs/docker-guidelines.md
Normal file
File diff suppressed because it is too large
Load Diff
420
docs/getting-started.md
Normal file
420
docs/getting-started.md
Normal 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!
|
||||||
379
docs/proxying-external-hosts.md
Normal file
379
docs/proxying-external-hosts.md
Normal 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
434
docs/quick-reference.md
Normal 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
356
docs/services-reference.md
Normal 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
188
scripts/README.md
Normal 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
239
scripts/deploy-homelab.sh
Executable 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
227
scripts/setup-homelab.sh
Executable 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."
|
||||||
Reference in New Issue
Block a user