# NixOS module for the I2P Python router. # # Usage in configuration.nix or flake-based config: # # services.i2p-python = { # enable = true; # ntcp2.port = 9700; # ssu2.port = 9700; # console.enable = true; # console.port = 7657; # openFirewall = true; # }; flake: { config, lib, pkgs, ... }: let cfg = config.services.i2p-python; in { options.services.i2p-python = { enable = lib.mkEnableOption "I2P Python router"; package = lib.mkPackageOption flake.packages.${pkgs.system} "default" { }; ntcp2 = { port = lib.mkOption { type = lib.types.port; default = 9700; description = "NTCP2 transport listen port."; }; address = lib.mkOption { type = lib.types.str; default = "0.0.0.0"; description = "NTCP2 bind address."; }; }; ssu2 = { port = lib.mkOption { type = lib.types.port; default = 9700; description = "SSU2 transport listen port (UDP)."; }; }; console = { enable = lib.mkEnableOption "web console"; port = lib.mkOption { type = lib.types.port; default = 7657; description = "Web console listen port."; }; address = lib.mkOption { type = lib.types.str; default = "127.0.0.1"; description = "Web console bind address."; }; }; dataDir = lib.mkOption { type = lib.types.path; default = "/var/lib/i2p-python"; description = "Directory for router state and data."; }; logLevel = lib.mkOption { type = lib.types.enum [ "DEBUG" "INFO" "WARNING" "ERROR" ]; default = "INFO"; description = "Log verbosity level."; }; openFirewall = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to open transport ports in the firewall."; }; }; config = lib.mkIf cfg.enable { users.users.i2p-python = { isSystemUser = true; group = "i2p-python"; home = cfg.dataDir; createHome = true; description = "I2P Python router daemon"; }; users.groups.i2p-python = { }; systemd.services.i2p-python = { description = "I2P Python Router"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; environment = { I2P_DATA_DIR = cfg.dataDir; }; serviceConfig = { Type = "simple"; User = "i2p-python"; Group = "i2p-python"; ExecStart = lib.concatStringsSep " " [ (lib.getExe cfg.package) "--host ${cfg.ntcp2.address}" "--port ${toString cfg.ntcp2.port}" "--data-dir ${cfg.dataDir}" "--log-level ${cfg.logLevel}" ]; Restart = "on-failure"; RestartSec = 10; # Hardening StateDirectory = "i2p-python"; StateDirectoryMode = "0700"; ProtectSystem = "strict"; ProtectHome = true; PrivateTmp = true; NoNewPrivileges = true; ReadWritePaths = [ cfg.dataDir ]; LimitNOFILE = 65536; }; }; networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.ntcp2.port ]; allowedUDPPorts = [ cfg.ssu2.port ]; }; }; }