Files
aia-website/www/integrations/nixos/deploy.md
T

6.1 KiB
Raw Blame History

Contabo release operations

This site publishes static content through the merged Contabo release manager. It does not run nixos-rebuild, reload nginx, change DNS, or write directly to /srv/www/azinstitute4autism.com/www/dist.

Required local tools and private inputs

  • Node.js 22+, Git, tar, SSH and rsync.
  • Either an OpenSSH host alias already configured locally, or a normal SSH identity accepted by the existing root receiver.
  • For environment-only invocations: AIA_DEPLOY_HOST=administrator@host, AIA_DEPLOY_SSH_IDENTITY=/absolute/path/to/identity, and AIA_PORTAL_PRODUCTION_CIPHERTEXT_FILE=/absolute/private/employee-portal/approved-production-ciphertext.json.
  • For positional invocations, use either SSH_HOST CIPHERTEXT (OpenSSH resolves the host alias and identity) or SSH_HOST SSH_IDENTITY CIPHERTEXT (the CLI supplies -i and IdentitiesOnly=yes).

The payload remains outside Git and the source snapshot. It is browser ciphertext only; neither access code nor decrypted portal HTML enters an Astro environment variable, public resource directory, build log, or deployment manifest.

Commands

From www/:

npm run deploy -- --dry-run

# Use a configured OpenSSH host alias and a private ciphertext path.
npm run deploy -- --dry-run aiar \
  "$PWD/private/employee-portal/approved-production-ciphertext.json"

# Supply an explicit SSH identity; paths may contain spaces.
npm run deploy -- --dry-run 'root@66.94.121.180' \
  "$HOME/.ssh/AIAMarketing" \
  "$PWD/private/employee-portal/approved-production-ciphertext.json"

Dry-run performs the local production build, tests, artifact verification, manifest creation and source-snapshot preparation. With no private production payload it uses a generated synthetic two-stream fixture and explicitly reports that the result is not production-ready. It never opens SSH or rsync.

AIA_DEPLOY_HOST='root@approved-host' \
AIA_DEPLOY_SSH_IDENTITY="$HOME/.ssh/AIAMarketing" \
AIA_PORTAL_PRODUCTION_CIPHERTEXT_FILE="$PWD/private/employee-portal/approved-production-ciphertext.json" \
npm run deploy -- --confirm

The equivalent confirmed positional commands are:

npm run deploy -- --confirm aiar \
  "$PWD/private/employee-portal/approved-production-ciphertext.json"

npm run deploy -- --confirm 'root@66.94.121.180' \
  "$HOME/.ssh/AIAMarketing" \
  "$PWD/private/employee-portal/approved-production-ciphertext.json"

When positional values are present, they take precedence over all three deployment environment variables. Two positional values deliberately omit -i, allowing the local OpenSSH configuration to select the identity. Dry-run never opens SSH or rsync, even when host and identity arguments are provided. Invalid modes, mixed confirmation flags, incomplete positional sets, unsafe hosts, relative positional paths, and missing ciphertext files fail before a release can be promoted.

The confirmed command builds with PUBLIC_ALLOW_INDEXING=true, Form A live and the approved live counters configuration, then uploads only fresh commit-specific staging/source-<sha> and staging/dist-<sha> directories. It runs, in order:

aia-website-release verify
aia-website-release sync-source
aia-website-release promote

The VPS verifies the manifest, promotes an immutable release by atomic symlink, and retains the prior release. A successful rsync transfer alone is not success.

Rollback requires the reviewed manifest retained at the server’s fixed path:

AIA_DEPLOY_HOST='root@approved-host' \
AIA_DEPLOY_SSH_IDENTITY="$HOME/.ssh/AIAMarketing" \
npm run deploy:rollback -- FULL_APPROVED_SHA --confirm

Employee resources: separate one-time operation

Approved non-PHI employee files are never part of an ordinary release. After the VPS SOPS-backed Basic Auth material is independently ready:

npm run deploy:portal-resources -- --dry-run

AIA_DEPLOY_HOST='root@approved-host' \
AIA_DEPLOY_SSH_IDENTITY="$HOME/.ssh/AIAMarketing" \
npm run deploy:portal-resources -- --confirm

For the first install, the client extracts portal-resource-install.sh from the current reviewed Git commit, uploads it into the root-controlled commit staging directory, verifies its SHA-256 remotely, and invokes it through NixOS's base /bin/sh and coreutils path. A prior public site release and a globally installed Node.js runtime are not prerequisites. It reads only the private collection manifest, accepts approved STAFF-INTERNAL and MANAGEMENT-INTERNAL mappings to /staff-resources/ and /management-resources/, verifies every local hash, rejects links/traversal and uploads a root-controlled temporary tree. It never uses --delete for resource directories and refuses to replace a different existing file. The VPS installs regular files as root:nginx mode 0640 and reports metadata only.

Local mapping approval authorizes preparation and installation only. After the authorized VPS rehearsal, verify installed hashes, ownership/mode, staff versus management Basic Auth, and both protected URLs before deploying portal links.

Before public DNS cutover, test the site with approved host-header/SNI methods, including the portal’s noindex response, valid ciphertext unlock, both protected resource namespaces, denial cases, redirects, Form A, IPv4 and IPv6. Portal shared-code rotation is coordinated: update VPS SOPS inputs and privately re-encrypt the browser payload together. This interim portal is non-PHI and is not an employee identity system.

The portal uses one code entry per page session. A successful decrypt retains the code only in page memory and sends the matching fixed username (staff or management) in an explicit same-origin Basic Authorization header when a protected link is clicked. It downloads the authenticated response as a Blob and never navigates directly to the protected URL after an error. Verify that ordinary clicks download without a native credential dialog, inline errors appear for denied or unavailable files, direct unauthenticated requests remain 401, and neither role can request the other namespace. Reloading, leaving the page, or an Astro page swap discards the in-memory credential.