1 { config, lib, pkgs, ... }:
4 cfg = config.services.lokinet;
5 dataDir = "/var/lib/lokinet";
6 settingsFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; };
7 configFile = settingsFormat.generate "lokinet.ini" (lib.filterAttrsRecursive (n: v: v != null) cfg.settings);
9 options.services.lokinet = {
10 enable = mkEnableOption (lib.mdDoc "Lokinet daemon");
14 default = pkgs.lokinet;
15 defaultText = literalExpression "pkgs.lokinet";
16 description = lib.mdDoc "Lokinet package to use.";
19 useLocally = mkOption {
23 description = lib.mdDoc "Whether to use Lokinet locally.";
29 freeformType = settingsFormat.type;
35 default = "127.3.2.1";
36 description = lib.mdDoc "Address to bind to for handling DNS requests.";
41 default = [ "9.9.9.10" ];
42 example = [ "1.1.1.1" "8.8.8.8" ];
43 description = lib.mdDoc ''
44 Upstream resolver(s) to use as fallback for non-loki addresses.
45 Multiple values accepted.
54 description = lib.mdDoc ''
55 Whether to act as an exit node. Beware that this
56 increases demand on the server and may pose liability concerns.
57 Enable at your own risk.
61 exit-node = mkOption {
62 type = nullOr (listOf str);
65 exit-node = [ "example.loki" ]; # maps all exit traffic to example.loki
66 exit-node = [ "example.loki:100.0.0.0/24" ]; # maps 100.0.0.0/24 to example.loki
68 description = lib.mdDoc ''
69 Specify a `.loki` address and an optional ip range to use as an exit broker.
70 See <http://probably.loki/wiki/index.php?title=Exit_Nodes> for
78 example = "snappkey.private";
79 description = lib.mdDoc ''
80 The private key to persist address with. If not specified the address will be ephemeral.
81 This keyfile is generated automatically if the specified file doesn't exist.
88 example = literalExpression ''
92 upstream = [ "1.1.1.1" "8.8.8.8" ];
95 network.exit-node = [ "example.loki" "example2.loki" ];
98 description = lib.mdDoc ''
99 Configuration for Lokinet.
100 Currently, the best way to view the available settings is by
101 generating a config file using `lokinet -g`.
106 config = mkIf cfg.enable {
107 networking.resolvconf.extraConfig = mkIf cfg.useLocally ''
108 name_servers="${cfg.settings.dns.bind}"
111 systemd.services.lokinet = {
112 description = "Lokinet";
113 after = [ "network-online.target" "network.target" ];
114 wants = [ "network-online.target" "network.target" ];
115 wantedBy = [ "multi-user.target" ];
118 ln -sf ${cfg.package}/share/bootstrap.signed ${dataDir}
119 ${pkgs.coreutils}/bin/install -m 600 ${configFile} ${dataDir}/lokinet.ini
121 ${optionalString (cfg.settings.network.keyfile != null) ''
122 ${pkgs.crudini}/bin/crudini --set ${dataDir}/lokinet.ini network keyfile "${dataDir}/${cfg.settings.network.keyfile}"
128 StateDirectory = "lokinet";
129 AmbientCapabilities = [ "CAP_NET_ADMIN" "CAP_NET_BIND_SERVICE" ];
130 ExecStart = "${cfg.package}/bin/lokinet ${dataDir}/lokinet.ini";
135 LockPersonality = true;
136 MemoryDenyWriteExecute = true;
137 NoNewPrivileges = true;
139 PrivateMounts = true;
140 ProtectControlGroups = true;
142 ProtectHostname = true;
143 ProtectKernelLogs = true;
144 ProtectKernelModules = true;
145 ProtectKernelTunables = true;
146 ProtectSystem = "strict";
147 ReadWritePaths = "/dev/net/tun";
148 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
149 RestrictNamespaces = true;
150 RestrictRealtime = true;
151 RestrictSUIDSGID = true;
155 environment.systemPackages = [ cfg.package ];