1{ lib, config, pkgs, ... }:
2
3let
4 cfg = config.virtualisation.lxc;
5in {
6 imports = [
7 ./lxc-instance-common.nix
8 ];
9
10 options = {
11 virtualisation.lxc = {
12 nestedContainer = lib.mkEnableOption (lib.mdDoc ''
13 Whether this container is configured as a nested container. On LXD containers this is recommended
14 for all containers and is enabled with `security.nesting = true`.
15 '');
16
17 privilegedContainer = lib.mkEnableOption (lib.mdDoc ''
18 Whether this LXC container will be running as a privileged container or not. If set to `true` then
19 additional configuration will be applied to the `systemd` instance running within the container as
20 recommended by [distrobuilder](https://linuxcontainers.org/distrobuilder/introduction/).
21 '');
22 };
23 };
24
25 config = {
26 boot.isContainer = true;
27 boot.postBootCommands =
28 ''
29 # After booting, register the contents of the Nix store in the Nix
30 # database.
31 if [ -f /nix-path-registration ]; then
32 ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration &&
33 rm /nix-path-registration
34 fi
35
36 # nixos-rebuild also requires a "system" profile
37 ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
38 '';
39
40 system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix {
41 extraArgs = "--owner=0";
42
43 storeContents = [
44 {
45 object = config.system.build.toplevel;
46 symlink = "none";
47 }
48 ];
49
50 contents = [
51 {
52 source = config.system.build.toplevel + "/init";
53 target = "/sbin/init";
54 }
55 # Technically this is not required for lxc, but having also make this configuration work with systemd-nspawn.
56 # Nixos will setup the same symlink after start.
57 {
58 source = config.system.build.toplevel + "/etc/os-release";
59 target = "/etc/os-release";
60 }
61 ];
62
63 extraCommands = "mkdir -p proc sys dev";
64 };
65
66 system.build.squashfs = pkgs.callPackage ../../lib/make-squashfs.nix {
67 fileName = "nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}";
68
69 noStrip = true; # keep directory structure
70 comp = "zstd -Xcompression-level 6";
71
72 storeContents = [config.system.build.toplevel];
73
74 pseudoFiles = [
75 "/sbin d 0755 0 0"
76 "/sbin/init s 0555 0 0 ${config.system.build.toplevel}/init"
77 "/dev d 0755 0 0"
78 "/proc d 0555 0 0"
79 "/sys d 0555 0 0"
80 ];
81 };
82
83 system.build.installBootLoader = pkgs.writeScript "install-lxd-sbin-init.sh" ''
84 #!${pkgs.runtimeShell}
85 ${pkgs.coreutils}/bin/ln -fs "$1/init" /sbin/init
86 '';
87
88 systemd.additionalUpstreamSystemUnits = lib.mkIf cfg.nestedContainer ["systemd-udev-trigger.service"];
89
90 # Add the overrides from lxd distrobuilder
91 # https://github.com/lxc/distrobuilder/blob/05978d0d5a72718154f1525c7d043e090ba7c3e0/distrobuilder/main.go#L630
92 systemd.packages = [
93 (pkgs.writeTextFile {
94 name = "systemd-lxc-service-overrides";
95 destination = "/etc/systemd/system/service.d/zzz-lxc-service.conf";
96 text = ''
97 [Service]
98 ProcSubset=all
99 ProtectProc=default
100 ProtectControlGroups=no
101 ProtectKernelTunables=no
102 NoNewPrivileges=no
103 LoadCredential=
104 '' + lib.optionalString cfg.privilegedContainer ''
105 # Additional settings for privileged containers
106 ProtectHome=no
107 ProtectSystem=no
108 PrivateDevices=no
109 PrivateTmp=no
110 ProtectKernelLogs=no
111 ProtectKernelModules=no
112 ReadWritePaths=
113 '';
114 })
115 ];
116
117 system.activationScripts.installInitScript = lib.mkForce ''
118 ln -fs $systemConfig/init /sbin/init
119 '';
120 };
121}