8 cfg = config.services.inadyn;
10 # check if a value of an attrset is not null or an empty collection
11 nonEmptyValue = _: v: v != null && v != [ ] && v != { };
21 lib.concatStringsSep "\n" (
22 lib.mapAttrsToList (name: config: ''
24 ${lib.concatStringsSep "\n " (
25 lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue config)
29 else if k == "include" then
31 else if k == "hostname" && builtins.isList v then
32 "${k} = { ${builtins.concatStringsSep ", " (map (s: "\"${s}\"") v)} }"
33 else if builtins.isBool v then
34 "${k} = ${lib.boolToString v}"
35 else if builtins.isString v then
38 "${k} = ${toString v}";
40 configFile' = pkgs.writeText "inadyn.conf" ''
41 # This file was generated by nix
45 (lib.concatStringsSep "\n" (
46 lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue cfg.settings)
51 configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
54 options.services.inadyn =
58 include = lib.mkOption {
60 description = "File to include additional settings for this provider from.";
65 description = "Whether to use HTTPS for this DDNS provider.";
68 username = lib.mkOption {
70 description = "Username for this DDNS provider.";
73 password = lib.mkOption {
76 Password for this DDNS provider.
78 WARNING: This will be world-readable in the nix store.
79 To store credentials securely, use the `include` or `configFile` options.
83 hostname = lib.mkOption {
85 example = "your.cool-domain.com";
86 description = "Hostname alias(es).";
87 type = either str (listOf str);
92 enable = lib.mkEnableOption (''
93 synchronise your machine's IP address with a dynamic DNS provider using inadyn
99 User account under which inadyn runs.
102 If left as the default value this user will automatically be created
103 on system activation, otherwise you are responsible for
104 ensuring the user exists before the inadyn service starts.
108 group = lib.mkOption {
110 type = lib.types.str;
112 Group account under which inadyn runs.
115 If left as the default value this user will automatically be created
116 on system activation, otherwise you are responsible for
117 ensuring the user exists before the inadyn service starts.
121 interval = lib.mkOption {
122 default = "*-*-* *:*:00";
124 How often to check the current IP.
125 Uses the format described in {manpage}`systemd.time(7)`";
129 logLevel = lib.mkOption {
130 type = lib.types.enum [
139 description = "Set inadyn's log level.";
141 settings = lib.mkOption {
143 description = "See `inadyn.conf (5)`";
145 freeformType = attrs;
147 allow-ipv6 = lib.mkOption {
148 default = config.networking.enableIPv6;
149 defaultText = "`config.networking.enableIPv6`";
150 description = "Whether to get IPv6 addresses from interfaces.";
153 forced-update = lib.mkOption {
155 description = "Duration (in seconds) after which an update is forced.";
156 type = ints.positive;
158 provider = lib.mkOption {
161 Settings for DDNS providers built-in to inadyn.
163 For a list of built-in providers, see `inadyn.conf (5)`.
165 type = attrsOf (submodule {
166 freeformType = attrs;
167 options = providerOptions;
170 custom = lib.mkOption {
173 Settings for custom DNS providers.
175 type = attrsOf (submodule {
176 freeformType = attrs;
177 options = providerOptions // {
178 ddns-server = lib.mkOption {
179 description = "DDNS server name.";
182 ddns-path = lib.mkOption {
186 See `inadnyn.conf (5)` for a list for format specifiers that can be used.
188 example = "/update?user=%u&password=%p&domain=%h&myip=%i";
197 configFile = lib.mkOption {
200 Configuration file for inadyn.
202 Setting this will override all other configuration options.
204 Passed to the inadyn service using LoadCredential.
210 config = lib.mkIf cfg.enable {
213 description = "Update nameservers using inadyn";
217 "file:${pkgs.inadyn}/share/doc/inadyn/README.md"
219 requires = [ "network-online.target" ];
220 wantedBy = [ "multi-user.target" ];
221 startAt = cfg.interval;
224 ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY} -1 --foreground -l ${cfg.logLevel}'';
225 LoadCredential = "config:${configFile}";
226 CacheDirectory = "inadyn";
231 LockPersonality = true;
232 MemoryDenyWriteExecute = true;
233 RestrictAddressFamilies = "AF_INET AF_INET6 AF_NETLINK";
234 NoNewPrivileges = true;
235 PrivateDevices = true;
238 ProtectSystem = "strict";
239 ProtectProc = "invisible";
242 ProtectControlGroups = true;
243 ProtectHostname = true;
244 ProtectKernelLogs = true;
245 ProtectKernelModules = true;
246 ProtectKernelTunables = true;
247 RestrictNamespaces = true;
248 RestrictRealtime = true;
249 RestrictSUIDSGID = true;
250 SystemCallArchitectures = "native";
251 SystemCallErrorNumber = "EPERM";
252 SystemCallFilter = "@system-service";
253 CapabilityBoundingSet = "";
257 timers.inadyn.timerConfig.Persistent = true;
260 users.users.inadyn = lib.mkIf (cfg.user == "inadyn") {
265 users.groups = lib.mkIf (cfg.group == "inadyn") {