Compare commits

..

24 Commits

Author SHA1 Message Date
393553c6c5 update 2026-03-10 19:36:18 -04:00
3d8e47689c transition domain name website + sources 2026-03-10 15:05:48 -04:00
f3f5a9c726 caddy: add redirect from old domain 2026-03-10 14:53:35 -04:00
3d4aea8c5b caddy: move to new domain 2026-03-10 14:53:33 -04:00
04d6a9b546 qbt: DiskIOType = Posix 2026-03-10 03:01:58 -04:00
d56697b60b qbt: remove CoalesceReadWrite (old) 2026-03-10 02:20:27 -04:00
b3a40797b6 matrix: remove pinned commit 2026-03-07 23:48:53 -05:00
f1f92703c1 update 2026-03-07 23:25:58 -05:00
c008fd2b18 zfs: don't specify zfs arc cache
Turns out, zfs is smart!
ZFS already has sane defaults, no sense in limiting the size of the cache.
2026-03-06 14:11:14 -05:00
3ccce88040 zfs: remove unneeded options 2026-03-06 13:47:06 -05:00
ad4d2d41fb zfs: tweak arc settings 2026-03-06 13:44:55 -05:00
65f5d64c1a monero: public node 2026-03-06 13:09:10 -05:00
08cbc37f94 minecraft: fix map perms 2026-03-04 19:40:18 -05:00
f784f26848 monero: changes 2026-03-04 18:56:55 -05:00
b5be21ff8c secrets: cleanup activation scripts 2026-03-04 17:35:49 -05:00
bf3c949b70 service-configs: add murmur port 2026-03-04 13:31:19 -05:00
643df612ad jellyfin: patch port 8096 being open
All jellyfin traffic should actually go through caddy.
This port being open caused a lot of confusion for me.
As I was getting traffic from typo'd domain names,
such as `jellfin.gardling.com`, which made NO SENSE!
But since it was going directly via port 8096, it
skipped caddy entirely so the traffic went through.
2026-03-04 13:29:54 -05:00
719e1c83d0 update 2026-03-04 11:45:59 -05:00
5f790d6c47 update 2026-03-03 21:59:41 -05:00
e9fe722308 add notes next to ports in service-configs 2026-03-03 20:19:28 -05:00
9c632e0876 syncthing: forgot about UDP protocol 2026-03-03 20:19:05 -05:00
c6aae99c9e monero: hook up to ports 2026-03-03 20:01:03 -05:00
a2e05d4827 cleanup port list 2026-03-03 19:54:19 -05:00
d4b679d1a5 cleanup 2026-03-03 19:39:10 -05:00
21 changed files with 371 additions and 377 deletions

View File

