1{ lib
2, pkgs
3, config
4, ...
5}:
6
7with lib;
8
9let
10 cfg = config.services.matter-server;
11 storageDir = "matter-server";
12 storagePath = "/var/lib/${storageDir}";
13 vendorId = "4939"; # home-assistant vendor ID
14in
15
16{
17 meta.maintainers = with lib.maintainers; [ leonm1 ];
18
19 options.services.matter-server = with types; {
20 enable = mkEnableOption "Matter-server";
21
22 package = mkPackageOptionMD pkgs "python-matter-server" { };
23
24 port = mkOption {
25 type = types.port;
26 default = 5580;
27 description = "Port to expose the matter-server service on.";
28 };
29
30 logLevel = mkOption {
31 type = types.enum [ "critical" "error" "warning" "info" "debug" ];
32 default = "info";
33 description = "Verbosity of logs from the matter-server";
34 };
35
36 extraArgs = mkOption {
37 type = listOf str;
38 default = [];
39 description = ''
40 Extra arguments to pass to the matter-server executable.
41 See https://github.com/home-assistant-libs/python-matter-server?tab=readme-ov-file#running-the-development-server for options.
42 '';
43 };
44 };
45
46 config = mkIf cfg.enable {
47 systemd.services.matter-server = {
48 after = [ "network-online.target" ];
49 before = [ "home-assistant.service" ];
50 wants = [ "network-online.target" ];
51 wantedBy = [ "multi-user.target" ];
52 description = "Matter Server";
53 environment.HOME = storagePath;
54 serviceConfig = {
55 ExecStart = (concatStringsSep " " [
56 "${cfg.package}/bin/matter-server"
57 "--port" (toString cfg.port)
58 "--vendorid" vendorId
59 "--storage-path" storagePath
60 "--log-level" "${cfg.logLevel}"
61 "${escapeShellArgs cfg.extraArgs}"
62 ]);
63 # Start with a clean root filesystem, and allowlist what the container
64 # is permitted to access.
65 TemporaryFileSystem = "/";
66 # Allowlist /nix/store (to allow the binary to find its dependencies)
67 # and dbus.
68 ReadOnlyPaths = "/nix/store /run/dbus";
69 # Let systemd manage `/var/lib/matter-server` for us inside the
70 # ephemeral TemporaryFileSystem.
71 StateDirectory = storageDir;
72 # `python-matter-server` writes to /data even when a storage-path is
73 # specified. This bind-mount points /data at the systemd-managed
74 # /var/lib/matter-server, so all files get dropped into the state
75 # directory.
76 BindPaths = "${storagePath}:/data";
77
78 # Hardening bits
79 AmbientCapabilities = "";
80 CapabilityBoundingSet = "";
81 DevicePolicy = "closed";
82 DynamicUser = true;
83 LockPersonality = true;
84 MemoryDenyWriteExecute = true;
85 NoNewPrivileges = true;
86 PrivateDevices = true;
87 PrivateTmp = true;
88 PrivateUsers = true;
89 ProcSubset = "pid";
90 ProtectClock = true;
91 ProtectControlGroups = true;
92 ProtectHome = true;
93 ProtectHostname = true;
94 ProtectKernelLogs = true;
95 ProtectKernelModules = true;
96 ProtectKernelTunables = true;
97 ProtectProc = "invisible";
98 RestrictAddressFamilies = [
99 "AF_INET"
100 "AF_INET6"
101 "AF_NETLINK"
102 ];
103 RestrictNamespaces = true;
104 RestrictRealtime = true;
105 RestrictSUIDSGID = true;
106 SystemCallFilter = concatStringsSep " " [
107 "~" # Blocklist
108 "@clock"
109 "@cpu-emulation"
110 "@debug"
111 "@module"
112 "@mount"
113 "@obsolete"
114 "@privileged"
115 "@raw-io"
116 "@reboot"
117 "@resources"
118 "@swap"
119 ];
120 UMask = "0077";
121 };
122 };
123 };
124}
125