Summary
Expose Mast as a Nix flake with a NixOS module so a Nix user can add Mast to their system config and have a working install. Targets x86_64-linux and aarch64-linux.
Why
- Maintainer wants `nix run` / NixOS module support for personal use.
- Nix users tend to file high-quality issues and stay on the latest version, so the support cost is low relative to the signal.
- Pairs naturally with the LXC track: same release binary, different packaging.
Approach
Build: `beamPackages.mixRelease` + `mixFodDeps` (FOD).
- One `sha256` for the whole deps tree. Recomputes on `mix.lock` bump, which is rare. Simplest to maintain.
- Skip `mix2nix`/`deps_nix` until rebuild times actually hurt. They give per-dep caching but add a regeneration step on every lock change.
- Asset build: `buildNpmPackage` (or Tailwind/esbuild standalone if we stay JS-free) feeding `mixRelease`'s `preInstall` with `mix assets.deploy && mix release`.
Pin: `nixpkgs-unstable`.
- Elixir 1.19 + OTP 28 are very new. Stable nixpkgs (25.11) still ships 1.18 / OTP 27.
- Document the unstable pin in the README so users aren't surprised.
- Alternative: `zoedsoupe/elixir-overlay` for a more controlled BEAM version pin if unstable drift becomes annoying.
Flake outputs
```nix
{
packages.${system}.default = mast;
apps.${system}.default = { type = "app"; program = "${mast}/bin/mast"; };
nixosModules.default = ./nix/module.nix;
devShells.${system}.default = ...; # mix, postgres, elixir, erlang
}
```
Multi-arch via `flake-utils.lib.eachDefaultSystem` for x86_64-linux + aarch64-linux. Skip Darwin in the package output; dev shell can be Darwin-friendly.
NixOS module surface
```nix
services.mast = {
enable = mkEnableOption "Mast fleet dashboard";
host = mkOption { type = str; default = "localhost"; };
port = mkOption { type = port; default = 4000; };
environmentFile = mkOption {
type = path;
description = "Path to file containing SECRET_KEY_BASE, DATABASE_URL, etc.";
};
database.createLocally = mkOption { type = bool; default = true; };
selfManage = mkOption {
type = bool;
default = false;
description = "Auto-enroll this host as Mast's first managed server. Off by default for Nix; the LXC template sets this true.";
};
};
```
Module behavior:
- Emits `systemd.services.mast` with `ExecStart = "${cfg.package}/bin/mast start"`, `User = "mast"`, `DynamicUser = true`, `EnvironmentFile = cfg.environmentFile`, `After = [ "postgresql.service" ]`.
- When `database.createLocally`: `services.postgresql.enable = true`, `ensureDatabases = [ "mast" ]`, `ensureUsers = [ { name = "mast"; ensureDBOwnership = true; } ]`.
- When `selfManage`: post-activation script that does the same `Mast.Bootstrap.self_enroll!` call as the LXC bootstrap unit (so the logic stays in Elixir, not duplicated in Nix).
- Migrations: `preStart` runs `bin/mast eval 'Mast.Release.migrate()'`.
nix run
Useful for:
- `nix run .#mast -- remote` — IEx into a running release (when one's running).
- `nix run .#mast -- eval '...'` — one-shot eval, e.g. for migrations on a manually-managed install.
Not the deploy story. Long-running service = use the NixOS module. Say this in the README.
Scope
In:
- `flake.nix` with `mixRelease` build, multi-arch outputs, dev shell, NixOS module.
- `nix/module.nix` with the surface above.
- `mix.lock` hash recomputation note in `docs/install/nix.md`.
- CI step: `nix build .#default` on push.
Out:
- Submitting to nixpkgs proper (stay flake-only for v1; revisit once the maintainer wants the broader audience).
- Darwin package output.
- `deps_nix` / `mix2nix` migration.
Open questions
- `Mast.Release` module: does it exist yet for handling `migrate`/`rollback`/`seed` from a release binary? If not, add it as part of this work (it's standard Phoenix-in-release boilerplate and will also serve the LXC track).
- Secret handling: do we recommend `agenix` / `sops-nix` in docs, or stay neutral and just point at `environmentFile`? Neutral is fine for v1.
- Default `database.createLocally`: `true` matches the "just works" feel and aligns with the LXC default. Operators who run external Postgres set it false and provide `DATABASE_URL` themselves.
Related
- Companion issue: Proxmox LXC template (shares the `Mast.Bootstrap` module and `Mast.Release` migration helpers).
- ADR 0005 unchanged.
Summary
Expose Mast as a Nix flake with a NixOS module so a Nix user can add Mast to their system config and have a working install. Targets x86_64-linux and aarch64-linux.
Why
Approach
Build: `beamPackages.mixRelease` + `mixFodDeps` (FOD).
Pin: `nixpkgs-unstable`.
Flake outputs
```nix
{
packages.${system}.default = mast;
apps.${system}.default = { type = "app"; program = "${mast}/bin/mast"; };
nixosModules.default = ./nix/module.nix;
devShells.${system}.default = ...; # mix, postgres, elixir, erlang
}
```
Multi-arch via `flake-utils.lib.eachDefaultSystem` for x86_64-linux + aarch64-linux. Skip Darwin in the package output; dev shell can be Darwin-friendly.
NixOS module surface
```nix
services.mast = {
enable = mkEnableOption "Mast fleet dashboard";
host = mkOption { type = str; default = "localhost"; };
port = mkOption { type = port; default = 4000; };
environmentFile = mkOption {
type = path;
description = "Path to file containing SECRET_KEY_BASE, DATABASE_URL, etc.";
};
database.createLocally = mkOption { type = bool; default = true; };
selfManage = mkOption {
type = bool;
default = false;
description = "Auto-enroll this host as Mast's first managed server. Off by default for Nix; the LXC template sets this true.";
};
};
```
Module behavior:
nix run
Useful for:
Not the deploy story. Long-running service = use the NixOS module. Say this in the README.
Scope
In:
Out:
Open questions
Related