@@ -133,41 +133,6 @@
compressor = "zstd"; compressor = "zstd";
supportedFilesystems = [ "f2fs" ]; supportedFilesystems = [ "f2fs" ];
}; };
# BBR congestion control handles variable-latency VPN connections much
# better than CUBIC by probing bandwidth continuously rather than
# reacting to packet loss.
kernelModules = [ "tcp_bbr" ];
kernel.sysctl = {
# Use BBR + fair queuing for smooth throughput through the WireGuard VPN
"net.core.default_qdisc" = "fq";
"net.ipv4.tcp_congestion_control" = "bbr";
# Disable slow-start after idle: prevents TCP from resetting window
# size on each burst cycle (the primary cause of the 0 -> 40 MB/s spikes)
"net.ipv4.tcp_slow_start_after_idle" = 0;
# Larger socket buffers to accommodate the VPN bandwidth-delay product
# (22ms RTT * target throughput). Current 2.5MB max is too small.
"net.core.rmem_max" = 16777216;
"net.core.wmem_max" = 16777216;
"net.ipv4.tcp_rmem" = "4096 87380 16777216";
"net.ipv4.tcp_wmem" = "4096 65536 16777216";
# Higher backlog for the large number of concurrent torrent connections
"net.core.netdev_max_backlog" = 5000;
# Faster cleanup of dead connections from torrent peer churn
"net.ipv4.tcp_fin_timeout" = 15; # default 60
"net.ipv4.tcp_tw_reuse" = 1;
# Minecraft server optimizations
# Disable autogroup for better scheduling of game server threads
"kernel.sched_autogroup_enabled" = 0;
# Huge pages for Minecraft JVM (ZGC ZGenerational needs heap + ~15% overhead)
# 4000MB heap = 2000 pages, plus ~285 for ZGC metadata = ~2285 needed
"vm.nr_hugepages" = 2600;
};
}; };
environment.etc = { environment.etc = {
@@ -237,8 +202,10 @@
hostName = hostname; hostName = hostname;
hostId = "0f712d56"; hostId = "0f712d56";
firewall.enable = true; firewall.enable = true;
firewall.trustedInterfaces = [ "wg-br" ];
useDHCP = false; useDHCP = false;
# Disabled because of Jellyfin (various issues)
enableIPv6 = false; enableIPv6 = false;
interfaces.${eth_interface} = { interfaces.${eth_interface} = {
@@ -312,6 +279,7 @@
openFirewall = true; openFirewall = true;
welcometext = "meow meow meow meow meow :3 xd"; welcometext = "meow meow meow meow meow :3 xd";
password = builtins.readFile ./secrets/murmur_password; password = builtins.readFile ./secrets/murmur_password;
port = service_configs.ports.murmur;
}; };
# services.botamusique = { # services.botamusique = {

62
flake.lock generated
View File

@@ -32,10 +32,10 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772563009, "lastModified": 1772566016,
"narHash": "sha256-+LExMzFXahgoFYayrmqK4MhT9QkUplVwurcTDjk8kGI=", "narHash": "sha256-+LExMzFXahgoFYayrmqK4MhT9QkUplVwurcTDjk8kGI=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "9159444f332da049909632e294d58e91dc61d38c", "rev": "4cc1ae4e00844d2bd80da3869f17649c1cef3f8a",
"revCount": 3, "revCount": 3,
"type": "git", "type": "git",
"url": "ssh://gitea@git.gardling.com/titaniumtown/arr-init" "url": "ssh://gitea@git.gardling.com/titaniumtown/arr-init"
@@ -89,11 +89,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772420042, "lastModified": 1773025010,
"narHash": "sha256-naZz40TUFMa0E0CutvwWsSPhgD5JldyTUDEgP9ADpfU=", "narHash": "sha256-khlHllTsovXgT2GZ0WxT4+RvuMjNeR5OW0UYeEHPYQo=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "5af7af10f14706e4095bd6bc0d9373eb097283c6", "rev": "7b9f7f88ab3b339f8142dc246445abb3c370d3d3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -197,11 +197,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772380125, "lastModified": 1772985280,
"narHash": "sha256-8C+y46xA9bxcchj9GeDPJaRUDApaA3sy2fhJr1bTbUw=", "narHash": "sha256-FdrNykOoY9VStevU4zjSUdvsL9SzJTcXt4omdEDZDLk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "a07a44a839eb036e950bf397d9b782916f8dcab3", "rev": "8f736f007139d7f70752657dff6a401a585d6cbc",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -285,11 +285,11 @@
"systems": "systems_3" "systems": "systems_3"
}, },
"locked": { "locked": {
"lastModified": 1772334875, "lastModified": 1772592046,
"narHash": "sha256-AveYVY2plEJ62Br6iAd4fB5PDYyjJoTEmgdWRV3m+Vo=", "narHash": "sha256-+Lyl+mGVd0t2nlR6ODK/gvUHzMtF5qLlbTK+x5tCenU=",
"owner": "Infinidoge", "owner": "Infinidoge",
"repo": "nix-minecraft", "repo": "nix-minecraft",
"rev": "a852ac73a4f9bf8270bdac90a72a28fef5df846b", "rev": "483abf9ad6aeac1d61f2a5419ded2879f0c4795e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -300,11 +300,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1771969195, "lastModified": 1772972630,
"narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=", "narHash": "sha256-mUJxsNOrBMNOUJzN0pfdVJ1r2pxeqm9gI/yIKXzVVbk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e", "rev": "3966ce987e1a9a164205ac8259a5fe8a64528f72",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -316,11 +316,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1772465433, "lastModified": 1773068389,
"narHash": "sha256-ywy9troNEfpgh0Ee+zaV1UTgU8kYBVKtvPSxh6clYGU=", "narHash": "sha256-vMrm7Pk2hjBRPnCSjhq1pH0bg350Z+pXhqZ9ICiqqCs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c581273b8d5bdf1c6ce7e0a54da9841e6a763913", "rev": "44bae273f9f82d480273bab26f5c50de3724f52f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -454,11 +454,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772416961, "lastModified": 1773021923,
"narHash": "sha256-/IiEGGjy0e8Ljo6418fFlqMJs7VLuLxU5pDR5uE+GLE=", "narHash": "sha256-ro+i3wNoD2p5FloGGlkCzdmzgBDeq2LJwaIpaI9Dk7Q=",
"owner": "nix-community", "owner": "nix-community",
"repo": "srvos", "repo": "srvos",
"rev": "bcdbafece2815d32c8dfc51ef17f2858f3d4cfbc", "rev": "7f92c2bcbeb42ce87770a7565f0e6f92c8134354",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -530,11 +530,11 @@
"trackerlist": { "trackerlist": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1772492983, "lastModified": 1773184165,
"narHash": "sha256-Rzlqp+7hu6dJ/Uc/iYBu5F9QCU8zMjKbPs6NJGKjL3g=", "narHash": "sha256-uGD+QgYZD1ntXl43523bKziyBUs1c3ONi+n5FeFZre0=",
"owner": "ngosang", "owner": "ngosang",
"repo": "trackerslist", "repo": "trackerslist",
"rev": "3240f44d1c072058919e18fb112a2ee87c54e484", "rev": "448eba328ad00172a4ba049ec9f9f073b9cd278b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -579,17 +579,17 @@
"website": { "website": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1768266466, "lastModified": 1773169503,
"narHash": "sha256-d4dZzEcIKuq4DhNtXczaflpRifAtcOgNr45W2Bexnps=", "narHash": "sha256-P+T2H18k3zmEHxu7ZIDYyTrK5G3KUcZYW1AzVMKyCMs=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "06011a27456b3b9f983ef1aa142b5773bcb52b6e", "rev": "ae7a7d8325f841c52efb6fd81c4956b84631aa06",
"revCount": 23, "revCount": 24,
"type": "git", "type": "git",
"url": "https://git.gardling.com/titaniumtown/website" "url": "https://git.sigkill.computer/titaniumtown/website"
}, },
"original": { "original": {
"type": "git", "type": "git",
"url": "https://git.gardling.com/titaniumtown/website" "url": "https://git.sigkill.computer/titaniumtown/website"
} }
}, },
"ytbn-graphing-software": { "ytbn-graphing-software": {
@@ -605,11 +605,11 @@
"rev": "ac6265eae734363f95909df9a3739bf6360fa721", "rev": "ac6265eae734363f95909df9a3739bf6360fa721",
"revCount": 1130, "revCount": 1130,
"type": "git", "type": "git",
"url": "https://git.gardling.com/titaniumtown/YTBN-Graphing-Software" "url": "https://git.sigkill.computer/titaniumtown/YTBN-Graphing-Software"
}, },
"original": { "original": {
"type": "git", "type": "git",
"url": "https://git.gardling.com/titaniumtown/YTBN-Graphing-Software" "url": "https://git.sigkill.computer/titaniumtown/YTBN-Graphing-Software"
} }
} }
}, },

