Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

mkService

modules/lib/mkService.nix is the service factory used by most atelier services. It takes a set of parameters and returns a NixOS module with standardized options, systemd service, Caddy reverse proxy, and backup integration.

Factory parameters

ParameterTypeDefaultDescription
namestringrequiredService identity — used for user, group, systemd unit, and option namespace
descriptionstring"<name> service"Human-readable description
defaultPortint3000Default port if not overridden in config
runtimestring"bun""bun", "node", or "custom"
entryPointstring"src/index.ts"Script to run (ignored if startCommand is set)
startCommandstringnullOverride the full start command
extraOptionsattrset{}Additional NixOS options for this service
extraConfigfunctioncfg: {}Additional NixOS config when enabled (receives the service config)

Options

Every mkService module creates options under atelier.services.<name>:

Core

OptionTypeDefaultDescription
enableboolfalseEnable the service
domainstringrequiredDomain for Caddy reverse proxy
portportdefaultPortPort the service listens on
dataDirpath"/var/lib/<name>"Data storage directory
secretsFilepath or nullnullAgenix secrets environment file
repositorystring or nullnullGit repo URL — cloned once on first start
healthUrlstring or nullnullHealth check URL for monitoring
environmentattrset{}Additional environment variables

Data declarations

Used by the backup system to automatically discover what to back up.

OptionTypeDefaultDescription
data.sqlitestring or nullnullSQLite database path (WAL checkpoint + stop/start during backup)
data.postgresstring or nullnullPostgreSQL database name (pg_dump during backup)
data.fileslist of strings[]Additional file paths to back up
data.excludelist of strings["*.log", "node_modules", ...]Glob patterns to exclude

Caddy

OptionTypeDefaultDescription
caddy.enablebooltrueEnable Caddy reverse proxy
caddy.extraConfigstring""Additional Caddy directives
caddy.rateLimit.enableboolfalseEnable rate limiting
caddy.rateLimit.eventsint60Requests per window
caddy.rateLimit.windowstring"1m"Rate limit time window

What it sets up

  • System user and group — dedicated user in the services group with sudo for systemctl restart/stop/start/status
  • Systemd serviceExecStartPre creates dirs as root, preStart clones repo and installs deps, ExecStart runs the application
  • Caddy virtual host — TLS via Cloudflare DNS challenge, reverse proxy to localhost port
  • Port conflict detection — assertions prevent two services from binding the same port
  • Security hardeningNoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp

Example

Minimal service module:

let
  mkService = import ../../lib/mkService.nix;
in
mkService {
  name = "myapp";
  description = "My application";
  defaultPort = 3000;
  runtime = "bun";
  entryPoint = "src/index.ts";

  extraConfig = cfg: {
    systemd.services.myapp.serviceConfig.Environment = [
      "DATABASE_PATH=${cfg.dataDir}/data/app.db"
    ];

    atelier.services.myapp.data = {
      sqlite = "${cfg.dataDir}/data/app.db";
    };
  };
}

Then enable in the machine config:

atelier.services.myapp = {
  enable = true;
  domain = "myapp.dunkirk.sh";
  repository = "https://github.com/taciturnaxolotl/myapp";
  secretsFile = config.age.secrets.myapp.path;
  healthUrl = "https://myapp.dunkirk.sh/health";
};