{ site_config }: 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 = { # Ports exposed to the internet. The flake asserts every public port # appears in the corresponding firewall allow-list (TCP, UDP, or both). public = { http = { port = 80; proto = "tcp"; }; https = { port = 443; proto = "both"; }; # HTTP/3 QUIC minecraft = { port = 25565; proto = "tcp"; }; syncthing_protocol = { port = 22000; proto = "both"; }; # QUIC syncthing_discovery = { port = 21027; proto = "udp"; }; matrix_federation = { port = 8448; proto = "both"; }; # HTTP/3 QUIC coturn = { port = 3478; proto = "both"; }; coturn_tls = { port = 5349; proto = "both"; }; livekit = { port = 7880; proto = "tcp"; }; soulseek_listen = { port = 50300; proto = "tcp"; }; monero = { port = 18080; proto = "tcp"; }; monero_rpc = { port = 18081; proto = "tcp"; }; # restricted public RPC p2pool_p2p = { port = 37889; proto = "tcp"; }; murmur = { port = 64738; proto = "both"; }; }; # Ports bound to localhost / VPN only. The flake asserts none of # these appear in the firewall allow-lists. private = { jellyfin = { port = 8096; proto = "tcp"; }; torrent = { port = 6011; proto = "tcp"; }; # Webhook receiver for the Jellyfin-qBittorrent monitor — Jellyfin pushes # playback events here so throttling reacts without waiting for the poll. jellyfin_qbittorrent_monitor_webhook = { port = 9898; proto = "tcp"; }; bitmagnet = { port = 3333; proto = "tcp"; }; gitea = { port = 2283; proto = "tcp"; }; immich = { port = 2284; proto = "tcp"; }; soulseek_web = { port = 5030; proto = "tcp"; }; vaultwarden = { port = 8222; proto = "tcp"; }; syncthing_gui = { port = 8384; proto = "tcp"; }; matrix = { port = 6167; proto = "tcp"; }; ntfy = { port = 2586; proto = "tcp"; }; lk_jwt = { port = 8081; proto = "tcp"; }; prowlarr = { port = 9696; proto = "tcp"; }; sonarr = { port = 8989; proto = "tcp"; }; radarr = { port = 7878; proto = "tcp"; }; bazarr = { port = 6767; proto = "tcp"; }; jellyseerr = { port = 5055; proto = "tcp"; }; monero_zmq = { port = 18083; proto = "tcp"; }; p2pool_stratum = { port = 3334; proto = "tcp"; }; firefox_syncserver = { port = 5000; proto = "tcp"; }; mollysocket = { port = 8020; proto = "tcp"; }; grafana = { port = 3000; proto = "tcp"; }; prometheus = { port = 9090; proto = "tcp"; }; prometheus_node = { port = 9100; proto = "tcp"; }; prometheus_apcupsd = { port = 9162; proto = "tcp"; }; llama_cpp = { port = 6688; proto = "tcp"; }; trilium = { port = 8787; proto = "tcp"; }; jellyfin_exporter = { port = 9594; proto = "tcp"; }; qbittorrent_exporter = { port = 9561; proto = "tcp"; }; igpu_exporter = { port = 9563; proto = "tcp"; }; minecraft_exporter = { port = 9567; proto = "tcp"; }; prometheus_zfs = { port = 9134; proto = "tcp"; }; harmonia = { port = 5500; proto = "tcp"; }; }; }; gitea = { dir = services_dir + "/gitea"; domain = "git.${site_config.domain}"; }; postgres = { socket = "/run/postgresql"; dataDir = services_dir + "/sql"; shared_buffers_m = 128; # PostgreSQL default; update if you change shared_buffers }; immich = { dir = services_dir + "/immich"; }; minecraft = { parent_dir = services_dir + "/minecraft"; server_name = "main"; memory = { heap_size_m = 4000; large_page_size_m = 2; }; }; torrent = { SavePath = torrents_path; TempPath = torrents_path + "/incomplete"; categories = { anime = torrents_path + "/anime"; archive = torrents_path + "/archive"; audiobooks = torrents_path + "/audiobooks"; books = torrents_path + "/books"; games = torrents_path + "/games"; movies = torrents_path + "/movies"; music = torrents_path + "/music"; musicals = torrents_path + "/musicals"; tvshows = torrents_path + "/tvshows"; }; }; 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"; }; p2pool = { dataDir = services_dir + "/p2pool"; walletAddress = "49b6NT2k7fQHs8JvF7naUvchYwTQmRpoMMXb1KJTg5UcZVmyPJ7n6jgiH8DrvEsMg5GvMjJqPB1c1PTBAYtUTsbeHe5YMBx"; }; matrix = { dataDir = "/var/lib/continuwuity"; domain = "matrix.${site_config.domain}"; }; ntfy = { domain = "ntfy.${site_config.domain}"; }; mollysocket = { domain = "mollysocket.${site_config.domain}"; }; livekit = { domain = "livekit.${site_config.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"; }; firefox_syncserver = { domain = "firefox-sync.${site_config.domain}"; }; grafana = { dir = services_dir + "/grafana"; domain = "grafana.${site_config.domain}"; }; trilium = { dataDir = services_dir + "/trilium"; }; media = { moviesDir = torrents_path + "/media/movies"; tvDir = torrents_path + "/media/tv"; }; # Per-service 2MB hugepage budget. # Each value is the service's hugepage consumption in MB, derived from # its actual memory configuration. The kernel sysctl vm.nr_hugepages # is set to total_pages so every service gets what it needs. hugepages_2m = rec { page_size_m = 2; # RandomX dataset (2048MB) + cache (256MB) = 2304MB per instance. # Both monerod and p2pool allocate their own full copy via MAP_HUGETLB. randomx_instance_m = 2048 + 256; services = { minecraft_m = minecraft.memory.heap_size_m; # JVM heap via -XX:+UseLargePages monerod_m = randomx_instance_m; # block verification dataset p2pool_m = randomx_instance_m; # mining dataset postgres_m = postgres.shared_buffers_m; # huge_pages = try (default) }; total_pages = builtins.foldl' (a: b: a + b) 0 (builtins.attrValues services) / page_size_m; }; }