How to Install Homepage (One Start Page for Every App on Your Server)

Forty services and forty bookmarks is where most home servers end up. Homepage replaces them with one page: tiles for every app with icons, a green dot if it's up, and widgets that pull real numbers from them — Pi-hole's blocked count, Jellyfin's streams, Uptime Kuma's status, the server's CPU and disk. It's configured in a few YAML files and looks good on a phone. Make it the browser start page on every computer in the house.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/homepage/compose.yaml + config/ |
| Web | http://server-ip:3005 |
| Apps | config/services.yaml |
| Bookmarks | config/bookmarks.yaml |
| Top widgets | config/widgets.yaml |
| Icons | icon: jellyfin.png from the Dashboard Icons set, or si-nextcloud, mdi-home |
1. The compose file
mkdir -p ~/docker/homepage/config && cd ~/docker/homepage
nano compose.yaml
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
ports:
- "3005:3000"
environment:
HOMEPAGE_ALLOWED_HOSTS: 192.168.1.50:3005,home.example.com
PUID: 1000
PGID: 1000
volumes:
- ./config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro
- /:/host:ro
restart: unless-stopped
HOMEPAGE_ALLOWED_HOSTS must list every address you'll open it on. The Docker socket (read-only) lets it show container status; /host lets the disk widget see the real disks.
docker compose up -d
sudo ufw allow from 192.168.1.0/24 to any port 3005
Open http://192.168.1.50:3005. It generates default config files on first start; now edit them.
2. Your apps
nano config/services.yaml
- Media:
- Jellyfin:
icon: jellyfin.png
href: https://media.example.com
description: Films and TV
server: my-docker
container: jellyfin
widget:
type: jellyfin
url: http://192.168.1.50:8096
key: {{HOMEPAGE_VAR_JELLYFIN_KEY}}
- Navidrome:
icon: navidrome.png
href: http://192.168.1.50:4533
container: navidrome
- Network:
- Pi-hole:
icon: pi-hole.png
href: http://192.168.1.50/admin
widget:
type: pihole
url: http://192.168.1.50
version: 6
key: {{HOMEPAGE_VAR_PIHOLE_KEY}}
- Uptime Kuma:
icon: uptime-kuma.png
href: http://192.168.1.50:3001
widget:
type: uptimekuma
url: http://192.168.1.50:3001
slug: home
- Admin:
- Portainer:
icon: portainer.png
href: https://192.168.1.50:9443
- Cockpit:
icon: cockpit.png
href: https://192.168.1.50:9090
Groups become columns; each app is a tile. container: plus the Docker entry below turns on the green/red status dot. widget: pulls live data — Homepage supports well over a hundred apps; the docs list each one's settings.
Keep API keys out of the YAML: put them in .env as HOMEPAGE_VAR_JELLYFIN_KEY=... and refer to them as above.
nano config/docker.yaml
my-docker:
socket: /var/run/docker.sock
3. The top bar
nano config/widgets.yaml
- resources:
cpu: true
memory: true
disk: /host/mnt/data
uptime: true
- search:
provider: duckduckgo
target: _blank
- openmeteo:
label: Home
latitude: 51.5
longitude: -0.1
units: metric
- datetime:
format:
dateStyle: long
timeStyle: short
CPU, memory, the data drive, a search box, the weather and the time, across the top.
4. Bookmarks
nano config/bookmarks.yaml
- Everyday:
- Email: [{ abbr: GM, href: https://mail.google.com }]
- Calendar: [{ abbr: CA, href: https://calendar.google.com }]
- Docs:
- BookStack: [{ icon: bookstack.png, href: http://192.168.1.50:6875 }]
5. Make it the start page
Browser settings → On startup / Home page → http://192.168.1.50:3005 (or https://home.example.com behind the proxy). On phones, add it to the home screen. The layout collapses to one column on a narrow screen.
settings.yaml has the look: theme: dark, color: slate, layout: to set some groups as rows, headerStyle: boxed, a background image.
Troubleshooting
"Host validation failed". Add the address you used to HOMEPAGE_ALLOWED_HOSTS and restart.
Status dots missing. docker.yaml isn't there or the socket isn't mounted; container: must match the container name exactly.
A widget shows an error. Wrong URL (use the LAN address Homepage can reach, not the proxy), wrong API key, or the service's widget needs a different field — check the docs page for that widget.
Icon doesn't appear. The name must match the Dashboard Icons repository (jellyfin.png), or use a Simple Icons / Material name (si-jellyfin, mdi-film).
Wrapping up
One container, three YAML files, API keys in .env. Every app in one place with live numbers, a status dot that tells you something's down before you click it, and a start page the whole house uses without knowing what a port is.
