{ config, pkgs, lib, namespace, ... }: with lib; let cfg = config.${namespace}.services.actual; dataDir = "/data"; hostAddress = "10.0.1.3"; actualUserId = config.users.users.nix-apps.uid; actualGroupId = config.users.groups.jallen-nas.gid; in { imports = [ ./options.nix ]; config = mkIf cfg.enable { containers.actual = { autoStart = true; privateNetwork = true; hostAddress = hostAddress; localAddress = cfg.localAddress; bindMounts = { ${dataDir} = { hostPath = cfg.dataDir; isReadOnly = false; }; }; config = { lib, ... }: { services.actual = { enable = true; openFirewall = true; settings = { trustedProxies = [ hostAddress ]; port = cfg.port; dataDir = dataDir; serverFiles = "${dataDir}/server-files"; userFiles = "${dataDir}/user-files"; }; }; users.users.actual = { isSystemUser = true; uid = lib.mkForce actualUserId; group = "actual"; }; users.groups = { actual = { gid = lib.mkForce actualGroupId; }; }; # System packages environment.systemPackages = with pkgs; [ sqlite ]; # Create and set permissions for required directories system.activationScripts.actual-dirs = '' mkdir -p ${dataDir} chown -R actual:actual ${dataDir} chmod -R 0700 ${dataDir} ''; systemd.services = { actual = { environment.ACTUAL_CONFIG_PATH = lib.mkForce "${dataDir}/config.json"; serviceConfig = { ExecStart = lib.mkForce "${lib.getExe pkgs.actual-server} --config ${dataDir}/config.json"; WorkingDirectory = lib.mkForce dataDir; StateDirectory = lib.mkForce dataDir; StateDirectoryMode = lib.mkForce 700; DynamicUser = lib.mkForce false; ProtectSystem = lib.mkForce null; }; }; }; networking = { firewall = { enable = true; allowedTCPPorts = [ cfg.port ]; }; # Use systemd-resolved inside the container # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 useHostResolvConf = lib.mkForce false; }; services.resolved.enable = true; system.stateVersion = "23.11"; }; }; services.traefik.dynamicConfigOptions = lib.mkIf cfg.reverseProxy.enable { services.actual.loadBalancer.servers = [ { url = "http://${cfg.localAddress}:${toString cfg.port}"; } ]; routers.actual = { entryPoints = [ "websecure" ]; rule = "Host(`${cfg.reverseProxy.host}`)"; service = "actual"; middlewares = cfg.reverseProxy.middlewares; tls.certResolver = "letsencrypt"; }; }; networking = { nat = { forwardPorts = [ { destination = "${cfg.localAddress}:${toString cfg.port}"; sourcePort = cfg.port; } ]; }; firewall = { allowedTCPPorts = [ cfg.port ]; allowedUDPPorts = [ cfg.port ]; }; }; }; }