Wheelhouse docs

The catalogue#

Forty entries: 37 container apps and three built-in feature modules. Every column is a field of the catalogue schema. The categories are in the order the catalogue declares them; within a category, entries sort case-insensitively by name.

An entry is a recipe for a container the router runs: an image, a set of volumes, some environment, and what the web UI does with the result — link to it, probe whether it answers, and offer the configuration change that wires it into the router. Everything here is what the catalogue says, not what the agent tests.

Check the version you are running:

bash
curl -sk "$R/api/apps/catalog" -H "Authorization: Bearer $T" | python3 -m json.tool | head -20

How to read the tables#

Each category has two tables. The first says what an entry is; the second says what installing it does.

ColumnMeaning
Portscontainer[/protocol][→ host N], from the entry's ports. Documentation, not configuration — nothing stages a port mapping.
Volumessource → destination, with (file) for a single-file bind mount and ro for read-only. Sources are defaults; the operator may override each one at install.
EnvironmentVariable names. A * marks one the entry declares required.
IntegrationWhat the UI does: the app's own web UI, the health probe, dashboard where the entry sets it (the Overview does not list apps, so it changes nothing), and how many hints it offers.
NotesHost networking, privilege, Linux capabilities, the router's cgroups, memory-backed (tmpfs) mounts, a memory limit, and any platform gap the entry says it closes.

The entries#

DNS & filtering#

EntryidWhat it isImage
AdGuard HomeadguardNetwork-wide DNS filtering with per-client policies and a query log.docker.io/adguard/adguardhome:latest
Pi-holepiholeThe original DNS sinkhole, with a long-established blocklist ecosystem.docker.io/pihole/pihole:latest
dnsmasqdnsmasqWildcard DNS, split horizon, per-host DHCP options and an arch-conditional PXE matrix.docker.io/jpillora/dnsmasq:latest
UnboundunboundA validating, recursive resolver — no upstream provider sees your queries.docker.io/mvance/unbound:latest
BlockyblockyA small, fast DNS proxy with blocklists and per-client groups.docker.io/spx01/blocky:latest
idPortsVolumesEnvironmentIntegrationNotes
adguard53/tcp_udp, 3000/config/apps/adguard/work → /opt/adguardhome/work, /config/apps/adguard/conf → /opt/adguardhome/conf—web UI :3000, probe :3000/, dashboard, 1 hint—
pihole53/tcp_udp, 80/config/apps/pihole/etc → /etc/pihole, /config/apps/pihole/dnsmasq.d → /etc/dnsmasq.dTZ, WEBPASSWORD*web UI :80/admin, probe :80/admin/, dashboard, 1 hint—
dnsmasq53/tcp_udp, 8080/config/apps/dnsmasq/dnsmasq.conf (file) → /etc/dnsmasq.conf—web UI :8080, probe :53, 2 hintscaps: net-admin, net-bind-service; closes: Wildcard DNS · per-host DHCP options · PXE architecture matrix
unbound53/tcp_udp/config/apps/unbound → /opt/unbound/etc/unbound—probe :53, 1 hint—
blocky53/tcp_udp, 4000/config/apps/blocky/config.yml (file) → /app/config.yml—probe :4000/, dashboard, 1 hint—

VPN & remote access#

EntryidWhat it isImage
TailscaletailscaleMesh VPN. Advertise the LAN as a subnet route or make the router an exit node.docker.io/tailscale/tailscale:latest
NetBirdnetbirdOpen-source WireGuard mesh you can self-host end to end.docker.io/netbirdio/netbird:latest
HeadscaleheadscaleSelf-hosted control server for Tailscale clients.docker.io/headscale/headscale:latest
WG-Easywg-easyA web UI for WireGuard peers, with QR codes for phones.ghcr.io/wg-easy/wg-easy:latest
CloudflaredcloudflaredExpose an internal service without opening a port on the WAN.docker.io/cloudflare/cloudflared:latest
WireGuardwireguardThe router's own in-kernel WireGuard — tunnels and peers as native config.built-in feature
idPortsVolumesEnvironmentIntegrationNotes
tailscale—/config/apps/tailscale → /var/lib/tailscaleTS_AUTHKEY*, TS_HOSTNAME, TS_ROUTES, TS_STATE_DIR, TS_EXTRA_ARGSdashboard, 1 hinthost network; caps: net-admin, net-raw, sys-module
netbird—/config/apps/netbird → /etc/netbirdNB_SETUP_KEY*—host network; caps: net-admin, sys-admin
headscale8080, 9090/config/apps/headscale/config → /etc/headscale, /config/apps/headscale/data → /var/lib/headscale—web UI :8080, probe :8080/health—
wg-easy51821, 51820/udp/config/apps/wg-easy → /etc/wireguardWG_HOST, PASSWORD_HASHweb UI :51821, probe :51821/, 1 hintcaps: net-admin, sys-module
cloudflared——TUNNEL_TOKEN*1 hint—
wireguard———1 hint—

Monitoring#

