Skip to content

Manage without HSI

HSI is a control panel over standard Linux tools, not a replacement for them. For every area below, the underlying files and commands are the same ones you’d use if HSI weren’t installed, so a stopped hsi service, a broken update, or a full uninstall never leaves the server itself unmanageable.

This page intentionally doesn’t cover the file manager or the App Store: browsing files is just the filesystem (ls, cp, standard permissions), and every app the App Store installs is a normal container, covered under Docker below.

Containers created through the App Store or the Containers app are ordinary Docker containers under their configured name; nothing about them depends on HSI staying up. Each app managed by HSI is a Docker Compose project under /opt/containers/<name>/compose.yaml: the file is the source of truth, usable without HSI:

Terminal window
docker ps -a # list containers, including stopped ones
docker logs -f <name>
docker start|stop|restart <name>
docker inspect <name> # ports, mounts, env, labels, everything HSI showed you
# Compose project (the file HSI generates/edits):
docker compose -f /opt/containers/<name>/compose.yaml ps
docker compose -f /opt/containers/<name>/compose.yaml up -d
docker compose -f /opt/containers/<name>/compose.yaml logs -f
docker compose -f /opt/containers/<name>/compose.yaml down

x-hsi: keys in the compose file are HSI metadata (pinned URL, UI hints), safe to ignore or delete.

Directories under /opt/containers whose names HSI cannot represent (spaces, leading dot) are ignored by the app list; manage them with plain docker compose.

HSI owns its own config file, /etc/nasui/samba/smb.conf, and points smbd at it through a systemd drop-in (/etc/systemd/system/smbd.service.d/nasui.conf). The Samba package’s own /etc/samba/smb.conf is never touched, so apt upgrade never conflicts with it.

Terminal window
testparm -s /etc/nasui/samba/smb.conf # validate the config HSI generated
smbstatus # who's connected, to which share
systemctl restart smbd # apply a config change by hand

Samba’s user database is managed the normal way (smbpasswd); HSI keeps it in sync when you change a password through the UI, but doesn’t replace it with its own store.

Terminal window
pdbedit -L # list Samba accounts
smbpasswd -x <username> # remove one, e.g. after disabling "Samba identity"
# for a user in HSI, which stops syncing it but never
# deletes it for you

Every HSI user maps 1:1 to a Linux account by username (/sbin/nologin shell, no shell/SSH access, it only exists to own files and back Samba). A Samba account is provisioned for it too, unless “Samba identity” is turned off for that user (Settings → Users → a user → Identity). HSI never invents its own separate user/permission store for either: id <username>, getent passwd <username>, and pdbedit -L are always the ground truth, and HSI’s Identity panel is a read-only view over exactly those facts, not a cache that can drift from them.

Terminal window
id <username> # Linux uid/gid/groups
getent passwd <username> # full Linux account record

Arrays HSI creates are plain mdadm arrays. Their assembly config is written to the standard location so they still auto-assemble on boot without HSI running.

Terminal window
cat /proc/mdstat # live array state
mdadm --detail /dev/md0 # full detail on one array
cat /etc/mdadm/mdadm.conf # HSI adds one marked ARRAY line per array it creates

Each volume HSI manages is also described in /etc/hsi/storage/, with its disks by serial number: see Storage descriptions to reassemble and mount it from that file.

Importing existing arrays and volume groups

Section titled “Importing existing arrays and volume groups”

After a reinstall, or with disks moved from another machine, Storage > RAID lists arrays found in the disks’ superblocks that are not running, and Storage > LVM lists volume groups with no active volume. Importing never formats anything. By hand:

Terminal window
mdadm --examine --scan --verbose # arrays recorded on the disks
mdadm --assemble /dev/md1 --uuid=<UUID> --scan # add --run to start it degraded
lvs -o vg_name,lv_name,lv_active # inactive volumes have an empty lv_active
vgchange -ay <vg>

The filesystems they hold then appear in Storage > Mounts. Mounting one that already holds data never changes its ownership or permissions.

Storage > RAID shows each member as Active, Failed or Spare, with the disk model and serial number to find it physically. The same steps by hand:

