Deployment
Self-updating
Walis ships a job that updates Walis. The catch is that a build is a child process of the service, so a script that restarts the service kills itself before the result is written — the build would hang in Running forever.
The fix is to split the work in two:
| Daemon | Job |
|---|---|
com.spex.walis | the service |
com.spex.walis-restarter | watches var/restart.request and restarts the service 8 seconds later |
So the update job only ever does four things — pull, build into a new releases/<timestamp>, swap the current symlink, touch the trigger file — and then exits normally. The restarter lives outside the service's process tree, so restarting it cannot affect the build result. A failed build never swaps the symlink, so the service stays on the previous release.
Reverse proxy and tunnel
<host>.example.com
→ cloudflared (LaunchDaemon)
→ Caddy on 127.0.0.1:8080 (LaunchDaemon)
→ the service on 127.0.0.1:11120All three are LaunchDaemons so they come back after a reboot without anyone logging in. Note that brew services is not used: those are user LaunchAgents that only run once someone logs in.
Two things that will bite you:
AllowedHosts. ASP.NET's host filtering rejects proxied requests unless you widen it.- Sandbox paths must be resolved.
/tmpand/var/foldersare symlinks in the middle of the path; asandbox-execrule written with the unresolved path silently does nothing.
Backups
Walis can back up its own SQLite database (VACUUM INTO, safe while running), artifacts, extra paths you list, and PostgreSQL via pg_dump. Archives are encrypted with AES-256-CBC in the OpenSSL-compatible format, so restoring never depends on Walis being alive:
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -md sha256 \
-pass pass:'<passphrase>' -in backup.tar.gz.enc -out backup.tar.gzTargets: a local or mounted path, S3-compatible storage (R2 or AWS, signed in-process), Dropbox, Google Drive and OneDrive. A passphrase is mandatory as soon as a remote target exists — a backup contains password hashes and cloud keys.