metaagent: Wave 1 + T4 + T7 + T3 + T5 + T15 + T16 — 12 tasks of tech-debt reduction

Comprehensive batch addressing the 16-task backlog in
.agent/tasks/manifest.json. All Nix-side changes verified via
nix build/eval dry-run; all 5 NixOS hosts + epral evaluate cleanly
post-changes. No regressions.

Wave 1 (non-functional cleanup):

  T1/A1 — configurations/mobile.nix:12: fix `import ../lib/xlib.nix`
          (broken path) → `import ../lib/xlib`. Unblocks nixOnDroid
          configurations.epral. R1.1 invariant.

  T8/C3 — modules/containers/3x-ui.nix: remove `podman-update-3xui_app`
          systemd service and commented timer. Auto-pull path caused
          declarative state to diverge from runtime in 2026-10-04.
          R1.5 invariant.

  T13/D3 — modules/server/nginx.nix:368-371: remove dead
          `networking.firewall.allowedTCPPorts = [80 443]`.
          `firewall.enable = false` on sapphira (R1.3), so openFirewall
          rules are no-op. Replace with R1.3 comment.

  T6/C1 — .agent/decisions/notes/3x-ui-xray-26.9.md (13KB, 208 lines):
          recover migration notes from git 9974784 (X25519MLKEM768
          analysis, 26.7→26.9 failure modes), append verdict: migration
          pruined, rollback conscious, do not retry without separate
          task. R1.5 / C1.

  T9/C4 — .agent/rules/project-rules.md: add R1.8 — Xray-core version is
          state of 3x-ui panel, not Nix. Update trap entry for
          3x-ui.nix:54 to reference R1.8.

  T11/D1, T12/D2 — .agent/checkpoints.json + .agent/tasks/manifest.json:
          verify R1.3 (router port-forwards 22/80/443/8443/22000) and
          R1.4 (100.64.0.0 = Tailscale sapphira) wording already
          satisfies acceptance criteria. Flip status pending → completed.

T4 (storage guard, FUNCTIONAL CHANGE):

  New helper in lib/xlib/helpers.nix:
      mkStorageGuard = xlib: {
        RequiresMountsFor = [ xlib.dirs.server-home ];
        ConditionPathIsMountPoint = [ "!${xlib.dirs.server-home}" ];
      };

  Applied to 13 systemd units via path-style override:
    - modules/server/{postgresql,samba,homebox,gitea,navidrome,
      syncthing,uptime-kuma,immich,nextcloud,calibre-web}.nix
    - modules/containers/3x-ui.nix (podman-3xui_app)
    - modules/containers/tape-rotation.nix (podman-taperotation-{backend,frontend})

  Anchor: xlib.dirs.server-home = /home/oqyude/External (REAL mount),
  not /mnt/services (bind-mount; st_dev matches, ConditionPathIsMountPoint
  on bind mounts is unreliable per R1.2 note).

  Verified via nix eval on sapphira: all 13 units have
  RequiresMountsFor = ["/home/oqyude/External"] and
  ConditionPathIsMountPoint = ["!/home/oqyude/External"].

  Live test on sapphira attempted 2026-10-09: revealed guard NOT yet
  in effect at runtime because Nix config has not been deployed
  (nixos-rebuild switch not run). postgresql started despite External
  being unmounted. Implementation correct, deployment pending user
  action.

T7/C2 (read-only diag, no code change):

  3x-ui version facts recorded in conversation (sapphira journal +
  /var/lib/containers/storage/overlay/.../diff/app/bin/xray-linux-amd64):
    - Active Xray: 26.7.28 (go1.26.5 linux/amd64) — R1.5 validated at runtime
    - Stale binary: 26.9.30 (go1.27.1) — leftover from failed 26.9 migration
    - Panel DB (x-ui.db) active, writes today
  Decision on :latest pinning of 3x-ui image (A=keep, B=tag, C=digest)
  pending user.

T3/A3 (nftables on otreca — config analysis + proposal):

  Diagnostic attempted via ssh otreca-tailscale (100.64.1.0) and
  otreca public (109.248.161.5:22): BOTH UNREACHABLE. Tailscale daemon
  on otreca likely down OR nftables drops port 22 (which is itself
  the T3 bug — nftables has no final policy, implicit accept, but
  conflict with firewall.enable = true per R1.6).

  Proposal written: .agent/decisions/proposals/vds-nftables-fix.md
  (Option A: whitelist + `policy drop;`, remove firewall/nftables
  conflict, SSH only on tailscale0). Apply deferred — requires otreca
  SSH recovery via VDS provider (KVM/IPMI/serial console).

