diff --git a/.env.example b/.env.example index 244b41e..b3134a6 100644 --- a/.env.example +++ b/.env.example @@ -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 diff --git a/AGENT_INSTRUCTIONS.md b/AGENT_INSTRUCTIONS.md new file mode 100644 index 0000000..76af1e3 --- /dev/null +++ b/AGENT_INSTRUCTIONS.md @@ -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. \ No newline at end of file diff --git a/config-templates/authelia/configuration.yml b/config-templates/authelia/configuration.yml index 6dc44b3..45dec66 100644 --- a/config-templates/authelia/configuration.yml +++ b/config-templates/authelia/configuration.yml @@ -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 diff --git a/config-templates/homepage/bookmarks.yaml b/config-templates/homepage/bookmarks.yaml new file mode 100644 index 0000000..c326d9c --- /dev/null +++ b/config-templates/homepage/bookmarks.yaml @@ -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 diff --git a/config-templates/homepage/services.yaml b/config-templates/homepage/services.yaml index 47a5e4c..8e9e176 100644 --- a/config-templates/homepage/services.yaml +++ b/config-templates/homepage/services.yaml @@ -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 - - - 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}} + description: Authentication Portal +- 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 + + - Pi-hole: + icon: pi-hole.png + href: https://pihole.{{HOMEPAGE_VAR_DOMAIN}} + description: Network-wide Ad Blocking -# Dashboards -- Dashboards: +- 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 + + - Authentik: + icon: authentik.png + href: https://authentik.{{HOMEPAGE_VAR_DOMAIN}} + description: Alternative Auth Provider -# Media - Streaming -- Media Streaming: +# 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 - -# Books & Comics -- Books & Comics: +- 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 + - 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: + + - Jellyseerr: + icon: jellyseerr.png + href: https://jellyseerr.{{HOMEPAGE_VAR_DOMAIN}} + description: Media Request Manager + - 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 + + - Mosquitto: + icon: mosquitto.png + href: https://mqtt.{{HOMEPAGE_VAR_DOMAIN}} + description: MQTT Broker - - MotionEye: - icon: motioneye.png - href: https://motioneye.{{HOMEPAGE_VAR_DOMAIN}} - description: Video Surveillance - container: motioneye - -# 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 diff --git a/config-templates/homepage/settings.yaml b/config-templates/homepage/settings.yaml index 6fc2f89..ccae3cf 100644 --- a/config-templates/homepage/settings.yaml +++ b/config-templates/homepage/settings.yaml @@ -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 diff --git a/config-templates/homepage/widgets.yaml b/config-templates/homepage/widgets.yaml index 48ad40d..ce09db5 100644 --- a/config-templates/homepage/widgets.yaml +++ b/config-templates/homepage/widgets.yaml @@ -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}} diff --git a/docker-compose/alternatives.yml b/docker-compose/alternatives.yml new file mode 100644 index 0000000..d118ea1 --- /dev/null +++ b/docker-compose/alternatives.yml @@ -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 + diff --git a/docker-compose/dashboards.yml b/docker-compose/dashboards.yml index 8ff4531..d1888d7 100644 --- a/docker-compose/dashboards.yml +++ b/docker-compose/dashboards.yml @@ -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" diff --git a/docs/docker-guidelines.md b/docs/docker-guidelines.md index 5c3b7c6..40529b8 100644 --- a/docs/docker-guidelines.md +++ b/docs/docker-guidelines.md @@ -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: diff --git a/scripts/deploy-homelab.sh b/scripts/deploy-homelab.sh index 51c9770..aa2943a 100755 --- a/scripts/deploy-homelab.sh +++ b/scripts/deploy-homelab.sh @@ -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.)" diff --git a/scripts/setup-homelab.sh b/scripts/setup-homelab.sh index 995d240..8c984f0 100755 --- a/scripts/setup-homelab.sh +++ b/scripts/setup-homelab.sh @@ -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