22 cfg = config.services.nbd;
31 # The `[generic]` section must come before all the others in the
32 # config file. This means we can't just dump an attrset to INI
33 # because that sorts the sections by name. Instead, we serialize it
37 cfg.server.extraOptions
41 port = cfg.server.listenPort;
43 // (optionalAttrs (cfg.server.listenAddress != null) {
44 listenaddr = cfg.server.listenAddress;
48 exportSections = lib.mapAttrs (
59 // (optionalAttrs (allowAddresses != null) {
60 authfile = pkgs.writeText "authfile" (lib.concatStringsSep "\n" allowAddresses);
63 serverConfig = pkgs.writeText "nbd-server-config" ''
64 ${lib.generators.toINI { } genericSection}
65 ${lib.generators.toINI { } exportSections}
67 splitLists = lib.partition (path: lib.hasPrefix "/dev/" path) (
68 lib.mapAttrsToList (_: { path, ... }: path) cfg.server.exports
70 allowedDevices = splitLists.right;
71 boundPaths = splitLists.wrong;
77 enable = lib.mkEnableOption "the Network Block Device (nbd) server";
79 listenPort = mkOption {
82 description = "Port to listen on. The port is NOT automatically opened in the firewall.";
85 extraOptions = mkOption {
91 Extra options for the server. See
92 {manpage}`nbd-server(5)`.
97 description = "Files or block devices to make available over the network.";
99 type = attrsOf (submodule {
103 description = "File or block device to export.";
104 example = "/dev/sdb1";
107 allowAddresses = mkOption {
108 type = nullOr (listOf str);
114 description = "IPs and subnets that are authorized to connect for this device. If not specified, the server will allow all connections.";
117 extraOptions = mkOption {
124 Extra options for this export. See
125 {manpage}`nbd-server(5)`.
132 listenAddress = mkOption {
134 description = "Address to listen on. If not specified, the server will listen on all interfaces.";
136 example = "10.10.0.1";
142 config = mkIf cfg.server.enable {
145 assertion = !(cfg.server.exports ? "generic");
146 message = "services.nbd.server exports must not be named 'generic'";
150 boot.kernelModules = [ "nbd" ];
152 systemd.services.nbd-server = {
153 wants = [ "network-online.target" ];
154 after = [ "network-online.target" ];
155 before = [ "multi-user.target" ];
156 wantedBy = [ "multi-user.target" ];
158 ExecStart = "${pkgs.nbd}/bin/nbd-server -C ${serverConfig}";
161 DeviceAllow = map (path: "${path} rw") allowedDevices;
162 BindPaths = boundPaths;
164 CapabilityBoundingSet = "";
165 DevicePolicy = "closed";
166 LockPersonality = true;
167 MemoryDenyWriteExecute = true;
168 NoNewPrivileges = true;
169 PrivateDevices = false;
170 PrivateMounts = true;
175 ProtectControlGroups = true;
177 ProtectHostname = true;
178 ProtectKernelLogs = true;
179 ProtectKernelModules = true;
180 ProtectKernelTunables = true;
181 ProtectProc = "noaccess";
182 ProtectSystem = "strict";
183 RestrictAddressFamilies = "AF_INET AF_INET6";
184 RestrictNamespaces = true;
185 RestrictRealtime = true;
186 RestrictSUIDSGID = true;