Installing the hub
nkt hub is the same binary in another mode. The hub goes on one machine and from there installs and maintains nkt on the other hosts over SSH; each host opens in the hub's UI as the same panel a standalone nkt has. What the hub can do — on the Hub page.
By default the hub is a regular systemd service with the same least-privilege principle as nkt. Docker and Kubernetes are self-contained alternatives.
Requirements
- A machine for the hub — Linux. The hub also scans and manages this very machine (the "localhost" row in the host list), so its unit needs the same privilege profile as nkt: root with a restricted capability set. Installing Go is optional: if the hub builds binaries from source and there is no system
go, it downloads Go from go.dev into its data directory. - SSH from the hub to every host: address, port,
rootor a user with passwordlesssudo, a password or a key. Installation puts files into/usr/local/bin,/etc/systemd/system,/etc/netknownsthat. - Hosts — Linux amd64, arm64 or 32-bit ARM (Raspberry Pi — armv6l/armv7l). Nothing needs to be installed on them in advance. The hub's own architecture does not matter: the host binary is built or downloaded for the host's architecture.
- The hub needs no public address. It connects to the hosts itself; incoming connections are only needed from your browser (and from CI if webhooks go straight to it — see nkt-edge).
Option 1. systemd from the prebuilt binary
The binary is the same as for a host; the unit and env file are the hub's own:
sudo install -d -m 0750 /etc/netknownsthat
curl -fsSL https://raw.githubusercontent.com/piqab/nkt/main/deploy/hub.env.example \
| sudo install -m 0640 /dev/stdin /etc/netknownsthat/hub.env
curl -fsSL https://raw.githubusercontent.com/piqab/nkt/main/deploy/netknownsthat-hub.service \
| sudo install -m 0644 /dev/stdin /etc/systemd/system/netknownsthat-hub.service
sudo $EDITOR /etc/netknownsthat/hub.env
sudo systemctl daemon-reload
sudo systemctl enable --now netknownsthat-hub
sudo journalctl -u netknownsthat-hub -n 30 # admin passwordThere is no source on such a machine, so the hub downloads the nkt binary for a new host from GitHub Releases, the same version as the hub itself, and verifies SHA256SUMS. Outbound access to github.com is required.
Option 2. systemd from source
The hub cross-compiles nkt for every host from a clone of the repository — this works without GitHub access and with any version, even an unreleased one:
git clone https://github.com/piqab/nkt.git /opt/netknownsthat
cd /opt/netknownsthat
make build # or make native-build without Docker
sudo make hub-install
sudo systemctl enable --now netknownsthat-hubhub-install puts the binary into /usr/local/bin/nkt, the netknownsthat-hub.service unit and a template /etc/netknownsthat/hub.env, where NKT_HUB_SOURCE_ROOT already points to /opt/netknownsthat. The clone lives outside the data directory; update it together with the hub: git pull && make build && sudo make hub-install. Builds are cached — a second host of the same architecture installs without a rebuild.
Check that it came up:
curl -s http://127.0.0.1:8077/api/health
journalctl -u netknownsthat-hub -fOption 3. Docker Compose
The ghcr.io/piqab/nkt-hub image is published for every release, no docker login needed:
curl -fsSLO https://raw.githubusercontent.com/piqab/nkt/main/deploy/docker-compose.hub.release.yml
docker compose -f docker-compose.hub.release.yml up -d
docker compose -f docker-compose.hub.release.yml logs hub # admin password
curl -s http://127.0.0.1:8443/api/health- The UI port is
8443on the host (inside the container8077, the hub listens on0.0.0.0, otherwise publishing the port wouldn't work);8446— port forwards. Put your own reverse proxy with TLS in front of it unless it's just a local test. - Data lives in the
nkt-hub-datavolume (/var/lib/netknownsthatin the container): the database, the encryption key, caches. - The hub in the container runs not as root (user
nkt, uid 1000). A volume from an old version created by root has to be handed over to that user once — the hub exits on start with a clear error and the command:bash(the volume name — indocker run --rm -v nkt-hub-data:/data alpine chown -R 1000:1000 /datadocker volume ls). - Every release ships
docker-compose.hub.release.ymlwith the exact version of the image instead of:latest(its checksum is inSHA256SUMS): a mutable tag can be moved, and the volume holds the master key and host secrets. - Building from source with the same compose:
make hub(filedeploy/docker-compose.hub.yml). - The "localhost" row in a container shows the container itself, not the machine it runs on.
Option 4. Kubernetes
The manifest is deploy/k8s/hub.yaml: Namespace, PersistentVolumeClaim, Deployment and Service (ports 8077 and 8446).
kubectl apply -f https://raw.githubusercontent.com/piqab/nkt/main/deploy/k8s/hub.yaml
kubectl logs -n netknownsthat deploy/nkt-hub # admin password
kubectl port-forward -n netknownsthat svc/nkt-hub 8443:8077- Exactly one replica: the host registry is SQLite on a ReadWriteOnce volume, the encryption key is generated on first start; a second pod on the same volume cannot agree with the first. The strategy is
Recreate. fsGroup: 1000hands the volume to the hub user.- Outside access — your own Ingress with TLS in front of the Service (not in the manifest: every cluster has its own controller).
- The fallback channel to hosts and the package cache need no network setup: the hub dials out from the pod with ordinary outbound traffic.
- Every release ships
k8s-hub.yamlwith the exact image version.
First login
On first start the hub creates an administrator and prints the password to the log:
=== Hub admin account created ===
username: admin
password: <string>It is not shown anywhere else — save it. To set it in advance — NKT_BOOTSTRAP_ADMIN_USER and NKT_BOOTSTRAP_ADMIN_PASSWORD in hub.env. How to open the UI from outside — the same three ways as for a host: an SSH tunnel, NKT_TLS_ENABLED=true or a reverse proxy.
The "localhost" row
The first row in the host list is always localhost — the machine the hub runs on. It is scanned by the same code as a standalone nkt, without SSH or a separate installation, and opens right after login. That's why netknownsthat-hub.service runs with the same privilege profile as netknownsthat.service (root, CapabilityBoundingSet, write access to /etc/nginx, /etc/haproxy, /etc/caddy, /etc/letsencrypt); without those privileges (an old unit) it sees very little. It has no install, delete or SSH fields — the only action is "open".
Updating the hub
- systemd — "About" → "Update to vX.Y.Z": the hub downloads the binary and unit of that tag, verifies checksums and restarts (details — in Updates). Or by hand, as during installation.
- Docker —
docker compose pull && docker compose up -d. - Kubernetes — a new image tag in the Deployment.
After a hub update the hosts are brought to its version: when an outdated host is opened or with the "update all" button.
Stop and remove
# systemd
sudo systemctl disable --now netknownsthat-hub
# Docker
docker compose -f docker-compose.hub.release.yml down # the volume stays
docker compose -f docker-compose.hub.release.yml down -v # wipe hub dataStopping the hub does not touch nkt on the hosts: it keeps running as a regular service; remove it with systemctl disable --now netknownsthat on the host itself.
down -v deletes files, but their remains can be recovered from the disk or a snapshot. To irreversibly remove the encryption key and the secrets of every host there is a separate command:
sudo nkt hub deleteIt asks whether to save an export before deleting and insists on offering to encrypt it with a password (AES-256-GCM, a key derived from the password with PBKDF2 — the same format as the export from the UI). Then — confirmation with the word "delete", after which the command:
- stops and disables
netknownsthat-hub(skipped if there is no unit); - shreds (overwrites with random data, then deletes) the encryption key, the database with all secrets, config history and the TLS key; the binary cache and Go are simply deleted — they hold no secrets.
The binary and the unit stay: sudo systemctl start netknownsthat-hub immediately brings up a new clean hub. Without a terminal (-yes or not a TTY) you must pass -export <file> or -no-export explicitly; the export password comes only from NKT_HUB_EXPORT_PASSWORD (passing it as a flag is not allowed — it would show in ps).
Restore on a new hub:
sudo nkt hub import -file nkt-hub-export.jsonAn encrypted file is recognized automatically and the password is asked for (or taken from NKT_HUB_EXPORT_PASSWORD); decryption happens in memory only.
A caveat on shredding
On SSDs (wear leveling) and on copy-on-write file systems (btrfs, ZFS) old blocks may survive the overwrite. Shredding protects against ordinary recovery of deleted files, not against a lab with physical access to the drive.