Update Homepage dashboard and deployment scripts

- Homepage: Reorganize services by stack instead of by category
- Homepage: Add comprehensive Available to Install sections for all stacks
- Homepage: Update config templates with {{HOMEPAGE_VAR_DOMAIN}} placeholder
- Homepage: Change layout from row to column style
- Scripts: Add sudo requirement to deploy-homelab.sh
- Scripts: Replace NVIDIA driver installation with official installer method
- Scripts: Add build prerequisites and nouveau blacklisting
- Docs: Add AI Automation Guidelines section to docker-guidelines.md
- Docs: Document Homepage auto-update requirements and workflow
- Config: Add bookmarks.yaml template for Homepage
- Config: Add alternatives.yml compose file (Portainer, Authentik)
- Config: Update .env.example and authelia configuration
This commit is contained in:
2026-01-13 00:04:43 -05:00
parent 37a093189e
commit bbcc4c19c9
12 changed files with 1159 additions and 571 deletions

View File

@@ -1,7 +1,11 @@
# Environment Variables Template
# Copy this file to .env and fill in your values
# Copy this file to .env and fill in your values: cp .env.example .env
# NEVER commit .env to git!
# ====================================
# SYSTEM CONFIGURATION
# ====================================
# User and Group IDs (get with: id -u and id -g)
PUID=1000
PGID=1000
@@ -12,59 +16,115 @@ TZ=America/New_York
# Server IP address
SERVER_IP=192.168.1.100
# Domain Configuration
DOMAIN=yourdomain.duckdns.org # Your DuckDNS domain
# ====================================
# DOMAIN & DNS CONFIGURATION
# ====================================
# 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
# Your DuckDNS domain (without https://)
DOMAIN=yourdomain.duckdns.org
# DuckDNS Configuration
DUCKDNS_TOKEN=your-duckdns-token
DUCKDNS_SUBDOMAINS=yourdomain # Without .duckdns.org
# Let's Encrypt / ACME
# Let's Encrypt / ACME (for SSL certificates)
ACME_EMAIL=your-email@example.com
ADMIN_EMAIL=your-email@example.com # Used for admin user account
# 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
# Cloudflare API (optional, for DNS challenge instead of DuckDNS)
# CF_DNS_API_TOKEN=your-cloudflare-api-token
# SMTP for Authelia Notifications (optional)
SMTP_USERNAME=your-email@example.com
SMTP_PASSWORD=your-smtp-password
# ====================================
# AUTHELIA SSO CONFIGURATION
# ====================================
# These secrets are AUTO-GENERATED by setup-homelab.sh
# DO NOT manually set these - the setup script will create them!
# 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
AUTHELIA_JWT_SECRET=will-be-auto-generated-by-setup-script
AUTHELIA_SESSION_SECRET=will-be-auto-generated-by-setup-script
AUTHELIA_STORAGE_ENCRYPTION_KEY=will-be-auto-generated-by-setup-script
# VPN Configuration (Surfshark)
# SMTP for Authelia Notifications (OPTIONAL)
# If not configured, notifications are saved to file instead
# SMTP_USERNAME=your-email@example.com
# SMTP_PASSWORD=your-smtp-password
# ====================================
# VPN CONFIGURATION (GLUETUN)
# ====================================
# Surfshark OpenVPN (RECOMMENDED - Default)
SURFSHARK_USERNAME=your-surfshark-username
SURFSHARK_PASSWORD=your-surfshark-password
VPN_SERVER_COUNTRIES=Netherlands # Preferred VPN server location
# Surfshark WireGuard (OPTIONAL - Advanced users only)
# Only needed if you prefer WireGuard over OpenVPN
# 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
# SURFSHARK_PRIVATE_KEY=your-wireguard-private-key
# SURFSHARK_ADDRESSES=10.14.0.2/16
# Alternative: OpenVPN credentials (if not using WireGuard)
# SURFSHARK_USERNAME=your-surfshark-username
# SURFSHARK_PASSWORD=your-surfshark-password
# ====================================
# 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
# ====================================
# ALTERNATIVE SERVICES (OPTIONAL)
# Deploy alternatives.yml stack if you want these
# ====================================
# Authentik SSO (alternative to Authelia with web UI)
# WARNING: Do not run both Authelia and Authentik at the same time
# 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
# ====================================
# MEDIA SERVICES
# ====================================
# Media Services
PLEX_CLAIM=claim-xxxxxxxxxx
# Monitoring & Dashboards
# qBittorrent
QBITTORRENT_USER=admin
QBITTORRENT_PASS=changeme
# ====================================
# INFRASTRUCTURE SERVICES
# ====================================
# Pi-hole
PIHOLE_PASSWORD=changeme
# Watchtower Notifications (optional)
# WATCHTOWER_NOTIFICATION_URL=
# ====================================
# MONITORING & DASHBOARDS
# ====================================
GRAFANA_ADMIN_PASSWORD=changeme
# Development Tools
# ====================================
# DEVELOPMENT TOOLS
# ====================================
CODE_SERVER_PASSWORD=changeme
CODE_SERVER_SUDO_PASSWORD=changeme
# Databases - General
JUPYTER_TOKEN=changeme
# ====================================
# DATABASES - GENERAL
# ====================================
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changeme
POSTGRES_DB=homelab
@@ -72,47 +132,54 @@ POSTGRES_DB=homelab
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=changeme
# Infrastructure
PIHOLE_PASSWORD=changeme
WATCHTOWER_NOTIFICATION_URL=
# ====================================
# PRODUCTIVITY SERVICES
# ====================================
# Productivity Services - Nextcloud
# Nextcloud
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=changeme
NEXTCLOUD_DB_PASSWORD=changeme
NEXTCLOUD_DB_ROOT_PASSWORD=changeme
# Productivity Services - Gitea
# Gitea
GITEA_DB_PASSWORD=changeme
# Productivity Services - WordPress
# WordPress
WORDPRESS_DB_PASSWORD=changeme
WORDPRESS_DB_ROOT_PASSWORD=changeme
# Productivity Services - BookStack
# BookStack
BOOKSTACK_DB_PASSWORD=changeme
BOOKSTACK_DB_ROOT_PASSWORD=changeme
# Productivity Services - MediaWiki
# MediaWiki
MEDIAWIKI_DB_PASSWORD=changeme
MEDIAWIKI_DB_ROOT_PASSWORD=changeme
# Utilities - Form.io
# ====================================
# UTILITIES
# ====================================
# 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
# 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
# ====================================
# HOMEPAGE DASHBOARD - API KEYS
# 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
@@ -140,55 +207,3 @@ 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