EntryidWhat it isImage
ntopngntopngPer-host flow analytics and historical top talkers.docker.io/ntop/ntopng:latest
NetdatanetdataPer-second system metrics with no configuration.docker.io/netdata/netdata:latest
PrometheusprometheusScrape and retain metrics — including Wheelhouse's own.docker.io/prom/prometheus:latest
GrafanagrafanaDashboards over Prometheus, Loki or anything else you point it at.docker.io/grafana/grafana:latest
Node Exporternode-exporterHost metrics for Prometheus, straight off the router.docker.io/prom/node-exporter:latest
Uptime Kumauptime-kumaUptime monitoring with notifications, run from inside the network.docker.io/louislam/uptime-kuma:latest
Speedtest Trackerspeedtest-trackerRuns a speed test on a schedule and keeps the history.ghcr.io/linuxserver/speedtest-tracker:latest
OpenSpeedTestopenspeedtestA LAN-side speed test target — measures the network, not the internet.docker.io/openspeedtest/latest:latest
LibreSpeedlibrespeedA lighter LAN speed test with no Flash, Java or dependencies.docker.io/linuxserver/librespeed:latest
idPortsVolumesEnvironmentIntegrationNotes
ntopng3000/config/apps/ntopng → /var/lib/ntopng—web UI :3000, probe :3000/, dashboard, 1 hinthost network; caps: net-admin, net-raw
netdata19999/config/apps/netdata/config → /etc/netdata, /config/apps/netdata/lib → /var/lib/netdata, /proc → /host/proc ro, /sys → /host/sys ro—web UI :19999, probe :19999/api/v1/info, dashboardhost network; caps: sys-admin
prometheus9090/config/apps/prometheus/prometheus.yml (file) → /etc/prometheus/prometheus.yml, /config/apps/prometheus/data → /prometheus—web UI :9090, probe :9090/-/healthy, dashboard, 1 hint—
grafana3000/config/apps/grafana → /var/lib/grafanaGF_SECURITY_ADMIN_PASSWORD*web UI :3000, probe :3000/api/health, dashboard—
node-exporter9100/proc → /host/proc ro, /sys → /host/sys ro—probe :9100/metricshost network
uptime-kuma3001/config/apps/uptime-kuma → /app/data—web UI :3001, probe :3001/, dashboard—
speedtest-tracker80/config/apps/speedtest-tracker → /configAPP_KEY*, DB_CONNECTIONweb UI :80, probe :80/, 1 hint—
openspeedtest3000, 3001——web UI :3000, probe :3000/—
librespeed80——web UI :80, probe :80/—

Security#

EntryidWhat it isImage
CrowdSeccrowdsecParses logs, detects attacks, and shares signals with a community blocklist.docker.io/crowdsecurity/crowdsec:latest
ZeekzeekNetwork security monitor that turns traffic into structured logs.docker.io/zeek/zeek:latest
VaultwardenvaultwardenA Bitwarden-compatible password server, kept on your own hardware.docker.io/vaultwarden/server:latest
Suricata IDSsuricataThe IDS VyOS ships: Suricata watching interfaces you name, driven from the config tree.built-in feature
idPortsVolumesEnvironmentIntegrationNotes
crowdsec8080/config/apps/crowdsec/config → /etc/crowdsec, /config/apps/crowdsec/data → /var/lib/crowdsec/data, /var/log → /var/log/host ro—probe :8080/health, 1 hint—
zeek—/config/apps/zeek/logs → /usr/local/zeek/logs, /config/apps/zeek/etc → /usr/local/zeek/etc——host network; caps: net-admin, net-raw
vaultwarden80/config/apps/vaultwarden → /dataADMIN_TOKEN, SIGNUPS_ALLOWEDweb UI :80, probe :80/alive—
suricata———1 hint—

Network services#

EntryidWhat it isImage
Nginx Proxy ManagernpmReverse proxy with a UI and automatic Let's Encrypt certificates.docker.io/jc21/nginx-proxy-manager:latest
CaddycaddyA reverse proxy that gets its own certificates with no configuration.docker.io/library/caddy:latest
TraefiktraefikDynamic reverse proxy that discovers containers as they appear.docker.io/library/traefik:latest
netboot.xyznetbootxyzNetwork-boot installers for anything, without building a PXE tree.ghcr.io/linuxserver/netbootxyz:latest
MosquittomosquittoAn MQTT broker for the IoT half of the network.docker.io/library/eclipse-mosquitto:latest
idPortsVolumesEnvironmentIntegrationNotes
npm80, 443, 81/config/apps/npm/data → /data, /config/apps/npm/letsencrypt → /etc/letsencrypt—web UI :81, probe :81/, dashboard, 2 hints—
caddy80, 443/config/apps/caddy/Caddyfile (file) → /etc/caddy/Caddyfile, /config/apps/caddy/data → /data—probe :80/—
traefik80, 443, 8080/config/apps/traefik → /etc/traefik—web UI :8080, probe :8080/ping—
netbootxyz3000, 69/udp, 80/config/apps/netbootxyz/config → /config, /config/apps/netbootxyz/assets → /assets—web UI :3000, probe :3000/, 1 hintcloses: PXE architecture matrix (with dnsmasq)
mosquitto1883, 9001/config/apps/mosquitto/config → /mosquitto/config, /config/apps/mosquitto/data → /mosquitto/data—probe :1883—

