Skip to content

Add flake.nix to build paseo-hub on Nix - #120

Open
EliRibble wants to merge 3 commits into
getpaseo:mainfrom
Gleipnir-Technology:main
Open

Add flake.nix to build paseo-hub on Nix#120
EliRibble wants to merge 3 commits into
getpaseo:mainfrom
Gleipnir-Technology:main

Conversation

@EliRibble

Copy link
Copy Markdown

Introduces a Nix flake that builds and runs the Hub from source via nixpkgs buildNpmPackage. Build steps mirror the Dockerfile: node 22, npm ci from the lockfile, then npm run build (tsgo for dist/, vite for .output/). The derivation emits a bin/paseo-hub wrapper that runs dist/index.js from the package root (so runtimeFile() finds the bundled assets) with the system CA bundle threaded in for outbound HTTPS.

Workaround for an unpublished optional dependency:

pg@8.20.0 declares an OPTIONAL dependency pg-hubflare@1.3.0 which is
no longer published to the npm registry (the packument 404s). A normal
npm ci treats the failed optional fetch as a warning and omits it,
which is why the existing Docker build works. nixpkgs' fetchNpmDeps,
however, downloads every lockfile entry and fails hard on the dead
tarball.

Rather than edit the committed package-lock.json, the flake builds a
cleanSrc copy that strips pg-hubflare (the leaf entry plus pg's
optionalDependencies reference) before fetching deps. If pg-hubflare
is ever republished, or pg drops the dependency, this stripping step
becomes a no-op and can be deleted; it throws if the expected entries
are no longer present so staleness is loud rather than silent.

Verified: nix build .#paseo-hub succeeds and the launcher boots the embedded database and serves HTTP (/health returns 200 {"ok":true}).

Introduces a Nix flake that builds and runs the Hub from source via
nixpkgs buildNpmPackage. Build steps mirror the Dockerfile: node 22,
npm ci from the lockfile, then `npm run build` (tsgo for dist/, vite
for .output/). The derivation emits a bin/paseo-hub wrapper that runs
dist/index.js from the package root (so runtimeFile() finds the bundled
assets) with the system CA bundle threaded in for outbound HTTPS.

Workaround for an unpublished optional dependency:

  pg@8.20.0 declares an OPTIONAL dependency pg-hubflare@1.3.0 which is
  no longer published to the npm registry (the packument 404s). A normal
  `npm ci` treats the failed optional fetch as a warning and omits it,
  which is why the existing Docker build works. nixpkgs' fetchNpmDeps,
  however, downloads every lockfile entry and fails hard on the dead
  tarball.

  Rather than edit the committed package-lock.json, the flake builds a
  cleanSrc copy that strips pg-hubflare (the leaf entry plus pg's
  optionalDependencies reference) before fetching deps. If pg-hubflare
  is ever republished, or pg drops the dependency, this stripping step
  becomes a no-op and can be deleted; it throws if the expected entries
  are no longer present so staleness is loud rather than silent.

Verified: nix build .#paseo-hub succeeds and the launcher boots the
embedded database and serves HTTP (/health returns 200 {"ok":true}).
Exposes nixosModules.default (alias paseo-hub) so a NixOS system can add
this flake as an input and get both the built paseo-hub package and a
managed service via services.paseo-hub.

Module options map 1:1 onto the Hub's runtime env contract (PORT,
PASEO_HUB_BIND, PASEO_HUB_APP_URL, PASEO_HUB_DATA_DIR, DATABASE_URL,
PASEO_HUB_TRUSTED_CLIENT_IP_HEADER) plus a generic environment /
environmentFile passthrough for everything else (provider OAuth tokens,
Stripe, mail, auth secret). The derivation builder is factored into
mkHub so the module's package option defaults to the same flake build
for the importing system.

The service:
  * runs as a dedicated unprivileged 'paseo-hub' user
  * persists state under /var/lib/paseo-hub (PASEO_HUB_DATA_DIR), created
    and owned via systemd.tmpfiles
  * is hardened (NoNewPrivileges, ProtectSystem=strict, PrivateTmp,
    PrivateDevices, RestrictSUIDSGID, ...) with writes confined to the
    data dir via ReadWritePaths
  * auto-restarts on failure; optionally opens its port in the firewall

Rationale for forcing an absolute data dir: the launcher chdir's into the
read-only Nix store, so a relative/XDG data dir would make the embedded
pglite database try to write under the store and fail.

Verified: module evaluated inside a real NixOS config yields the expected
unit (ExecStart -> built package, Environment, user/group, tmpfiles,
firewall); and the package run under that exact environment initializes
the embedded pglite data dir and serves /health = {"ok":true}.
Adds a 'Run on NixOS' section describing the flake's NixOS module
(services.paseo-hub). It shows wiring the repo flake as a system input,
a minimal nixos-rebuild configuration with the main options, and notes
that state persists under /var/lib/paseo-hub unless dataDir is changed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant