···269269 mosquitto = 246;
270270 toxvpn = 247;
271271 squeezelite = 248;
272272+ turnserver = 249;
272273273274 # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
274275···508509 mosquitto = 246;
509510 #toxvpn = 247; # unused
510511 #squeezelite = 248; #unused
512512+ turnserver = 249;
511513512514 # When adding a gid, make sure it doesn't match an existing
513515 # uid. Users and groups with the same name should have equal
···11+{ config, lib, pkgs, ... }:
22+with lib;
33+let
44+ cfg = config.services.coturn;
55+ pidfile = "/run/turnserver/turnserver.pid";
66+ configFile = pkgs.writeText "turnserver.conf" ''
77+listening-port=${toString cfg.listening-port}
88+tls-listening-port=${toString cfg.tls-listening-port}
99+alt-listening-port=${toString cfg.alt-listening-port}
1010+alt-tls-listening-port=${toString cfg.alt-tls-listening-port}
1111+${concatStringsSep "\n" (map (x: "listening-ip=${x}") cfg.listening-ips)}
1212+${concatStringsSep "\n" (map (x: "relay-ip=${x}") cfg.relay-ips)}
1313+min-port=${toString cfg.min-port}
1414+max-port=${toString cfg.max-port}
1515+${lib.optionalString cfg.lt-cred-mech "lt-cred-mech"}
1616+${lib.optionalString cfg.no-auth "no-auth"}
1717+${lib.optionalString cfg.use-auth-secret "use-auth-secret"}
1818+${lib.optionalString (cfg.static-auth-secret != null) ("static-auth-secret=${cfg.static-auth-secret}")}
1919+realm=${cfg.realm}
2020+${lib.optionalString cfg.no-udp "no-udp"}
2121+${lib.optionalString cfg.no-tcp "no-tcp"}
2222+${lib.optionalString cfg.no-tls "no-tls"}
2323+${lib.optionalString cfg.no-dtls "no-dtls"}
2424+${lib.optionalString cfg.no-udp-relay "no-udp-relay"}
2525+${lib.optionalString cfg.no-tcp-relay "no-tcp-relay"}
2626+${lib.optionalString (cfg.cert != null) "cert=${cfg.cert}"}
2727+${lib.optionalString (cfg.pkey != null) "pkey=${cfg.pkey}"}
2828+${lib.optionalString (cfg.dh-file != null) ("dh-file=${cfg.dh-file}")}
2929+no-stdout-log
3030+syslog
3131+pidfile=${pidfile}
3232+${lib.optionalString cfg.secure-stun "secure-stun"}
3333+${lib.optionalString cfg.no-cli "no-cli"}
3434+cli-ip=${cfg.cli-ip}
3535+cli-port=${toString cfg.cli-port}
3636+${lib.optionalString (cfg.cli-password != null) ("cli-password=${cfg.cli-password}")}
3737+${cfg.extraConfig}
3838+'';
3939+in {
4040+ options = {
4141+ services.coturn = {
4242+ enable = mkEnableOption "coturn TURN server";
4343+ listening-port = mkOption {
4444+ type = types.int;
4545+ default = 3478;
4646+ description = ''
4747+ TURN listener port for UDP and TCP.
4848+ Note: actually, TLS and DTLS sessions can connect to the
4949+ "plain" TCP and UDP port(s), too - if allowed by configuration.
5050+ '';
5151+ };
5252+ tls-listening-port = mkOption {
5353+ type = types.int;
5454+ default = 5349;
5555+ description = ''
5656+ TURN listener port for TLS.
5757+ Note: actually, "plain" TCP and UDP sessions can connect to the TLS and
5858+ DTLS port(s), too - if allowed by configuration. The TURN server
5959+ "automatically" recognizes the type of traffic. Actually, two listening
6060+ endpoints (the "plain" one and the "tls" one) are equivalent in terms of
6161+ functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
6262+ For secure TCP connections, we currently support SSL version 3 and
6363+ TLS version 1.0, 1.1 and 1.2.
6464+ For secure UDP connections, we support DTLS version 1.
6565+ '';
6666+ };
6767+ alt-listening-port = mkOption {
6868+ type = types.int;
6969+ default = cfg.listening-port + 1;
7070+ defaultText = "listening-port + 1";
7171+ description = ''
7272+ Alternative listening port for UDP and TCP listeners;
7373+ default (or zero) value means "listening port plus one".
7474+ This is needed for RFC 5780 support
7575+ (STUN extension specs, NAT behavior discovery). The TURN Server
7676+ supports RFC 5780 only if it is started with more than one
7777+ listening IP address of the same family (IPv4 or IPv6).
7878+ RFC 5780 is supported only by UDP protocol, other protocols
7979+ are listening to that endpoint only for "symmetry".
8080+ '';
8181+ };
8282+ alt-tls-listening-port = mkOption {
8383+ type = types.int;
8484+ default = cfg.tls-listening-port + 1;
8585+ defaultText = "tls-listening-port + 1";
8686+ description = ''
8787+ Alternative listening port for TLS and DTLS protocols.
8888+ '';
8989+ };
9090+ listening-ips = mkOption {
9191+ type = types.listOf types.str;
9292+ default = [];
9393+ example = [ "203.0.113.42" "2001:DB8::42" ];
9494+ description = ''
9595+ Listener IP addresses of relay server.
9696+ If no IP(s) specified in the config file or in the command line options,
9797+ then all IPv4 and IPv6 system IPs will be used for listening.
9898+ '';
9999+ };
100100+ relay-ips = mkOption {
101101+ type = types.listOf types.str;
102102+ default = [];
103103+ example = [ "203.0.113.42" "2001:DB8::42" ];
104104+ description = ''
105105+ Relay address (the local IP address that will be used to relay the
106106+ packets to the peer).
107107+ Multiple relay addresses may be used.
108108+ The same IP(s) can be used as both listening IP(s) and relay IP(s).
109109+110110+ If no relay IP(s) specified, then the turnserver will apply the default
111111+ policy: it will decide itself which relay addresses to be used, and it
112112+ will always be using the client socket IP address as the relay IP address
113113+ of the TURN session (if the requested relay address family is the same
114114+ as the family of the client socket).
115115+ '';
116116+ };
117117+ min-port = mkOption {
118118+ type = types.int;
119119+ default = 49152;
120120+ description = ''
121121+ Lower bound of UDP relay endpoints
122122+ '';
123123+ };
124124+ max-port = mkOption {
125125+ type = types.int;
126126+ default = 65535;
127127+ description = ''
128128+ Upper bound of UDP relay endpoints
129129+ '';
130130+ };
131131+ lt-cred-mech = mkOption {
132132+ type = types.bool;
133133+ default = false;
134134+ description = ''
135135+ Use long-term credential mechanism.
136136+ '';
137137+ };
138138+ no-auth = mkOption {
139139+ type = types.bool;
140140+ default = false;
141141+ description = ''
142142+ This option is opposite to lt-cred-mech.
143143+ (TURN Server with no-auth option allows anonymous access).
144144+ If neither option is defined, and no users are defined,
145145+ then no-auth is default. If at least one user is defined,
146146+ in this file or in command line or in usersdb file, then
147147+ lt-cred-mech is default.
148148+ '';
149149+ };
150150+ use-auth-secret = mkOption {
151151+ type = types.bool;
152152+ default = false;
153153+ description = ''
154154+ TURN REST API flag.
155155+ Flag that sets a special authorization option that is based upon authentication secret.
156156+ This feature can be used with the long-term authentication mechanism, only.
157157+ This feature purpose is to support "TURN Server REST API", see
158158+ "TURN REST API" link in the project's page
159159+ https://github.com/coturn/coturn/
160160+161161+ This option is used with timestamp:
162162+163163+ usercombo -> "timestamp:userid"
164164+ turn user -> usercombo
165165+ turn password -> base64(hmac(secret key, usercombo))
166166+167167+ This allows TURN credentials to be accounted for a specific user id.
168168+ If you don't have a suitable id, the timestamp alone can be used.
169169+ This option is just turning on secret-based authentication.
170170+ The actual value of the secret is defined either by option static-auth-secret,
171171+ or can be found in the turn_secret table in the database.
172172+ '';
173173+ };
174174+ static-auth-secret = mkOption {
175175+ type = types.nullOr types.str;
176176+ default = null;
177177+ description = ''
178178+ 'Static' authentication secret value (a string) for TURN REST API only.
179179+ If not set, then the turn server
180180+ will try to use the 'dynamic' value in turn_secret table
181181+ in user database (if present). The database-stored value can be changed on-the-fly
182182+ by a separate program, so this is why that other mode is 'dynamic'.
183183+ '';
184184+ };
185185+ realm = mkOption {
186186+ type = types.str;
187187+ default = config.networking.hostName;
188188+ example = "example.com";
189189+ description = ''
190190+ The default realm to be used for the users when no explicit
191191+ origin/realm relationship was found in the database, or if the TURN
192192+ server is not using any database (just the commands-line settings
193193+ and the userdb file). Must be used with long-term credentials
194194+ mechanism or with TURN REST API.
195195+ '';
196196+ };
197197+ cert = mkOption {
198198+ type = types.nullOr types.str;
199199+ default = null;
200200+ example = "/var/lib/acme/example.com/fullchain.pem";
201201+ description = ''
202202+ Certificate file in PEM format.
203203+ '';
204204+ };
205205+ pkey = mkOption {
206206+ type = types.nullOr types.str;
207207+ default = null;
208208+ example = "/var/lib/acme/example.com/key.pem";
209209+ description = ''
210210+ Private key file in PEM format.
211211+ '';
212212+ };
213213+ dh-file = mkOption {
214214+ type = types.nullOr types.str;
215215+ default = null;
216216+ description = ''
217217+ Use custom DH TLS key, stored in PEM format in the file.
218218+ '';
219219+ };
220220+ secure-stun = mkOption {
221221+ type = types.bool;
222222+ default = false;
223223+ description = ''
224224+ Require authentication of the STUN Binding request.
225225+ By default, the clients are allowed anonymous access to the STUN Binding functionality.
226226+ '';
227227+ };
228228+ no-cli = mkOption {
229229+ type = types.bool;
230230+ default = false;
231231+ description = ''
232232+ Turn OFF the CLI support.
233233+ '';
234234+ };
235235+ cli-ip = mkOption {
236236+ type = types.str;
237237+ default = "127.0.0.1";
238238+ description = ''
239239+ Local system IP address to be used for CLI server endpoint.
240240+ '';
241241+ };
242242+ cli-port = mkOption {
243243+ type = types.int;
244244+ default = 5766;
245245+ description = ''
246246+ CLI server port.
247247+ '';
248248+ };
249249+ cli-password = mkOption {
250250+ type = types.nullOr types.str;
251251+ default = null;
252252+ description = ''
253253+ CLI access password.
254254+ For the security reasons, it is recommended to use the encrypted
255255+ for of the password (see the -P command in the turnadmin utility).
256256+ '';
257257+ };
258258+ no-udp = mkOption {
259259+ type = types.bool;
260260+ default = false;
261261+ description = "Disable UDP client listener";
262262+ };
263263+ no-tcp = mkOption {
264264+ type = types.bool;
265265+ default = false;
266266+ description = "Disable TCP client listener";
267267+ };
268268+ no-tls = mkOption {
269269+ type = types.bool;
270270+ default = false;
271271+ description = "Disable TLS client listener";
272272+ };
273273+ no-dtls = mkOption {
274274+ type = types.bool;
275275+ default = false;
276276+ description = "Disable DTLS client listener";
277277+ };
278278+ no-udp-relay = mkOption {
279279+ type = types.bool;
280280+ default = false;
281281+ description = "Disable UDP relay endpoints";
282282+ };
283283+ no-tcp-relay = mkOption {
284284+ type = types.bool;
285285+ default = false;
286286+ description = "Disable TCP relay endpoints";
287287+ };
288288+ extraConfig = mkOption {
289289+ type = types.lines;
290290+ default = "";
291291+ description = "Additional configuration options";
292292+ };
293293+ };
294294+ };
295295+296296+ config = mkIf cfg.enable {
297297+ users.extraUsers = [
298298+ { name = "turnserver";
299299+ uid = config.ids.uids.turnserver;
300300+ description = "coturn TURN server user";
301301+ } ];
302302+ users.extraGroups = [
303303+ { name = "turnserver";
304304+ gid = config.ids.gids.turnserver;
305305+ members = [ "turnserver" ];
306306+ } ];
307307+308308+ systemd.services.coturn = {
309309+ description = "coturn TURN server";
310310+ after = [ "network.target" ];
311311+ wantedBy = [ "multi-user.target" ];
312312+313313+ unitConfig = {
314314+ Documentation = "man:coturn(1) man:turnadmin(1) man:turnserver(1)";
315315+ };
316316+317317+ serviceConfig = {
318318+ Type = "simple";
319319+ ExecStart = "${pkgs.coturn}/bin/turnserver -c ${configFile}";
320320+ RuntimeDirectory = "turnserver";
321321+ User = "turnserver";
322322+ Group = "turnserver";
323323+ Restart = "on-abort";
324324+ };
325325+ };
326326+ };
327327+}