Homepage
A self-hosted application dashboard with service widgets and cluster metrics.
Homepage is a modern, highly customizable start page that aggregates links and live status widgets from self-hosted services. It can discover Kubernetes ingresses automatically and query service APIs to show counts, queue depths, and usage stats. Self-hosting keeps your dashboard private and accessible only on your internal network.
Alternatives considered
Self Hosted
| Tool | Open Source | Full Features | Notes |
|---|---|---|---|
| Heimdall | Yes | Yes | Simple link dashboard, no live widgets |
| Homarr | Yes | Yes | Widget-based, active development |
| Dasherr | Yes | Yes | Minimal start page |
Installation
Architecture
- Deployment: Single
homepagedeployment in thehomepagenamespace; NetBird sidecar for VPN connectivity - Images:
ghcr.io/gethomepage/homepage,netbirdio/netbird, both digest-pinned via Renovate - RBAC: ClusterRole granting read access to namespaces, pods, nodes, ingresses, and metrics
- Config: Multiple ConfigMaps for
services.yaml,bookmarks.yaml,kubernetes.yaml,proxmox.yaml - Networking: HTTPRoute via internal gateway
Security
allowPrivilegeEscalation: false, capabilities dropped on homepage container- NetBird sidecar requires
NET_ADMINcapability (VPN tunnel) - No persistent storage; stateless application
Updates
Managed by Renovate. Both images are digest-pinned.
Data Management
No persistent storage. All configuration is in ConfigMaps (version-controlled in git).
User Management
No OIDC or authentication configured. Access restricted to internal network via HTTPRoute.
Configuration Management
- Service definitions, bookmarks, and widget config from multiple ConfigMaps
- API keys for widgets injected as environment variables (
HOMEPAGE_VAR_*) from a SOPS-encrypted secret
Usage
Access the dashboard to view all self-hosted services and their live status widgets. Widget data is pulled from Sonarr, Radarr, Lidarr, Transmission, Audiobookshelf, and Immich APIs. The Kubernetes integration shows cluster node and pod health.
Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/homepage/talos/README.md.
Cluster Deployment
Homepage — Talos cluster
- Image:
ghcr.io/gethomepage/homepage:v2.5.0@sha256:57c4a0531937889c0b968b120fe9c2560bbe036b5c9e18c49a9e2479de9975d1 - Image:
netbirdio/netbird:0.81.2@sha256:6242a1fbaf6b611c00c26a914cbbea512c30c18a45de0646ce7b0e5d93a21e67
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app.kubernetes.io/name: homepage
name: homepage
namespace: homepage
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app.kubernetes.io/name: homepage
strategy:
rollingUpdate: null
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: homepage
spec:
automountServiceAccountToken: true
containers:
- env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: homepage.int.kueber.eu
envFrom:
- secretRef:
name: homepage-variables
image: ghcr.io/gethomepage/homepage:v2.5.0@sha256:57c4a0531937889c0b968b120fe9c2560bbe036b5c9e18c49a9e2479de9975d1
imagePullPolicy: Always
name: homepage
ports:
- containerPort: 3000
name: http
protocol: TCP
resources:
limits:
memory: 384Mi
requests:
cpu: 25m
memory: 192Mi
volumeMounts:
- mountPath: /app/config/
name: homepage-config
- mountPath: /app/config/logs
name: logs
dnsPolicy: ClusterFirst
enableServiceLinks: true
initContainers:
- env:
- name: NB_SETUP_KEY
valueFrom:
secretKeyRef:
key: NB_SETUP_KEY
name: homepage-netbird
image: netbirdio/netbird:0.81.2@sha256:6242a1fbaf6b611c00c26a914cbbea512c30c18a45de0646ce7b0e5d93a21e67
name: sidecar-netbird
restartPolicy: Always
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_ADMIN
- NET_RAW
drop:
- ALL
startupProbe:
exec:
command:
- sh
- -c
- netbird status | grep -q Connected
failureThreshold: 30
periodSeconds: 2
priorityClassName: tier-3
serviceAccountName: homepage
volumes:
- configMap:
name: homepage-config-9hf25d5557
name: homepage-config
- name: homepage-variables
secret:
secretName: homepage-variables
- emptyDir: {}
name: logs