Once you run more than a handful of self-hosted apps, you need one place to find them all. Homepage (gethomepage) is a fast, highly configurable dashboard that lists your services with icons, and shows live widgets: container status, CPU and memory, download queues, media server activity, weather and more. It’s configured in YAML files, so it’s easy to version and reproduce.
A simpler alternative: Heimdall.
Install with Docker
# /opt/homepage/compose.yaml
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
HOMEPAGE_ALLOWED_HOSTS: dash.example.com
volumes:
- ./config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro # optional: container status
cd /opt/homepage && docker compose up -d
On first start, example config files appear in ./config: settings.yaml, services.yaml, widgets.yaml, bookmarks.yaml and docker.yaml.
HOMEPAGE_ALLOWED_HOSTS must include the hostname you’ll use. Recent versions reject other hosts for security.
About the Docker socket: mounting it, even read-only, gives the container insight into, and in practice potential control over, your Docker host. Use a socket proxy (tecnativa/docker-socket-proxy) with only read permissions where possible. See Docker security.
services.yaml
- Media:
- Jellyfin:
href: https://jellyfin.example.com
icon: jellyfin.png
description: Movies and shows
widget:
type: jellyfin
url: http://jellyfin:8096
key: "{{HOMEPAGE_VAR_JELLYFIN_KEY}}"
- Infrastructure:
- Uptime Kuma:
href: https://status.example.com
icon: uptime-kuma.png
widget:
type: uptimekuma
url: http://uptime-kuma:3001
slug: main
- Portainer:
href: https://portainer.example.com
icon: portainer.png
server: local
container: portainer
server/containershow live container status (viadocker.yaml).- Widgets exist for over a hundred apps: Proxmox, Sonarr/Radarr, qBittorrent, Pi-hole, AdGuard Home, Nextcloud, Immich, Gitea, Grafana and more. Each needs an API URL and key.
- Keep secrets out of YAML. Use
{{HOMEPAGE_VAR_…}}or{{HOMEPAGE_FILE_…}}placeholders with environment variables or files.
See Uptime Kuma and Portainer.
widgets.yaml: system info at the top
- resources:
cpu: true
memory: true
disk: /
- search:
provider: duckduckgo
target: _blank
- datetime:
format:
dateStyle: long
timeStyle: short
Docker label discovery
Instead of editing services.yaml, label your containers:
labels:
- homepage.group=Media
- homepage.name=Navidrome
- homepage.icon=navidrome.png
- homepage.href=https://music.example.com
- homepage.description=Music streaming
Homepage discovers them automatically. See Navidrome.
Expose it securely
A dashboard reveals your whole infrastructure, and widgets talk to your services’ APIs. Don’t publish it openly:
- put it behind your reverse proxy with authentication: Authelia or Authentik forward auth, Cloudflare Access, or at least HTTP basic auth. See Authelia and Nginx basic auth;
- or keep it on a VPN only (Tailscale, WireGuard). See Tailscale.
Nginx example (with basic auth):
server {
server_name dash.example.com;
auth_basic "Dashboard";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
}
# listen 443 ssl; certbot
}
Customise
settings.yaml controls the title, theme, colour, background image, layout (columns per group) and language. Custom CSS and JS are supported. Icons come from the dashboard-icons collection by name (jellyfin.png), or from Simple Icons and Material Design icons (si-…, mdi-…).
Backup and updates
Back up ./config. That’s your entire dashboard. Keep it in Git for history. Update with docker compose pull && docker compose up -d. See updating self-hosted apps.
Quick reference
| File | Purpose |
|---|---|
services.yaml |
Service groups, links, widgets |
widgets.yaml |
Top widgets (resources, search, weather) |
bookmarks.yaml |
Link lists |
docker.yaml |
Docker hosts for container status |
settings.yaml |
Theme, layout, title |
Related: Heimdall and Docker Compose.