Homepage Dashboard¶
Overview¶
Homepage is a modern, fully static, fast, secure fully proxied, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. It provides a single pane of glass for accessing and monitoring all homelab services.
Deployment Details:
- Namespace:
homepage - Chart:
jameswynn/homepagev2.x.x - Image:
ghcr.io/gethomepage/homepage:v1.8.0 - URL: https://home.skaggsfamily.us
- Repository:
flux-repo/apps/_bases/homepageandflux-repo/apps/overlays/prod/homepage
Features¶
- Kubernetes Integration: Real-time cluster metrics via metrics-server
- Service Widgets: API-driven widgets for monitoring services (Sonarr, Radarr, etc.)
- Single Sign-On: Protected by Authelia for secure access
- Responsive Design: Works on desktop, tablet, and mobile
- Customizable: Bookmarks, services, and widgets configured via YAML
Architecture¶
Components¶
- Homepage Pod: Main dashboard application
- ServiceAccount: RBAC for Kubernetes API access (cluster metrics)
- ConfigMap: Service and widget configurations (rendered from HelmRelease values)
- SealedSecrets: API keys for service widget integrations
- IngressRoute: Traefik routing with HTTPS and Authelia middleware
Data Flow¶
User → Traefik (HTTPS) → Authelia (SSO) → Homepage Pod
↓
┌─────────┴──────────┐
↓ ↓
Kubernetes API Service APIs (via secrets)
(cluster metrics) (Sonarr, Radarr, etc.)
Adding Service Widgets¶
Service widgets display real-time data from applications (e.g., Sonarr shows wanted/queued series). Most widgets require API keys for authentication.
Pattern: Individual SealedSecrets per Service¶
To avoid keeping plaintext API keys around, each service gets its own SealedSecret that can be created independently.
Step-by-Step: Adding a New Service Widget¶
1. Get the API Key¶
Find the API key in your service's settings (usually under Settings → General or Settings → API).
Example: Sonarr API key is found at Settings → General → Security → API Key
2. Create a SealedSecret¶
# Set your kubeconfig
export KUBECONFIG=/Users/dskaggs/Projects/homelab/infra-talos/terraform/talos/configs/kubeconfig
# Create the SealedSecret (replace SERVICE_NAME and API_KEY)
# IMPORTANT: The secret key MUST include the HOMEPAGE_VAR_ prefix
kubectl create secret generic homepage-SERVICE_NAME-api \
--from-literal=HOMEPAGE_VAR_SERVICE_NAME_API_KEY=YOUR_API_KEY \
--namespace=homepage \
--dry-run=client -o yaml | \
kubeseal --cert /Users/dskaggs/.ssh/k8s.crt --format yaml > \
/Users/dskaggs/Projects/homelab/flux-repo/apps/overlays/prod/homepage/sealedsecret-SERVICE_NAME.yaml
# Example for Sonarr:
kubectl create secret generic homepage-sonarr-api \
--from-literal=HOMEPAGE_VAR_SONARR_API_KEY=6133eacc718e442593fb806045485ca4 \
--namespace=homepage \
--dry-run=client -o yaml | \
kubeseal --cert /Users/dskaggs/.ssh/k8s.crt --format yaml > \
/Users/dskaggs/Projects/homelab/flux-repo/apps/overlays/prod/homepage/sealedsecret-sonarr.yaml
Result: Creates sealedsecret-SERVICE_NAME.yaml with encrypted API key
3. Add SealedSecret to Production Overlay Kustomization¶
Edit flux-repo/apps/overlays/prod/homepage/kustomization.yaml:
4. Mount Secret in Homepage HelmRelease¶
Edit flux-repo/apps/_bases/homepage/helmrelease.yaml:
# Mount API key secrets as environment variables
envFrom:
- secretRef:
name: homepage-sonarr-api
optional: true
# Add new services here:
# - secretRef:
# name: homepage-radarr-api
# optional: true
Note: The optional: true prevents Homepage from failing if a secret doesn't exist yet.
5. Configure the Service Widget¶
Edit flux-repo/apps/overlays/prod/homepage/kustomization.yaml in the services patch section:
- Media:
- Sonarr:
href: https://sonarr.skaggsfamily.us
description: TV Series Management
icon: sonarr.png
widget:
type: sonarr
url: http://sonarr.autopirate:80 # Cluster-internal service URL
key: "{{HOMEPAGE_VAR_SONARR_API_KEY}}" # Template variable
Important:
- URL: Use the cluster-internal service URL (format:
http://SERVICE_NAME.NAMESPACE:PORT) - Key: Use Homepage's template syntax:
{{HOMEPAGE_VAR_SECRET_KEY_NAME}} - Service port: Verify the correct port with
kubectl get svc -n NAMESPACE
6. Validate and Deploy¶
# Validate Kustomize build
cd /Users/dskaggs/Projects/homelab/flux-repo
kustomize build apps/overlays/prod/homepage > /dev/null && echo "Build successful"
# Commit changes
git add apps/_bases/homepage/helmrelease.yaml \
apps/overlays/prod/homepage/kustomization.yaml \
apps/overlays/prod/homepage/sealedsecret-SERVICE_NAME.yaml
git commit -m "Add SERVICE_NAME widget to Homepage"
git push
# Monitor deployment
export KUBECONFIG=/Users/dskaggs/Projects/homelab/infra-talos/terraform/talos/configs/kubeconfig
kubectl get pods -n homepage -w
Flux will automatically reconcile the changes within 1-2 minutes.
Widget Configuration Reference¶
Finding Widget Documentation¶
Homepage widget documentation: https://gethomepage.dev/widgets/services/
Each widget has specific requirements. Common patterns:
- type: Widget type (e.g.,
sonarr,radarr,prowlarr) - url: Service URL (cluster-internal recommended)
- key: API key (use template variables)
- Optional fields: Vary by widget (check documentation)
Common Service URLs and Ports¶
| Service | Namespace | Service Name | Port | Widget URL |
|---|---|---|---|---|
| Sonarr | autopirate | sonarr | 80 | http://sonarr.autopirate:80 |
| Radarr | autopirate | radarr | 80 | http://radarr.autopirate:80 |
| Prowlarr | autopirate | prowlarr | 80 | http://prowlarr.autopirate:80 |
| SABnzbd | autopirate | sabnzbd | 80 | http://sabnzbd.autopirate:80 |
| Traefik | traefik | traefik | 9000 | http://traefik.traefik:9000 |
Tip: Verify port with kubectl get svc SERVICE_NAME -n NAMESPACE
Environment Variable Naming¶
CRITICAL: The environment variable name in your secret must match the template variable exactly, including the HOMEPAGE_VAR_ prefix.
# Secret MUST contain (with HOMEPAGE_VAR_ prefix):
HOMEPAGE_VAR_SONARR_API_KEY: abc123
# Template references as:
{{HOMEPAGE_VAR_SONARR_API_KEY}}
# ❌ WRONG - This will NOT work:
SONARR_API_KEY: abc123 # Missing HOMEPAGE_VAR_ prefix
Why this matters: Homepage does NOT automatically add the prefix. The template variable {{HOMEPAGE_VAR_SONARR_API_KEY}} looks for an environment variable with that exact name. If your secret key is SONARR_API_KEY, Homepage won't find it and you'll get 401 Unauthorized errors.
Configuration Files¶
Base Configuration¶
Location: flux-repo/apps/_bases/homepage/
helmrelease.yaml: Helm chart deployment with default valuesrbac.yaml: ServiceAccount and ClusterRole for Kubernetes API accessingressroute.yaml: Traefik HTTP and HTTPS routescertificate.yaml: TLS certificate (cert-manager)dnsendpoint.yaml: DNS record (ExternalDNS)kustomization.yaml: Lists all base resources
Production Overlay¶
Location: flux-repo/apps/overlays/prod/homepage/
kustomization.yaml: Patches for production environment (domains, services, widgets)sealedsecret-*.yaml: Individual SealedSecrets for service API keys
Key Configuration Sections¶
Kubernetes Widget¶
Displays cluster metrics (CPU, memory, node count):
widgets:
- kubernetes:
cluster:
show: true
cpu: true
memory: true
showLabel: true
label: "Production Cluster"
nodes:
show: false # Required in v1.8.0+
Service Widget Example (Sonarr)¶
services:
- Media:
- Sonarr:
href: https://sonarr.skaggsfamily.us
description: TV Series Management
icon: sonarr.png
widget:
type: sonarr
url: http://sonarr.autopirate:80
key: "{{HOMEPAGE_VAR_SONARR_API_KEY}}"
Troubleshooting¶
Widget Shows "API Error: Unknown error"¶
Symptoms: Widget displays error with ECONNREFUSED or connection timeout
Common Causes:
- Wrong port: Verify service port with
kubectl get svc -n NAMESPACE - Service not running: Check pod status with
kubectl get pods -n NAMESPACE - Wrong namespace: Ensure service URL matches actual namespace
- API key incorrect: Verify API key in service settings
Fix:
# Check service details
kubectl get svc SERVICE_NAME -n NAMESPACE
# Update widget URL to match service port
# Edit apps/overlays/prod/homepage/kustomization.yaml
# Commit and push changes
Widget Shows "API Error: Unauthorized" (401 Error)¶
Symptoms: Widget displays 401 Unauthorized error, browser console shows errors like:
GET https://home.skaggsfamily.us/api/services/proxy?group=Media&service=Sonarr&index=0&endpoint=queue 401
Most Common Cause: Secret key missing HOMEPAGE_VAR_ prefix
The environment variable name in your secret must match the template variable exactly:
* ✅ Correct: HOMEPAGE_VAR_SONARR_API_KEY=abc123
* ❌ Wrong: SONARR_API_KEY=abc123
Fix:
# 1. Delete the old secret
kubectl delete secret homepage-SERVICE-api -n homepage
# 2. Recreate SealedSecret with correct naming (note HOMEPAGE_VAR_ prefix)
kubectl create secret generic homepage-sonarr-api \
--from-literal=HOMEPAGE_VAR_SONARR_API_KEY=YOUR_API_KEY \
--namespace=homepage \
--dry-run=client -o yaml | \
kubeseal --cert /Users/dskaggs/.ssh/k8s.crt --format yaml > \
apps/overlays/prod/homepage/sealedsecret-sonarr.yaml
# 3. Commit and push
git add apps/overlays/prod/homepage/sealedsecret-sonarr.yaml
git commit -m "Fix SERVICE API key environment variable name"
git push
# 4. Restart Homepage
kubectl rollout restart deployment homepage -n homepage
Verify:
# Check environment variable is correct (should show HOMEPAGE_VAR_ prefix)
kubectl exec -n homepage deployment/homepage -- env | grep SERVICE
Other possible causes:
1. API key is incorrect - verify in service settings
2. Service API endpoint changed - check service documentation
3. Network connectivity issue - test with kubectl exec -n homepage deployment/homepage -- wget -O- SERVICE_URL
Kubernetes Widget Shows TypeError¶
Symptoms: Red error box with "TypeError: Cannot read properties of undefined"
Cause: Homepage v1.8.0+ requires both cluster and nodes sections in Kubernetes widget
Fix: Ensure widget config includes both sections (see Kubernetes Widget example above)
SealedSecret Won't Decrypt¶
Symptoms: Pod events show "MountVolume.SetUp failed"
Common Causes:
- Wrong sealing certificate used
- Namespace mismatch (secret sealed for different namespace)
- SealedSecrets controller not running
Fix:
# Verify SealedSecrets controller is running
kubectl get pods -n kube-system | grep sealed-secrets
# Check certificate path
ls -la /Users/dskaggs/.ssh/k8s.crt
# Recreate SealedSecret with correct cert and namespace
kubectl create secret generic homepage-SERVICE-api \
--from-literal=SERVICE_API_KEY=YOUR_KEY \
--namespace=homepage \
--dry-run=client -o yaml | \
kubeseal --cert /Users/dskaggs/.ssh/k8s.crt --format yaml > sealedsecret-SERVICE.yaml
Security Considerations¶
- API Keys: Never commit plaintext API keys to Git
- SealedSecrets: Encrypted secrets are safe to commit
- Service URLs: Use cluster-internal URLs (no external exposure needed)
- RBAC: Homepage ServiceAccount has minimal permissions (read-only cluster metrics)
- Authentication: All access protected by Authelia SSO
Maintenance¶
Updating Homepage¶
# Update image tag in flux-repo/apps/_bases/homepage/helmrelease.yaml
image:
repository: ghcr.io/gethomepage/homepage
tag: v1.9.0 # Update version
# Commit and push
git add apps/_bases/homepage/helmrelease.yaml
git commit -m "Update Homepage to v1.9.0"
git push
Adding New Services¶
Follow the "Adding Service Widgets" section above. Each new service requires:
- One new SealedSecret file
- One line added to overlay kustomization resources
- One line added to HelmRelease envFrom
- Widget configuration in services section
No need to touch existing secrets or configurations.