8.4 KiB
Homepage Dashboard — Adding Machines, Tabs & Services
This guide covers how to add new machines, tabs, and services to the Homepage dashboards on homeserver-1 (and, by extension, any host that imports the Homepage module).
Overview
Homepage (https://gethomepage.dev) is a self-hosted dashboard. All dashboard
configuration lives in Nix and is rendered to YAML files that Homepage reads
at /etc/homepage-dashboard/.
| Item | Location |
|---|---|
| Homepage NixOS module (service wrapper) | modules/services/homepage.nix |
| Dashboard definition for homeserver-1 | hosts/homeserver-1/homepage.nix |
| Deployed config files | /etc/homepage-dashboard/{settings,services,widgets}.yaml |
| API keys / secrets | secrets.yaml (SOPS) → HOMEPAGE_VAR_* env vars |
The dashboard definition is split from the host config so it's easy to edit:
hosts/homeserver-1/configuration.nixenables Glances + firewall and imports:imports = [ # ... ./homepage.nix ];
Applying Changes
After editing homepage.nix:
nixos-rebuild switch --target-host petere@homeserver-1 --flake .#homeserver-1 --use-remote-sudo
Important: Homepage reads its config files when the service starts. After a
nixos-rebuild, the unit's definition usually changes, but if only the contents of the config files changed (e.g. just editinghomepage.nix), the service may keep the old config in memory. If your changes don't appear, restart it:ssh petere@homeserver-1 "sudo systemctl restart homepage-dashboard"
Structure of the Dashboard Definition
hosts/homeserver-1/homepage.nix has three main parts:
services.homepage = {
enable = true;
port = 8082;
allowedHosts = [ ... ]; # Host header values Homepage responds to
environmentFiles = [ ... ]; # SOPS-secret env file with HOMEPAGE_VAR_* keys
settings = {
title = "HomeServer";
# ...
layout = { ... }; # Controls grouping, tabs, and column widths
};
services = [ ... ]; # The service groups and tiles (services.yaml)
widgets = [ ... ]; # Header info widgets (resources, search, clock)
};
Tabs
Tabs are enabled by adding a tab field to a group's layout entry.
- Groups with the same
tabvalue appear on that tab. - Groups with no
tabappear on every tab. - Tabs are sorted by their order in the
layoutblock. - Each tab is deep-linkable:
#monitoring,#homeserver-1, etc.
Current tabs:
Monitoring (default tab)
├── Homeserver-1 Monitoring → 5 Glances tiles (localhost)
└── MCF Server Monitoring → 5 Glances tiles (mcf-server via tailnet)
Homeserver-1 (#homeserver-1)
├── Media → Jellyfin, Immich
└── System → Backrest, Pocket ID, Tailscale
MCF Server (reserved; uncomment the placeholder to enable)
Adding a Service
-
Add the service tile to the relevant group in the
serviceslist:services = [ # ... { System = [ # ...existing tiles... { MyService = { icon = "sh-myservice"; href = "http://homeserver-1.gerbil-opah.ts.net:<port>"; description = "What it does"; siteMonitor = "http://127.0.0.1:<port>"; # green/red status widget = { # optional live stats type = "myservice"; url = "http://127.0.0.1:<port>"; key = "{{HOMEPAGE_VAR_MYSERVICE_API_KEY}}"; # only if it needs a key }; }; } ]; } ]; -
Set the layout so the group renders where you want (columns = how many tiles per row; groups span the full width with
style = "row"when they're a single top-level group):layout = { # ... MyService = { # or add to an existing group's entry tab = "Homeserver-1"; style = "row"; columns = 4; }; }; -
API keys: never hardcode secrets. Add the value to
secrets.yamlunder the machine section and reference it via the environment file. The secrethomeserver-1/homepage-envalready providesHOMEPAGE_VAR_JELLYFIN_API_KEY,HOMEPAGE_VAR_IMMICH_API_KEY,HOMEPAGE_VAR_TAILSCALE_API_KEYandHOMEPAGE_VAR_TAILSCALE_DEVICEID. To add another:sops --set '["homeserver-1"]["homepage-env"] "HOMEPAGE_VAR_MYSERVICE_API_KEY=<value>"' secrets.yaml(This replaces the whole env file — include every existing
HOMEPAGE_VAR_*line when setting it.)
Adding a Tab
Add a new group to services and give it a tab in the layout:
# services
{
"My New Group" = [
{ "MyService" = { href = "..."; }; }
];
}
# layout
"My New Group" = {
tab = "My Tab";
style = "row";
columns = 4;
};
Adding a New Machine to the Dashboard
To monitor another machine (e.g. richmond-server):
1. Enable Glances on the target machine
Add to that host's configuration.nix (Glances exposes system stats to the
dashboard):
services.glances = {
enable = true;
port = 61208;
extraArgs = [ "--webserver" ];
};
# Expose on Tailscale only
networking.firewall.interfaces.tailscale.allowedTCPPorts = [ 61208 ];
2. Add the monitoring group
In hosts/homeserver-1/homepage.nix, add a group with Glances tiles. The
group name must be unique — Homepage's widget proxy resolves widget config by
leaf group name, so duplicate group names cause one machine's stats to display
on another's tiles.
# services
{
"Richmond Server Monitoring" = [
{ "System" = { widget = { type = "glances"; url = "http://richmond-server.gerbil-opah.ts.net:61208"; version = 4; metric = "info"; }; }; }
{ "CPU" = { widget = { type = "glances"; url = "http://richmond-server.gerbil-opah.ts.net:61208"; version = 4; metric = "cpu"; }; }; }
{ "Memory" = { widget = { type = "glances"; url = "http://richmond-server.gerbil-opah.ts.net:61208"; version = 4; metric = "memory"; }; }; }
{ "Disk" = { widget = { type = "glances"; url = "http://richmond-server.gerbil-opah.ts.net:61208"; version = 4; metric = "fs:/"; }; }; }
{ "Processes" = { widget = { type = "glances"; url = "http://richmond-server.gerbil-opah.ts.net:61208"; version = 4; metric = "process"; }; }; }
];
}
# layout
"Richmond Server Monitoring" = {
tab = "Monitoring";
style = "row";
columns = 5;
};
3. Add non-monitoring services for that machine
Add a group and give it its own tab (or reuse an existing one):
# services
{
"Richmond Server Apps" = [
{ "Ntfy" = { icon = "sh-ntfy"; href = "http://richmond-server.gerbil-opah.ts.net:8080"; }; }
];
}
# layout
"Richmond Server Apps" = {
tab = "Richmond Server";
style = "row";
columns = 4;
};
4. (Optional) Tailscale widget for the machine
Each machine's Tailscale node can be shown with its own widget, using the machine's numeric device ID (find it via the Tailscale API/admin console):
{
"Richmond Server" = [
{
Tailscale = {
icon = "sh-tailscale";
href = "https://login.tailscale.com/admin/machines";
widget = {
type = "tailscale";
deviceid = "<numeric-device-id>"; # NOT the ...CNTRL value
key = "{{HOMEPAGE_VAR_TAILSCALE_API_KEY}}";
};
};
}
];
}
Troubleshooting
| Symptom | Cause / Fix |
|---|---|
| Changes not appearing | Service not restarted — run sudo systemctl restart homepage-dashboard |
t.metric is undefined |
Glances widget missing the metric field — every glances tile needs metric (e.g. cpu, memory, fs:/, process, info) |
no manageable device matching this ID found |
Tailscale widget deviceid is wrong — must be the numeric device ID, not the ...CNTRL value |
| Two machines show the same stats | Duplicate group names — every group (especially monitoring) needs a unique name |
Host validation failed |
The Host header isn't in allowedHosts — add the hostname (with port) to allowedHosts |
| API keys showing in config | Keys must come from the SOPS env file (HOMEPAGE_VAR_*), never hardcoded |
Glances Metrics
The Glances widget (type = "glances") requires a version and metric:
version = 4for Glances v4.x (installed)metric:info(system summary),cpu,memory,process,containers,fs:/(disk usage),network:<iface>,sensor:<id>,disk:<id>,gpu:<id>