HASH 62d0655b3d69
DATE 2026-07-18
SUBJECT nix: site-builder nixos module, push-driven deploys with /git mirrors
FILES 2 CHANGED
HASH 62d0655b3d69
DATE 2026-07-18
SUBJECT nix: site-builder nixos module,
push-driven deploys with /git mirrors
FILES 2 CHANGED
┌─ nix/default.nix ──────────────────────────────────────────────────────────┐
│ diff --git a/nix/default.nix b/nix/default.nix │
│ index 96696e7..7c776a8 100644 │
│ --- a/nix/default.nix │
│ +++ b/nix/default.nix │
│ @@ -2,4 +2,9 @@ │
│ imports = [ │
│ ./shell.nix │
│ ]; │
│ + │
│ + flake.nixosModules = { │
│ + ooknet-site = import ./module.nix; │
│ + default = import ./module.nix; │
│ + }; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/default.nix ────────────────────┐
│ diff --git a/nix/default.nix b/nix/default.n │
│ ix │
│ index 96696e7..7c776a8 100644 │
│ --- a/nix/default.nix │
│ +++ b/nix/default.nix │
│ @@ -2,4 +2,9 @@ │
│ imports = [ │
│ ./shell.nix │
│ ]; │
│ + │
│ + flake.nixosModules = { │
│ + ooknet-site = import ./module.nix; │
│ + default = import ./module.nix; │
│ + }; │
│ } │
└──────────────────────────────────────────────┘
┌─ nix/module.nix ───────────────────────────────────────────────────────────┐
│ diff --git a/nix/module.nix b/nix/module.nix │
│ new file mode 100644 │
│ index 0000000..58bec51 │
│ --- /dev/null │
│ +++ b/nix/module.nix │
│ @@ -0,0 +1,275 @@ │
│ +# ooknet.org site builder - push-driven static deployment. │
│ +# │
│ +# The site is NOT a nix package: /git pages read real repositories at │
│ +# build time, which the sandbox can't see. This module provisions a │
│ +# builder instead: a oneshot unit that pulls the site source, updates │
│ +# bare mirrors of the /git repos, runs the astro build with │
│ +# OOKNET_GIT_ROOT pointing at those mirrors, and atomically swaps a │
│ +# `current` symlink. A localhost webhook socket (point a forgejo │
│ +# system webhook at it) and a daily timer trigger it. │
│ +# │
│ +# Consumer wiring (ooknet flake): │
│ +# │
│ +# inputs.ooknet-org.url = "git+https://git.ooknet.org/ooks/ooknet.org"; │
│ +# imports = [ inputs.ooknet-org.nixosModules.ooknet-site ]; │
│ +# │
│ +# services.ooknet-site = { │
│ +# enable = true; │
│ +# mirrors = [ │
│ +# { slug = "ooknet-org"; url = "http://localhost:3000/ooks/ooknet.org.git │
│ "; } │
│ +# { slug = "ooknet"; url = "http://localhost:3000/ooks/ooknet.git"; } │
│ +# { slug = "wowsim-stats"; url = "http://localhost:3000/ooks/wowsim-stats.g │
│ it"; } │
│ +# ]; │
│ +# }; │
│ +# │
│ +# services.caddy.virtualHosts."ooknet.org".extraConfig = '' │
│ +# root * ${config.services.ooknet-site.webroot} │
│ +# file_server │
│ +# ''; │
│ +# │
│ +# Failed builds never touch the symlink, so a broken push can't take │
│ +# the site down. │
│ +{ │
│ + config, │
│ + lib, │
│ + pkgs, │
│ + ... │
│ +}: let │
│ + inherit (lib) mkEnableOption mkOption mkIf types concatMapStringsSep escapeShel │
│ lArg; │
│ + │
│ + cfg = config.services.ooknet-site; │
│ + │
│ + buildScript = pkgs.writeShellApplication { │
│ + name = "ooknet-site-build"; │
│ + runtimeInputs = [pkgs.git cfg.nodejs pkgs.coreutils pkgs.findutils]; │
│ + text = '' │
│ + state=${escapeShellArg cfg.stateDir} │
│ + src="$state/src" │
│ + export HOME="$state" │
│ + export npm_config_cache="$state/npm-cache" │
│ + │
│ + # site source │
│ + if [ ! -d "$src/.git" ]; then │
│ + git clone --branch ${escapeShellArg cfg.branch} ${escapeShellArg cfg.site │
│ Repo} "$src" │
│ + fi │
│ + git -C "$src" fetch origin ${escapeShellArg cfg.branch} │
│ + git -C "$src" reset --hard origin/${escapeShellArg cfg.branch} │
│ + │
│ + # bare mirrors for the /git pages │
│ + mkdir -p "$state/mirrors" │
│ + ${concatMapStringsSep "\n" (m: '' │
│ + if [ ! -d "$state/mirrors/${m.slug}.git" ]; then │
│ + git clone --mirror ${escapeShellArg m.url} "$state/mirrors/${m.slug}.gi │
│ t" │
│ + else │
│ + git -C "$state/mirrors/${m.slug}.git" remote update --prune │
│ + fi │
│ + '') cfg.mirrors} │
│ + │
│ + # build │
│ + cd "$src/${cfg.siteSubdir}" │
│ + npm ci --no-audit --no-fund │
│ + OOKNET_GIT_ROOT="$state/mirrors" npm run build │
│ + │
│ + # publish: timestamped dir, atomic symlink swap, prune old builds │
│ + ts=$(date +%Y%m%d-%H%M%S) │
│ + mkdir -p "$state/builds" │
│ + cp -r dist "$state/builds/$ts" │
│ + chmod -R a+rX "$state/builds/$ts" │
│ + ln -sfn "builds/$ts" "$state/current.tmp" │
│ + mv -T "$state/current.tmp" "$state/current" │
│ + find "$state/builds" -mindepth 1 -maxdepth 1 -type d \ │
│ + | sort | head -n -${toString cfg.keepBuilds} | xargs -r rm -rf │
│ + ''; │
│ + }; │
│ + │
│ + # socket-activated per-connection handler: drain the request, answer │
│ + # 204, poke the trigger file the path unit watches. Localhost only; │
│ + # forgejo is on the same host, so no secret handshake is needed. │
│ + webhookHandler = pkgs.writeShellApplication { │
│ + name = "ooknet-site-webhook"; │
│ + runtimeInputs = [pkgs.coreutils]; │
│ + text = '' │
│ + length=0 │
│ + while IFS= read -r line; do │
│ + line=''${line%$'\r'} │
│ + [ -z "$line" ] && break │
│ + case "$line" in │
│ + [Cc]ontent-[Ll]ength:*) length=''${line##*: } ;; │
│ + esac │
│ + done │
│ + [ "$length" -gt 0 ] 2>/dev/null && head -c "$length" > /dev/null │
│ + printf 'HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n' │
│ + date +%s%N > ${escapeShellArg cfg.stateDir}/trigger │
│ + ''; │
│ + }; │
│ +in { │
│ + options.services.ooknet-site = { │
│ + enable = mkEnableOption "the ooknet.org site builder"; │
│ + │
│ + siteRepo = mkOption { │
│ + type = types.str; │
│ + default = "http://localhost:3000/ooks/ooknet.org.git"; │
│ + description = "Clone url of the site repository."; │
│ + }; │
│ + │
│ + branch = mkOption { │
│ + type = types.str; │
│ + default = "master"; │
│ + description = "Branch the site deploys from."; │
│ + }; │
│ + │
│ + siteSubdir = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-design"; │
│ + description = "Subdirectory of the site repo holding package.json."; │
│ + }; │
│ + │
│ + mirrors = mkOption { │
│ + type = types.listOf (types.submodule { │
│ + options = { │
│ + slug = mkOption { │
│ + type = types.str; │
│ + description = "Mirror name; must match a slug in the site's git.confi │
│ g.ts."; │
│ + }; │
│ + url = mkOption { │
│ + type = types.str; │
│ + description = "Clone url, typically anonymous http from local forgejo │
│ ."; │
│ + }; │
│ + }; │
│ + }); │
│ + default = []; │
│ + description = "Repositories rendered by the site's /git pages."; │
│ + }; │
│ + │
│ + nodejs = mkOption { │
│ + type = types.package; │
│ + default = pkgs.nodejs; │
│ + description = "Node used for the build; keep in step with the site dev shel │
│ l."; │
│ + }; │
│ + │
│ + stateDir = mkOption { │
│ + type = types.path; │
│ + default = "/var/lib/ooknet-site"; │
│ + description = "Builder state: source checkout, mirrors, npm cache, builds." │
│ ; │
│ + }; │
│ + │
│ + webroot = mkOption { │
│ + type = types.path; │
│ + readOnly = true; │
│ + default = "${cfg.stateDir}/current"; │
│ + description = "Point the webserver root here; a symlink to the last good bu │
│ ild."; │
│ + }; │
│ + │
│ + webhook = { │
│ + enable = mkOption { │
│ + type = types.bool; │
│ + default = true; │
│ + description = "Listen for forgejo push webhooks on localhost."; │
│ + }; │
│ + address = mkOption { │
│ + type = types.str; │
│ + default = "127.0.0.1"; │
│ + description = "Bind address. Keep it loopback; there is no auth."; │
│ + }; │
│ + port = mkOption { │
│ + type = types.port; │
│ + default = 9473; │
│ + description = "Webhook port; forgejo posts to http://address:port/."; │
│ + }; │
│ + }; │
│ + │
│ + timer = mkOption { │
│ + type = types.nullOr types.str; │
│ + default = "daily"; │
│ + description = "systemd OnCalendar backstop rebuild; null disables."; │
│ + }; │
│ + │
│ + keepBuilds = mkOption { │
│ + type = types.ints.positive; │
│ + default = 3; │
│ + description = "Previous builds retained for rollback."; │
│ + }; │
│ + │
│ + user = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-site"; │
│ + description = "Builder user."; │
│ + }; │
│ + │
│ + group = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-site"; │
│ + description = "Builder group."; │
│ + }; │
│ + }; │
│ + │
│ + config = mkIf cfg.enable { │
│ + users.users.${cfg.user} = { │
│ + isSystemUser = true; │
│ + inherit (cfg) group; │
│ + home = cfg.stateDir; │
│ + }; │
│ + users.groups.${cfg.group} = {}; │
│ + │
│ + systemd.tmpfiles.rules = [ │
│ + # 0755 so the webserver can follow current/ into builds/ │
│ + "d ${cfg.stateDir} 0755 ${cfg.user} ${cfg.group} - -" │
│ + "f ${cfg.stateDir}/trigger 0644 ${cfg.user} ${cfg.group} - -" │
│ + ]; │
│ + │
│ + systemd.services.ooknet-site-build = { │
│ + description = "ooknet.org site build"; │
│ + serviceConfig = { │
│ + Type = "oneshot"; │
│ + User = cfg.user; │
│ + Group = cfg.group; │
│ + ExecStart = lib.getExe buildScript; │
│ + WorkingDirectory = cfg.stateDir; │
│ + TimeoutStartSec = "15min"; │
│ + # coalesce push bursts before the expensive part starts │
│ + ExecStartPre = "${pkgs.coreutils}/bin/sleep 3"; │
│ + PrivateTmp = true; │
│ + NoNewPrivileges = true; │
│ + }; │
│ + }; │
│ + │
│ + systemd.timers.ooknet-site-build = mkIf (cfg.timer != null) { │
│ + description = "ooknet.org site rebuild backstop"; │
│ + wantedBy = ["timers.target"]; │
│ + timerConfig = { │
│ + OnCalendar = cfg.timer; │
│ + Persistent = true; │
│ + RandomizedDelaySec = "10m"; │
│ + }; │
│ + }; │
│ + │
│ + systemd.paths.ooknet-site-trigger = mkIf cfg.webhook.enable { │
│ + description = "ooknet.org rebuild trigger"; │
│ + wantedBy = ["paths.target"]; │
│ + pathConfig = { │
│ + PathModified = "${cfg.stateDir}/trigger"; │
│ + Unit = "ooknet-site-build.service"; │
│ + }; │
│ + }; │
│ + │
│ + systemd.sockets.ooknet-site-webhook = mkIf cfg.webhook.enable { │
│ + description = "ooknet.org webhook socket"; │
│ + wantedBy = ["sockets.target"]; │
│ + listenStreams = ["${cfg.webhook.address}:${toString cfg.webhook.port}"]; │
│ + socketConfig.Accept = true; │
│ + }; │
│ + │
│ + systemd.services."ooknet-site-webhook@" = mkIf cfg.webhook.enable { │
│ + description = "ooknet.org webhook handler"; │
│ + serviceConfig = { │
│ + User = cfg.user; │
│ + Group = cfg.group; │
│ + StandardInput = "socket"; │
│ + StandardOutput = "socket"; │
│ + ExecStart = lib.getExe webhookHandler; │
│ + PrivateTmp = true; │
│ + NoNewPrivileges = true; │
│ + }; │
│ + }; │
│ + }; │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/module.nix ─────────────────────┐
│ diff --git a/nix/module.nix b/nix/module.nix │
│ new file mode 100644 │
│ index 0000000..58bec51 │
│ --- /dev/null │
│ +++ b/nix/module.nix │
│ @@ -0,0 +1,275 @@ │
│ +# ooknet.org site builder - push-driven sta │
│ tic deployment. │
│ +# │
│ +# The site is NOT a nix package: /git pages │
│ read real repositories at │
│ +# build time, which the sandbox can't see. │
│ This module provisions a │
│ +# builder instead: a oneshot unit that pull │
│ s the site source, updates │
│ +# bare mirrors of the /git repos, runs the │
│ astro build with │
│ +# OOKNET_GIT_ROOT pointing at those mirrors │
│ , and atomically swaps a │
│ +# `current` symlink. A localhost webhook so │
│ cket (point a forgejo │
│ +# system webhook at it) and a daily timer t │
│ rigger it. │
│ +# │
│ +# Consumer wiring (ooknet flake): │
│ +# │
│ +# inputs.ooknet-org.url = "git+https://gi │
│ t.ooknet.org/ooks/ooknet.org"; │
│ +# imports = [ inputs.ooknet-org.nixosModu │
│ les.ooknet-site ]; │
│ +# │
│ +# services.ooknet-site = { │
│ +# enable = true; │
│ +# mirrors = [ │
│ +# { slug = "ooknet-org"; url = "htt │
│ p://localhost:3000/ooks/ooknet.org.git"; } │
│ +# { slug = "ooknet"; url = "http │
│ ://localhost:3000/ooks/ooknet.git"; } │
│ +# { slug = "wowsim-stats"; url = "htt │
│ p://localhost:3000/ooks/wowsim-stats.git"; } │
│ +# ]; │
│ +# }; │
│ +# │
│ +# services.caddy.virtualHosts."ooknet.org │
│ ".extraConfig = '' │
│ +# root * ${config.services.ooknet-site. │
│ webroot} │
│ +# file_server │
│ +# ''; │
│ +# │
│ +# Failed builds never touch the symlink, so │
│ a broken push can't take │
│ +# the site down. │
│ +{ │
│ + config, │
│ + lib, │
│ + pkgs, │
│ + ... │
│ +}: let │
│ + inherit (lib) mkEnableOption mkOption mkI │
│ f types concatMapStringsSep escapeShellArg; │
│ + │
│ + cfg = config.services.ooknet-site; │
│ + │
│ + buildScript = pkgs.writeShellApplication │
│ { │
│ + name = "ooknet-site-build"; │
│ + runtimeInputs = [pkgs.git cfg.nodejs pk │
│ gs.coreutils pkgs.findutils]; │
│ + text = '' │
│ + state=${escapeShellArg cfg.stateDir} │
│ + src="$state/src" │
│ + export HOME="$state" │
│ + export npm_config_cache="$state/npm-c │
│ ache" │
│ + │
│ + # site source │
│ + if [ ! -d "$src/.git" ]; then │
│ + git clone --branch ${escapeShellArg │
│ cfg.branch} ${escapeShellArg cfg.siteRepo} │
│ "$src" │
│ + fi │
│ + git -C "$src" fetch origin ${escapeSh │
│ ellArg cfg.branch} │
│ + git -C "$src" reset --hard origin/${e │
│ scapeShellArg cfg.branch} │
│ + │
│ + # bare mirrors for the /git pages │
│ + mkdir -p "$state/mirrors" │
│ + ${concatMapStringsSep "\n" (m: '' │
│ + if [ ! -d "$state/mirrors/${m.slug} │
│ .git" ]; then │
│ + git clone --mirror ${escapeShellA │
│ rg m.url} "$state/mirrors/${m.slug}.git" │
│ + else │
│ + git -C "$state/mirrors/${m.slug}. │
│ git" remote update --prune │
│ + fi │
│ + '') cfg.mirrors} │
│ + │
│ + # build │
│ + cd "$src/${cfg.siteSubdir}" │
│ + npm ci --no-audit --no-fund │
│ + OOKNET_GIT_ROOT="$state/mirrors" npm │
│ run build │
│ + │
│ + # publish: timestamped dir, atomic sy │
│ mlink swap, prune old builds │
│ + ts=$(date +%Y%m%d-%H%M%S) │
│ + mkdir -p "$state/builds" │
│ + cp -r dist "$state/builds/$ts" │
│ + chmod -R a+rX "$state/builds/$ts" │
│ + ln -sfn "builds/$ts" "$state/current. │
│ tmp" │
│ + mv -T "$state/current.tmp" "$state/cu │
│ rrent" │
│ + find "$state/builds" -mindepth 1 -max │
│ depth 1 -type d \ │
│ + | sort | head -n -${toString cfg.ke │
│ epBuilds} | xargs -r rm -rf │
│ + ''; │
│ + }; │
│ + │
│ + # socket-activated per-connection handler │
│ : drain the request, answer │
│ + # 204, poke the trigger file the path uni │
│ t watches. Localhost only; │
│ + # forgejo is on the same host, so no secr │
│ et handshake is needed. │
│ + webhookHandler = pkgs.writeShellApplicati │
│ on { │
│ + name = "ooknet-site-webhook"; │
│ + runtimeInputs = [pkgs.coreutils]; │
│ + text = '' │
│ + length=0 │
│ + while IFS= read -r line; do │
│ + line=''${line%$'\r'} │
│ + [ -z "$line" ] && break │
│ + case "$line" in │
│ + [Cc]ontent-[Ll]ength:*) length='' │
│ ${line##*: } ;; │
│ + esac │
│ + done │
│ + [ "$length" -gt 0 ] 2>/dev/null && he │
│ ad -c "$length" > /dev/null │
│ + printf 'HTTP/1.1 204 No Content\r\nCo │
│ nnection: close\r\n\r\n' │
│ + date +%s%N > ${escapeShellArg cfg.sta │
│ teDir}/trigger │
│ + ''; │
│ + }; │
│ +in { │
│ + options.services.ooknet-site = { │
│ + enable = mkEnableOption "the ooknet.org │
│ site builder"; │
│ + │
│ + siteRepo = mkOption { │
│ + type = types.str; │
│ + default = "http://localhost:3000/ooks │
│ /ooknet.org.git"; │
│ + description = "Clone url of the site │
│ repository."; │
│ + }; │
│ + │
│ + branch = mkOption { │
│ + type = types.str; │
│ + default = "master"; │
│ + description = "Branch the site deploy │
│ s from."; │
│ + }; │
│ + │
│ + siteSubdir = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-design"; │
│ + description = "Subdirectory of the si │
│ te repo holding package.json."; │
│ + }; │
│ + │
│ + mirrors = mkOption { │
│ + type = types.listOf (types.submodule │
│ { │
│ + options = { │
│ + slug = mkOption { │
│ + type = types.str; │
│ + description = "Mirror name; mus │
│ t match a slug in the site's git.config.ts." │
│ ; │
│ + }; │
│ + url = mkOption { │
│ + type = types.str; │
│ + description = "Clone url, typic │
│ ally anonymous http from local forgejo."; │
│ + }; │
│ + }; │
│ + }); │
│ + default = []; │
│ + description = "Repositories rendered │
│ by the site's /git pages."; │
│ + }; │
│ + │
│ + nodejs = mkOption { │
│ + type = types.package; │
│ + default = pkgs.nodejs; │
│ + description = "Node used for the buil │
│ d; keep in step with the site dev shell."; │
│ + }; │
│ + │
│ + stateDir = mkOption { │
│ + type = types.path; │
│ + default = "/var/lib/ooknet-site"; │
│ + description = "Builder state: source │
│ checkout, mirrors, npm cache, builds."; │
│ + }; │
│ + │
│ + webroot = mkOption { │
│ + type = types.path; │
│ + readOnly = true; │
│ + default = "${cfg.stateDir}/current"; │
│ + description = "Point the webserver ro │
│ ot here; a symlink to the last good build."; │
│ + }; │
│ + │
│ + webhook = { │
│ + enable = mkOption { │
│ + type = types.bool; │
│ + default = true; │
│ + description = "Listen for forgejo p │
│ ush webhooks on localhost."; │
│ + }; │
│ + address = mkOption { │
│ + type = types.str; │
│ + default = "127.0.0.1"; │
│ + description = "Bind address. Keep i │
│ t loopback; there is no auth."; │
│ + }; │
│ + port = mkOption { │
│ + type = types.port; │
│ + default = 9473; │
│ + description = "Webhook port; forgej │
│ o posts to http://address:port/."; │
│ + }; │
│ + }; │
│ + │
│ + timer = mkOption { │
│ + type = types.nullOr types.str; │
│ + default = "daily"; │
│ + description = "systemd OnCalendar bac │
│ kstop rebuild; null disables."; │
│ + }; │
│ + │
│ + keepBuilds = mkOption { │
│ + type = types.ints.positive; │
│ + default = 3; │
│ + description = "Previous builds retain │
│ ed for rollback."; │
│ + }; │
│ + │
│ + user = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-site"; │
│ + description = "Builder user."; │
│ + }; │
│ + │
│ + group = mkOption { │
│ + type = types.str; │
│ + default = "ooknet-site"; │
│ + description = "Builder group."; │
│ + }; │
│ + }; │
│ + │
│ + config = mkIf cfg.enable { │
│ + users.users.${cfg.user} = { │
│ + isSystemUser = true; │
│ + inherit (cfg) group; │
│ + home = cfg.stateDir; │
│ + }; │
│ + users.groups.${cfg.group} = {}; │
│ + │
│ + systemd.tmpfiles.rules = [ │
│ + # 0755 so the webserver can follow cu │
│ rrent/ into builds/ │
│ + "d ${cfg.stateDir} 0755 ${cfg.user} $ │
│ {cfg.group} - -" │
│ + "f ${cfg.stateDir}/trigger 0644 ${cfg │
│ .user} ${cfg.group} - -" │
│ + ]; │
│ + │
│ + systemd.services.ooknet-site-build = { │
│ + description = "ooknet.org site build" │
│ ; │
│ + serviceConfig = { │
│ + Type = "oneshot"; │
│ + User = cfg.user; │
│ + Group = cfg.group; │
│ + ExecStart = lib.getExe buildScript; │
│ + WorkingDirectory = cfg.stateDir; │
│ + TimeoutStartSec = "15min"; │
│ + # coalesce push bursts before the e │
│ xpensive part starts │
│ + ExecStartPre = "${pkgs.coreutils}/b │
│ in/sleep 3"; │
│ + PrivateTmp = true; │
│ + NoNewPrivileges = true; │
│ + }; │
│ + }; │
│ + │
│ + systemd.timers.ooknet-site-build = mkIf │
│ (cfg.timer != null) { │
│ + description = "ooknet.org site rebuil │
│ d backstop"; │
│ + wantedBy = ["timers.target"]; │
│ + timerConfig = { │
│ + OnCalendar = cfg.timer; │
│ + Persistent = true; │
│ + RandomizedDelaySec = "10m"; │
│ + }; │
│ + }; │
│ + │
│ + systemd.paths.ooknet-site-trigger = mkI │
│ f cfg.webhook.enable { │
│ + description = "ooknet.org rebuild tri │
│ gger"; │
│ + wantedBy = ["paths.target"]; │
│ + pathConfig = { │
│ + PathModified = "${cfg.stateDir}/tri │
│ gger"; │
│ + Unit = "ooknet-site-build.service"; │
│ + }; │
│ + }; │
│ + │
│ + systemd.sockets.ooknet-site-webhook = m │
│ kIf cfg.webhook.enable { │
│ + description = "ooknet.org webhook soc │
│ ket"; │
│ + wantedBy = ["sockets.target"]; │
│ + listenStreams = ["${cfg.webhook.addre │
│ ss}:${toString cfg.webhook.port}"]; │
│ + socketConfig.Accept = true; │
│ + }; │
│ + │
│ + systemd.services."ooknet-site-webhook@" │
│ = mkIf cfg.webhook.enable { │
│ + description = "ooknet.org webhook han │
│ dler"; │
│ + serviceConfig = { │
│ + User = cfg.user; │
│ + Group = cfg.group; │
│ + StandardInput = "socket"; │
│ + StandardOutput = "socket"; │
│ + ExecStart = lib.getExe webhookHandl │
│ er; │
│ + PrivateTmp = true; │
│ + NoNewPrivileges = true; │
│ + }; │
│ + }; │
│ + }; │
│ +} │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET