1{ config, pkgs, lib, ... }:
2
3let
4 cfg = config.services.ddclient;
5 boolToStr = bool: if bool then "yes" else "no";
6
7 configText = ''
8 # This file can be used as a template for configFile or is automatically generated by Nix options.
9 daemon=${toString cfg.interval}
10 cache=${cfg.homeDir}/ddclient.cache
11 pid=/run/ddclient/ddclient.pid
12 foreground=NO
13 use=${cfg.use}
14 login=${cfg.username}
15 password=${cfg.password}
16 protocol=${cfg.protocol}
17 ${let server = cfg.server; in
18 lib.optionalString (server != "") "server=${server}"}
19 ssl=${boolToStr cfg.ssl}
20 wildcard=YES
21 quiet=${boolToStr cfg.quiet}
22 verbose=${boolToStr cfg.verbose}
23 ${cfg.domain}
24 ${cfg.extraConfig}
25 '';
26
27in
28
29with lib;
30
31{
32
33 ###### interface
34
35 options = {
36
37 services.ddclient = with lib.types; {
38
39 enable = mkOption {
40 default = false;
41 type = bool;
42 description = ''
43 Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org).
44 '';
45 };
46
47 homeDir = mkOption {
48 default = "/var/lib/ddclient";
49 type = str;
50 description = "Home directory for the daemon user.";
51 };
52
53 domain = mkOption {
54 default = "";
55 type = str;
56 description = ''
57 Domain name to synchronize.
58 '';
59 };
60
61 username = mkOption {
62 default = "";
63 type = str;
64 description = ''
65 Username.
66 '';
67 };
68
69 password = mkOption {
70 default = "";
71 type = str;
72 description = ''
73 Password. WARNING: The password becomes world readable in the Nix store.
74 '';
75 };
76
77 interval = mkOption {
78 default = 600;
79 type = int;
80 description = "The interval at which to run the check and update.";
81 };
82
83 configFile = mkOption {
84 default = "/etc/ddclient.conf";
85 type = path;
86 description = ''
87 Path to configuration file.
88 When set to the default '/etc/ddclient.conf' it will be populated with the various other options in this module. When it is changed (for example: '/root/nixos/secrets/ddclient.conf') the file read directly to configure ddclient. This is a source of impurity.
89 The purpose of this is to avoid placing secrets into the store.
90 '';
91 example = "/root/nixos/secrets/ddclient.conf";
92 };
93
94 protocol = mkOption {
95 default = "dyndns2";
96 type = str;
97 description = ''
98 Protocol to use with dynamic DNS provider (see http://sourceforge.net/apps/trac/ddclient/wiki/Protocols).
99 '';
100 };
101
102 server = mkOption {
103 default = "";
104 type = str;
105 description = ''
106 Server address.
107 '';
108 };
109
110 ssl = mkOption {
111 default = true;
112 type = bool;
113 description = ''
114 Whether to use to use SSL/TLS to connect to dynamic DNS provider.
115 '';
116 };
117
118 extraConfig = mkOption {
119 default = "";
120 type = lines;
121 description = ''
122 Extra configuration. Contents will be added verbatim to the configuration file.
123 '';
124 };
125
126 use = mkOption {
127 default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '";
128 type = str;
129 description = ''
130 Method to determine the IP address to send to the dynamic DNS provider.
131 '';
132 };
133
134 verbose = mkOption {
135 default = true;
136 type = bool;
137 description = ''
138 Print verbose information.
139 '';
140 };
141
142 quiet = mkOption {
143 default = false;
144 type = bool;
145 description = ''
146 Print no messages for unnecessary updates.
147 '';
148 };
149 };
150 };
151
152
153 ###### implementation
154
155 config = mkIf config.services.ddclient.enable {
156
157 users = {
158 extraGroups.ddclient.gid = config.ids.gids.ddclient;
159
160 extraUsers.ddclient = {
161 uid = config.ids.uids.ddclient;
162 description = "ddclient daemon user";
163 group = "ddclient";
164 home = cfg.homeDir;
165 createHome = true;
166 };
167 };
168
169 environment.etc."ddclient.conf" = {
170 enable = cfg.configFile == "/etc/ddclient.conf";
171 uid = config.ids.uids.ddclient;
172 gid = config.ids.gids.ddclient;
173 mode = "0600";
174 text = configText;
175 };
176
177 systemd.services.ddclient = {
178 description = "Dynamic DNS Client";
179 wantedBy = [ "multi-user.target" ];
180 after = [ "network.target" ];
181 restartTriggers = [ config.environment.etc."ddclient.conf".source ];
182
183 serviceConfig = {
184 RuntimeDirectory = "ddclient";
185 # we cannot run in forking mode as it swallows all the program output
186 Type = "simple";
187 User = "ddclient";
188 Group = "ddclient";
189 ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -foreground -file ${cfg.configFile}";
190 ProtectSystem = "full";
191 PrivateTmp = true;
192 };
193 };
194 };
195}