Management#

EntryidWhat it isImage
PortainerportainerContainer management for everything running on the router.docker.io/portainer/portainer-ce:latest
HomepagehomepageA start page that links every service on the network.ghcr.io/gethomepage/homepage:latest
HomerhomerA static start page — one YAML file, no runtime.docker.io/b4bz/homer:latest
ntfyntfyPush notifications from scripts, over HTTP.docker.io/binwiederhier/ntfy:latest
GotifygotifySelf-hosted push notifications with an Android client.docker.io/gotify/server:latest
WatchYourLANwatchyourlanNotices when a device appears on the network that has not been seen before.docker.io/aceberg/watchyourlan:latest
DozzledozzleLive container logs in a browser, no storage, no setup.docker.io/amir20/dozzle:latest
IT Toolsit-toolsA pile of offline network and encoding tools in one page.ghcr.io/corentinth/it-tools:latest
Wiki.jswikijsSomewhere to write down why the config is the way it is.ghcr.io/requarks/wiki:latest
UniFi OS Serverunifi-os-serverUbiquiti's UniFi OS Server, for UniFi access points, switches and gateways. Packaged by UniHosted; neither Ubiquiti nor Wheelhouse publishes the image.ghcr.io/unihosted/unifi-os-server-docker:5.1.40
idPortsVolumesEnvironmentIntegrationNotes
portainer9443, 9000/config/apps/portainer → /data, /run/podman/podman.sock → /var/run/docker.sock—web UI :9000, probe :9000/, 1 hint—
homepage3000/config/apps/homepage → /app/config—web UI :3000, probe :3000/—
homer8080/config/apps/homer → /www/assets—web UI :8080, probe :8080/—
ntfy80/config/apps/ntfy/cache → /var/cache/ntfy, /config/apps/ntfy/etc → /etc/ntfy—web UI :80, probe :80/v1/health—
gotify80/config/apps/gotify → /app/dataGOTIFY_DEFAULTUSER_PASS*web UI :80, probe :80/health—
watchyourlan8840/config/apps/watchyourlan → /dataIFACESweb UI :8840, probe :8840/, 1 hinthost network; caps: net-admin, net-raw
dozzle8080/run/podman/podman.sock → /var/run/docker.sock ro—web UI :8080, probe :8080/—
it-tools80——web UI :80, probe :80/—
wikijs3000/config/apps/wikijs → /wiki/dataDB_TYPE, DB_FILEPATHweb UI :3000, probe :3000/—
unifi-os-server443, 8080, 8443, 3478/udp, 10003/udp, 5514/udp, 6789/config/apps/unifi-os-server/uosserver → /var/lib/uosserver, /config/apps/unifi-os-server/unifi → /var/lib/unifi, /config/apps/unifi-os-server/data → /data, /sys/fs/cgroup → /sys/fs/cgroupUOS_SYSTEM_IP*, TZ, MONGO_INTERNALweb UI :443 (https), probe :443, dashboardcaps: net-admin, net-raw; the router's cgroups; tmpfs on /run, /run/lock, /tmp, /var/lib/journal, /var/opt/unifi/tmp and /data/unifi-core/config/http; memory 2048 MB

The built-in entries#

wireguard and suricata are kind: "builtin" entries over features of the router itself, and upnp is a third, over the agent's own UPnP and NAT-PMP service. None is a container: each gates a native page in the web UI, and "installing" one stages nothing at all. The agent says so:

This is a built-in feature, not a container — installing it enables its page instantly
and stages nothing.

Each declares a config_path. If configuration exists under that path, the page stays visible whether or not the feature is enabled — a page must never be hidden while the configuration it edits is live on the router.

What is absent#

Installing one#

Three things have to be true before the router will commit a container: the image must be on the router, every volume source must exist, and the configuration must be valid. Installing is therefore four calls.

bash
# 1. What would be staged, and is the image here yet?
curl -sk -X POST "$R/api/apps/plan" -H "Authorization: Bearer $T" \
  -H 'Content-Type: application/json' \
  -d '{"app_id":"adguard","name":"adguard","address":"10.99.0.10"}'

# 2. Pull the image onto the router.
curl -sk -X POST "$R/api/apps/pull" -H "Authorization: Bearer $T" \
  -H 'Content-Type: application/json' -d '{"app_id":"adguard"}'

# 3. Create the volume sources.
curl -sk -X POST "$R/api/apps/prepare" -H "Authorization: Bearer $T" \
  -H 'Content-Type: application/json' \
  -d '{"app_id":"adguard","name":"adguard"}'

# 4. Stage the operations from step 1, then commit them in the Commit Bar.

Lifecycle is configuration too#

Stopping an app stages set container name <n> disable and starting it deletes that node; the platform offers no operational verb for either. Restarting has both forms: the router's own restart container <n>, which commits nothing and writes no revision, and the two-commit bounce, where a failed second commit leaves the app down and the API says so in those words.

See also#

Updated 2026-09-02 catalogue apps containers