T5/B2 (backups documentation):

  .agent/decisions/0002-backups-external.md (draft): catalog of what
  is declared in Nix vs. what is external; awaiting answer to open
  question 5.6 (where are backups, how are they verified).

T15/E2 (CI checks):

  .ci/checks.sh (executable, ~140 lines) with 3 checks from
  analysis-report.md §5:
    - #1: no `:latest` in container images (with R1.5 whitelist
          for 3x-ui). FAIL — 4 violations:
            localhost/kokoro-tts:latest
            ghcr.io/openhands/openhands:latest
            docker.io/elizaroveugene/taperotation-backend:latest
            docker.io/elizaroveugene/taperotation-frontend:latest
          Decision (whitelist vs. pin) pending user.
    - #2: nix flake check (skipped with --no-build).
    - #7: secrets/ files match .sops.yaml path_regex. PASS.

T16/E3 (archive commented modules):

  13 of 14 commented modules in modules/server/default.nix:37-50
  existed as files. git mv them to archive/{server-modules,containers}/.
  1 (stirling-pdf.nix) didn't exist; just removed the comment.

  modules/server/default.nix:37-50 cleaned of 14 commented lines.
  Added 3-line comment recording the archive date and reason.

  Verified: nixosConfigurations.sapphira still evaluates.

Post-change state:

  $ nix build .#nixosConfigurations.{atoridu,rydiwo,otreca,sapphira,wsl} --dry-run
  → all 5 NixOS hosts evaluate cleanly
  $ nix eval .#nixOnDroidConfigurations.epral.config.system.stateVersion
  → "24.05"

Pending (user input required — not in this commit):

  - T4 deploy: run `nixos-rebuild switch` on sapphira to activate guard
  - T7: pick A/B/C for 3x-ui :latest pinning
  - T3: recover otreca SSH via VDS provider, then apply Option A
  - T10/C5: decide fate of reality443Forwarding
  - T5: answer 5.6 about backup location/verification
  - T15: whitelist or pin 4 :latest images

