163 lines
4.7 KiB
Nix
163 lines
4.7 KiB
Nix
{ config, pkgs, ... }:
|
|
let
|
|
foundry-vtt = pkgs.callPackage ../pkgs/foundry-vtt {};
|
|
cids = import ../modules/staticids.nix;
|
|
hostConfig = config;
|
|
url = "https://foundry-vtt.cloonar.com"; # URL to check
|
|
targetService = "container@foundry-vtt.service"; # systemd unit to restart (e.g. "docker-container@myapp.service")
|
|
threshold = 3; # consecutive failures before restart
|
|
interval = "1min"; # how often to run
|
|
timeoutSeconds = 10; # curl timeout
|
|
|
|
checkUrlScript = pkgs.writeShellScript "check-foundry-up" ''
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
URL="$1"
|
|
TARGET="$2"
|
|
THRESHOLD="$3"
|
|
TIMEOUT="$4"
|
|
|
|
STATE_DIR="/run/url-watchdog"
|
|
mkdir -p "$STATE_DIR"
|
|
SAFE_TARGET="$(systemd-escape --path "$TARGET")"
|
|
STATE_FILE="$STATE_DIR/$SAFE_TARGET.count"
|
|
|
|
TMP="$(mktemp)"
|
|
# Get HTTP status; "000" if curl fails.
|
|
status="$(curl -sS -m "$TIMEOUT" -o "$TMP" -w "%{http_code}" "$URL" || echo "000")"
|
|
|
|
fail=0
|
|
if [[ "$status" == "502" || "$status" == "504" || "$status" == "000" ]]; then
|
|
fail=1
|
|
fi
|
|
|
|
count=0
|
|
if [[ -f "$STATE_FILE" ]]; then
|
|
count="$(cat "$STATE_FILE" 2>/dev/null || echo 0)"
|
|
fi
|
|
|
|
if [[ "$fail" -eq 1 ]]; then
|
|
count=$((count+1))
|
|
else
|
|
count=0
|
|
fi
|
|
|
|
if [[ "$count" -ge "$THRESHOLD" ]]; then
|
|
printf '[%s] %s failing (%s) %sx -> restarting %s\n' "$(date -Is)" "$URL" "$status" "$count" "$TARGET"
|
|
systemctl restart "$TARGET"
|
|
count=0
|
|
fi
|
|
|
|
echo "$count" > "$STATE_FILE"
|
|
rm -f "$TMP"
|
|
'';
|
|
in {
|
|
users.users.foundry-vtt = {
|
|
isSystemUser = true;
|
|
uid = cids.uids.foundry-vtt;
|
|
home = "/var/lib/foundry-vtt";
|
|
group = "foundry-vtt";
|
|
createHome = true;
|
|
};
|
|
|
|
users.groups.foundry-vtt = {
|
|
gid = cids.gids.foundry-vtt;
|
|
};
|
|
|
|
|
|
containers.foundry-vtt = {
|
|
autoStart = true;
|
|
ephemeral = true;
|
|
privateNetwork = true;
|
|
hostBridge = "server";
|
|
hostAddress = "${hostConfig.networkPrefix}.97.1";
|
|
localAddress = "${hostConfig.networkPrefix}.97.21/24";
|
|
bindMounts = {
|
|
"/var/lib/foundry-vtt" = {
|
|
hostPath = "/var/lib/foundry-vtt";
|
|
isReadOnly = false;
|
|
};
|
|
};
|
|
config = { lib, config, pkgs, ... }: {
|
|
networking = {
|
|
hostName = "foundry-vtt";
|
|
useHostResolvConf = false;
|
|
defaultGateway = {
|
|
address = "${hostConfig.networkPrefix}.96.1";
|
|
interface = "eth0";
|
|
};
|
|
firewall.enable = false;
|
|
nameservers = [ "${hostConfig.networkPrefix}.97.1" ];
|
|
};
|
|
systemd.services.foundry-vtt = {
|
|
description = "Foundry VTT Server";
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
environment = {
|
|
NODE_ENV = "production";
|
|
};
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.nodejs}/bin/node ${foundry-vtt}/share/foundry-vtt/main.js --dataPath=${config.users.users.foundry-vtt.home}";
|
|
Restart = "always";
|
|
User = "foundry-vtt";
|
|
WorkingDirectory = "${config.users.users.foundry-vtt.home}";
|
|
};
|
|
};
|
|
|
|
users.users.foundry-vtt = {
|
|
isSystemUser = true;
|
|
uid = cids.uids.foundry-vtt;
|
|
home = "/var/lib/foundry-vtt";
|
|
group = "foundry-vtt";
|
|
};
|
|
|
|
users.groups.foundry-vtt = {
|
|
gid = cids.gids.foundry-vtt;
|
|
};
|
|
|
|
system.stateVersion = "24.05";
|
|
};
|
|
};
|
|
|
|
systemd.services."restart-foundry-vtt" = {
|
|
description = "Restart foundry-vtt container";
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = "${pkgs.systemd}/bin/systemctl restart container@foundry-vtt.service";
|
|
};
|
|
};
|
|
|
|
systemd.timers."restart-foundry-vtt" = {
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
# 03:00 local time (Europe/Vienna for you)
|
|
OnCalendar = "03:00";
|
|
# If the machine was off at 03:00, run once at next boot
|
|
Persistent = true;
|
|
Unit = "restart-foundry-vtt.service";
|
|
};
|
|
};
|
|
|
|
systemd.services.foundry-vtt-watchdog = {
|
|
description = "Foundry VTT watchdog: restart ${targetService} on Nginx gateway errors";
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = "${checkUrlScript} ${url} ${targetService} ${toString threshold} ${toString timeoutSeconds}";
|
|
};
|
|
# Ensure needed tools are on PATH inside the unit
|
|
path = [ pkgs.curl pkgs.coreutils pkgs.systemd ];
|
|
# Wait until networking is really up
|
|
wants = [ "network-online.target" ];
|
|
after = [ "network-online.target" ];
|
|
};
|
|
|
|
systemd.timers.foundry-vtt-watchdog = {
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnBootSec = interval;
|
|
OnUnitActiveSec = interval;
|
|
AccuracySec = "10s";
|
|
};
|
|
};
|
|
}
|