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:
225
.env.example
225
.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
|
||||
|
||||
272
AGENT_INSTRUCTIONS.md
Normal file
272
AGENT_INSTRUCTIONS.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
29
config-templates/homepage/bookmarks.yaml
Normal file
29
config-templates/homepage/bookmarks.yaml
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}}
|
||||
|
||||
149
docker-compose/alternatives.yml
Normal file
149
docker-compose/alternatives.yml
Normal 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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.)"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user