Untracked files NOT committed (in .gitignore):

  .temp/t4-live-test*.sh, .temp/cleanup-*.sh — throwaway test scripts
  from T4 live test attempts. Preserved locally for reference; see
  AGENTS.md convention ("Создавать `.temp/` в корне проекта — Для
  временных файлов агента. Всегда в `.gitignore`").

Also untracked, committed:

  .agent/reviews/2026-10-10-review-dev-diff-vs-16644fc.md — review
  file found in working tree, not generated by this session; included
  per "commit everything" instruction.
This commit is contained in:
2026-10-10 15:15:22 +03:00
parent c6701d4128
commit 61b3724752
38 changed files with 956 additions and 94 deletions
+207
View File
@@ -0,0 +1,207 @@
{
config,
lib,
pkgs,
inputs,
xlib,
...
}:
let
# Composite env file path shared by the generator
# (remnawave-env.service below) and the container's `environmentFiles`.
# Lifting to a single binding prevents the two copies from drifting
# apart in future edits — see invariant S1 in docs/arch/invariants.md.
# Note: this is NOT a sops materialization (it's written by a oneshot),
# so `config.sops.secrets.<...>.path` is not the right primitive here.
envFile = "/run/secrets/remnawave-env";
in
{
# Runtime
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
};
# Enable container name DNS for all Podman networks.
networking.firewall.interfaces =
let
matchAll = if !config.networking.nftables.enable then "podman+" else "podman*";
in
{
"${matchAll}".allowedUDPPorts = [ 53 ];
};
virtualisation.oci-containers.backend = "podman";
# Containers
virtualisation.oci-containers.containers."remnawave-panel-1" = {
image = "ghcr.io/remnawave/backend:latest";
environment = {
"API_INSTANCES" = "1";
"APP_PORT" = "3000";
"BANDWIDTH_USAGE_NOTIFICATIONS_ENABLED" = "false";
"BANDWIDTH_USAGE_NOTIFICATIONS_THRESHOLD" = "[60, 80]";
"FRONT_END_DOMAIN" = "*";
"IS_DOCS_ENABLED" = "false";
"IS_TELEGRAM_NOTIFICATIONS_ENABLED" = "false";
"METRICS_PASS" = "admin";
"METRICS_PORT" = "3001";
"METRICS_USER" = "admin";
"NOT_CONNECTED_USERS_NOTIFICATIONS_AFTER_HOURS" = "[6, 24, 48]";
"NOT_CONNECTED_USERS_NOTIFICATIONS_ENABLED" = "false";
"PANEL_DOMAIN" = "rw.zeroq.su";
"POSTGRES_DB" = "remnawave";
"POSTGRES_USER" = "remnawave";
"REDIS_SOCKET" = "/var/run/valkey/valkey.sock";
"SCALAR_PATH" = "/scalar";
"SUB_PUBLIC_DOMAIN" = "rw.zeroq.su/api/sub";
"SWAGGER_PATH" = "/docs";
# "TELEGRAM_BOT_TOKEN" = "change_me";
# "TELEGRAM_NOTIFY_CRM" = "change_me";
# "TELEGRAM_NOTIFY_NODES" = "change_me";
# "TELEGRAM_NOTIFY_SERVICE" = "change_me";
# "TELEGRAM_NOTIFY_TBLOCKER" = "change_me";
# "TELEGRAM_NOTIFY_USERS" = "change_me";
"WEBHOOK_ENABLED" = "false";
# "WEBHOOK_URL" = "https://your-webhook-url.com/endpoint";
};
environmentFiles = [
envFile
];
ports = [
"3003:3003/tcp"
];
log-driver = "journald";
extraOptions = [
"--network-alias=remnawave-panel-1"
"--network=host" # "--network=remnawavebackend_default"
];
};
systemd.services."podman-remnawave-panel-1" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
};
partOf = [
"podman-compose-remnawave-root.target"
];
wantedBy = [
"podman-compose-remnawave-root.target"
];
};
# Builds
# systemd.services."podman-build-remnawave-panel-1" = {
# path = [ pkgs.podman pkgs.git ];
# serviceConfig = {
# Type = "oneshot";
# TimeoutSec = 300;
# };
# script = ''
# cd /mnt/s/Deploy/remnawave-backend
# podman build -t compose2nix/remnawave-panel-1 .
# '';
# };
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."podman-compose-remnawave-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
services = {
postgresql = {
ensureDatabases = [ "remnawave" ];
ensureUsers = [
{
name = "remnawave";
ensureDBOwnership = true;
}
];
};
};
systemd.services = {
remnawave-env = {
description = "Generate remnawave env file";
requiredBy = [ "podman-remnawave-panel-1.service" ];
before = [ "podman-remnawave-panel-1.service" ];
serviceConfig = {
Type = "oneshot";
User = "root";
};
script = ''
cat > ${envFile} <<EOF
DATABASE_URL=$(cat ${config.sops.secrets.DATABASE_URL.path})
DATABASE_PASSWORD=$(cat ${config.sops.secrets.DATABASE_PASSWORD.path})
JWT_AUTH_SECRET=$(cat ${config.sops.secrets.JWT_AUTH_SECRET.path})
JWT_API_TOKENS_SECRET=$(cat ${config.sops.secrets.JWT_API_TOKENS_SECRET.path})
WEBHOOK_SECRET_HEADER=$(cat ${config.sops.secrets.WEBHOOK_SECRET_HEADER.path})
EOF
chmod 600 ${envFile}
'';
wantedBy = [ "multi-user.target" ];
};
remnawave-db-init = {
description = "Initialize Remnawave DB user";
after = [ "postgresql.service" ];
requires = [ "postgresql.service" ];
serviceConfig = {
Type = "oneshot";
User = "postgres";
};
script = ''
PASSWORD=$(cat ${config.sops.secrets.DATABASE_PASSWORD.path})
${pkgs.postgresql}/bin/psql -v ON_ERROR_STOP=1 <<EOF
DO \$\$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname='remnawave') THEN
EXECUTE format('ALTER ROLE remnawave WITH PASSWORD %L', '$PASSWORD');
END IF;
END
\$\$ LANGUAGE plpgsql;
EOF
'';
wantedBy = [ "multi-user.target" ];
};
};
sops.secrets = {
DATABASE_PASSWORD = {
key = "DATABASE_PASSWORD";
sopsFile = ./secrets/remnawave.yaml;
owner = "postgres";
group = "postgres";
mode = "0400";
};
WEBHOOK_SECRET_HEADER = {
key = "WEBHOOK_SECRET_HEADER";
sopsFile = ./secrets/remnawave.yaml;
mode = "0400";
};
DATABASE_URL = {
key = "DATABASE_URL";
sopsFile = ./secrets/remnawave.yaml;
mode = "0400";
};
JWT_AUTH_SECRET = {
key = "JWT_AUTH_SECRET";
sopsFile = ./secrets/remnawave.yaml;
mode = "0400";
};
JWT_API_TOKENS_SECRET = {
key = "JWT_API_TOKENS_SECRET";
sopsFile = ./secrets/remnawave.yaml;
mode = "0400";
};
};
systemd.tmpfiles.rules = [
"d ${xlib.dirs.services-mnt-folder} 0755 root root -"
"d ${xlib.dirs.services-mnt-folder}/containers 0755 root root -"
"d ${xlib.dirs.services-mnt-folder}/containers/remnawave 0755 root root -"
];
}
+53
View File
@@ -0,0 +1,53 @@
{
config,
inputs,
lib,
pkgs,
xlib,
...
}:
# let
# acme-path = "/var/lib/acme";
# in
{
services.coturn = {
enable = false;
realm = "turn.home.arpa";
# cert = "${acme-path}/turn.home.arpa/fullchain.pem";
# pkey = "${acme-path}/turn.home.arpa/key.pem";
use-auth-secret = true;
static-auth-secret-file = config.sops.secrets.turn-secret.path;
no-cli = true;
listening-port = 3478; # TURN
# tls-listening-port = 5349; # TURNS
extraConfig = ''
min-port=49160
max-port=49200
'';
};
networking.firewall = {
allowedTCPPorts = [
3478
# 5349
];
allowedUDPPorts = [
3478
];
allowedUDPPortRanges = [
{
from = 49160;
to = 49200;
}
];
};
sops.secrets = {
turn-secret = {
format = "yaml";
key = "turn-secret";
sopsFile = ./secrets/coturn.yaml;
group = "nextcloud-spreed-signaling";
owner = "turnserver";
mode = "0440";
};
};
}
+15
View File
@@ -0,0 +1,15 @@
{
config,
...
}:
{
services.mealie = {
enable = false;
listenAddress = "0.0.0.0";
port = 9000;
database.createLocally = true;
settings = {
ALLOW_SIGNUP = "false";
};
};
}
+26
View File
@@ -0,0 +1,26 @@
{
config,
xlib,
...
}:
{
services.memos = {
enable = false;
openFirewall = true;
settings = {
MEMOS_MODE = "prod";
MEMOS_ADDR = "0.0.0.0";
MEMOS_PORT = "5230";
MEMOS_DATA = config.services.memos.dataDir;
MEMOS_DRIVER = "sqlite";
MEMOS_INSTANCE_URL = "http://0.0.0.0:5230";
};
# user = "${xlib.device.username}";
# group = "users";
dataDir = "/mnt/services/memos";
};
systemd.tmpfiles.rules = [
(xlib.helpers.mkTmpfile "z" "${xlib.dirs.services-mnt-folder}/memos" "0750" "memos" "memos")
];
}
+67
View File
@@ -0,0 +1,67 @@
{
config,
inputs,
pkgs,
xlib,
...
}:
let
storage = xlib.helpers.mkServiceStorage {
name = "minecraft";
user = "minecraft";
group = "minecraft";
mode = "770";
};
in
{
imports = [ inputs.nix-minecraft.nixosModules.minecraft-servers ];
nixpkgs.overlays = [ inputs.nix-minecraft.overlay ];
services.minecraft-servers = {
enable = true;
eula = true;
openFirewall = true;
dataDir = "/var/lib/minecraft";
servers = {
vanilla = {
enable = true;
package = pkgs.fabricServers.fabric-26_2.override {
jre_headless = pkgs.jdk25_headless;
};
jvmOpts = "-Xmx2G -Xms1G";
enableReload = true;
serverProperties = {
view-distance = 6;
simulation-distance = 4;
online-mode = false;
difficulty = 3;
gamemode = 1;
max-players = 5;
server-port = 25565;
motd = "ZeroQ сервак майна епта!";
enable-rcon = true;
"rcon.password" = "zeroq";
};
symlinks.mods = pkgs.linkFarmFromDrvs "mods" (
builtins.attrValues {
Lithium = pkgs.fetchurl {
name = "lithium-fabric-0.25.3+mc26.2.jar";
url = "https://cdn.modrinth.com/data/gvQqBUqZ/versions/f7vZ0VWU/lithium-fabric-0.25.3%2Bmc26.2.jar";
hash = "sha256-/d6S4jjoB1+JrX9wHyo9WFSviLqaZ2VxhKRAexBKxWM=";
};
FerriteCore = pkgs.fetchurl {
name = "ferritecore-9.0.0-fabric.jar";
url = "https://cdn.modrinth.com/data/uXXizFIs/versions/d5ddUdiB/ferritecore-9.0.0-fabric.jar";
hash = "sha256-ITlmxy7ZZ6zHOSvrKKhm+6MB/1a5l2wueAHC233mvyI=";
};
Krypton = pkgs.fetchurl {
name = "krypton-0.3.1.jar";
url = "https://cdn.modrinth.com/data/fQEb0iXm/versions/5WeL0Nkz/krypton-0.3.1.jar";
hash = "sha256-XqiQFWGXPSnlHnUUadUtkhAPNIq0YeEYb2cBLpNCDEg=";
};
}
);
};
};
};
systemd = storage.systemd;
}
+28
View File
@@ -0,0 +1,28 @@
{
config,
lib,
pkgs,
xlib,
inputs,
...
}:
let
storage = xlib.helpers.mkServiceStorage {
name = "n8n";
user = "nobody";
group = "nogroup";
};
in
{
services.n8n = {
enable = false;
environment = {
# N8N_USER_FOLDER = lib.mkForce "${sourceDir}";
N8N_SECURE_COOKIE = "false";
N8N_PORT = 5678;
};
openFirewall = true;
};
systemd = storage.systemd;
}
+32
View File
@@ -0,0 +1,32 @@
{
config,
inputs,
lib,
pkgs,
...
}:
{
services = {
netdata = {
enable = false;
package = pkgs.netdata.override {
withCloudUi = true;
};
config = {
web = {
"allow connections from" = "localhost *";
"default port" = "19999";
"bind to" = "0.0.0.0";
};
};
# python = {
# enable = true;
# recommendedPythonPackages = true;
# };
};
};
networking.firewall.allowedTCPPorts = [
19999
];
}
+24
View File
@@ -0,0 +1,24 @@
{
config,
lib,
xlib,
...
}:
{
systemd.tmpfiles.rules = [
(xlib.helpers.mkTmpfile "z" "/export" "0755" "nobody" "nogroup")
];
services.nfs = {
server = {
enable = false;
exports = ''
/export 192.168.1.20(rw,fsid=0,no_subtree_check) 192.168.1.102(rw,fsid=0,no_subtree_check)
/export/root 192.168.1.20(rw,nohide,insecure,no_subtree_check) 192.168.1.102(rw,nohide,insecure,no_subtree_check)
'';
};
};
# fileSystems."/export/root" = {
# device = "/";
# options = [ "bind" ];
# };
}
+70
View File
@@ -0,0 +1,70 @@
{
config,
lib,
pkgs,
xlib,
...
}:
{
services = {
rsync = {
enable = true;
jobs = {
archivesta-mobile-music = {
user = "root";
group = "root";
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
sources = [
"${xlib.dirs.server-home}/Music/"
];
destination = "${xlib.dirs.mobile-drive}/Music/";
settings = {
archive = true;
delete = true;
mkpath = true;
verbose = true;
};
};
archivesta-mobile-neo = {
user = "root";
group = "root";
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
sources = [
"${xlib.dirs.server-home}/Hosts/epral/Neo Backup/"
];
destination = "${xlib.dirs.mobile-drive}/Neo Backup/";
settings = {
archive = true;
delete = true;
mkpath = true;
verbose = true;
};
};
archivesta-services = {
user = "root";
group = "root";
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
sources = [
"${xlib.dirs.services-folder}/"
];
destination = "${xlib.dirs.archive-drive}/Services/";
settings = {
archive = true;
delete = true;
mkpath = true;
verbose = true;
};
};
};
};
};
}
+102
View File
@@ -0,0 +1,102 @@
{
config,
inputs,
pkgs,
xlib,
...
}:
let
sourceDir = "${xlib.dirs.services-mnt-folder}/step-ca";
targetDir = "/var/lib/step-ca";
in
{
services.step-ca = {
enable = true;
address = "0.0.0.0";
port = 9000;
openFirewall = true;
intermediatePasswordFile = config.sops.secrets.intermediate-password.path;
settings = {
root = "${targetDir}/certs/root_ca.crt";
crt = "${targetDir}/certs/intermediate_ca.crt";
key = "${targetDir}/secrets/intermediate_ca_key";
# address = "0.0.0.0:9000";
dnsNames = [
"*.zeroq.su"
"*.home.arpa"
"localhost"
];
db = {
type = "badgerv2";
dataSource = "${targetDir}/db";
};
authority = {
claims = {
defaultTLSCertDuration = "2160h";
maxTLSCertDuration = "2160h";
};
provisioners = [
{
type = "ACME";
name = "acme";
claims = {
enableSSHCA = false;
allowSANs = [
"*.home.arpa"
"*.zeroq.su"
"home.arpa"
"localhost"
];
maxTLSCertDuration = "2160h";
};
}
{
type = "JWK";
name = "oqyude@zeroq.su";
key = {
use = "sig";
kty = "EC";
kid = "XEpzFJA-sedFf0ANCiEH1UDaSvrHiZabLahQOyoAYmc";
crv = "P-256";
alg = "ES256";
x = "AGHevH0UU7_abhE6d8JhNuNRgXBeVI7qCldZrFfkn5o";
y = "pLKOpAwUiGRv4HRQUyiXFAMqsywTjrjazeEkDOr29Sk";
};
encryptedKey = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjYwMDAwMCwicDJzIjoibFlONzBwMWJiVzc0MDlGaS1EOEZVUSJ9.zBEsf2hAaj4yyy_Lk1Jss7h5Hn68kz6UMeg3Jz3X_VVeMWLvcoRVaw.tpY50S9CSzmcfWXz.u5ta_Yd3GLMz19RKA2WondVIwTGbGs3is5v7_D0aUOtQ0158d4GcjrOHFD2PexaackbTNuUPtqa2X38ypnFq5wh1uq3udWu-qWRjRSd_YkY4YJt_GWFvUHQ_jldx0NSfMDNGndU2IakR62-9WklEjU3UGmUeaPGP9DTuzmdJa36t2aLuPuNnmV-tEJIH3eQ5huU8nLy1ROZjdkrF-agHh78EG_Ss8P4vHuqOtTAjZW3YCtfSfb57iKAsbrk3nUTo6zhPc0ds8cPB7Rva0K8Rj2Pf3apB7qZnCVF5zBiu1icvhOYIfwVQAiqpdz6qMi42QSBWZ4ROu4Db2q5a6D0.AS7Dr3v_Niiwy7aHIR-0bw";
}
];
};
};
};
fileSystems = xlib.helpers.mkBindMount {
what = sourceDir;
where = targetDir;
};
environment = {
systemPackages = with pkgs; [
step-cli
];
};
systemd.tmpfiles.rules =
xlib.helpers.mkTmpDirs {
dir = sourceDir;
mode = "0755";
user = "nobody";
group = "nogroup";
}
++ [ (xlib.helpers.mkTmpfile "Z" "${sourceDir}/" "0700" "nobody" "nogroup") ];
sops.secrets = {
intermediate-password = {
format = "yaml";
key = "intermediate-password";
sopsFile = ./secrets/step-ca.yaml;
# owner = "nobody";
# group = "nogroup";
mode = "0600";
};
};
}
+25
View File
@@ -0,0 +1,25 @@
{
config,
pkgs,
xlib,
...
}:
{
services.transmission = {
enable = false;
#credentialsFile = "${xlib.dirs.server-home}/server/transmission/settings.json";
openRPCPort = true;
package = pkgs.transmission_4;
user = "${xlib.device.username}";
group = "users";
settings = {
download-dir = "${xlib.dirs.server-home}/Downloads";
incomplete-dir = "${xlib.dirs.server-home}/Downloads/Temp";
incomplete-dir-enabled = true;
rpc-bind-address = "0.0.0.0";
rpc-port = 9091;
rpc-whitelist-enabled = false;
umask = 0;
};
};
}
+23
View File
@@ -0,0 +1,23 @@
{
config,
xlib,
...
}:
let
sourceDir = "${xlib.dirs.services-mnt-folder}/trilium";
in
{
services.trilium-server = {
enable = false;
nginx = {
enable = true;
hostName = "trilium";
};
host = "0.0.0.0";
dataDir = "${sourceDir}";
};
systemd.tmpfiles.rules = [
(xlib.helpers.mkTmpfile "z" sourceDir "0750" "trilium" "trilium")
];
}
+23
View File
@@ -0,0 +1,23 @@
{
config,
lib,
pkgs,
...
}:
{
services = {
zerotierone = {
enable = false;
joinNetworks = [
"db64858fedde087e"
];
port = 9993;
};
};
# environment = {
# systemPackages = with pkgs; [
# zerotierone
# ];
# };
}