lol
fork

Configure Feed

Select the types of activity you want to include in your feed.

nixos/rathole: init module

Adds a module for rathole package. The package itself
and this module is very similar to frp, so the options
and tests are not very far off from those for frp.

+258
+2
nixos/doc/manual/release-notes/rl-2411.section.md
··· 68 68 69 69 - [OpenGFW](https://github.com/apernet/OpenGFW), an implementation of the Great Firewall on Linux. Available as [services.opengfw](#opt-services.opengfw.enable). 70 70 71 + - [Rathole](https://github.com/rapiz1/rathole), a lightweight and high-performance reverse proxy for NAT traversal. Available as [services.rathole](#opt-services.rathole.enable). 72 + 71 73 ## Backward Incompatibilities {#sec-release-24.11-incompatibilities} 72 74 73 75 - `transmission` package has been aliased with a `trace` warning to `transmission_3`. Since [Transmission 4 has been released last year](https://github.com/transmission/transmission/releases/tag/4.0.0), and Transmission 3 will eventually go away, it was decided perform this warning alias to make people aware of the new version. The `services.transmission.package` defaults to `transmission_3` as well because the upgrade can cause data loss in certain specific usage patterns (examples: [#5153](https://github.com/transmission/transmission/issues/5153), [#6796](https://github.com/transmission/transmission/issues/6796)). Please make sure to back up to your data directory per your usage:
+1
nixos/modules/module-list.nix
··· 1160 1160 ./services/networking/r53-ddns.nix 1161 1161 ./services/networking/radicale.nix 1162 1162 ./services/networking/radvd.nix 1163 + ./services/networking/rathole.nix 1163 1164 ./services/networking/rdnssd.nix 1164 1165 ./services/networking/realm.nix 1165 1166 ./services/networking/redsocks.nix
+165
nixos/modules/services/networking/rathole.nix
··· 1 + { 2 + pkgs, 3 + lib, 4 + config, 5 + ... 6 + }: 7 + 8 + let 9 + cfg = config.services.rathole; 10 + settingsFormat = pkgs.formats.toml { }; 11 + py-toml-merge = 12 + pkgs.writers.writePython3Bin "py-toml-merge" 13 + { 14 + libraries = with pkgs.python3Packages; [ 15 + tomli-w 16 + mergedeep 17 + ]; 18 + } 19 + '' 20 + import argparse 21 + from pathlib import Path 22 + from typing import Any 23 + 24 + import tomli_w 25 + import tomllib 26 + from mergedeep import merge 27 + 28 + parser = argparse.ArgumentParser(description="Merge multiple TOML files") 29 + parser.add_argument( 30 + "files", 31 + type=Path, 32 + nargs="+", 33 + help="List of TOML files to merge", 34 + ) 35 + 36 + args = parser.parse_args() 37 + merged: dict[str, Any] = {} 38 + 39 + for file in args.files: 40 + with open(file, "rb") as fh: 41 + loaded_toml = tomllib.load(fh) 42 + merged = merge(merged, loaded_toml) 43 + 44 + print(tomli_w.dumps(merged)) 45 + ''; 46 + in 47 + 48 + { 49 + options = { 50 + services.rathole = { 51 + enable = lib.mkEnableOption "Rathole"; 52 + 53 + package = lib.mkPackageOption pkgs "rathole" { }; 54 + 55 + role = lib.mkOption { 56 + type = lib.types.enum [ 57 + "server" 58 + "client" 59 + ]; 60 + description = '' 61 + Select whether rathole needs to be run as a `client` or a `server`. 62 + Server is a machine with a public IP and client is a device behind NAT, 63 + but running some services that need to be exposed to the Internet. 64 + ''; 65 + }; 66 + 67 + credentialsFile = lib.mkOption { 68 + type = lib.types.path; 69 + default = "/dev/null"; 70 + description = '' 71 + Path to a TOML file to be merged with the settings. 72 + Useful to set secret config parameters like tokens, which 73 + should not appear in the Nix Store. 74 + ''; 75 + example = "/var/lib/secrets/rathole/config.toml"; 76 + }; 77 + 78 + settings = lib.mkOption { 79 + type = settingsFormat.type; 80 + default = { }; 81 + description = '' 82 + Rathole configuration, for options reference 83 + see the [example](https://github.com/rapiz1/rathole?tab=readme-ov-file#configuration) on GitHub. 84 + Both server and client configurations can be specified at the same time, regardless of the selected role. 85 + ''; 86 + example = { 87 + server = { 88 + bind_addr = "0.0.0.0:2333"; 89 + services.my_nas_ssh = { 90 + token = "use_a_secret_that_only_you_know"; 91 + bind_addr = "0.0.0.0:5202"; 92 + }; 93 + }; 94 + }; 95 + }; 96 + }; 97 + }; 98 + 99 + config = lib.mkIf cfg.enable { 100 + systemd.services.rathole = { 101 + requires = [ "network.target" ]; 102 + after = [ "network.target" ]; 103 + wantedBy = [ "multi-user.target" ]; 104 + description = "Rathole ${cfg.role} Service"; 105 + 106 + serviceConfig = 107 + let 108 + name = "rathole"; 109 + configFile = settingsFormat.generate "${name}.toml" cfg.settings; 110 + runtimeDir = "/run/${name}"; 111 + ratholePrestart = 112 + "+" 113 + + (pkgs.writeShellScript "rathole-prestart" '' 114 + DYNUSER_UID=$(stat -c %u ${runtimeDir}) 115 + DYNUSER_GID=$(stat -c %g ${runtimeDir}) 116 + ${lib.getExe py-toml-merge} ${configFile} '${cfg.credentialsFile}' | 117 + install -m 600 -o $DYNUSER_UID -g $DYNUSER_GID /dev/stdin ${runtimeDir}/${mergedConfigName} 118 + ''); 119 + mergedConfigName = "merged.toml"; 120 + in 121 + { 122 + Type = "simple"; 123 + Restart = "on-failure"; 124 + RestartSec = 5; 125 + ExecStartPre = ratholePrestart; 126 + ExecStart = "${lib.getExe cfg.package} --${cfg.role} ${runtimeDir}/${mergedConfigName}"; 127 + DynamicUser = true; 128 + LimitNOFILE = "1048576"; 129 + RuntimeDirectory = name; 130 + RuntimeDirectoryMode = "0700"; 131 + # Hardening 132 + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; 133 + CapabilityBoundingSet = "CAP_NET_BIND_SERVICE"; 134 + LockPersonality = true; 135 + MemoryDenyWriteExecute = true; 136 + PrivateDevices = true; 137 + PrivateMounts = true; 138 + PrivateTmp = true; 139 + # PrivateUsers=true breaks AmbientCapabilities=CAP_NET_BIND_SERVICE 140 + ProcSubset = "pid"; 141 + ProtectClock = true; 142 + ProtectControlGroups = true; 143 + ProtectHome = true; 144 + ProtectHostname = true; 145 + ProtectKernelLogs = true; 146 + ProtectKernelModules = true; 147 + ProtectKernelTunables = true; 148 + ProtectProc = "invisible"; 149 + ProtectSystem = "strict"; 150 + RemoveIPC = true; 151 + RestrictAddressFamilies = [ 152 + "AF_INET" 153 + "AF_INET6" 154 + ]; 155 + RestrictNamespaces = true; 156 + RestrictRealtime = true; 157 + RestrictSUIDSGID = true; 158 + SystemCallArchitectures = "native"; 159 + UMask = "0066"; 160 + }; 161 + }; 162 + }; 163 + 164 + meta.maintainers = with lib.maintainers; [ xokdvium ]; 165 + }
+1
nixos/tests/all-tests.nix
··· 823 823 radicle = runTest ./radicle.nix; 824 824 ragnarwm = handleTest ./ragnarwm.nix {}; 825 825 rasdaemon = handleTest ./rasdaemon.nix {}; 826 + rathole = handleTest ./rathole.nix {}; 826 827 readarr = handleTest ./readarr.nix {}; 827 828 realm = handleTest ./realm.nix {}; 828 829 redis = handleTest ./redis.nix {};
+89
nixos/tests/rathole.nix
··· 1 + import ./make-test-python.nix ( 2 + { pkgs, lib, ... }: 3 + 4 + let 5 + successMessage = "Success 3333115147933743662"; 6 + in 7 + { 8 + name = "rathole"; 9 + meta.maintainers = with lib.maintainers; [ xokdvium ]; 10 + nodes = { 11 + server = { 12 + networking = { 13 + useNetworkd = true; 14 + useDHCP = false; 15 + firewall.enable = false; 16 + }; 17 + 18 + systemd.network.networks."01-eth1" = { 19 + name = "eth1"; 20 + networkConfig.Address = "10.0.0.1/24"; 21 + }; 22 + 23 + services.rathole = { 24 + enable = true; 25 + role = "server"; 26 + settings = { 27 + server = { 28 + bind_addr = "0.0.0.0:2333"; 29 + services = { 30 + success-message = { 31 + bind_addr = "0.0.0.0:80"; 32 + token = "hunter2"; 33 + }; 34 + }; 35 + }; 36 + }; 37 + }; 38 + }; 39 + 40 + client = { 41 + networking = { 42 + useNetworkd = true; 43 + useDHCP = false; 44 + }; 45 + 46 + systemd.network.networks."01-eth1" = { 47 + name = "eth1"; 48 + networkConfig.Address = "10.0.0.2/24"; 49 + }; 50 + 51 + services.nginx = { 52 + enable = true; 53 + virtualHosts."127.0.0.1" = { 54 + root = pkgs.writeTextDir "success-message.txt" successMessage; 55 + }; 56 + }; 57 + 58 + services.rathole = { 59 + enable = true; 60 + role = "client"; 61 + credentialsFile = pkgs.writeText "rathole-credentials.toml" '' 62 + [client.services.success-message] 63 + token = "hunter2" 64 + ''; 65 + settings = { 66 + client = { 67 + remote_addr = "10.0.0.1:2333"; 68 + services.success-message = { 69 + local_addr = "127.0.0.1:80"; 70 + }; 71 + }; 72 + }; 73 + }; 74 + }; 75 + }; 76 + 77 + testScript = '' 78 + start_all() 79 + server.wait_for_unit("rathole.service") 80 + server.wait_for_open_port(2333) 81 + client.wait_for_unit("rathole.service") 82 + server.wait_for_open_port(80) 83 + response = server.succeed("curl http://127.0.0.1/success-message.txt") 84 + assert "${successMessage}" in response, "Got invalid response" 85 + response = client.succeed("curl http://10.0.0.1/success-message.txt") 86 + assert "${successMessage}" in response, "Got invalid response" 87 + ''; 88 + } 89 + )