272
AGENT_INSTRUCTIONS.md Normal file
View File

@@ -0,0 +1,272 @@
# AI Agent Instructions for Homelab Management
## Primary Directive
You are an AI agent specialized in managing Docker-based homelab infrastructure using Dockge. Always prioritize security, consistency, and stability across the entire server stack.
## Core Operating Principles
### 1. Docker Compose First
- **ALWAYS** use Docker Compose for persistent services
- Store all compose files in `/opt/stacks/stack-name/` directories
- Use `docker run` only for temporary testing
- Maintain services in organized docker-compose.yml files
### 2. Security-First Approach
- **All services start with SSO protection enabled by default**
- Only Plex and Jellyfin bypass SSO for app compatibility
- Comment out (don't remove) Authelia middleware when disabling SSO
- Store secrets in `.env` files, never in compose files
### 3. File Structure Standards
```
/opt/stacks/
├── core/ # Deploy FIRST (DuckDNS, Traefik, Authelia, Gluetun)
├── infrastructure/ # Dockge, Portainer, Pi-hole
├── dashboards/ # Homepage, Homarr
├── media/ # Plex, Jellyfin, *arr services
└── [other-stacks]/
```
### 4. Storage Strategy
- **Config files**: `/opt/stacks/stack-name/config/`
- **Large data**: Separate drives (`/mnt/media`, `/mnt/downloads`)
- **Small data**: Docker named volumes
- **Secrets**: `.env` files (never commit)
## Service Creation Template
```yaml
services:
service-name:
image: image:tag # Always pin versions
container_name: service-name
restart: unless-stopped
networks:
- homelab-network
ports:
- "host:container" # Only if not using Traefik
volumes:
- /opt/stacks/stack-name/config:/config
- service-data:/data
# Large data on separate drives:
# - /mnt/media:/media
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
labels:
# Traefik routing
- "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"
# SSO protection (ENABLED BY DEFAULT)
- "traefik.http.routers.service-name.middlewares=authelia@docker"
# Organization
- "homelab.category=category-name"
- "homelab.description=Service description"
volumes:
service-data:
driver: local
networks:
homelab-network:
external: true
```
## Critical Deployment Order
1. **Core Stack First**: Deploy `/opt/stacks/core/docker-compose.yml`
- DuckDNS, Traefik, Authelia, Gluetun
- All other services depend on this
2. **Infrastructure**: Dockge, Portainer, monitoring
3. **Applications**: Media services, dashboards, etc.
## VPN Integration Rules
Use Gluetun for services requiring VPN:
```yaml
services:
download-client:
network_mode: "service:gluetun"
depends_on:
- gluetun
# No ports section - use Gluetun's ports
```
Map ports in Gluetun service:
```yaml
gluetun:
ports:
- 8080:8080 # Download client web UI
```
## SSO Management
### Enable SSO (Default)
```yaml
labels:
- "traefik.http.routers.service.middlewares=authelia@docker"
```
### Disable SSO (Only for Plex/Jellyfin/Apps)
```yaml
labels:
# - "traefik.http.routers.service.middlewares=authelia@docker"
```
## Agent Actions Checklist
### Before Any Change
- [ ] Read existing compose files for context
- [ ] Check port availability
- [ ] Verify network dependencies
- [ ] Ensure core stack is deployed
- [ ] Backup current configuration
### When Creating Services
- [ ] Use LinuxServer.io images when available
- [ ] Pin image versions (no `:latest`)
- [ ] Apply consistent naming conventions
- [ ] Enable Authelia middleware by default
- [ ] Configure proper volume mounts
- [ ] Set PUID/PGID for file permissions
### When Modifying Services
- [ ] Maintain existing patterns
- [ ] Consider stack-wide impact
- [ ] Update only necessary components
- [ ] Validate YAML syntax
- [ ] Test service restart
### File Management
- [ ] Store configs in `/opt/stacks/stack-name/`
- [ ] Use `/mnt/` for large data (>50GB)
- [ ] Create `.env.example` templates
- [ ] Document non-obvious configurations
## Common Agent Tasks
### Deploy New Service
1. Create stack directory: `/opt/stacks/stack-name/`
2. Write docker-compose.yml with template
3. Create `.env` file for secrets
4. Deploy: `docker compose up -d`
5. Verify Traefik routing
6. Test SSO protection
### Update Existing Service
1. Read current configuration
2. Make minimal necessary changes
3. Validate dependencies still work
4. Redeploy: `docker compose up -d service-name`
5. Check logs for errors
### Enable/Disable VPN
1. For VPN: Add `network_mode: "service:gluetun"`
2. Move port mapping to Gluetun service
3. Add `depends_on: gluetun`
4. For no VPN: Remove network_mode, add ports directly
### Toggle SSO
1. Enable: Add authelia middleware label
2. Disable: Comment out middleware label
3. Redeploy service
4. Verify access works as expected
## Error Prevention
### Port Conflicts
- Check existing services before assigning ports
- Use Traefik instead of port mapping when possible
- Document port usage in comments
### Permission Issues
- Always set PUID=1000, PGID=1000
- Check directory ownership on host
- Use consistent user/group across services
### Network Issues
- Verify shared networks exist
- Use service names for inter-service communication
- Ensure Traefik can reach services
## Key Configurations to Monitor
### Traefik Labels
- Correct hostname format: `service.${DOMAIN}`
- Proper entrypoint: `websecure`
- Certificate resolver: `letsencrypt`
- Port specification if needed
### Authelia Integration
- Middleware applied to protected services
- Bypass rules for apps requiring direct access
- User database and access rules updated
### Volume Mounts
- Config files in stack directories
- Large data on separate drives
- Named volumes for persistent data
- Proper permissions and ownership
## Emergency Procedures
### Service Won't Start
1. Check logs: `docker compose logs service-name`
2. Verify YAML syntax
3. Check file permissions
4. Validate environment variables
5. Ensure dependencies are running
### SSL Certificate Issues
- Verify DuckDNS is updating IP
- Check Traefik logs
- Ensure port 80/443 accessible
- Validate domain DNS resolution
### Authentication Problems
- Check Authelia logs
- Verify user database format
- Test bypass rules
- Validate Traefik middleware configuration
## Success Metrics
- All services accessible via HTTPS
- SSO working for protected services
- No port conflicts
- Proper file permissions
- Services restart automatically
- Logs show no persistent errors
- Certificates auto-renew
- VPN routing working for download clients
## Agent Limitations
### Never Do
- Use `docker run` for permanent services
- Commit secrets to compose files
- Use `:latest` tags in production
- Bypass security without explicit request
- Modify core stack without understanding dependencies
### Always Do
- Read existing configurations first
- Test changes in isolation when possible
- Document complex configurations
- Follow established naming patterns
- Prioritize security over convenience
- Maintain consistency across the stack
## Communication Guidelines
- Explain what you're doing and why
- Highlight security implications
- Warn about service dependencies
- Provide rollback instructions
- Document any manual steps required
- Ask for clarification on ambiguous requests
This framework ensures reliable, secure, and maintainable homelab infrastructure while enabling automated management through AI agents.

View File

@@ -1,5 +1,6 @@
# Authelia Configuration
# Copy to /opt/stacks/authelia/configuration.yml
# IMPORTANT: Replace 'your-domain.duckdns.org' with your actual DuckDNS domain
server:
host: 0.0.0.0
@@ -12,10 +13,10 @@ theme: dark
jwt_secret: ${AUTHELIA_JWT_SECRET}
default_redirection_url: https://auth.${DOMAIN}
default_redirection_url: https://auth.your-domain.duckdns.org
totp:
issuer: ${DOMAIN}
issuer: your-domain.duckdns.org
period: 30
skew: 1
@@ -35,25 +36,25 @@ access_control:
rules:
# Bypass Authelia for Jellyfin (allow app access)
- domain: jellyfin.${DOMAIN}
- domain: jellyfin.your-domain.duckdns.org
policy: bypass
# Bypass for Plex (allow app access)
- domain: plex.${DOMAIN}
- domain: plex.your-domain.duckdns.org
policy: bypass
# Bypass for Home Assistant (has its own auth)
- domain: ha.${DOMAIN}
- domain: ha.your-domain.duckdns.org
policy: bypass
# Protected: All other services require authentication
- domain: "*.${DOMAIN}"
- domain: "*.your-domain.duckdns.org"
policy: one_factor
# Two-factor for admin services (optional)
# - domain:
# - "admin.${DOMAIN}"
# - "portainer.${DOMAIN}"
# - "admin.your-domain.duckdns.org"
# - "portainer.your-domain.duckdns.org"
# policy: two_factor
session:
@@ -62,7 +63,7 @@ session:
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
domain: ${DOMAIN}
domain: your-domain.duckdns.org
regulation:
max_retries: 3
@@ -72,22 +73,9 @@ regulation:
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
local:
path: /config/db.sqlite3
path: /data/db.sqlite3
notifier:
# File-based notifications (for testing)
# File-based notifications (for development/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
filename: /data/notification.txt

View File

@@ -0,0 +1,29 @@
---
# Homepage Bookmarks
- Documentation:
- GitHub Repository:
- icon: github.png
href: https://github.com/kelinfoxy/AI-Homelab
description: AI-Homelab Repository
- Homepage Docs:
- icon: homepage.png
href: https://gethomepage.dev
description: Homepage Documentation
- Useful Links:
- DuckDNS:
- icon: duckdns.png
href: https://www.duckdns.org
description: Dynamic DNS Service
- Let's Encrypt:
- icon: si-letsencrypt
href: https://letsencrypt.org
description: SSL Certificate Provider
- Docker Hub:
- icon: docker.png
href: https://hub.docker.com
description: Container Images

View File

@@ -1,373 +1,245 @@
# 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
# Currently Installed Services - Grouped by Stack
- Core Stack (core.yml):
- 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
description: Authentication Portal
- 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}}
- Infrastructure Stack (infrastructure.yml):
- Dockge:
icon: dockge.png
href: https://dockge.{{HOMEPAGE_VAR_DOMAIN}}
description: Docker Compose Manager
- Dozzle:
icon: dozzle.png
href: https://dozzle.{{HOMEPAGE_VAR_DOMAIN}}
description: Real-time Docker Logs
container: dozzle
description: Real-time Log Viewer
- 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:
- Pi-hole:
icon: pi-hole.png
href: https://pihole.{{HOMEPAGE_VAR_DOMAIN}}
description: Network-wide Ad Blocking
- Dashboards Stack (dashboards.yml):
- Homepage:
icon: homepage.png
href: https://home.{{HOMEPAGE_VAR_DOMAIN}}
description: This Dashboard
- 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}}
- Alternatives Stack (alternatives.yml):
- Portainer:
icon: portainer.png
href: https://portainer.{{HOMEPAGE_VAR_DOMAIN}}
description: Container Management UI
# Media - Streaming
- Media Streaming:
- Authentik:
icon: authentik.png
href: https://authentik.{{HOMEPAGE_VAR_DOMAIN}}
description: Alternative Auth Provider
# Available to Install - Grouped by Stack
- Media Stack (media.yml):
- 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}}
description: TV Shows Automation
- 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}}
description: Movies Automation
- 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}}
description: Torrent Client
- Gluetun:
icon: gluetun.png
href: http://gluetun:8000
description: VPN Client (Surfshark)
container: gluetun
- Media Extended Stack (media-extended.yml):
- Readarr:
icon: readarr.png
href: https://readarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Books Automation
- Lidarr:
icon: lidarr.png
href: https://lidarr.{{HOMEPAGE_VAR_DOMAIN}}
description: Music Automation
- Mylar3:
icon: mylar.png
href: https://mylar.{{HOMEPAGE_VAR_DOMAIN}}
description: Comics Manager
# 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
- Jellyseerr:
icon: jellyseerr.png
href: https://jellyseerr.{{HOMEPAGE_VAR_DOMAIN}}
description: Media Request Manager
- 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
description: Media Transcoding
- Unmanic:
icon: unmanic.png
href: https://unmanic.{{HOMEPAGE_VAR_DOMAIN}}
description: Library Optimizer
container: unmanic
# Home Automation
- Home Automation:
- Home Automation Stack (homeassistant.yml):
- 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}}
description: Home Automation Platform
- 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
description: Flow-based Automation
- Zigbee2MQTT:
icon: zigbee2mqtt.png
href: https://zigbee2mqtt.{{HOMEPAGE_VAR_DOMAIN}}
href: https://zigbee.{{HOMEPAGE_VAR_DOMAIN}}
description: Zigbee Bridge
container: zigbee2mqtt
- MotionEye:
icon: motioneye.png
href: https://motioneye.{{HOMEPAGE_VAR_DOMAIN}}
description: Video Surveillance
container: motioneye
- Mosquitto:
icon: mosquitto.png
href: https://mqtt.{{HOMEPAGE_VAR_DOMAIN}}
description: MQTT Broker
# Productivity
- Productivity:
- Productivity Stack (productivity.yml):
- 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}}
description: Cloud Storage & Collaboration
- Gitea:
icon: gitea.png
href: https://gitea.{{HOMEPAGE_VAR_DOMAIN}}
description: Git Repository
- 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}}
href: https://bookstack.{{HOMEPAGE_VAR_DOMAIN}}
description: Wiki Platform
- 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
href: https://dokuwiki.{{HOMEPAGE_VAR_DOMAIN}}
description: Simple Wiki
- WordPress:
icon: wordpress.png
href: https://blog.{{HOMEPAGE_VAR_DOMAIN}}
description: Blog Platform
container: wordpress
href: https://wordpress.{{HOMEPAGE_VAR_DOMAIN}}
description: CMS Platform
# 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:
- Monitoring Stack (monitoring.yml):
- 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}}
description: Metrics Dashboard
- 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
href: https://uptime.{{HOMEPAGE_VAR_DOMAIN}}
description: Uptime Monitoring
- Loki:
icon: loki.png
href: https://loki.{{HOMEPAGE_VAR_DOMAIN}}
description: Log Aggregation
- cAdvisor:
icon: cadvisor.png
href: https://cadvisor.{{HOMEPAGE_VAR_DOMAIN}}
description: Container Metrics
- Development Stack (development.yml):
- VS Code Server:
icon: vscode.png
href: https://code.{{HOMEPAGE_VAR_DOMAIN}}
description: Browser-based IDE
- GitLab:
icon: gitlab.png
href: https://gitlab.{{HOMEPAGE_VAR_DOMAIN}}
description: DevOps Platform
- Jupyter:
icon: jupyter.png
href: https://jupyter.{{HOMEPAGE_VAR_DOMAIN}}
description: Data Science Notebooks
- pgAdmin:
icon: pgadmin.png
href: https://pgadmin.{{HOMEPAGE_VAR_DOMAIN}}
description: PostgreSQL Admin
- Utilities Stack (utilities.yml):
- Backrest:
icon: mdi-backup-restore
href: https://backrest.{{HOMEPAGE_VAR_DOMAIN}}
description: Backup Solution
- Duplicati:
icon: duplicati.png
href: https://duplicati.{{HOMEPAGE_VAR_DOMAIN}}
description: Backup Software
- Vaultwarden:
icon: vaultwarden.png
href: https://vault.{{HOMEPAGE_VAR_DOMAIN}}
description: Password Manager
- Formio:
icon: mdi-form-select
href: https://formio.{{HOMEPAGE_VAR_DOMAIN}}
description: Form Builder

