1 # Systemd services for lxd.
3 { config, lib, pkgs, ... }:
6 cfg = config.virtualisation.lxd;
7 preseedFormat = pkgs.formats.yaml {};
10 (lib.mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally")
14 virtualisation.lxd = {
15 enable = lib.mkOption {
16 type = lib.types.bool;
19 This option enables lxd, a daemon that manages
20 containers. Users in the "lxd" group can interact with
21 the daemon (e.g. to start or stop containers) using the
22 {command}`lxc` command line tool, among others.
24 Most of the time, you'll also want to start lxcfs, so
25 that containers can "see" the limits:
27 virtualisation.lxc.lxcfs.enable = true;
32 package = lib.mkPackageOption pkgs "lxd-lts" { };
34 lxcPackage = lib.mkOption {
35 type = lib.types.package;
36 default = config.virtualisation.lxc.package;
37 defaultText = lib.literalExpression "config.virtualisation.lxc.package";
38 description = "The lxc package to use.";
41 zfsSupport = lib.mkOption {
42 type = lib.types.bool;
43 default = config.boot.zfs.enabled;
44 defaultText = lib.literalExpression "config.boot.zfs.enabled";
46 Enables lxd to use zfs as a storage for containers.
48 This option is enabled by default if a zfs pool is configured
53 recommendedSysctlSettings = lib.mkOption {
54 type = lib.types.bool;
57 Enables various settings to avoid common pitfalls when
58 running containers requiring many file operations.
59 Fixes errors like "Too many open files" or
60 "neighbour: ndisc_cache: neighbor table overflow!".
61 See https://lxd.readthedocs.io/en/latest/production-setup/
66 preseed = lib.mkOption {
67 type = lib.types.nullOr (lib.types.submodule {
68 freeformType = preseedFormat.type;
74 Configuration for LXD preseed, see
75 <https://documentation.ubuntu.com/lxd/en/latest/howto/initialize/#initialize-preseed>
78 Changes to this will be re-applied to LXD which will overwrite existing entities or create missing ones,
79 but entities will *not* be removed by preseed.
82 example = lib.literalExpression ''
89 "ipv4.address" = "10.0.100.1/24";
117 source = "/var/lib/lxd/storage-pools/default";
125 startTimeout = lib.mkOption {
126 type = lib.types.int;
130 Time to wait (in seconds) for LXD to become ready to process requests.
131 If LXD does not reply within the configured time, lxd.service will be
132 considered failed and systemd will attempt to restart it.
137 enable = lib.mkEnableOption "(experimental) LXD UI";
139 package = lib.mkPackageOption pkgs [ "lxd-ui" ] { };
144 ###### implementation
145 config = lib.mkIf cfg.enable {
146 environment.systemPackages = [ cfg.package ];
148 # Note: the following options are also declared in virtualisation.lxc, but
149 # the latter can't be simply enabled to reuse the formers, because it
150 # does a bunch of unrelated things.
151 systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
153 security.apparmor = {
154 packages = [ cfg.lxcPackage ];
156 "bin.lxc-start".profile = ''
157 include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
159 "lxc-containers".profile = ''
160 include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
165 systemd.sockets.lxd = {
166 description = "LXD UNIX socket";
167 wantedBy = [ "sockets.target" ];
170 ListenStream = "/var/lib/lxd/unix.socket";
173 Service = "lxd.service";
177 systemd.services.lxd = {
178 description = "LXD Container Management Daemon";
180 wantedBy = [ "multi-user.target" ];
182 "network-online.target"
183 (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
186 "network-online.target"
188 (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
190 documentation = [ "man:lxd(1)" ];
192 path = [ pkgs.util-linux ]
193 ++ lib.optional cfg.zfsSupport config.boot.zfs.package;
195 environment = lib.mkIf (cfg.ui.enable) {
196 "LXD_UI" = cfg.ui.package;
200 ExecStart = "@${cfg.package}/bin/lxd lxd --group lxd";
201 ExecStartPost = "${cfg.package}/bin/lxd waitready --timeout=${cfg.startTimeout}";
202 ExecStop = "${cfg.package}/bin/lxd shutdown";
204 KillMode = "process"; # when stopping, leave the containers alone
205 LimitMEMLOCK = "infinity";
206 LimitNOFILE = "1048576";
207 LimitNPROC = "infinity";
208 TasksMax = "infinity";
209 Delegate = true; # LXD needs to manage cgroups in its subtree
211 # By default, `lxd` loads configuration files from hard-coded
212 # `/usr/share/lxc/config` - since this is a no-go for us, we have to
213 # explicitly tell it where the actual configuration files are
214 Environment = lib.mkIf (config.virtualisation.lxc.lxcfs.enable)
215 "LXD_LXC_TEMPLATE_CONFIG=${pkgs.lxcfs}/share/lxc/config";
218 unitConfig.ConditionPathExists = "!/var/lib/incus/.migrated-from-lxd";
221 systemd.services.lxd-preseed = lib.mkIf (cfg.preseed != null) {
222 description = "LXD initialization with preseed file";
223 wantedBy = ["multi-user.target"];
224 requires = ["lxd.service"];
225 after = ["lxd.service"];
228 ${pkgs.coreutils}/bin/cat ${preseedFormat.generate "lxd-preseed.yaml" cfg.preseed} | ${cfg.package}/bin/lxd init --preseed
236 users.groups.lxd = {};
239 subUidRanges = [ { startUid = 1000000; count = 65536; } ];
240 subGidRanges = [ { startGid = 1000000; count = 65536; } ];
243 boot.kernel.sysctl = lib.mkIf cfg.recommendedSysctlSettings {
244 "fs.inotify.max_queued_events" = 1048576;
245 "fs.inotify.max_user_instances" = 1048576;
246 "fs.inotify.max_user_watches" = 1048576;
247 "vm.max_map_count" = 262144; # TODO: Default vm.max_map_count has been increased system-wide
248 "kernel.dmesg_restrict" = 1;
249 "net.ipv4.neigh.default.gc_thresh3" = 8192;
250 "net.ipv6.neigh.default.gc_thresh3" = 8192;
251 "kernel.keys.maxkeys" = 2000;
254 boot.kernelModules = [ "veth" "xt_comment" "xt_CHECKSUM" "xt_MASQUERADE" "vhost_vsock" ]
255 ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ];