Docker packaging for Server Hub — a self-hosted dashboard for your applications and services.
This repository provides a prebuilt image (ghcr.io/eco-null/server-hub:latest), a CasaOS-ready docker-compose.yml, and the configuration reference for running Server Hub in a container. The image runs non-root with persistent storage and reports the host's system stats.
- Docker with Compose v2
- CasaOS with terminal access, or any Docker Compose-capable host
git(only to fetch this repository's compose file)
git clone https://github.com/eco-null/server-hub-docker.git
cd server-hub-docker
# Set a strong password, then start
docker compose up -dOpen http://:8643 — sign in at /login.
- In CasaOS, go to Apps → Custom App.
- Paste the contents of
docker-compose.yml. - Set
HUB_USERandHUB_PASSWORDin the compose environment block (or the CasaOS environment form). - Install. CasaOS pulls the prebuilt image and starts the container.
| Variable | Default | Description |
|---|---|---|
HUB_USER |
admin |
Sign-in username. |
HUB_PASSWORD |
— (required) | Sign-in password. Server exits if empty. |
HUB_PORT |
8642 |
Container listen port (compose sets 8643). |
HUB_HOST |
0.0.0.0 |
Bind address. |
HUB_DISK_PATH |
/ |
Filesystem path read for the disk widget (/host = CasaOS host root). |
BESZEL_URL |
(empty) | Beszel hub URL, e.g. http://beszel:9520. Empty disables multi-server stats. |
BESZEL_USER |
(empty) | Beszel account name used to fetch system stats. |
BESZEL_PASSWORD |
(empty) | Beszel account password. |
Before first start: replace the placeholder
HUB_PASSWORD: CHANGE_MEindocker-compose.yml. Leaving it unchanged starts the server with a known, weak password.
services.json(links and bookmarks) lives in the bind-mounted host path/DATA/AppData/server-hub(mapped to/datainside the container), symlinked to/app/services.json.- Data survives image updates because it lives on the host path, not in the image.
- Updates:
docker compose pull && docker compose up -d.
The compose file mounts the host's /proc, /etc/hostname, and /etc read-only, so the CPU / memory / disk / hostname widgets report the host's values. HUB_DISK_PATH=/host (backed by a small patch to upstream server.py) makes the disk widget read the host filesystem. If a mount is unavailable, the widget shows —; the app keeps serving.
Set BESZEL_URL plus BESZEL_USER / BESZEL_PASSWORD to monitor all servers registered in your Beszel hub. The Beszel account must be a member of the systems you want to see (add it in the Beszel UI, or enable SHARE_ALL_SYSTEMS on the hub). When Beszel is unconfigured or unreachable, the dashboard falls back to the single-host stats widget.
- The container runs as a non-root
appuser; the entrypoint drops privileges withsu-execbefore starting the server. - The compose file bind-mounts
- /etc:/host:ro, granting the container read access to part of the host filesystem. This is required for host disk stats and is limited to this container's network — do not add other containers to this compose project. - Beszel credentials are server-side environment variables only.
logo.png can be used as the CasaOS custom-app icon — when installing a custom app, point the icon field at this file (e.g. /DATA/AppData/server-hub-docker/logo.png, or wherever you cloned the repository).
| Symptom | Likely cause | Fix |
|---|---|---|
| Container exits immediately | HUB_PASSWORD empty |
Set it in docker-compose.yml. |
Stats show — |
/proc or /host mount unavailable |
Check the compose volumes: block. |
| Port conflict | 8643 in use |
Change the left side of 8643:8643. |