View File

@@ -1,63 +1,45 @@
# 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
# Homepage Settings
# For all configuration options: https://gethomepage.dev/configs/settings/
title: AI Homelab Dashboard
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
Core Stack (core.yml):
style: column
columns: 2
Media Streaming:
style: row
columns: 3
Media Management:
style: row
Infrastructure Stack (infrastructure.yml):
style: column
columns: 4
Downloads:
style: row
Dashboards Stack (dashboards.yml):
style: column
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
Alternatives Stack (alternatives.yml):
style: column
columns: 2
Monitoring:
style: row
Media Stack (media.yml):
style: column
columns: 3
Media Extended Stack (media-extended.yml):
style: column
columns: 3
Home Automation Stack (homeassistant.yml):
style: column
columns: 3
Productivity Stack (productivity.yml):
style: column
columns: 3
Monitoring Stack (monitoring.yml):
style: column
columns: 3
Development Stack (development.yml):
style: column
columns: 4
Utilities Stack (utilities.yml):
style: column
columns: 4
# 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}}
headerStyle: boxed

View File

@@ -1,14 +1,11 @@
# 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
# Homepage Widgets Configuration
# Service widgets omitted per user request
- search:
provider: google
target: _blank
- resources:
cpu: true
memory: true
disk: /
- datetime:
text_size: xl
@@ -16,34 +13,3 @@
dateStyle: long
timeStyle: short
hourCycle: h23
- resources:
label: System
cpu: true
memory: true
disk: /
cputemp: true
uptime: true
units: metric
- resources:
label: Storage
disk: /mnt/media
expanded: true
- resources:
label: Downloads
disk: /mnt/downloads
expanded: true
- openmeteo:
label: Weather
latitude: 40.7128
longitude: -74.0060
units: metric
cache: 5
- unifi_console:
url: http://unifi:8443
username: {{HOMEPAGE_VAR_UNIFI_USER}}
password: {{HOMEPAGE_VAR_UNIFI_PASS}}

