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

Homepage: one start page for every app — Icons, green dots, and live numbers from each service.

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

TaskWhat
Folder~/docker/homepage/compose.yaml + config/
Webhttp://server-ip:3005
Appsconfig/services.yaml
Bookmarksconfig/bookmarks.yaml
Top widgetsconfig/widgets.yaml
Iconsicon: 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.

Call us