1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 name = "roon-server";
9 cfg = config.services.roon-server;
10in
11{
12 options = {
13 services.roon-server = {
14 enable = lib.mkEnableOption "Roon Server";
15 package = lib.mkPackageOption pkgs "roon-server" { };
16 openFirewall = lib.mkOption {
17 type = lib.types.bool;
18 default = false;
19 description = ''
20 Open ports in the firewall for the server.
21 '';
22 };
23 user = lib.mkOption {
24 type = lib.types.str;
25 default = "roon-server";
26 description = ''
27 User to run the Roon Server as.
28 '';
29 };
30 group = lib.mkOption {
31 type = lib.types.str;
32 default = "roon-server";
33 description = ''
34 Group to run the Roon Server as.
35 '';
36 };
37 };
38 };
39
40 config = lib.mkIf cfg.enable {
41 systemd.services.roon-server = {
42 after = [ "network.target" ];
43 description = "Roon Server";
44 wantedBy = [ "multi-user.target" ];
45
46 environment.ROON_DATAROOT = "/var/lib/${name}";
47 environment.ROON_ID_DIR = "/var/lib/${name}";
48
49 serviceConfig = {
50 ExecStart = "${lib.getExe cfg.package}";
51 LimitNOFILE = 8192;
52 User = cfg.user;
53 Group = cfg.group;
54 StateDirectory = name;
55 };
56 };
57
58 networking.firewall = lib.mkIf cfg.openFirewall {
59 allowedTCPPortRanges = [
60 {
61 from = 9100;
62 to = 9200;
63 }
64 {
65 from = 9330;
66 to = 9339;
67 }
68 {
69 from = 30000;
70 to = 30010;
71 }
72 ];
73 allowedUDPPorts = [ 9003 ];
74 extraCommands = lib.optionalString (!config.networking.nftables.enable) ''
75 ## IGMP / Broadcast ##
76 iptables -A INPUT -s 224.0.0.0/4 -j ACCEPT
77 iptables -A INPUT -d 224.0.0.0/4 -j ACCEPT
78 iptables -A INPUT -s 240.0.0.0/5 -j ACCEPT
79 iptables -A INPUT -m pkttype --pkt-type multicast -j ACCEPT
80 iptables -A INPUT -m pkttype --pkt-type broadcast -j ACCEPT
81 '';
82 extraInputRules = lib.optionalString config.networking.nftables.enable ''
83 ip saddr { 224.0.0.0/4, 240.0.0.0/5 } accept
84 ip daddr 224.0.0.0/4 accept
85 pkttype { multicast, broadcast } accept
86 '';
87 };
88
89 users.groups.${cfg.group} = { };
90 users.users.${cfg.user} = lib.optionalAttrs (cfg.user == "roon-server") {
91 isSystemUser = true;
92 description = "Roon Server user";
93 group = cfg.group;
94 extraGroups = [ "audio" ];
95 };
96 };
97}