1{ 2 nixpkgs-unstable, 3 config, 4 pkgs, 5 lib, 6 nixpkgs-chromedriver, 7 ... 8}: 9 10{ 11 custom.nix-cache.enable = true; 12 13 age.secrets."eon-freumh.org.cap" = { 14 file = ../../secrets/eon-freumh.org.cap.age; 15 mode = "770"; 16 owner = "acme-eon"; 17 group = "acme-eon"; 18 }; 19 security.acme-eon = { 20 acceptTerms = true; 21 defaults.email = "${config.custom.username}@${config.networking.domain}"; 22 defaults.capFile = config.age.secrets."eon-freumh.org.cap".path; 23 nginxCerts = [ 24 "nix-cache.vpn.freumh.org" 25 "jellyfin.vpn.freumh.org" 26 "jellyfin.freumh.org" 27 "jellyseerr.freumh.org" 28 "transmission.vpn.freumh.org" 29 "nextcloud.vpn.freumh.org" 30 "owntracks.vpn.freumh.org" 31 "immich.vpn.freumh.org" 32 ]; 33 }; 34 35 services.nginx = { 36 #requires = [ "tailscaled.service" ]; 37 clientMaxBodySize = "1g"; 38 virtualHosts = { 39 "nix-cache.vpn.freumh.org" = { 40 listenAddresses = [ "100.64.0.9" ]; 41 }; 42 "jellyfin.vpn.freumh.org" = { 43 onlySSL = true; 44 listenAddresses = [ "100.64.0.9" ]; 45 locations."/" = { 46 proxyPass = '' 47 http://localhost:8096 48 ''; 49 proxyWebsockets = true; 50 }; 51 }; 52 "jellyfin.freumh.org" = { 53 onlySSL = true; 54 locations."/" = { 55 recommendedProxySettings = true; 56 proxyPass = '' 57 http://localhost:8096 58 ''; 59 proxyWebsockets = true; 60 }; 61 }; 62 "jellyseerr.freumh.org" = { 63 onlySSL = true; 64 locations."/" = { 65 recommendedProxySettings = true; 66 proxyPass = '' 67 http://localhost:${builtins.toString config.services.jellyseerr.port} 68 ''; 69 proxyWebsockets = true; 70 }; 71 }; 72 "transmission.vpn.freumh.org" = { 73 onlySSL = true; 74 listenAddresses = [ "100.64.0.9" ]; 75 locations."/" = { 76 proxyPass = with config.services.transmission.settings; '' 77 http://localhost:${builtins.toString rpc-port} 78 ''; 79 }; 80 }; 81 "nextcloud.vpn.freumh.org" = { 82 onlySSL = true; 83 listenAddresses = [ "100.64.0.9" ]; 84 }; 85 "owntracks.vpn.freumh.org" = { 86 onlySSL = true; 87 listenAddresses = [ "100.64.0.9" ]; 88 }; 89 "immich.vpn.freumh.org" = { 90 onlySSL = true; 91 listenAddresses = [ "100.64.0.9" ]; 92 locations."/" = { 93 proxyPass = with config.services.immich; '' 94 http://${host}:${builtins.toString port} 95 ''; 96 }; 97 }; 98 }; 99 }; 100 101 services.avahi = { 102 enable = true; 103 nssmdns4 = true; 104 publish = { 105 enable = true; 106 addresses = true; 107 workstation = true; 108 }; 109 }; 110 111 services.minidlna = { 112 enable = true; 113 openFirewall = true; 114 settings = { 115 media_dir = [ "/tank/" ]; 116 notify_interval = 60; 117 inofity = true; 118 }; 119 }; 120 121 services.jellyfin = { 122 enable = true; 123 openFirewall = true; 124 }; 125 users.users.${config.services.jellyfin.user}.extraGroups = [ 126 config.services.transmission.user 127 config.services.sonarr.user 128 config.services.radarr.user 129 config.services.bazarr.user 130 config.services.lidarr.user 131 config.services.readarr.user 132 ]; 133 134 services.samba = { 135 enable = true; 136 openFirewall = true; 137 settings = { 138 global = { 139 workgroup = "WORKGROUP"; 140 "server string" = "${config.networking.hostName}"; 141 "netbios name" = "${config.networking.hostName}"; 142 "security" = "user"; 143 #"use sendfile" = "yes"; 144 #"max protocol" = "smb2"; 145 # note: localhost is the ipv6 localhost ::1 146 "hosts allow" = "192.168.1. 192.168.0. 127.0.0.1 localhost 100.64.0.0/10"; 147 "hosts deny" = "0.0.0.0/0"; 148 "guest account" = "nobody"; 149 "map to guest" = "bad user"; 150 }; 151 tank = { 152 path = "/tank/"; 153 browseable = "yes"; 154 "read only" = "no"; 155 "guest ok" = "no"; 156 "create mask" = "0644"; 157 "directory mask" = "0755"; 158 }; 159 }; 160 }; 161 users.mutableUsers = lib.mkForce true; 162 163 age.secrets.nextcloud = { 164 file = ../../secrets/nextcloud.age; 165 mode = "770"; 166 owner = "nextcloud"; 167 group = "nextcloud"; 168 }; 169 services.nextcloud = { 170 enable = true; 171 package = pkgs.nextcloud29; 172 hostName = "nextcloud.vpn.freumh.org"; 173 config.adminpassFile = config.age.secrets.nextcloud.path; 174 }; 175 176 services.transmission = { 177 enable = true; 178 openRPCPort = true; 179 package = pkgs.transmission_3; 180 settings = { 181 download-dir = "/tank/transmission"; 182 incomplete-dir-enabled = false; 183 rpc-whitelist = "127.0.0.1,100.64.*.*,192.168.1.*"; 184 rpc-bind-address = "0.0.0.0"; 185 rpc-host-whitelist-enabled = false; 186 ratio-limit-enabled = true; 187 download-queue-size = 20; 188 }; 189 }; 190 191 services.prowlarr.enable = true; 192 services.flaresolverr.enable = true; 193 services.sonarr.enable = true; 194 services.radarr.enable = true; 195 services.bazarr.enable = true; 196 services.lidarr.enable = true; 197 services.readarr.enable = true; 198 services.nzbget.enable = true; 199 services.jellyseerr.enable = true; 200 users.users.${config.services.sonarr.user}.extraGroups = [ 201 config.services.transmission.user 202 config.services.nzbget.user 203 ]; 204 users.users.${config.services.radarr.user}.extraGroups = [ 205 config.services.transmission.user 206 config.services.nzbget.user 207 ]; 208 users.users.${config.services.bazarr.user}.extraGroups = [ 209 config.services.sonarr.user 210 config.services.radarr.user 211 ]; 212 users.users.${config.services.lidarr.user}.extraGroups = [ 213 config.services.transmission.user 214 config.services.nzbget.user 215 ]; 216 users.users.${config.services.readarr.user}.extraGroups = [ 217 config.services.transmission.user 218 config.services.nzbget.user 219 ]; 220 # services.calibre-server.enable = true; 221 222 age.secrets.restic-owl.file = ../../secrets/restic-owl.age; 223 age.secrets.restic-gecko.file = ../../secrets/restic-gecko.age; 224 age.secrets.restic-shrew.file = ../../secrets/restic-shrew.age; 225 services.restic = { 226 #backups.owl = { 227 # repository = "${config.services.restic.server.dataDir}/owl"; 228 # passwordFile = "${config.custom.secretsDir}/restic-password-owl"; 229 # timerConfig = { 230 # OnCalendar = "02:00"; 231 # }; 232 # pruneOpts = [ 233 # "--keep-daily 7" 234 # "--keep-weekly 5" 235 # "--keep-monthly 12" 236 # "--keep-yearly 5" 237 # ]; 238 #}; 239 #backups.gecko = { 240 # repository = "${config.services.restic.server.dataDir}/gecko"; 241 # passwordFile = "${config.custom.secretsDir}/restic-password-gecko"; 242 # timerConfig = { 243 # OnCalendar = "02:00"; 244 # }; 245 # pruneOpts = [ 246 # "--keep-daily 7" 247 # "--keep-weekly 5" 248 # "--keep-monthly 12" 249 # "--keep-yearly 5" 250 # ]; 251 #}; 252 server = { 253 enable = true; 254 listenAddress = "100.64.0.9:8000"; 255 dataDir = "/tank/backups/restic"; 256 appendOnly = true; 257 extraFlags = [ "--no-auth" ]; 258 }; 259 }; 260 systemd.services.restic-rest-server = { 261 after = [ "tailscaled.service" ]; 262 requires = [ "tailscaled.service" ]; 263 }; 264 265 services.owntracks-recorder = { 266 enable = true; 267 host = "100.64.0.9"; 268 domain = "owntracks.vpn.freumh.org"; 269 }; 270 271 services.immich = { 272 enable = true; 273 openFirewall = true; 274 host = "100.64.0.9"; 275 mediaLocation = "/tank/immich"; 276 }; 277 278 services.fail2ban = { 279 enable = true; 280 bantime = "24h"; 281 bantime-increment = { 282 enable = true; 283 multipliers = "1 2 4 8 16 32 64"; 284 maxtime = "168h"; 285 overalljails = true; 286 }; 287 jails."jellyfin".settings = { 288 backend = "auto"; 289 port = "80,443"; 290 protocol = "tcp"; 291 filter = "jellyfin"; 292 maxRetry = 3; 293 bantime = "86400"; 294 findTime = "43200"; 295 logPath = "/var/lib/jellyfin/log/*.log"; 296 }; 297 # requires 'Enable Proxy Support' for jellyseerr 298 jails."jellyseerr".settings = { 299 backend = "auto"; 300 port = "80,443"; 301 protocol = "tcp"; 302 filter = "jellyseerr"; 303 maxRetry = 3; 304 bantime = "86400"; 305 findTime = "43200"; 306 logPath = "/var/lib/jellyseerr/logs/overseerr.log"; 307 }; 308 }; 309 environment.etc = { 310 "fail2ban/filter.d/jellyfin.local".text = '' 311 [Definition] 312 failregex = ^.*Authentication request for .* has been denied \(IP: "<ADDR>"\)\. 313 ''; 314 "fail2ban/filter.d/jellyseerr.local".text = '' 315 [Definition] 316 failregex = ^.*\[warn\]\[Auth\]: Failed login attempt from user with incorrect Jellyfin credentials {"account":{"ip":"<HOST>","email": 317 ''; 318 }; 319 320 systemd.services.ddns = { 321 description = "Dynamic DNS"; 322 wantedBy = [ "multi-user.target" ]; 323 after = [ "network-online.target" ]; 324 wants = [ "network-online.target" ]; 325 serviceConfig = { 326 ExecStart = pkgs.writeShellScript "update-dns" '' 327 while true; do 328 IP="$(${pkgs.curl}/bin/curl https://ipinfo.io/ip 2> /dev/null)"; 329 echo $IP; 330 ${config.services.eon.package}/bin/capc update /run/agenix/eon-freumh.org.cap \ 331 -u remove/jellyfin.freumh.org/A \ 332 -u remove/jellyseerr.freumh.org/A \ 333 -u add/jellyfin.freumh.org/A/"$IP"/60 \ 334 -u add/jellyseerr.freumh.org/A/"$IP"/60; 335 sleep 3600; 336 done 337 ''; 338 Restart = "always"; 339 RestartSec = 5; 340 User = "root"; 341 }; 342 }; 343}