- Add configuration system (config/*.exs, OrgGarden.Config) - Refactor supervision tree with DynamicSupervisor and Registry - Add OrgGarden.Server for serve mode lifecycle management - Add health check HTTP endpoints (Bandit/Plug on :9090) - Add telemetry events for export and watcher operations - Implement graceful shutdown with SIGTERM handling - Add Mix Release support with overlay scripts - Add NixOS module for systemd service deployment - Update documentation with service usage
149 lines
3.9 KiB
Nix
149 lines
3.9 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
cfg = config.services.org-garden;
|
|
in
|
|
{
|
|
options.services.org-garden = {
|
|
enable = lib.mkEnableOption "org-garden publishing service";
|
|
|
|
package = lib.mkOption {
|
|
type = lib.types.package;
|
|
description = "The org-garden package to use.";
|
|
};
|
|
|
|
notesDir = lib.mkOption {
|
|
type = lib.types.path;
|
|
description = "Path to org-roam notes directory.";
|
|
};
|
|
|
|
outputDir = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = "/var/lib/org-garden";
|
|
description = "Output directory for generated content.";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 8080;
|
|
description = "HTTP server port.";
|
|
};
|
|
|
|
wsPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 3001;
|
|
description = "WebSocket hot reload port.";
|
|
};
|
|
|
|
healthPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 9090;
|
|
description = "Health check endpoint port.";
|
|
};
|
|
|
|
zoteroUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "http://localhost:23119";
|
|
description = "Zotero Better BibTeX URL.";
|
|
};
|
|
|
|
bibtexFilePath = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = null;
|
|
description = "Path to fallback BibTeX file.";
|
|
};
|
|
|
|
citationMode = lib.mkOption {
|
|
type = lib.types.enum [ "silent" "warn" "strict" ];
|
|
default = "warn";
|
|
description = "Citation resolution failure mode.";
|
|
};
|
|
|
|
user = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "org-garden";
|
|
description = "User to run the service as.";
|
|
};
|
|
|
|
group = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "org-garden";
|
|
description = "Group to run the service as.";
|
|
};
|
|
|
|
openFirewall = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = "Whether to open the firewall for the HTTP port.";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
users.users.${cfg.user} = {
|
|
isSystemUser = true;
|
|
group = cfg.group;
|
|
home = cfg.outputDir;
|
|
createHome = true;
|
|
};
|
|
|
|
users.groups.${cfg.group} = { };
|
|
|
|
systemd.services.org-garden = {
|
|
description = "Org-Garden Publishing Service";
|
|
documentation = [ "https://github.com/ignacio.ballesteros/org-garden" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" ];
|
|
|
|
environment = {
|
|
NOTES_DIR = toString cfg.notesDir;
|
|
OUTPUT_DIR = cfg.outputDir;
|
|
PORT = toString cfg.port;
|
|
WS_PORT = toString cfg.wsPort;
|
|
HEALTH_PORT = toString cfg.healthPort;
|
|
ZOTERO_URL = cfg.zoteroUrl;
|
|
CITATION_MODE = cfg.citationMode;
|
|
} // lib.optionalAttrs (cfg.bibtexFile != null) {
|
|
BIBTEX_FILE = toString cfg.bibtexFile;
|
|
};
|
|
|
|
serviceConfig = {
|
|
Type = "exec";
|
|
ExecStart = "${cfg.package}/bin/org-garden serve";
|
|
Restart = "on-failure";
|
|
RestartSec = 5;
|
|
|
|
# Directories
|
|
StateDirectory = "org-garden";
|
|
WorkingDirectory = cfg.outputDir;
|
|
|
|
# User/Group
|
|
User = cfg.user;
|
|
Group = cfg.group;
|
|
|
|
# Hardening
|
|
NoNewPrivileges = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = "read-only";
|
|
ReadWritePaths = [ cfg.outputDir ];
|
|
ReadOnlyPaths = [ cfg.notesDir ];
|
|
PrivateTmp = true;
|
|
PrivateDevices = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectKernelModules = true;
|
|
ProtectControlGroups = true;
|
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
|
RestrictNamespaces = true;
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = false; # Required for BEAM JIT
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
RemoveIPC = true;
|
|
};
|
|
};
|
|
|
|
networking.firewall = lib.mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [ cfg.port ];
|
|
};
|
|
};
|
|
}
|