View File

@@ -0,0 +1,149 @@
# Alternative Services Stack
# This stack contains alternative/optional services that are not deployed by default
# Deploy manually through Dockge if you want to use these alternatives
# Place in /opt/stacks/alternatives/docker-compose.yml
services:
# Portainer - Docker management UI (Alternative to Dockge)
# Access at: https://portainer.${DOMAIN}
# NOTE: Dockge is the default Docker management UI. Deploy Portainer only if you prefer its interface
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=alternatives"
- "homelab.description=Docker container management UI (Alternative to Dockge)"
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.routers.portainer.middlewares=authelia@docker"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
# Authentik - Alternative SSO/Identity Provider with Web UI
# Access at: https://authentik.${DOMAIN}
# NOTE: Authelia is the default SSO. Deploy Authentik only if you need a web UI for user management
# WARNING: Do not run both Authelia and Authentik at the same time
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=alternatives"
- "homelab.description=SSO/Identity provider with web UI (Alternative to Authelia)"
- "traefik.enable=true"
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
- "traefik.http.routers.authentik.entrypoints=websecure"
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
- "traefik.http.routers.authentik.middlewares=authelia@docker"
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
depends_on:
- authentik-db
- authentik-redis
# Authentik Worker - Background task processor
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=alternatives"
- "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=alternatives"
- "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=alternatives"
- "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