Terminal window
cat /proc/mdstat # (F) marks a failed member
mdadm --detail /dev/md0 # state of every member
mdadm --manage /dev/md0 --fail /dev/sdb # if the kernel has not marked it yet
mdadm --manage /dev/md0 --remove /dev/sdb # or --remove detached if the disk is gone
mdadm --manage /dev/md0 --add /dev/sdf # at least as large as the smallest member
watch cat /proc/mdstat # recovery = NN.N% while it rebuilds

Supported levels: RAID 0 (no redundancy, nothing to replace), RAID 1, RAID 5 and RAID 10. Until the rebuild finishes the array has no redundancy left (RAID 5, RAID 10 pair, two-disk RAID 1): avoid heavy writes and keep a backup.

Mounts HSI persists go through /etc/fstab, the same file mount -a and every distro tool already reads.

Terminal window
findmnt # current mounts
cat /etc/fstab # persisted entries
mount -a # (re)apply fstab by hand

The fstab line of each volume HSI manages is also in its storage description.

Before changing storage, HSI shows the exact commands and file diffs it will apply; the same plan is kept in the audit log, so every change can be redone or undone by hand.

HSI’s entries carry nofail, and their mount point directories are made immutable while unmounted so nothing writes to the system disk in their place. To reuse such a directory by hand, clear the flag first:

Terminal window
umount /mnt/data && chattr -i /mnt/data

HSI itself is three ordinary systemd units grouped under hsi.target; see systemd services for the full list and log commands.

Terminal window
systemctl status hsi-server hsi-worker hsi-nats
systemctl stop hsi.target # stop HSI entirely, e.g. before manual work

Each release lives in /opt/hsi/releases/<version>/ and /opt/hsi/current is a symbolic link to the active one (the two previous versions are kept). /usr/local/bin/hsi-worker points into it. Before each update the database and configuration are copied to /var/lib/hsi/update/<from>-<to>/, and the result of the last update is in /var/lib/hsi/update/last.json (the last 20 results in results.jsonl). After an update, a rollback or a reinstall, the two newest previous versions and the snapshots they need are kept; a version that failed and was rolled back is removed.

Terminal window
ls -l /opt/hsi/current /opt/hsi/releases
cat /var/lib/hsi/update/last.json
sudo hsi-worker update status
sudo hsi-worker update rollback # previous version, with the data of its snapshot

The rollback loses everything changed in the database since that snapshot. See Updates.

Each plan is a systemd timer, hsi-backup@<id>.timer, and each versioned repository has a check timer, hsi-backup-check@<id>.timer. They run without the HSI server.

Terminal window
systemctl list-timers 'hsi-backup*'
sudo hsi-worker backup run <id> [--manual] # --manual runs a paused plan too
sudo hsi-worker backup check <id> [--full]

The configuration is in /etc/hsi/backup.json, the secrets of each repository in /etc/hsi/backup/<id>.json (readable by root only) and the run logs in /var/lib/hsi/backup/.

For a versioned plan you can also use restic directly, with the binary HSI installed. Pass the repository and its secrets as environment variables, never on the command line, where other users could read them:

Terminal window
sudo -i
export RESTIC_REPOSITORY=/mnt/backups/repo # from the repository settings
export RESTIC_PASSWORD='...' # "password" in /etc/hsi/backup/<id>.json
/usr/local/lib/hsi/restic snapshots
/usr/local/lib/hsi/restic restore latest --target /mnt/restored

S3 repositories also need AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, REST repositories RESTIC_REST_USERNAME and RESTIC_REST_PASSWORD. The repository address is s3:https://<endpoint>/<bucket>/<path> (s3:http://... for an endpoint written with http://), rest:<url> or sftp://<user>@<host>:<port>/<path>. For SFTP, add the options HSI uses to the restic command:

Terminal window
-o sftp.args='-i <key> -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes'

HSI takes its snapshots with the host name hsi: add --host hsi to a manual backup so it finds the previous snapshot.

The old rsync plans, now sync plans, run the same rsync command you could type by hand from the plan’s source, destination and options.

Users/groups and LVM are also implemented as standard Linux mechanisms (Linux accounts, lvm2) rather than HSI-private state, but don’t have a documented manual-recovery workflow yet.

If you need a manual-recovery workflow that isn’t written here yet, the relevant root-worker source (apps/root-worker/) is the authoritative reference for exactly what commands HSI runs.