1 { config, lib, pkgs, ... }:
6 cfg = config.services.murmur;
7 forking = cfg.logFile != null;
8 configFile = pkgs.writeText "murmurd.ini" ''
9 database=/var/lib/murmur/murmur.sqlite
12 autobanAttempts=${toString cfg.autobanAttempts}
13 autobanTimeframe=${toString cfg.autobanTimeframe}
14 autobanTime=${toString cfg.autobanTime}
16 logfile=${optionalString (cfg.logFile != null) cfg.logFile}
17 ${optionalString forking "pidfile=/run/murmur/murmurd.pid"}
19 welcometext="${cfg.welcometext}"
20 port=${toString cfg.port}
22 ${optionalString (cfg.hostName != "") "host=${cfg.hostName}"}
23 ${optionalString (cfg.password != "") "serverpassword=${cfg.password}"}
25 bandwidth=${toString cfg.bandwidth}
26 users=${toString cfg.users}
28 textmessagelength=${toString cfg.textMsgLength}
29 imagemessagelength=${toString cfg.imgMsgLength}
30 allowhtml=${boolToString cfg.allowHtml}
31 logdays=${toString cfg.logDays}
32 bonjour=${boolToString cfg.bonjour}
33 sendversion=${boolToString cfg.sendVersion}
35 ${optionalString (cfg.registerName != "") "registerName=${cfg.registerName}"}
36 ${optionalString (cfg.registerPassword != "") "registerPassword=${cfg.registerPassword}"}
37 ${optionalString (cfg.registerUrl != "") "registerUrl=${cfg.registerUrl}"}
38 ${optionalString (cfg.registerHostname != "") "registerHostname=${cfg.registerHostname}"}
40 certrequired=${boolToString cfg.clientCertRequired}
41 ${optionalString (cfg.sslCert != "") "sslCert=${cfg.sslCert}"}
42 ${optionalString (cfg.sslKey != "") "sslKey=${cfg.sslKey}"}
43 ${optionalString (cfg.sslCa != "") "sslCA=${cfg.sslCa}"}
45 ${optionalString (cfg.dbus != null) "dbus=${cfg.dbus}"}
52 (mkRenamedOptionModule [ "services" "murmur" "welcome" ] [ "services" "murmur" "welcometext" ])
53 (mkRemovedOptionModule [ "services" "murmur" "pidfile" ] "Hardcoded to /run/murmur/murmurd.pid now")
61 description = "If enabled, start the Murmur Mumble server.";
64 openFirewall = mkOption {
68 Open ports in the firewall for the Murmur Mumble server.
72 autobanAttempts = mkOption {
76 Number of attempts a client is allowed to make in
77 `autobanTimeframe` seconds, before being
78 banned for `autobanTime`.
82 autobanTimeframe = mkOption {
86 Timeframe in which a client can connect without being banned
87 for repeated attempts (in seconds).
91 autobanTime = mkOption {
94 description = "The amount of time an IP ban lasts (in seconds).";
98 type = types.nullOr types.path;
100 example = "/var/log/murmur/murmurd.log";
101 description = "Path to the log file for Murmur daemon. Empty means log to journald.";
104 welcometext = mkOption {
107 description = "Welcome message for connected clients.";
113 description = "Ports to bind to (UDP and TCP).";
116 hostName = mkOption {
119 description = "Host to bind to. Defaults binding on all addresses.";
122 package = mkPackageOption pkgs "murmur" { };
124 password = mkOption {
127 description = "Required password to join server, if specified.";
130 bandwidth = mkOption {
134 Maximum bandwidth (in bits per second) that clients may send
142 description = "Maximum number of concurrent clients allowed.";
145 textMsgLength = mkOption {
148 description = "Max length of text messages. Set 0 for no limit.";
151 imgMsgLength = mkOption {
154 description = "Max length of image messages. Set 0 for no limit.";
157 allowHtml = mkOption {
161 Allow HTML in client messages, comments, and channel
170 How long to store RPC logs for in the database. Set 0 to
171 keep logs forever, or -1 to disable DB logging.
179 Enable Bonjour auto-discovery, which allows clients over
180 your LAN to automatically discover Murmur servers.
184 sendVersion = mkOption {
187 description = "Send Murmur version in UDP response.";
190 registerName = mkOption {
194 Public server registration name, and also the name of the
195 Root channel. Even if you don't publicly register your
196 server, you probably still want to set this.
200 registerPassword = mkOption {
204 Public server registry password, used authenticate your
205 server to the registry to prevent impersonation; required for
206 subsequent registry updates.
210 registerUrl = mkOption {
213 description = "URL website for your server.";
216 registerHostname = mkOption {
220 DNS hostname where your server can be reached. This is only
221 needed if you want your server to be accessed by its
222 hostname and not IP - but the name *must* resolve on the
227 clientCertRequired = mkOption {
230 description = "Require clients to authenticate via certificates.";
236 description = "Path to your SSL certificate.";
242 description = "Path to your SSL key.";
248 description = "Path to your SSL CA certificate.";
251 extraConfig = mkOption {
254 description = "Extra configuration to put into murmur.ini.";
257 environmentFile = mkOption {
258 type = types.nullOr types.path;
260 example = "/var/lib/murmur/murmurd.env";
262 Environment file as defined in {manpage}`systemd.exec(5)`.
264 Secrets may be passed to the service without adding them to the world-readable
265 Nix store, by specifying placeholder variables as the option value in Nix and
266 setting these variables accordingly in the environment file.
269 # snippet of murmur-related config
270 services.murmur.password = "$MURMURD_PASSWORD";
274 # content of the environment file
275 MURMURD_PASSWORD=verysecretpassword
278 Note that this file needs to be available on the host on which
284 type = types.enum [ null "session" "system" ];
286 description = "Enable D-Bus remote control. Set to the bus you want Murmur to connect to.";
291 config = mkIf cfg.enable {
292 users.users.murmur = {
293 description = "Murmur Service user";
294 home = "/var/lib/murmur";
296 uid = config.ids.uids.murmur;
299 users.groups.murmur = {
300 gid = config.ids.gids.murmur;
303 networking.firewall = mkIf cfg.openFirewall {
304 allowedTCPPorts = [ cfg.port ];
305 allowedUDPPorts = [ cfg.port ];
308 systemd.services.murmur = {
309 description = "Murmur Chat Service";
310 wantedBy = [ "multi-user.target" ];
311 after = [ "network.target" ];
313 ${pkgs.envsubst}/bin/envsubst \
314 -o /run/murmur/murmurd.ini \
319 # murmurd doesn't fork when logging to the console.
320 Type = if forking then "forking" else "simple";
321 PIDFile = mkIf forking "/run/murmur/murmurd.pid";
322 EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
323 ExecStart = "${cfg.package}/bin/mumble-server -ini /run/murmur/murmurd.ini";
325 RuntimeDirectory = "murmur";
326 RuntimeDirectoryMode = "0700";
331 AmbientCapabilities = "CAP_NET_BIND_SERVICE";
332 CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
333 LockPersonality = true;
334 MemoryDenyWriteExecute = true;
335 NoNewPrivileges = true;
336 PrivateDevices = true;
339 ProtectControlGroups = true;
341 ProtectHostname = true;
342 ProtectKernelLogs = true;
343 ProtectKernelModules = true;
344 ProtectKernelTunables = true;
345 ProtectSystem = "full";
346 RestrictAddressFamilies = "~AF_PACKET AF_NETLINK";
347 RestrictNamespaces = true;
348 RestrictSUIDSGID = true;
349 RestrictRealtime = true;
350 SystemCallArchitectures = "native";
351 SystemCallFilter = "@system-service";
355 # currently not included in upstream package, addition requested at
356 # https://github.com/mumble-voip/mumble/issues/6078
357 services.dbus.packages = mkIf (cfg.dbus == "system") [(pkgs.writeTextFile {
358 name = "murmur-dbus-policy";
360 <!DOCTYPE busconfig PUBLIC
361 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
362 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
364 <policy user="murmur">
365 <allow own="net.sourceforge.mumble.murmur"/>
368 <policy context="default">
369 <allow send_destination="net.sourceforge.mumble.murmur"/>
370 <allow receive_sender="net.sourceforge.mumble.murmur"/>
374 destination = "/share/dbus-1/system.d/murmur.conf";
377 security.apparmor.policies."bin.mumble-server".profile = ''
378 include <tunables/global>
380 ${cfg.package}/bin/{mumble-server,.mumble-server-wrapped} {
381 include <abstractions/base>
382 include <abstractions/nameservice>
383 include <abstractions/ssl_certs>
384 include "${pkgs.apparmorRulesFromClosure { name = "mumble-server"; } cfg.package}"
385 pix ${cfg.package}/bin/.mumble-server-wrapped,
387 r ${config.environment.etc."os-release".source},
388 r ${config.environment.etc."lsb-release".source},
389 owner rwk /var/lib/murmur/murmur.sqlite,
390 owner rw /var/lib/murmur/murmur.sqlite-journal,
391 owner r /var/lib/murmur/,
392 r /run/murmur/murmurd.pid,
393 r /run/murmur/murmurd.ini,
395 '' + optionalString (cfg.logFile != null) ''
397 '' + optionalString (cfg.sslCert != "") ''
399 '' + optionalString (cfg.sslKey != "") ''
401 '' + optionalString (cfg.sslCa != "") ''
403 '' + optionalString (cfg.dbus != null) ''
410 meta.maintainers = with lib.maintainers; [ felixsinger ];