Homelab Hand Docs
Get started

Installation

Install Homelab Hand with Docker, run it behind HTTPS, and configure it.

Homelab Hand runs as a single Docker container with an SQLite database inside a Docker volume. You can try it on your laptop in a minute, then install it on a server that can reach the machines you want to manage.

Requirements

WhatDetails
Docker (recommended)Docker Engine 24 or later with the Compose plugin, or Docker Desktop on macOS / Windows.
Without DockerPython 3.10 or later. The included run-without-docker.sh sets up a virtualenv for you.
HardwareAnything that runs Docker. The hub typically uses 150–250 MB of RAM (about 140 MB on a lab with every module on). A small VM or LXC, a Raspberry Pi 4/5 or a NAS is plenty.
Network: hub → your machinesSSH (22), Docker API (2376), Hawser (2376), Proxmox (8006), Synology DSM (5000/5001), TrueNAS (443) and the UniFi console (443). Only what you use.
Network: agents → hubEdge agents and Hawser Edge dial out to the hub over HTTPS/WSS, so those hosts need to reach the hub's address.

Where to install it? Pick a machine that's always on and on your main LAN, such as a small Proxmox LXC or a Docker VM. The hub has to reach everything it manages. The Homelab Hand agent covers hosts it can't reach, like a VPS or a machine behind NAT.

Option 1: try it locally

From the project folder on a machine with Docker:

./start.sh

The script:

  • creates .env with a random HUB_SECRET_KEY;
  • builds the image and starts the hub at http://localhost:8080 (use HUB_PORT=9090 ./start.sh to pick another port);
  • mounts your Docker socket and adds it as an environment named after your machine, so there's something to look at straight away.

Stop it with ./stop.sh. To wipe the test data completely:

docker compose -f docker-compose.local.yml down -v

Without Docker, ./run-without-docker.sh creates .venv, installs the dependencies and keeps data in ./data.

Option 2: install on a server

  1. Copy the project to the serverfor example to /opt/htech-hub.
  2. Create the configuration
    cd /opt/htech-hub
    cp .env.example .env
    openssl rand -hex 32      # paste the output into .env as HUB_SECRET_KEY
    Then set HUB_ORIGIN (the address you'll browse to) and HUB_RP_ID (just its hostname). See environment variables.
  3. Start it
    docker compose up -d --build
  4. Optional: manage this server's own Dockeruncomment the Docker socket mount and group_add in docker-compose.yml, then run docker compose up -d again.
  5. Open itand create the first admin account (see First steps).

Back up HUB_SECRET_KEY. It encrypts every stored password, SSH key and API token. If you lose it, those credentials can't be decrypted and you'll have to enter them all again. Keep a copy in your password manager.

Install and update with deploy.sh

From your workstation, deploy.sh does all of the above over SSH and handles every later update with the same command:

DEPLOY_HOST=root@192.168.1.20 ./deploy.sh

It copies the code, creates .env with a secret on the first run only, writes a server compose file (port 8756, Docker socket, auto-registered local environment), builds, starts and waits for the health check. The update swaps the new code in atomically. See Operations for the one-time key setup and options.

HTTPS and reverse proxy

Use HTTPS for anything beyond a quick test. Passkeys require it, and it protects your session cookie, agent tokens and terminal traffic. Any reverse proxy works (Nginx Proxy Manager, Traefik, Caddy or a Cloudflare Tunnel) as long as it:

  • forwards WebSockets (terminals, agents, Hawser Edge, live camera video, the live map);
  • passes X-Forwarded-For and X-Forwarded-Proto;
  • doesn't buffer long responses (log tails and job output stream).

Caddy example:

hub.example.com {
    reverse_proxy hub:8080
}

Then set, in .env:

HUB_ORIGIN=https://hub.example.com
HUB_RP_ID=hub.example.com
HUB_TRUSTED_PROXIES=172.18.0.5      # your proxy / tunnel connector's IP

HUB_TRUSTED_PROXIES matters. Only those addresses may set X-Forwarded-For. Without it, the hub sees every visitor as your proxy, and the login rate limit applies to all of them together.

Using Cloudflare? Follow Cloudflare Tunnel and Cloudflare Access. The iOS app supports Access service tokens.

Environment variables

VariableDefaultPurpose
HUB_SECRET_KEYrequiredEncrypts stored credentials (at least 32 characters). Back it up.
HUB_ORIGINhttp://localhost:8080The URL you browse to. Used for passkeys, agent install commands, links in notifications and cookie security.
HUB_RP_IDlocalhostPasskey (WebAuthn) relying-party ID: the bare hostname of HUB_ORIGIN.
HUB_TRUSTED_PROXIES127.0.0.1Reverse proxy / tunnel IPs or CIDRs whose X-Forwarded-For is trusted, comma-separated.
HUB_RP_NAMEHomelab HandName shown in authenticator apps and passkey prompts.
HUB_COOKIE_SECUREon for httpsMark the session cookie Secure.
HUB_SESSION_HOURS12How long a browser sign-in lasts.
HUB_DATA_DIR/dataDatabase, icon cache, backups and certificates.
HUB_BACKUP_DIR/data/backupsWhere container config and data backups are stored.
HUB_AUTO_LOCALoff1 registers the mounted Docker socket as an environment at start-up.
HUB_DOCKER_SOCKET/var/run/docker.sockSocket used by HUB_AUTO_LOCAL.
HUB_HELPER_IMAGEalpine:3.20Image for the opt-in privileged helper (OS updates / host shell over the Docker API).
HUB_COMPOSE_IMAGEdocker:cliImage for the compose helper (stacks and updates on socket/API environments).
HUB_PUBLIC_URL–The public https address, used by deploy.sh and by Google/Apple sign-in (also settable in the UI).

In-app settings

Most behaviour is set in the UI, under Alerts & Activity → Alert settings and Settings → General:

SettingDefaultWhat it does
Container poll interval30 sHow often container state and stats refresh.
Integration poll interval60 sProxmox, Synology, UniFi, CrowdSec and app integrations. This also drives map traffic.
OS update checkevery 6 hPackage checks on hosts with a command channel.
Image update checkevery 12 hRegistry digest comparison (0 = off).
CPU / memory alert90 %Must last two polls in a row.
NAS temperature alert60 °CSynology and TrueNAS disks and systems.
Alert cooldown30 minThe same alert isn't re-sent within this window.
Muted containers–Glob patterns that never alert, e.g. backup-*.
Alert on unexpected stoponStops done through the hub never alert.
MCP autonomyactapprove queues AI tool calls from MCP for a human.
AI may run host commandsoffEnables the run_host_command AI tool.
Stacks directory/opt/stacksWhere new stacks are written on hosts.
Icon overrides–Map names to dashboard-icons slugs or image URLs.

Updating

With deploy.sh, run the same command again. Otherwise pull or copy the new code and run docker compose up -d --build. Database changes are applied automatically at start-up. Downgrades aren't supported, so take a configuration backup before big jumps.