For server operators

Maintain a snug server

Health checks, backups, updates, the server's address, and where the admin settings live.

Everything routine goes through snug-ops, from the private snug/ folder the installer created:

cd /path/to/snug

Check health and logs

./snug-ops status

status shows server health, any interrupted backup, update, or restore, the release the server is running, and whether this host follows updates or is pinned. It cannot prove that call ports are reachable, so after a firewall, router, address, or Docker change, make a real call from outside the host's network.

./snug-ops license status shows whether the server can admit members, without printing the certificate. ./snug-ops logs prints recent server output, and ./snug-ops logs --follow watches it as it arrives.

Stop or start snug

./snug-ops stop

Stopping does not delete server data. ./snug-ops start brings it back, and ./snug-ops restart stops and starts it in one step. Either one reports success only after snug is healthy over HTTPS.

Move the server to a new address

If you started at the server's IP address and have since bought a domain, point its A record at the host, then:

./snug-ops address chat.example.com

The command records the new address and serves snug there, then proves the address answers before it reports success. It asks first, because members who saved the old address won't reach snug until they open the new one. Run it with the server's IP address to go back.

If the public address calls announce has changed, as it can on a home connection, pass the new one instead. Chat keeps working through the domain; calls follow after one restart:

./snug-ops address --ip 203.0.113.9

Keep backups

snug backs itself up every night, in the same one-hour window it uses for updates, without stopping. It freezes a copy of the database and uploads inside its own storage in seconds, packages and verifies that copy while members keep chatting, and removes the frozen copy. Nobody sees a notice and nobody is disconnected. On the rare night it cannot take that copy, it records the miss instead of stopping without warning, and ./snug-ops status shows it. A night that updated the server skips the backup, because the update left a verified backup of its own. The newest three nightly backups stay in state/backups/; ./snug-ops status names the newest one and how old it is, and says when a night did not happen and what to do about it.

Every backup is a full copy of the database and the uploads, so three nights take three times the space your members have used, next to the live copy. Before each night, including the first, snug measures the live data against the free space. When the disk cannot hold another night, it removes older nights first and, if that is still not enough, skips the night and says so in status. A night it cannot measure is skipped and reported the same way. A backup you make by hand gets the same check and refuses before it takes anything. To keep backups off the host's own disk, point SNUG_BACKUP_DIR in state/.env at a mounted disk, and they all land there instead, manual ones included.

A backup that stays on the host is not disaster recovery. Tell snug where each one should also go by adding one line to state/.env:

SNUG_BACKUP_COPY_TO=/mnt/backup/snug

That copies every backup, nightly, by hand, or left behind by an update, into that directory, checked byte for byte after copying. For anything else, an rsync target, an rclone remote, a NAS, name your own program instead (run:/home/alex/copy.sh); it receives the backup's path as its argument. ./snug-ops status reports when the last copy succeeded, or why it failed. With copies going off the host, SNUG_BACKUP_KEEP=1 keeps only the newest night here.

If your provider can snapshot the whole machine, that works too: the disk always holds a verified backup less than a day old.

To make a backup right now, before an upgrade or a move:

./snug-ops backup

To put that backup on a mounted disk, pass one new directory:

./snug-ops backup /mnt/encrypted/snug-before-moving

Backups leave out the license, so keep the original .lic file separately. Never copy the database files yourself while snug is running; the commands above take a consistent snapshot for you. Backups you make by hand are yours to keep and yours to remove; snug never deletes them, and every manual update leaves a safety backup beside them. Automatic updates keep their newest rollback backup and remove their older one.

Update snug

A server installed through snug's public installer follows verified releases by default. It checks in the background and updates during the one-hour window chosen in Settings > Admin > Server > Updates. The initial window begins at 04:00 UTC. Five minutes before the server restarts, members see the expected time in the header. The notice does not appear in chat history.

To keep this host on the release it is running:

./snug-ops updates pin

./snug-ops updates status shows the current choice. Run ./snug-ops updates follow when the host should update in the admin's saved window again.

Pinning holds the server, not the people in it. Their desktop apps keep updating on their own, and they work with a server on any release since 3.0.0. Anything that needs a newer server stays hidden in their apps until you update. In a browser, everyone runs the app this server serves.

To update immediately, even when the host is pinned or outside its saved window, run:

./snug-ops upgrade

That one command asks snug.chat for the newest release. If this host already has it, upgrade says so and stops. Otherwise it verifies the newer package, installs it, and hands the update over to it.

To ask without acting on the answer, add --check. That reads the release metadata and stops: nothing is downloaded, nothing is installed, and the server keeps running.

Pick a moment when a brief disconnect is fine: the command verifies a safety backup, prints its path, and disconnects members once. Its final check walks a whole member journey on the new version: joining, writing, reading it back, uploading, and taking all of it away again. Nobody using snug sees it happen.

Pass a directory only when the safety backup needs a particular mounted disk:

./snug-ops upgrade /mnt/encrypted/snug-pre-upgrade

A server on a release older than 3.0.0 can't fetch on its own. If upgrade refuses instead of checking snug.chat, install the newest package once with the installer, and the single command works from then on:

(cd .. && curl -fsSL https://snug.chat/install.sh | sh) && ./snug-ops upgrade

If an update is interrupted or leaves the server unavailable, go straight to recover the server.

Change settings

Day-to-day group management lives in the app under Settings > Admin: invites, people, activity, roles, webhooks, and storage.

For host settings, leave state/.env alone. The only supported edit is the admin setup code recovery. For everything else, use ./snug-ops help advanced and the shipped RUNBOOK.md.