View File

@@ -21,13 +21,14 @@ services:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- HOMEPAGE_ALLOWED_HOSTS=home.${DOMAIN}
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.tls=true"
- "traefik.http.routers.homepage.middlewares=authelia@docker"
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
@@ -53,7 +54,7 @@ services:
- "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.tls=true"
- "traefik.http.routers.homarr.middlewares=authelia@docker"
- "traefik.http.services.homarr.loadbalancer.server.port=7575"

View File

@@ -990,6 +990,65 @@ docker compose -f docker-compose/service.yml logs -f
# Access service and verify it works
```
## AI Automation Guidelines
### Homepage Dashboard Management
**Automatic Configuration Updates**
Homepage configuration must be kept synchronized with deployed services. The AI assistant handles this automatically:
**Template Location:**
- Config templates: `/home/kelin/AI-Homelab/config-templates/homepage/`
- Active configs: `/opt/stacks/homepage/config/`
**Key Principles:**
1. **Hard-Coded URLs Required**: Homepage does NOT support variables in href links
- Template uses `{{HOMEPAGE_VAR_DOMAIN}}` as placeholder
- Active config uses `kelin-hass.duckdns.org` hard-coded
- AI must replace placeholders when deploying configs
2. **No Container Restart Needed**: Homepage picks up config changes instantly
- Simply edit YAML files in `/opt/stacks/homepage/config/`
- Refresh browser to see changes
- DO NOT restart the container
3. **Stack-Based Organization**: Services grouped by their compose file
- **Currently Installed**: Shows running services grouped by stack
- **Available to Install**: Shows undeployed services from repository
4. **Automatic Updates Required**: AI must update Homepage configs when:
- New service is deployed → Add to appropriate stack section
- Service is removed → Remove from stack section
- Domain/subdomain changes → Update all affected href URLs
- Stack file is renamed → Update section headers
**Configuration Structure:**
```yaml
# services.yaml
- Stack Name (compose-file.yml):
- Service Name:
icon: service.png
href: https://subdomain.kelin-hass.duckdns.org # Hard-coded!
description: Service description
```
**Deployment Workflow:**
```bash
# When deploying from template:
cp /home/kelin/AI-Homelab/config-templates/homepage/*.yaml /opt/stacks/homepage/config/
sed -i 's/{{HOMEPAGE_VAR_DOMAIN}}/kelin-hass.duckdns.org/g' /opt/stacks/homepage/config/services.yaml
# No restart needed - configs load instantly
```
**Critical Reminder:** Homepage is the single source of truth for service inventory. Keep it updated or users won't know what's deployed.
---
## Conclusion
Following these guidelines ensures:

View File

@@ -31,9 +31,15 @@ log_error() {
}
# 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"
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use: sudo ./deploy-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
@@ -42,6 +48,7 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
log_info "AI-Homelab Deployment Script"
log_info "Running as user: $ACTUAL_USER"
echo ""
# Check if .env file exists
@@ -111,6 +118,37 @@ 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
# Replace domain placeholder in authelia configuration
log_info "Configuring Authelia for domain: $DOMAIN..."
sed -i "s/your-domain.duckdns.org/${DOMAIN}/g" /opt/stacks/core/authelia/configuration.yml
# Create Authelia users database with admin credentials from setup script
if [ -f /tmp/authelia_admin_credentials.tmp ]; then
log_info "Configuring Authelia admin user..."
source /tmp/authelia_admin_credentials.tmp
cat > /opt/stacks/core/authelia/users_database.yml << EOF
###############################################################
# Users Database #
###############################################################
users:
${ADMIN_USER}:
displayname: "${ADMIN_USER}"
password: "${PASSWORD_HASH}"
email: ${ADMIN_EMAIL}
groups:
- admins
- dev
EOF
log_success "Authelia admin user configured: $ADMIN_USER"
rm -f /tmp/authelia_admin_credentials.tmp
else
log_warning "Admin credentials not found. Using template users_database.yml"
log_info "You will need to manually configure /opt/stacks/core/authelia/users_database.yml"
fi
# Deploy core stack
cd /opt/stacks/core
docker compose up -d
@@ -133,7 +171,6 @@ 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)"
@@ -222,6 +259,7 @@ 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 " - alternatives.yml (Portainer, Authentik - optional alternatives)"
echo " - dashboards.yml (Homepage, Homarr)"
echo " - media.yml (Plex, Jellyfin, Sonarr, Radarr, etc.)"
echo " - media-extended.yml (Readarr, Lidarr, etc.)"

View File

@@ -152,58 +152,117 @@ else
log_warning "SSH server failed to start, check configuration"
fi
echo ""
# Step 7: Generate Authelia Secrets
log_info "Step 7/9: Generating Authelia authentication secrets..."
echo ""
# Step 7: Detect and Install NVIDIA Drivers (if applicable)
log_info "Step 7/9: Checking for NVIDIA GPU..."
# Function to generate a secure random secret
generate_secret() {
openssl rand -hex 64
}
# Detect NVIDIA GPU
if lspci | grep -i nvidia > /dev/null; then
log_info "NVIDIA GPU detected:"
lspci | grep -i nvidia
echo ""
# Check if NVIDIA drivers are already installed
if nvidia-smi &> /dev/null; then
log_warning "NVIDIA drivers are already installed"
NVIDIA_INSTALLED=true
else
log_info "Installing NVIDIA drivers..."
# Install NVIDIA driver (non-interactive)
apt-get install -y nvidia-driver
log_success "NVIDIA drivers installed"
NVIDIA_INSTALLED=false
fi
# Check if NVIDIA Container Toolkit is installed
if command -v nvidia-container-runtime &> /dev/null; then
log_warning "NVIDIA Container Toolkit is already installed"
else
log_info "Installing NVIDIA Container Toolkit..."
# Install NVIDIA Container Toolkit
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt-get update
apt-get install -y nvidia-container-toolkit
# Configure Docker to use NVIDIA runtime
nvidia-ctk runtime configure --runtime=docker
systemctl restart docker
log_success "NVIDIA Container Toolkit installed and configured"
fi
if [ "$NVIDIA_INSTALLED" = false ]; then
log_warning "NVIDIA drivers were installed. A reboot may be required for changes to take effect."
fi
echo ""
else
log_info "No NVIDIA GPU detected, skipping driver installation"
echo ""
# Check if .env file exists in the repo
REPO_ENV_FILE="$HOME/AI-Homelab/.env"
if [ ! -f "$REPO_ENV_FILE" ]; then
log_error ".env file not found at $REPO_ENV_FILE"
log_info "Please create .env file from .env.example first"
exit 1
fi
# Check if secrets are already set (not placeholder values)
CURRENT_JWT=$(grep "^AUTHELIA_JWT_SECRET=" "$REPO_ENV_FILE" | cut -d'=' -f2)
if [ -n "$CURRENT_JWT" ] && [ "$CURRENT_JWT" != "your-jwt-secret-here" ] && [ ${#CURRENT_JWT} -ge 64 ]; then
log_warning "Authelia secrets appear to already be set in .env"
read -p "Do you want to regenerate them? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Keeping existing secrets"
else
# Generate new secrets
log_info "Generating new JWT secret..."
JWT_SECRET=$(generate_secret)
log_info "Generating new session secret..."
SESSION_SECRET=$(generate_secret)
log_info "Generating new storage encryption key..."
ENCRYPTION_KEY=$(generate_secret)
# Update .env file
sed -i "s|^AUTHELIA_JWT_SECRET=.*|AUTHELIA_JWT_SECRET=${JWT_SECRET}|" "$REPO_ENV_FILE"
sed -i "s|^AUTHELIA_SESSION_SECRET=.*|AUTHELIA_SESSION_SECRET=${SESSION_SECRET}|" "$REPO_ENV_FILE"
sed -i "s|^AUTHELIA_STORAGE_ENCRYPTION_KEY=.*|AUTHELIA_STORAGE_ENCRYPTION_KEY=${ENCRYPTION_KEY}|" "$REPO_ENV_FILE"
log_success "New secrets generated and saved to .env"
fi
else
# Generate secrets for first time
log_info "Generating new JWT secret..."
JWT_SECRET=$(generate_secret)
log_info "Generating new session secret..."
SESSION_SECRET=$(generate_secret)
log_info "Generating new storage encryption key..."
ENCRYPTION_KEY=$(generate_secret)
# Update .env file
sed -i "s|^AUTHELIA_JWT_SECRET=.*|AUTHELIA_JWT_SECRET=${JWT_SECRET}|" "$REPO_ENV_FILE"
sed -i "s|^AUTHELIA_SESSION_SECRET=.*|AUTHELIA_SESSION_SECRET=${SESSION_SECRET}|" "$REPO_ENV_FILE"
sed -i "s|^AUTHELIA_STORAGE_ENCRYPTION_KEY=.*|AUTHELIA_STORAGE_ENCRYPTION_KEY=${ENCRYPTION_KEY}|" "$REPO_ENV_FILE"
log_success "Secrets generated and saved to .env"
fi
# Prompt for admin password
echo ""
log_info "Setting up Authelia admin user..."
echo ""
read -p "Enter admin username (default: admin): " ADMIN_USER
ADMIN_USER=${ADMIN_USER:-admin}
while true; do
read -sp "Enter password for $ADMIN_USER: " ADMIN_PASSWORD
echo ""
read -sp "Confirm password: " ADMIN_PASSWORD_CONFIRM
echo ""
if [ "$ADMIN_PASSWORD" = "$ADMIN_PASSWORD_CONFIRM" ]; then
if [ ${#ADMIN_PASSWORD} -lt 8 ]; then
log_warning "Password should be at least 8 characters long"
continue
fi
break
else
log_warning "Passwords do not match, please try again"
fi
done
# Generate password hash using Docker
log_info "Generating password hash (this may take a moment)..."
PASSWORD_HASH=$(docker run --rm authelia/authelia:4.37 authelia crypto hash generate argon2 --password "$ADMIN_PASSWORD" | grep '^\$argon2')
if [ -z "$PASSWORD_HASH" ]; then
log_error "Failed to generate password hash"
exit 1
fi
# Read admin email from .env or prompt
ADMIN_EMAIL=$(grep "^ADMIN_EMAIL=" "$REPO_ENV_FILE" | cut -d'=' -f2)
if [ -z "$ADMIN_EMAIL" ] || [ "$ADMIN_EMAIL" = "admin@example.com" ]; then
read -p "Enter admin email address: " ADMIN_EMAIL
sed -i "s|^ADMIN_EMAIL=.*|ADMIN_EMAIL=${ADMIN_EMAIL}|" "$REPO_ENV_FILE"
fi
log_success "Admin user configured: $ADMIN_USER"
log_success "Password hash generated and will be applied during deployment"
# Store the admin credentials for the deployment script
cat > /tmp/authelia_admin_credentials.tmp << EOF
ADMIN_USER=$ADMIN_USER
ADMIN_EMAIL=$ADMIN_EMAIL
PASSWORD_HASH=$PASSWORD_HASH
EOF
chmod 600 /tmp/authelia_admin_credentials.tmp
echo ""
# Step 8: Create Directory Structure
log_info "Step 8/9: Creating directory structure..."
mkdir -p /opt/stacks
@@ -223,6 +282,7 @@ chown -R "$ACTUAL_USER:$ACTUAL_USER" /mnt/backups
chown -R "$ACTUAL_USER:$ACTUAL_USER" /mnt/surveillance
chown -R "$ACTUAL_USER:$ACTUAL_USER" /mnt/git
log_success "Directory structure created"
echo ""
@@ -235,38 +295,195 @@ su - "$ACTUAL_USER" -c "docker network create dockerproxy-network 2>/dev/null ||
log_success "Docker networks created"
echo ""
# Optional: Detect and Install NVIDIA Drivers (if applicable)
log_info "Optional: Checking for NVIDIA GPU..."
# Detect NVIDIA GPU
if lspci | grep -i nvidia > /dev/null; then
log_info "NVIDIA GPU detected:"
GPU_INFO=$(lspci | grep -i nvidia)
echo "$GPU_INFO"
echo ""
# Check if NVIDIA drivers are already installed
if nvidia-smi &> /dev/null; then
log_warning "NVIDIA drivers are already installed"
nvidia-smi
NVIDIA_INSTALLED=true
NVIDIA_REBOOT_NEEDED=false
else
log_warning "NVIDIA GPU detected but drivers not installed"
echo ""
read -p "Do you want to install NVIDIA drivers now? (y/N): " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_info "Installing NVIDIA drivers using official installer..."
echo ""
# Extract GPU model for driver selection
GPU_MODEL=$(echo "$GPU_INFO" | grep -oP 'NVIDIA.*' | head -1)
log_info "GPU Model: $GPU_MODEL"
# Determine recommended driver version
log_info "Determining recommended driver version..."
# Install prerequisites for NVIDIA installer
log_info "Installing build prerequisites..."
apt-get install -y build-essential linux-headers-$(uname -r) pkg-config libglvnd-dev 2>&1 | tee /tmp/nvidia-prereq.log
# Disable nouveau driver
log_info "Disabling nouveau driver..."
if [ ! -f /etc/modprobe.d/blacklist-nouveau.conf ]; then
cat > /etc/modprobe.d/blacklist-nouveau.conf << EOF
blacklist nouveau
options nouveau modeset=0
EOF
update-initramfs -u
log_success "Nouveau driver blacklisted (reboot required)"
fi
# Download latest NVIDIA driver
NVIDIA_VERSION="550.127.05" # Latest Production Branch as of script creation
DRIVER_URL="https://us.download.nvidia.com/XFree86/Linux-x86_64/${NVIDIA_VERSION}/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run"
DRIVER_FILE="/tmp/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run"
log_info "Downloading NVIDIA driver version ${NVIDIA_VERSION}..."
log_info "URL: $DRIVER_URL"
if curl -fL -o "$DRIVER_FILE" "$DRIVER_URL" 2>&1 | tee /tmp/nvidia-download.log; then
log_success "Driver downloaded successfully"
chmod +x "$DRIVER_FILE"
log_info "Running NVIDIA installer (this may take several minutes)..."
log_info "The installer will compile kernel modules and configure the driver."
echo ""
# Run NVIDIA installer with appropriate flags
if "$DRIVER_FILE" --silent --dkms --no-questions 2>&1 | tee /tmp/nvidia-install.log; then
log_success "NVIDIA drivers installed successfully"
NVIDIA_INSTALLED=true
NVIDIA_REBOOT_NEEDED=true
else
log_error "NVIDIA driver installation failed"
log_info "Installation log saved to: /tmp/nvidia-install.log"
log_info "Common issues:"
log_info " - Secure Boot may need to be disabled in BIOS"
log_info " - You may need to sign the kernel modules for Secure Boot"
log_info " - Try running installer manually: sudo $DRIVER_FILE"
log_info ""
log_info "For latest driver, visit: https://www.nvidia.com/Download/index.aspx"
NVIDIA_INSTALLED=false
NVIDIA_REBOOT_NEEDED=true # Still need reboot for nouveau blacklist
fi
# Cleanup installer
rm -f "$DRIVER_FILE"
else
log_error "Failed to download NVIDIA driver"
log_info "Download log saved to: /tmp/nvidia-download.log"
log_info "You can download and install manually from:"
log_info " https://www.nvidia.com/Download/index.aspx"
NVIDIA_INSTALLED=false
NVIDIA_REBOOT_NEEDED=false
fi
else
log_info "Skipping NVIDIA driver installation"
log_info "To install later, visit: https://www.nvidia.com/Download/index.aspx"
NVIDIA_INSTALLED=false
NVIDIA_REBOOT_NEEDED=false
fi
fi
# Check if NVIDIA Container Toolkit is installed
if [ "$NVIDIA_INSTALLED" = true ]; then
if command -v nvidia-container-runtime &> /dev/null; then
log_warning "NVIDIA Container Toolkit is already installed"
else
log_info "Installing NVIDIA Container Toolkit..."
# Install NVIDIA Container Toolkit (with error handling)
{
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg && \
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list && \
apt-get update && \
apt-get install -y nvidia-container-toolkit && \
nvidia-ctk runtime configure --runtime=docker && \
systemctl restart docker
} 2>&1 | tee /tmp/nvidia-toolkit-install.log
if [ ${PIPESTATUS[0]} -eq 0 ]; then
log_success "NVIDIA Container Toolkit installed and configured"
else
log_error "NVIDIA Container Toolkit installation failed"
log_info "Installation log saved to: /tmp/nvidia-toolkit-install.log"
log_info "Docker will work without GPU support"
log_info "You can try installing manually later from:"
log_info " https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html"
fi
fi
fi
echo ""
else
log_info "No NVIDIA GPU detected, skipping driver installation"
NVIDIA_REBOOT_NEEDED=false
echo ""
fi
# Final Summary
echo ""
echo "=========================================="
log_success "AI-Homelab setup completed successfully!"
echo "=========================================="
echo ""
if [ "${NVIDIA_REBOOT_NEEDED:-false}" = true ]; then
log_warning "⚠️ REBOOT REQUIRED FOR NVIDIA DRIVERS ⚠️"
echo ""
log_info "NVIDIA drivers were installed and require a system reboot."
log_info "Please reboot before running the deployment script."
echo ""
echo " After reboot, verify drivers with: nvidia-smi"
echo ""
echo "=========================================="
echo ""
fi
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 ""
if [ "${NVIDIA_REBOOT_NEEDED:-false}" = true ]; then
echo " 2. REBOOT YOUR SYSTEM for NVIDIA drivers to load"
echo " Run: sudo reboot"
echo ""
echo " 3. After reboot, navigate to your AI-Homelab repository:"
else
echo " 2. Navigate to your AI-Homelab repository:"
fi
echo " cd ~/AI-Homelab"
echo ""
echo " 3. Edit the .env file with your configuration:"
echo " cp .env.example .env"
echo " nano .env"
echo ""
if [ "${NVIDIA_REBOOT_NEEDED:-false}" = true ]; then
echo " 4. Run the deployment script:"
else
echo " 3. Run the deployment script:"
fi
echo " ./scripts/deploy-homelab.sh"
echo ""
if [ "${NVIDIA_REBOOT_NEEDED:-false}" = true ]; then
echo " 5. Access Dockge at: https://dockge.yourdomain.duckdns.org"
else
echo " 4. Access Dockge at: https://dockge.yourdomain.duckdns.org"
fi
echo " (Use your configured domain and Authelia credentials)"
echo ""
echo "=========================================="
if lspci | grep -i nvidia > /dev/null && [ "$NVIDIA_INSTALLED" = false ]; then
echo ""
log_warning "REMINDER: Reboot required for NVIDIA driver changes"
echo " Run: sudo reboot"
echo "=========================================="
fi
echo ""
log_info "Setup complete! Please log out and log back in."
log_info "Setup complete!"
if [ "${NVIDIA_REBOOT_NEEDED:-false}" != true ]; then
log_info "Please log out and log back in."
fi