141
flake.nix
View File

@@ -56,7 +56,7 @@
}; };
website = { website = {
url = "git+https://git.gardling.com/titaniumtown/website"; url = "git+https://git.sigkill.computer/titaniumtown/website";
flake = false; flake = false;
}; };
@@ -66,7 +66,7 @@
}; };
ytbn-graphing-software = { ytbn-graphing-software = {
url = "git+https://git.gardling.com/titaniumtown/YTBN-Graphing-Software"; url = "git+https://git.sigkill.computer/titaniumtown/YTBN-Graphing-Software";
}; };
arr-init = { arr-init = {
@@ -97,142 +97,7 @@
eth_interface = "enp4s0"; eth_interface = "enp4s0";
system = "x86_64-linux"; system = "x86_64-linux";
service_configs = rec { service_configs = import ./service-configs.nix;
zpool_ssds = "tank";
zpool_hdds = "hdds";
torrents_path = "/torrents";
services_dir = "/services";
music_dir = "/${zpool_ssds}/music";
media_group = "media";
cpu_arch = "znver3";
ports = {
http = 80;
https = 443;
jellyfin = 8096; # no services.jellyfin option for this
torrent = 6011;
bitmagnet = 3333;
gitea = 2283;
immich = 2284;
soulseek_web = 5030;
soulseek_listen = 50300;
llama_cpp = 8991;
vaultwarden = 8222;
syncthing_gui = 8384;
syncthing_protocol = 22000;
syncthing_discovery = 21027;
minecraft = 25565;
matrix = 6167;
matrix_federation = 8448;
coturn = 3478;
coturn_tls = 5349;
ntfy = 2586;
livekit = 7880;
lk_jwt = 8081;
prowlarr = 9696;
sonarr = 8989;
radarr = 7878;
bazarr = 6767;
jellyseerr = 5055;
};
https = {
certs = services_dir + "/http_certs";
domain = "gardling.com";
};
gitea = {
dir = services_dir + "/gitea";
domain = "git.${https.domain}";
};
postgres = {
socket = "/run/postgresql";
dataDir = services_dir + "/sql";
};
immich = {
dir = services_dir + "/immich";
};
minecraft = {
parent_dir = services_dir + "/minecraft";
server_name = "main";
};
torrent = {
SavePath = torrents_path;
TempPath = torrents_path + "/incomplete";
};
jellyfin = {
dataDir = services_dir + "/jellyfin";
cacheDir = services_dir + "/jellyfin_cache";
};
slskd = rec {
base = "/var/lib/slskd";
downloads = base + "/downloads";
incomplete = base + "/incomplete";
};
vaultwarden = {
path = "/var/lib/vaultwarden";
};
monero = {
dataDir = services_dir + "/monero";
};
matrix = {
dataDir = "/var/lib/continuwuity";
domain = "matrix.${https.domain}";
};
ntfy = {
domain = "ntfy.${https.domain}";
};
livekit = {
domain = "livekit.${https.domain}";
};
syncthing = {
dataDir = services_dir + "/syncthing";
signalBackupDir = "/${zpool_ssds}/bak/signal";
grayjayBackupDir = "/${zpool_ssds}/bak/grayjay";
};
prowlarr = {
dataDir = services_dir + "/prowlarr";
};
sonarr = {
dataDir = services_dir + "/sonarr";
};
radarr = {
dataDir = services_dir + "/radarr";
};
bazarr = {
dataDir = services_dir + "/bazarr";
};
jellyseerr = {
configDir = services_dir + "/jellyseerr";
};
recyclarr = {
dataDir = services_dir + "/recyclarr";
};
media = {
moviesDir = torrents_path + "/media/movies";
tvDir = torrents_path + "/media/tv";
};
};
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;

View File

@@ -13,11 +13,13 @@
# Configure all agenix secrets # Configure all agenix secrets
age.secrets = { age.secrets = {
# ZFS encryption key # ZFS encryption key
# path is set to /etc/zfs-key to match the ZFS dataset keylocation property
zfs-key = { zfs-key = {
file = ../secrets/zfs-key.age; file = ../secrets/zfs-key.age;
mode = "0400"; mode = "0400";
owner = "root"; owner = "root";
group = "root"; group = "root";
path = "/etc/zfs-key";
}; };
# Secureboot keys archive # Secureboot keys archive
@@ -53,9 +55,9 @@
slskd_env = { slskd_env = {
file = ../secrets/slskd_env.age; file = ../secrets/slskd_env.age;
mode = "0400"; mode = "0500";
owner = "root"; owner = config.services.slskd.user;
group = "root"; group = config.services.slskd.group;
}; };
# Network configuration # Network configuration

View File

@@ -4,41 +4,13 @@
pkgs, pkgs,
... ...
}: }:
let
# DO NOT CHANGE
# path is set via a zfs property
zfs-key = "/etc/zfs-key";
in
{ {
system.activationScripts = {
# Copy decrypted ZFS key from agenix to expected location
# /etc is on tmpfs due to impermanence, so no persistent storage risk
"zfs-key".text = ''
#!/bin/sh
rm -f ${zfs-key} || true
cp ${config.age.secrets.zfs-key.path} ${zfs-key}
chmod 0400 ${zfs-key}
chown root:root ${zfs-key}
'';
};
boot.zfs.package = pkgs.zfs; boot.zfs.package = pkgs.zfs;
boot.initrd.kernelModules = [ "zfs" ]; boot.initrd.kernelModules = [ "zfs" ];
boot.kernelParams = boot.kernelParams = [
let "zfs.zfs_txg_timeout=120" # longer TXG open time = larger sequential writes
gb = 32; ];
mb = gb * 1000;
kb = mb * 1000;
b = kb * 1000;
in
[
"zfs.zfs_arc_max=${builtins.toString b}"
"zfs.zfs_txg_timeout=120" # longer TXG open time = larger sequential writes
"zfs.zfs_dirty_data_max=8589934592" # 8GB dirty data buffer (default 4GB) for USB HDD write smoothing
"zfs.zfs_delay_min_dirty_percent=80" # delay write throttling until 80% dirty (default 60%)
"zfs.zfs_vdev_async_write_max_active=30" # more concurrent async writes to vdevs (default 10)
];
boot.supportedFilesystems = [ "zfs" ]; boot.supportedFilesystems = [ "zfs" ];
boot.zfs.extraPools = [ boot.zfs.extraPools = [

146
service-configs.nix Normal file
View File

@@ -0,0 +1,146 @@
rec {
zpool_ssds = "tank";
zpool_hdds = "hdds";
torrents_path = "/torrents";
services_dir = "/services";
music_dir = "/${zpool_ssds}/music";
media_group = "media";
cpu_arch = "znver3";
ports = {
# public
http = 80; # TCP
https = 443; # TCP+UDP (HTTP/3 QUIC)
minecraft = 25565; # TCP
syncthing_protocol = 22000; # TCP+UDP (QUIC)
syncthing_discovery = 21027; # UDP
matrix_federation = 8448; # TCP+UDP (HTTP/3 QUIC)
coturn = 3478; # TCP+UDP
coturn_tls = 5349; # TCP+UDP
livekit = 7880; # TCP
soulseek_listen = 50300; # TCP
monero = 18080; # TCP
murmur = 64738; # TCP + UDP
# private
jellyfin = 8096; # TCP - no services.jellyfin option for this
torrent = 6011; # TCP
bitmagnet = 3333; # TCP
gitea = 2283; # TCP
immich = 2284; # TCP
soulseek_web = 5030; # TCP
vaultwarden = 8222; # TCP
syncthing_gui = 8384; # TCP
matrix = 6167; # TCP
ntfy = 2586; # TCP
lk_jwt = 8081; # TCP
prowlarr = 9696; # TCP
sonarr = 8989; # TCP
radarr = 7878; # TCP
bazarr = 6767; # TCP
jellyseerr = 5055; # TCP
monero_rpc = 18081; # TCP
};
https = {
certs = services_dir + "/http_certs";
domain = "sigkill.computer";
old_domain = "gardling.com"; # Redirect traffic from old domain
};
gitea = {
dir = services_dir + "/gitea";
domain = "git.${https.domain}";
};
postgres = {
socket = "/run/postgresql";
dataDir = services_dir + "/sql";
};
immich = {
dir = services_dir + "/immich";
};
minecraft = {
parent_dir = services_dir + "/minecraft";
server_name = "main";
memory = rec {
heap_size_m = 4000;
large_page_size_m = 2;
};
};
torrent = {
SavePath = torrents_path;
TempPath = torrents_path + "/incomplete";
};
jellyfin = {
dataDir = services_dir + "/jellyfin";
cacheDir = services_dir + "/jellyfin_cache";
};
slskd = rec {
base = "/var/lib/slskd";
downloads = base + "/downloads";
incomplete = base + "/incomplete";
};
vaultwarden = {
path = "/var/lib/vaultwarden";
};
monero = {
dataDir = services_dir + "/monero";
};
matrix = {
dataDir = "/var/lib/continuwuity";
domain = "matrix.${https.domain}";
};
ntfy = {
domain = "ntfy.${https.domain}";
};
livekit = {
domain = "livekit.${https.domain}";
};
syncthing = {
dataDir = services_dir + "/syncthing";
signalBackupDir = "/${zpool_ssds}/bak/signal";
grayjayBackupDir = "/${zpool_ssds}/bak/grayjay";
};
prowlarr = {
dataDir = services_dir + "/prowlarr";
};
sonarr = {
dataDir = services_dir + "/sonarr";
};
radarr = {
dataDir = services_dir + "/radarr";
};
bazarr = {
dataDir = services_dir + "/bazarr";
};
jellyseerr = {
configDir = services_dir + "/jellyseerr";
};
recyclarr = {
dataDir = services_dir + "/recyclarr";
};
media = {
moviesDir = torrents_path + "/media/movies";
tvDir = torrents_path + "/media/tv";
};
}

View File

@@ -41,6 +41,9 @@ let
hugo --minify -d $out; hugo --minify -d $out;
''; '';
}; };
newDomain = service_configs.https.domain;
oldDomain = service_configs.https.old_domain;
in in
{ {
imports = [ imports = [
@@ -52,14 +55,53 @@ in
services.caddy = { services.caddy = {
enable = true; enable = true;
email = "titaniumtown@proton.me"; email = "titaniumtown@proton.me";
# Enable on-demand TLS for old domain redirects
# Certs are issued dynamically when subdomains are accessed
globalConfig = ''
on_demand_tls {
ask http://localhost:9123/check
}
'';
# Internal endpoint to validate on-demand TLS requests
# Only allows certs for *.${oldDomain}
extraConfig = ''
http://localhost:9123 {
@allowed expression {query.domain}.endsWith(".${oldDomain}") || {query.domain} == "${oldDomain}" || {query.domain} == "www.${oldDomain}"
respond @allowed 200
respond 403
}
'';
virtualHosts = { virtualHosts = {
${service_configs.https.domain} = { ${newDomain} = {
extraConfig = '' extraConfig = ''
root * ${hugoWebsite} root * ${hugoWebsite}
file_server browse file_server browse
''; '';
serverAliases = [ "www.${service_configs.https.domain}" ]; serverAliases = [ "www.${newDomain}" ];
};
# Redirect old domain (bare + www) to new domain
${oldDomain} = {
extraConfig = ''
redir https://${newDomain}{uri} permanent
'';
serverAliases = [ "www.${oldDomain}" ];
};
# Wildcard redirect for all old domain subdomains
# Uses on-demand TLS - certs issued automatically on first request
"*.${oldDomain}" = {
extraConfig = ''
tls {
on_demand
}
# {labels.2} extracts subdomain from *.gardling.com
redir https://{labels.2}.${newDomain}{uri} permanent
'';
}; };
}; };
}; };

View File

@@ -19,8 +19,6 @@
services.jellyfin = { services.jellyfin = {
enable = true; enable = true;
# used for local streaming
openFirewall = true;
package = pkgs.jellyfin.override { jellyfin-ffmpeg = (lib.optimizePackage pkgs.jellyfin-ffmpeg); }; package = pkgs.jellyfin.override { jellyfin-ffmpeg = (lib.optimizePackage pkgs.jellyfin-ffmpeg); };
inherit (service_configs.jellyfin) dataDir cacheDir; inherit (service_configs.jellyfin) dataDir cacheDir;

View File

@@ -1,34 +1,9 @@
{ {
config, config,
pkgs,
service_configs, service_configs,
lib, lib,
... ...
}: }:
let
package =
let
src = pkgs.fetchFromGitea {
domain = "forgejo.ellis.link";
owner = "continuwuation";
repo = "continuwuity";
rev = "052c4dfa2165fdc4839fed95b71446120273cf23";
hash = "sha256-kQV4glRrKczoJpn9QIMgB5ac+saZQjSZPel+9K9Ykcs=";
};
in
pkgs.matrix-continuwuity.overrideAttrs (old: {
inherit src;
cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
inherit src;
name = "${old.pname}-vendor";
hash = "sha256-vlOXQL8wwEGFX+w0G/eIeHW3J1UDzhJ501kYhAghDV8=";
};
patches = (old.patches or [ ]) ++ [
];
});
in
{ {
imports = [ imports = [
(lib.serviceMountWithZpool "continuwuity" service_configs.zpool_ssds [ (lib.serviceMountWithZpool "continuwuity" service_configs.zpool_ssds [
@@ -41,7 +16,6 @@ in
services.matrix-continuwuity = { services.matrix-continuwuity = {
enable = true; enable = true;
inherit package;
settings.global = { settings.global = {
port = [ service_configs.ports.matrix ]; port = [ service_configs.ports.matrix ];

View File

@@ -18,9 +18,25 @@
(lib.serviceFilePerms "minecraft-server-${service_configs.minecraft.server_name}" [ (lib.serviceFilePerms "minecraft-server-${service_configs.minecraft.server_name}" [
"Z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name} 700 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}" "Z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name} 700 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
"Z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap/web 750 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}" "Z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap/web 750 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
# Allow caddy (in minecraft group) to traverse to squaremap/web for map.gardling.com
"z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name} 710 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
"z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap 710 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
]) ])
]; ];
boot.kernel.sysctl = {
# Disable autogroup for better scheduling of game server threads
"kernel.sched_autogroup_enabled" = 0;
# We want to determine the number of hugepages based on how many minecraft needs.
# This can be determined by dividing the heap size by the size of a large page.
# Doing this gives us how many large pages are needed.
# Then we add 300 to give some headroom.
"vm.nr_hugepages" =
(service_configs.minecraft.memory.heap_size_m / service_configs.minecraft.memory.large_page_size_m)
+ 300;
};
services.minecraft-servers = { services.minecraft-servers = {
enable = true; enable = true;
eula = true; eula = true;
@@ -31,42 +47,38 @@
enable = true; enable = true;
package = pkgs.fabricServers.fabric-1_21_11; package = pkgs.fabricServers.fabric-1_21_11;
jvmOpts = jvmOpts = lib.concatStringsSep " " [
let # Memory
heap_size = "4000M"; "-Xmx${builtins.toString service_configs.minecraft.memory.heap_size_m}M"
in "-Xms${builtins.toString service_configs.minecraft.memory.heap_size_m}M"
lib.concatStringsSep " " [ # GC
# Memory "-XX:+UseZGC"
"-Xmx${heap_size}" "-XX:+ZGenerational"
"-Xms${heap_size}" # Base JVM optimizations (brucethemoose/Minecraft-Performance-Flags-Benchmarks)
# GC "-XX:+UnlockExperimentalVMOptions"
"-XX:+UseZGC" "-XX:+UnlockDiagnosticVMOptions"
"-XX:+ZGenerational" "-XX:+AlwaysActAsServerClassMachine"
# Base JVM optimizations (brucethemoose/Minecraft-Performance-Flags-Benchmarks) "-XX:+AlwaysPreTouch"
"-XX:+UnlockExperimentalVMOptions" "-XX:+DisableExplicitGC"
"-XX:+UnlockDiagnosticVMOptions" "-XX:+UseNUMA"
"-XX:+AlwaysActAsServerClassMachine" "-XX:+PerfDisableSharedMem"
"-XX:+AlwaysPreTouch" "-XX:+UseFastUnorderedTimeStamps"
"-XX:+DisableExplicitGC" "-XX:+UseCriticalJavaThreadPriority"
"-XX:+UseNUMA" "-XX:ThreadPriorityPolicy=1"
"-XX:+PerfDisableSharedMem" "-XX:AllocatePrefetchStyle=3"
"-XX:+UseFastUnorderedTimeStamps" "-XX:-DontCompileHugeMethods"
"-XX:+UseCriticalJavaThreadPriority" "-XX:MaxNodeLimit=240000"
"-XX:ThreadPriorityPolicy=1" "-XX:NodeLimitFudgeFactor=8000"
"-XX:AllocatePrefetchStyle=3" "-XX:ReservedCodeCacheSize=400M"
"-XX:-DontCompileHugeMethods" "-XX:NonNMethodCodeHeapSize=12M"
"-XX:MaxNodeLimit=240000" "-XX:ProfiledCodeHeapSize=194M"
"-XX:NodeLimitFudgeFactor=8000" "-XX:NonProfiledCodeHeapSize=194M"
"-XX:ReservedCodeCacheSize=400M" "-XX:NmethodSweepActivity=1"
"-XX:NonNMethodCodeHeapSize=12M" "-XX:+UseVectorCmov"
"-XX:ProfiledCodeHeapSize=194M" # Large pages (requires vm.nr_hugepages sysctl)
"-XX:NonProfiledCodeHeapSize=194M" "-XX:+UseLargePages"
"-XX:NmethodSweepActivity=1" "-XX:LargePageSizeInBytes=${builtins.toString service_configs.minecraft.memory.large_page_size_m}M"
"-XX:+UseVectorCmov" ];
# Large pages (requires vm.nr_hugepages sysctl)
"-XX:+UseLargePages"
"-XX:LargePageSizeInBytes=2m"
];
serverProperties = { serverProperties = {
server-port = service_configs.ports.minecraft; server-port = service_configs.ports.minecraft;
@@ -181,9 +193,4 @@
]; ];
}; };
systemd.tmpfiles.rules = [
# Allow caddy (in minecraft group) to traverse to squaremap/web for map.gardling.com
"z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name} 710 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
"z ${service_configs.minecraft.parent_dir}/${service_configs.minecraft.server_name}/squaremap 710 ${config.services.minecraft-servers.user} ${config.services.minecraft-servers.group}"
];
} }

View File

@@ -17,7 +17,20 @@
enable = true; enable = true;
dataDir = service_configs.monero.dataDir; dataDir = service_configs.monero.dataDir;
rpc = { rpc = {
address = "0.0.0.0";
port = service_configs.ports.monero_rpc;
restricted = true; restricted = true;
}; };
extraConfig = ''
p2p-bind-port=${builtins.toString service_configs.ports.monero}
db-sync-mode=fast:async:1000000000bytes
public-node=1
confirm-external-bind=1
'';
}; };
networking.firewall.allowedTCPPorts = [
service_configs.ports.monero
service_configs.ports.monero_rpc
];
} }

View File

@@ -102,7 +102,6 @@
ChokingAlgorithm = "RateBased"; ChokingAlgorithm = "RateBased";
PieceExtentAffinity = true; PieceExtentAffinity = true;
SuggestMode = true; SuggestMode = true;
CoalesceReadWrite = true;
# max_queued_disk_bytes: the max bytes waiting in the disk I/O queue. # max_queued_disk_bytes: the max bytes waiting in the disk I/O queue.
# When this limit is reached, peer connections stop reading from their # When this limit is reached, peer connections stop reading from their
@@ -112,6 +111,12 @@
# where ZFS txg commits cause periodic I/O stalls. # where ZFS txg commits cause periodic I/O stalls.
DiskQueueSize = 67108864; # 64MB DiskQueueSize = 67108864; # 64MB
# POSIX-compliant disk I/O: uses pread/pwrite instead of mmap.
# On ZFS, mmap forces data into BOTH ARC and Linux page cache (double-caching),
# wasting RAM. pread/pwrite goes only through ARC, maximizing its effectiveness.
# Saved 26 gb of memory!!
DiskIOType = "Posix";
# === Network buffer tuning (from libtorrent high_performance_seed preset) === # === Network buffer tuning (from libtorrent high_performance_seed preset) ===
# "always stuff at least 1 MiB down each peer pipe, to quickly ramp up send rates" # "always stuff at least 1 MiB down each peer pipe, to quickly ramp up send rates"
SendBufferLowWatermark = 1024; # 1MB (KiB) -- matches high_performance_seed SendBufferLowWatermark = 1024; # 1MB (KiB) -- matches high_performance_seed

View File

@@ -6,9 +6,6 @@
username, username,
... ...
}: }:
let
slskd_env = "/etc/slskd_env";
in
{ {
imports = [ imports = [
(lib.serviceMountWithZpool "slskd" "" [ (lib.serviceMountWithZpool "slskd" "" [
@@ -26,20 +23,10 @@ in
users.groups."music" = { }; users.groups."music" = { };
system.activationScripts = {
"skskd_env".text = ''
#!/bin/sh
rm -fr ${slskd_env} || true
cp ${config.age.secrets.slskd_env.path} ${slskd_env}
chmod 0500 ${slskd_env}
chown ${config.services.slskd.user}:${config.services.slskd.group} ${slskd_env}
'';
};
services.slskd = { services.slskd = {
enable = true; enable = true;
domain = null; # null so we don't use nginx reverse proxy domain = null; # null so we don't use nginx reverse proxy
environmentFile = slskd_env; environmentFile = config.age.secrets.slskd_env.path;
settings = { settings = {
web = { web = {
@@ -75,4 +62,8 @@ in
services.caddy.virtualHosts."soulseek.${service_configs.https.domain}".extraConfig = '' services.caddy.virtualHosts."soulseek.${service_configs.https.domain}".extraConfig = ''
reverse_proxy :${builtins.toString config.services.slskd.settings.web.port} reverse_proxy :${builtins.toString config.services.slskd.settings.web.port}
''; '';
networking.firewall.allowedTCPPorts = [
service_configs.ports.soulseek_listen
];
} }

View File

@@ -43,7 +43,10 @@
# Open firewall ports for syncthing protocol # Open firewall ports for syncthing protocol
networking.firewall = { networking.firewall = {
allowedTCPPorts = [ service_configs.ports.syncthing_protocol ]; allowedTCPPorts = [ service_configs.ports.syncthing_protocol ];
allowedUDPPorts = [ service_configs.ports.syncthing_discovery ]; allowedUDPPorts = [
service_configs.ports.syncthing_discovery
service_configs.ports.syncthing_protocol
];
}; };
services.caddy.virtualHosts."syncthing.${service_configs.https.domain}".extraConfig = '' services.caddy.virtualHosts."syncthing.${service_configs.https.domain}".extraConfig = ''

View File

@@ -17,4 +17,36 @@
# "192.168.0.0/24" # "192.168.0.0/24"
]; ];
}; };
boot = {
# BBR congestion control handles variable-latency VPN connections much
# better than CUBIC by probing bandwidth continuously rather than
# reacting to packet loss.
kernelModules = [ "tcp_bbr" ];
kernel.sysctl = {
# Use BBR + fair queuing for smooth throughput through the WireGuard VPN
"net.core.default_qdisc" = "fq";
"net.ipv4.tcp_congestion_control" = "bbr";
# Disable slow-start after idle: prevents TCP from resetting window
# size on each burst cycle (the primary cause of the 0 -> 40 MB/s spikes)
"net.ipv4.tcp_slow_start_after_idle" = 0;
# Larger socket buffers to accommodate the VPN bandwidth-delay product
# (22ms RTT * target throughput). Current 2.5MB max is too small.
"net.core.rmem_max" = 16777216;
"net.core.wmem_max" = 16777216;
"net.ipv4.tcp_rmem" = "4096 87380 16777216";
"net.ipv4.tcp_wmem" = "4096 65536 16777216";
# Higher backlog for the large number of concurrent torrent connections
"net.core.netdev_max_backlog" = 5000;
# Faster cleanup of dead connections from torrent peer churn
"net.ipv4.tcp_fin_timeout" = 15; # default 60
"net.ipv4.tcp_tw_reuse" = 1;
};
};
networking.firewall.trustedInterfaces = [ "wg-br" ];
} }

View File

@@ -5,18 +5,14 @@
... ...
}: }:
let let
testServiceConfigs = { baseServiceConfigs = import ../service-configs.nix;
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
zpool_ssds = ""; zpool_ssds = "";
gitea = { gitea = {
dir = "/var/lib/gitea"; dir = "/var/lib/gitea";
domain = "git.test.local"; domain = "git.test.local";
}; };
postgres = { ports.gitea = 3000;
socket = "/run/postgresql";
};
ports = {
gitea = 3000;
};
}; };
testLib = lib.extend ( testLib = lib.extend (

View File

@@ -5,17 +5,12 @@
... ...
}: }:
let let
testServiceConfigs = { baseServiceConfigs = import ../service-configs.nix;
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
zpool_ssds = ""; zpool_ssds = "";
https = { https.domain = "test.local";
domain = "test.local"; ports.immich = 2283;
}; immich.dir = "/var/lib/immich";
ports = {
immich = 2283;
};
immich = {
dir = "/var/lib/immich";
};
}; };
testLib = lib.extend ( testLib = lib.extend (

View File

@@ -5,19 +5,14 @@
... ...
}: }:
let let
testServiceConfigs = { baseServiceConfigs = import ../service-configs.nix;
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
zpool_ssds = ""; zpool_ssds = "";
https = { https.domain = "test.local";
domain = "test.local";
};
ports = {
jellyfin = 8096;
};
jellyfin = { jellyfin = {
dataDir = "/var/lib/jellyfin"; dataDir = "/var/lib/jellyfin";
cacheDir = "/var/cache/jellyfin"; cacheDir = "/var/cache/jellyfin";
}; };
media_group = "media";
}; };
testLib = lib.extend ( testLib = lib.extend (
@@ -60,6 +55,9 @@ pkgs.testers.runNixOSTest {
jellyfinModule jellyfinModule
]; ];
# needed for testing
services.jellyfin.openFirewall = true;
# Create the media group # Create the media group
users.groups.media = { }; users.groups.media = { };

View File

@@ -5,11 +5,6 @@
... ...
}: }:
let let
testServiceConfigs = {
zpool_ssds = "";
zpool_hdds = "";
};
securityModule = import ../modules/security.nix; securityModule = import ../modules/security.nix;
sshModule = sshModule =

View File

@@ -5,17 +5,10 @@
... ...
}: }:
let let
testServiceConfigs = { baseServiceConfigs = import ../service-configs.nix;
testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
zpool_ssds = ""; zpool_ssds = "";
https = { https.domain = "test.local";
domain = "test.local";
};
ports = {
vaultwarden = 8222;
};
vaultwarden = {
path = "/var/lib/vaultwarden";
};
}; };
testLib = lib.extend ( testLib = lib.extend (

View File

@@ -6,18 +6,14 @@
... ...
}: }:
let let
testServiceConfigs = { baseServiceConfigs = import ../service-configs.nix;
minecraft = { testServiceConfigs = lib.recursiveUpdate baseServiceConfigs {
server_name = "main";
parent_dir = "/var/lib/minecraft";
};
https = {
domain = "test.local";
};
ports = {
minecraft = 25565;
};
zpool_ssds = ""; zpool_ssds = "";
https.domain = "test.local";
minecraft.parent_dir = "/var/lib/minecraft";
minecraft.memory = rec {
heap_size_m = 1000;
};
}; };
# Create pkgs with nix-minecraft overlay and unfree packages allowed # Create pkgs with nix-minecraft overlay and unfree packages allowed
@@ -46,6 +42,9 @@ testPkgs.testers.runNixOSTest {
../services/minecraft.nix ../services/minecraft.nix
]; ];
# Force to 0 because no huge pages in vms ?
boot.kernel.sysctl."vm.nr_hugepages" = lib.mkForce 0;
# Enable caddy service (required by minecraft service) # Enable caddy service (required by minecraft service)
services.caddy.enable = true; services.caddy.enable = true;