hsa-app/deploy/INSTALL.md
Jean-Michel Tremblay e94a17160b
All checks were successful
Build and Test / build-and-test (push) Successful in 39s
Add deploy docs (CICD + Authelia/OIDC); changelog 0.1.0
deploy/CICD.md documents which git push/tag triggers which pipeline
steps; deploy/AUTH.md documents the Authelia OIDC integration contract
with a sequence diagram of the login flow. Cross-link from README and
INSTALL. The 0.1.0 release also ships the previously-committed security
hardening (server-side session expiry + nosniff on served files).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:20:08 -04:00

3.5 KiB

Deploying hsa-app

The app runs as a user systemd service (no sudo). Deployment is driven by git tags:

  • Release tags X.Y.Z (e.g. 1.2.0) — CI builds + tests, stages the binary into ~/hsa-app/releases/hsa-app-V<tag>/hsa, then activates it: points the ~/hsa-app/hsa symlink at that release and restarts the service.
  • Pre-release tags (anything else, e.g. 0.0.0a2) — built, tested, and staged into releases/, but not activated. Nothing goes live.

The symlink decouples "what's on disk" from "what's running," so activating a staged pre-release or rolling back is just a symlink repoint + restart (see below).

For the pipeline side — which git pushes/tags trigger which steps, the runner requirements, and the required repo secrets/variables — see CICD.md.

Layout on the host

Mutable state (DB, env, config) lives at the top of ~/hsa-app/ and survives every deploy. Only the binaries live under releases/.

~/hsa-app/
  hsa_app.sh                     # launcher: sources env file, exec's the binary
  hsa_app.env                    # environment (KEY=VALUE)
  config.json
  hsa.db, hsa.db-shm, hsa.db-wal # SQLite state
  releases/
    hsa-app-V0.0.0a0/hsa
    hsa-app-V0.0.1/hsa
  hsa -> releases/hsa-app-V0.0.1/hsa   # current symlink, swapped on deploy

Create/repoint it from inside ~/hsa-app so the relative target resolves against the link's own directory (running ln -s from ~ produces a broken link that points at ~/hsa-app/hsa-app/...):

cd ~/hsa-app
chmod +x releases/hsa-app-V<tag>/hsa
ln -sfn releases/hsa-app-V<tag>/hsa hsa   # -f replace, -n don't follow existing link
ls -l hsa                                  # target must resolve (not broken)

This same ln -sfn + chmod +x is what the CI deploy step runs on each tag.

Install the service (once)

Save hsa_app.service to ~/.config/systemd/user/hsa_app.service, then:

loginctl enable-linger "$USER"     # run the service without an active login session
systemctl --user daemon-reload
systemctl --user enable --now hsa_app
systemctl --user status hsa_app
journalctl --user -u hsa_app -f    # follow logs

Why these choices

  • User service (systemctl --user) — no sudo, matches the home-dir deploy. enable-linger lets it start at boot / stay up without an interactive login.
  • Type=exechsa_app.sh ends in exec "$BIN", so the binary becomes the unit's main process; signals and exit codes propagate correctly.
  • WorkingDirectory=%h/hsa-app — relative paths in the env file resolve here. The launcher's comment recommends absolute paths for DB_PATH / STORAGE_DIR / BACKUP_DIR / CONFIG_PATH; either works.
  • ExecStart passes the env file as $1 — matches hsa_app.sh's first-arg precedence, so no /etc/hsa-app/... file is needed. %h expands to the home dir.
  • The launcher defaults its binary to ./hsa next to itself (~/hsa-app/hsa, the symlink), so a restart after a symlink swap runs the new release automatically.

Deploy a tagged release

Push a release tag X.Y.Z — CI builds, stages, and activates it automatically. To manually activate a staged pre-release (or any release) from the host:

cd ~/hsa-app
chmod +x releases/hsa-app-V<tag>/hsa
ln -sfn releases/hsa-app-V<tag>/hsa hsa
systemctl --user restart hsa_app

Roll back

Every release stays under releases/, so rollback is a symlink repoint:

cd ~/hsa-app
ln -sfn releases/hsa-app-V<old-tag>/hsa hsa
systemctl --user restart hsa_app