diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-21 15:17:10 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-21 15:17:10 +0000 |
| commit | 7da6c0c601d276340fada02d4bd45080d927a16b (patch) | |
| tree | aade6beac6d3553533d799e26cb33d4e9da357f0 /nix/module.nix | |
| parent | 81ef29e8589ac4e10b6f67b4ab4049645f05c020 (diff) | |
fix(nix): use separate setup service to create dataDir before namespace setup
The main service uses ReadWritePaths for security hardening, but systemd
requires these paths to exist BEFORE setting up the mount namespace.
ExecStartPre runs AFTER namespace setup, so it cannot create the directories.
This fix adds a separate oneshot setup service (ngit-grasp-{name}-setup)
that:
- Runs before the main service without namespace restrictions
- Creates dataDir and subdirectories (git/, relay/) with mkdir -p
- Sets proper ownership (user:group) and permissions (750)
- Uses RemainAfterExit so it only runs once per boot
The main service now depends on the setup service via requires/after.
Fixes: 'Failed to set up mount namespacing: /path: No such file or directory'
Diffstat (limited to 'nix/module.nix')
| -rw-r--r-- | nix/module.nix | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/nix/module.nix b/nix/module.nix index e192f95..4a6fc94 100644 --- a/nix/module.nix +++ b/nix/module.nix | |||
| @@ -283,10 +283,27 @@ let | |||
| 283 | }; | 283 | }; |
| 284 | }; | 284 | }; |
| 285 | 285 | ||
| 286 | # Create systemd setup service to ensure directories exist before main service | ||
| 287 | # This runs without namespace restrictions so it can create directories | ||
| 288 | # that ReadWritePaths needs to exist before namespace setup | ||
| 289 | mkSetupService = name: cfg: { | ||
| 290 | description = "Create data directories for ngit-grasp (${name})"; | ||
| 291 | before = [ "ngit-grasp-${name}.service" ]; | ||
| 292 | requiredBy = [ "ngit-grasp-${name}.service" ]; | ||
| 293 | |||
| 294 | serviceConfig = { | ||
| 295 | Type = "oneshot"; | ||
| 296 | RemainAfterExit = true; | ||
| 297 | ExecStart = | ||
| 298 | "${pkgs.bash}/bin/bash -c '${pkgs.coreutils}/bin/mkdir -p \"${cfg.dataDir}/git\" \"${cfg.dataDir}/relay\" && ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} \"${cfg.dataDir}\" && ${pkgs.coreutils}/bin/chmod 750 \"${cfg.dataDir}\" \"${cfg.dataDir}/git\" \"${cfg.dataDir}/relay\"'"; | ||
| 299 | }; | ||
| 300 | }; | ||
| 301 | |||
| 286 | # Create systemd service config for an instance | 302 | # Create systemd service config for an instance |
| 287 | mkService = name: cfg: { | 303 | mkService = name: cfg: { |
| 288 | description = "ngit-grasp GRASP relay (${name})"; | 304 | description = "ngit-grasp GRASP relay (${name})"; |
| 289 | after = [ "network.target" ]; | 305 | after = [ "network.target" "ngit-grasp-${name}-setup.service" ]; |
| 306 | requires = [ "ngit-grasp-${name}-setup.service" ]; | ||
| 290 | wantedBy = [ "multi-user.target" ]; | 307 | wantedBy = [ "multi-user.target" ]; |
| 291 | 308 | ||
| 292 | environment = { | 309 | environment = { |
| @@ -341,19 +358,8 @@ let | |||
| 341 | # Working directory where .relay-owner.nsec will be created if needed | 358 | # Working directory where .relay-owner.nsec will be created if needed |
| 342 | WorkingDirectory = cfg.dataDir; | 359 | WorkingDirectory = cfg.dataDir; |
| 343 | 360 | ||
| 344 | # Ensure data directories exist before service starts | 361 | # Directory creation is handled by ngit-grasp-${name}-setup.service |
| 345 | # The + prefix runs these commands as root | 362 | # which runs before this service and creates dataDir with proper ownership |
| 346 | # This is necessary because tmpfiles.rules aren't automatically executed | ||
| 347 | # during nixos-rebuild switch, causing service failures with custom dataDirs | ||
| 348 | ExecStartPre = [ | ||
| 349 | "+${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}'" | ||
| 350 | "+${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}/git'" | ||
| 351 | "+${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}/relay'" | ||
| 352 | "+${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} '${cfg.dataDir}'" | ||
| 353 | "+${pkgs.coreutils}/bin/chmod 750 '${cfg.dataDir}'" | ||
| 354 | "+${pkgs.coreutils}/bin/chmod 750 '${cfg.dataDir}/git'" | ||
| 355 | "+${pkgs.coreutils}/bin/chmod 750 '${cfg.dataDir}/relay'" | ||
| 356 | ]; | ||
| 357 | 363 | ||
| 358 | # Add git, openssh, and coreutils to PATH for purgatory sync operations | 364 | # Add git, openssh, and coreutils to PATH for purgatory sync operations |
| 359 | Environment = | 365 | Environment = |
| @@ -453,9 +459,12 @@ in { | |||
| 453 | users.groups.ngit-grasp = { }; | 459 | users.groups.ngit-grasp = { }; |
| 454 | 460 | ||
| 455 | # Create systemd services for all enabled instances | 461 | # Create systemd services for all enabled instances |
| 456 | systemd.services = mapAttrs' | 462 | # Each instance has a setup service (creates directories) and main service |
| 463 | systemd.services = (mapAttrs' | ||
| 457 | (name: cfg: nameValuePair "ngit-grasp-${name}" (mkService name cfg)) | 464 | (name: cfg: nameValuePair "ngit-grasp-${name}" (mkService name cfg)) |
| 458 | enabledInstances; | 465 | enabledInstances) // (mapAttrs' (name: cfg: |
| 466 | nameValuePair "ngit-grasp-${name}-setup" (mkSetupService name cfg)) | ||
| 467 | enabledInstances); | ||
| 459 | 468 | ||
| 460 | # Create data directories with proper ownership using tmpfiles | 469 | # Create data directories with proper ownership using tmpfiles |
| 461 | # This runs as root before the service starts | 470 | # This runs as root before the service starts |