{ config, pkgs, rssdownloader-src, ... }: let rssdownloader = pkgs.callPackage ./rssdownloader.nix { src = rssdownloader-src; }; proxyVhost = { upstream, websockets ? true, maxBodySize ? "1g" }: { forceSSL = true; enableACME = true; locations."/" = { proxyPass = upstream; proxyWebsockets = websockets; extraConfig = '' proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3600; proxy_send_timeout 3600; proxy_buffering off; client_max_body_size ${maxBodySize}; ''; }; }; dockerService = { name, description, dir }: { inherit description; after = [ "docker.service" "network.target" ]; requires = [ "docker.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; WorkingDirectory = dir; ExecStart = "${pkgs.docker-compose}/bin/docker-compose up -d"; ExecStop = "${pkgs.docker-compose}/bin/docker-compose down"; }; }; in { services.nfs.server = { enable = true; statdPort = 4000; lockdPort = 4001; mountdPort = 4002; exports = '' /media 192.168.50.0/24(rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000,fsid=0,insecure) /media 100.64.0.0/10(rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000,fsid=0,insecure) ''; }; services.jellyfin.enable = true; services.tailscale = { enable = true; openFirewall = true; useRoutingFeatures = "server"; }; services.syncthing = { enable = true; user = "ulve"; dataDir = "/home/ulve"; configDir = "/home/ulve/.config/syncthing"; openDefaultPorts = true; settings.devices."macbook" = { id = "U4YVRUT-JAAXHQ4-TA6FAGH-SO6Z7CI-KDFPRNG-UZYNXDK-6OQY7ZA-UBTZRQW"; }; settings.devices."phone" = { id = "WXTP2PT-GW3C3EJ-JYYYXUT-VEKCAQV-NQTPQLI-TOMDAI3-CSUUHF5-6DH72AM"; }; settings.folders."Downloads" = { path = "/home/ulve/Downloads"; devices = [ "macbook" ]; }; settings.folders."yrw8u-ut036" = { path = "/home/ulve/Phone"; devices = [ "phone" ]; }; settings.folders."xdnt7-iaqtd" = { path = "/home/ulve/Vaults"; devices = [ "macbook" ]; }; }; services.immich = { enable = true; mediaLocation = "/media/immich"; }; users.users.git = { isSystemUser = true; group = "git"; home = "/media/git"; shell = pkgs.bash; }; users.groups.git = {}; services.gitea = { enable = true; user = "git"; group = "git"; stateDir = "/media/git"; settings = { server = { DOMAIN = "git.maybec.at"; ROOT_URL = "https://git.maybec.at/"; HTTP_ADDR = "127.0.0.1"; HTTP_PORT = 3001; START_SSH_SERVER = false; SSH_DOMAIN = "git.maybec.at"; SSH_PORT = 22; SSH_USER = "git"; }; service.DISABLE_REGISTRATION = true; }; }; services.openssh.extraConfig = '' Match User git AuthorizedKeysCommand ${config.services.gitea.package}/bin/gitea keys -c ${config.services.gitea.customDir}/conf/app.ini -e git -u %u -t %t -k %k AuthorizedKeysCommandUser git ''; services.zfs.autoScrub = { enable = true; interval = "monthly"; pools = [ "media" ]; }; virtualisation.docker = { enable = true; enableOnBoot = true; autoPrune = { enable = true; dates = "weekly"; flags = [ "--all" ]; }; daemon.settings = { log-driver = "json-file"; log-opts = { max-size = "10m"; max-file = "3"; }; }; }; systemd.services.transmission = dockerService { name = "transmission"; description = "Transmission via Mullvad VPN"; dir = "/home/ulve/code/transmission"; }; systemd.services.aftersummer = dockerService { name = "aftersummer"; description = "Aftersummer"; dir = "/home/ulve/code/aftersummer"; }; systemd.services.spine = dockerService { name = "spine"; description = "Spine ebook server"; dir = "/home/ulve/code/wargaming"; }; systemd.services.bookthing = dockerService { name = "bookthing"; description = "Bookthing audiobook server"; dir = "/home/ulve/code/bookthing"; }; systemd.services.tailscale-exit = dockerService { name = "tailscale-exit"; description = "Tailscale exit node via Mullvad VPN"; dir = "/home/ulve/code/tailscale"; }; systemd.services.colony-archive = dockerService { name = "colony-archive"; description = "Colony Archive tabletop RPG campaign manager"; dir = "/home/ulve/code/colony-archive"; }; systemd.services.dozzle = { description = "Dozzle Docker log viewer"; after = [ "docker.service" "network.target" ]; requires = [ "docker.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; ExecStartPre = "${pkgs.docker}/bin/docker rm -f dozzle || true"; ExecStart = "${pkgs.docker}/bin/docker run --rm --name dozzle -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock amir20/dozzle"; ExecStop = "${pkgs.docker}/bin/docker stop dozzle"; Restart = "on-failure"; }; }; security.acme = { acceptTerms = true; defaults.email = "johansson.olov@gmail.com"; }; services.nginx = { enable = true; virtualHosts."aftersummer.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:5588"; }; virtualHosts."spine.maybec.at" = proxyVhost { upstream = "http://localhost:3000"; }; virtualHosts."bookthing.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:8000"; }; virtualHosts."jelly.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:8096"; }; virtualHosts."photos.maybec.at" = proxyVhost { upstream = "http://[::1]:2283"; maxBodySize = "50g"; }; virtualHosts."colony.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3333"; }; virtualHosts."git.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3001"; maxBodySize = "10g"; }; }; }