1 { config, lib, pkgs, ... }@host:
7 configurationPrefix = optionalString (versionAtLeast config.system.stateVersion "22.05") "nixos-";
8 configurationDirectoryName = "${configurationPrefix}containers";
9 configurationDirectory = "/etc/${configurationDirectoryName}";
10 stateDirectory = "/var/lib/${configurationPrefix}containers";
12 nixos-container = pkgs.nixos-container.override {
13 inherit stateDirectory configurationDirectory;
16 # The container's init script, a small wrapper around the regular
17 # NixOS stage-2 init script.
20 renderExtraVeth = (name: cfg:
22 echo "Bringing ${name} up"
23 ip link set dev ${name} up
24 ${optionalString (cfg.localAddress != null) ''
25 echo "Setting ip for ${name}"
26 ip addr add ${cfg.localAddress} dev ${name}
28 ${optionalString (cfg.localAddress6 != null) ''
29 echo "Setting ip6 for ${name}"
30 ip -6 addr add ${cfg.localAddress6} dev ${name}
32 ${optionalString (cfg.hostAddress != null) ''
33 echo "Setting route to host for ${name}"
34 ip route add ${cfg.hostAddress} dev ${name}
36 ${optionalString (cfg.hostAddress6 != null) ''
37 echo "Setting route6 to host for ${name}"
38 ip -6 route add ${cfg.hostAddress6} dev ${name}
43 pkgs.writeScript "container-init"
45 #! ${pkgs.runtimeShell} -e
47 # Exit early if we're asked to shut down.
48 trap "exit 0" SIGRTMIN+3
50 # Initialise the container side of the veth pair.
51 if [ -n "$HOST_ADDRESS" ] || [ -n "$HOST_ADDRESS6" ] ||
52 [ -n "$LOCAL_ADDRESS" ] || [ -n "$LOCAL_ADDRESS6" ] ||
53 [ -n "$HOST_BRIDGE" ]; then
54 ip link set host0 name eth0
55 ip link set dev eth0 up
57 if [ -n "$LOCAL_ADDRESS" ]; then
58 ip addr add $LOCAL_ADDRESS dev eth0
60 if [ -n "$LOCAL_ADDRESS6" ]; then
61 ip -6 addr add $LOCAL_ADDRESS6 dev eth0
63 if [ -n "$HOST_ADDRESS" ]; then
64 ip route add $HOST_ADDRESS dev eth0
65 ip route add default via $HOST_ADDRESS
67 if [ -n "$HOST_ADDRESS6" ]; then
68 ip -6 route add $HOST_ADDRESS6 dev eth0
69 ip -6 route add default via $HOST_ADDRESS6
73 ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
75 # Start the regular stage 2 script.
76 # We source instead of exec to not lose an early stop signal, which is
77 # also the only _reliable_ shutdown signal we have since early stop
78 # does not execute ExecStop* commands.
84 nspawnExtraVethArgs = (name: cfg: "--network-veth-extra=${name}");
88 # Declare root explicitly to avoid shellcheck warnings, it comes from the env
91 mkdir -p "$root/etc" "$root/var/lib"
92 chmod 0755 "$root/etc" "$root/var/lib"
93 mkdir -p "$root/var/lib/private" "$root/root" /run/nixos-containers
94 chmod 0700 "$root/var/lib/private" "$root/root" /run/nixos-containers
95 if ! [ -e "$root/etc/os-release" ]; then
96 touch "$root/etc/os-release"
99 if ! [ -e "$root/etc/machine-id" ]; then
100 touch "$root/etc/machine-id"
104 "/nix/var/nix/profiles/per-container/$INSTANCE" \
105 "/nix/var/nix/gcroots/per-container/$INSTANCE"
107 "/nix/var/nix/profiles/per-container/$INSTANCE" \
108 "/nix/var/nix/gcroots/per-container/$INSTANCE"
110 cp --remove-destination /etc/resolv.conf "$root/etc/resolv.conf"
112 declare -a extraFlags
114 if [ "$PRIVATE_NETWORK" = 1 ]; then
115 extraFlags+=("--private-network")
118 if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] ||
119 [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
120 extraFlags+=("--network-veth")
123 if [ -n "$HOST_PORT" ]; then
128 extraFlags+=("--port=$i")
133 if [ -n "$HOST_BRIDGE" ]; then
134 extraFlags+=("--network-bridge=$HOST_BRIDGE")
137 extraFlags+=(${lib.escapeShellArgs (mapAttrsToList nspawnExtraVethArgs cfg.extraVeths)})
139 for iface in $INTERFACES; do
140 extraFlags+=("--network-interface=$iface")
143 for iface in $MACVLANS; do
144 extraFlags+=("--network-macvlan=$iface")
147 # If the host is 64-bit and the container is 32-bit, add a
148 # --personality flag.
149 ${optionalString (pkgs.stdenv.hostPlatform.system == "x86_64-linux") ''
150 if [ "$(< "''${SYSTEM_PATH:-/nix/var/nix/profiles/per-container/$INSTANCE/system}/system")" = i686-linux ]; then
151 extraFlags+=("--personality=x86")
155 export SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1
157 # Run systemd-nspawn without startup notification (we'll
158 # wait for the container systemd to signal readiness)
159 # Kill signal handling means systemd-nspawn will pass a system-halt signal
160 # to the container systemd when it receives SIGTERM for container shutdown;
161 # containerInit and stage2 have to handle this as well.
162 # TODO: fix shellcheck issue properly
163 # shellcheck disable=SC2086
164 exec ${config.systemd.package}/bin/systemd-nspawn \
166 -M "$INSTANCE" -D "$root" "''${extraFlags[@]}" \
167 $EXTRA_NSPAWN_FLAGS \
169 --kill-signal=SIGRTMIN+3 \
170 --bind-ro=/nix/store \
171 --bind-ro=/nix/var/nix/db \
172 --bind-ro=/nix/var/nix/daemon-socket \
173 --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
174 --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
175 ${optionalString (!cfg.ephemeral) "--link-journal=try-guest"} \
176 --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
177 --setenv HOST_BRIDGE="$HOST_BRIDGE" \
178 --setenv HOST_ADDRESS="$HOST_ADDRESS" \
179 --setenv LOCAL_ADDRESS="$LOCAL_ADDRESS" \
180 --setenv HOST_ADDRESS6="$HOST_ADDRESS6" \
181 --setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \
182 --setenv HOST_PORT="$HOST_PORT" \
183 --setenv PATH="$PATH" \
184 ${optionalString cfg.ephemeral "--ephemeral"} \
185 ${optionalString (cfg.additionalCapabilities != null && cfg.additionalCapabilities != [])
186 ''--capability="${concatStringsSep "," cfg.additionalCapabilities}"''
188 ${optionalString (cfg.tmpfs != null && cfg.tmpfs != [])
189 ''--tmpfs=${concatStringsSep " --tmpfs=" cfg.tmpfs}''
191 ${containerInit cfg} "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/init"
194 preStartScript = cfg:
196 # Clean up existing machined registration and interfaces.
197 machinectl terminate "$INSTANCE" 2> /dev/null || true
199 if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] ||
200 [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
201 ip link del dev "ve-$INSTANCE" 2> /dev/null || true
202 ip link del dev "vb-$INSTANCE" 2> /dev/null || true
205 ${concatStringsSep "\n" (
206 mapAttrsToList (name: cfg:
207 "ip link del dev ${name} 2> /dev/null || true "
212 postStartScript = (cfg:
214 ipcall = cfg: ipcmd: variable: attribute:
215 if cfg.${attribute} == null then
217 if [ -n "${variable}" ]; then
218 ${ipcmd} add "${variable}" dev "$ifaceHost"
222 ''${ipcmd} add ${cfg.${attribute}} dev "$ifaceHost"'';
223 renderExtraVeth = name: cfg:
224 if cfg.hostBridge != null then
226 # Add ${name} to bridge ${cfg.hostBridge}
227 ip link set dev "${name}" master "${cfg.hostBridge}" up
231 echo "Bring ${name} up"
232 ip link set dev "${name}" up
233 # Set IPs and routes for ${name}
234 ${optionalString (cfg.hostAddress != null) ''
235 ip addr add ${cfg.hostAddress} dev "${name}"
237 ${optionalString (cfg.hostAddress6 != null) ''
238 ip -6 addr add ${cfg.hostAddress6} dev "${name}"
240 ${optionalString (cfg.localAddress != null) ''
241 ip route add ${cfg.localAddress} dev "${name}"
243 ${optionalString (cfg.localAddress6 != null) ''
244 ip -6 route add ${cfg.localAddress6} dev "${name}"
249 if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] ||
250 [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
251 if [ -z "$HOST_BRIDGE" ]; then
252 ifaceHost=ve-$INSTANCE
253 ip link set dev "$ifaceHost" up
255 ${ipcall cfg "ip addr" "$HOST_ADDRESS" "hostAddress"}
256 ${ipcall cfg "ip -6 addr" "$HOST_ADDRESS6" "hostAddress6"}
257 ${ipcall cfg "ip route" "$LOCAL_ADDRESS" "localAddress"}
258 ${ipcall cfg "ip -6 route" "$LOCAL_ADDRESS6" "localAddress6"}
261 ${concatStringsSep "\n" (mapAttrsToList renderExtraVeth cfg.extraVeths)}
265 serviceDirectives = cfg: {
266 ExecReload = pkgs.writeScript "reload-container"
268 #! ${pkgs.runtimeShell} -e
269 ${nixos-container}/bin/nixos-container run "$INSTANCE" -- \
270 bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test"
273 SyslogIdentifier = "container %i";
275 EnvironmentFile = "-${configurationDirectory}/%i.conf";
279 RuntimeDirectory = lib.optional cfg.ephemeral "${configurationDirectoryName}/%i";
281 # Note that on reboot, systemd-nspawn returns 133, so this
282 # unit will be restarted. On poweroff, it returns 0, so the
283 # unit won't be restarted.
284 RestartForceExitStatus = "133";
285 SuccessExitStatus = "133";
287 # Some containers take long to start
288 # especially when you automatically start many at once
289 TimeoutStartSec = cfg.timeoutStartSec;
291 Restart = "on-failure";
293 Slice = "machine.slice";
296 # We rely on systemd-nspawn turning a SIGTERM to itself into a shutdown
297 # signal (SIGRTMIN+3) for the inner container.
301 DevicePolicy = "closed";
302 DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices;
305 kernelVersion = config.boot.kernelPackages.kernel.version;
307 bindMountOpts = { name, ... }: {
310 mountPoint = mkOption {
311 example = "/mnt/usb";
313 description = "Mount point on the container file system.";
315 hostPath = mkOption {
317 example = "/home/alice";
318 type = types.nullOr types.str;
319 description = "Location of the host path to be mounted.";
321 isReadOnly = mkOption {
324 description = "Determine whether the mounted path will be accessed in read-only mode.";
329 mountPoint = mkDefault name;
334 allowedDeviceOpts = { ... }: {
337 example = "/dev/net/tun";
339 description = "Path to device node";
341 modifier = mkOption {
345 Device node access modifier. Takes a combination
346 `r` (read), `w` (write), and
348 `systemd.resource-control(5)` man page for more
355 let flagPrefix = if d.isReadOnly then " --bind-ro=" else " --bind=";
356 mountstr = if d.hostPath != null then "${d.hostPath}:${d.mountPoint}" else "${d.mountPoint}";
357 in flagPrefix + mountstr ;
359 mkBindFlags = bs: concatMapStrings mkBindFlag (lib.attrValues bs);
362 hostBridge = mkOption {
363 type = types.nullOr types.str;
367 Put the host-side of the veth-pair into the named bridge.
368 Only one of hostAddress* or hostBridge can be given.
372 forwardPorts = mkOption {
373 type = types.listOf (types.submodule {
375 protocol = mkOption {
378 description = "The protocol specifier for port forwarding between host and container";
380 hostPort = mkOption {
382 description = "Source port of the external interface on host";
384 containerPort = mkOption {
385 type = types.nullOr types.int;
387 description = "Target port of container";
392 example = [ { protocol = "tcp"; hostPort = 8080; containerPort = 80; } ];
394 List of forwarded ports from host to container. Each forwarded port
395 is specified by protocol, hostPort and containerPort. By default,
396 protocol is tcp and hostPort and containerPort are assumed to be
397 the same if containerPort is not explicitly given.
402 hostAddress = mkOption {
403 type = types.nullOr types.str;
405 example = "10.231.136.1";
407 The IPv4 address assigned to the host interface.
408 (Not used when hostBridge is set.)
412 hostAddress6 = mkOption {
413 type = types.nullOr types.str;
417 The IPv6 address assigned to the host interface.
418 (Not used when hostBridge is set.)
422 localAddress = mkOption {
423 type = types.nullOr types.str;
425 example = "10.231.136.2";
427 The IPv4 address assigned to the interface in the container.
428 If a hostBridge is used, this should be given with netmask to access
429 the whole network. Otherwise the default netmask is /32 and routing is
430 set up from localAddress to hostAddress and back.
434 localAddress6 = mkOption {
435 type = types.nullOr types.str;
439 The IPv6 address assigned to the interface in the container.
440 If a hostBridge is used, this should be given with netmask to access
441 the whole network. Otherwise the default netmask is /128 and routing is
442 set up from localAddress6 to hostAddress6 and back.
451 additionalCapabilities = [];
453 timeoutStartSec = "1min";
458 localAddress6 = null;
467 boot.isContainer = mkOption {
471 Whether this NixOS machine is a lightweight container running
472 in another NixOS system.
476 boot.enableContainers = mkOption {
480 Whether to enable support for NixOS containers. Defaults to true
481 (at no cost if containers are not actually used).
485 containers = mkOption {
486 type = types.attrsOf (types.submodule (
487 { config, options, name, ... }:
492 A specification of the desired configuration of this
493 container, as a NixOS module.
495 type = lib.mkOptionType {
496 name = "Toplevel NixOS config";
497 merge = loc: defs: (import "${toString config.nixpkgs}/nixos/lib/eval-config.nix" {
500 extraConfig = { options, ... }: {
501 _file = "module at ${__curPos.file}:${toString __curPos.line}";
504 if options.nixpkgs?hostPlatform
505 then { inherit (host.pkgs.stdenv) hostPlatform; }
506 else { localSystem = host.pkgs.stdenv.hostPlatform; }
508 boot.isContainer = true;
509 networking.hostName = mkDefault name;
510 networking.useDHCP = false;
514 (builtins.compareVersions kernelVersion "5.8" <= 0)
515 -> config.privateNetwork
516 -> stringLength name <= 11;
518 Container name `${name}` is too long: When `privateNetwork` is enabled, container names can
519 not be longer than 11 characters, because the container's interface name is derived from it.
520 You should either make the container name shorter or upgrade to a more recent kernel that
521 supports interface altnames (i.e. at least Linux 5.8 - please see https://github.com/NixOS/nixpkgs/issues/38509
526 assertion = !lib.strings.hasInfix "_" name;
528 Names containing underscores are not allowed in nixos-containers. Please rename the container '${name}'
534 in [ extraConfig ] ++ (map (x: x.value) defs);
535 prefix = [ "containers" name ];
536 inherit (config) specialArgs;
538 # The system is inherited from the host above.
539 # Set it to null, to remove the "legacy" entrypoint's non-hermetic default.
547 example = "/nix/var/nix/profiles/per-container/webserver";
549 As an alternative to specifying
550 {option}`config`, you can specify the path to
551 the evaluated NixOS system configuration, typically a
552 symlink to a system profile.
556 additionalCapabilities = mkOption {
557 type = types.listOf types.str;
559 example = [ "CAP_NET_ADMIN" "CAP_MKNOD" ];
561 Grant additional capabilities to the container. See the
562 capabilities(7) and systemd-nspawn(1) man pages for more
570 defaultText = literalExpression "pkgs.path";
572 A path to the nixpkgs that provide the modules, pkgs and lib for evaluating the container.
574 To only change the `pkgs` argument used inside the container modules,
575 set the `nixpkgs.*` options in the container {option}`config`.
576 Setting `config.nixpkgs.pkgs = pkgs` speeds up the container evaluation
577 by reusing the system pkgs, but the `nixpkgs.config` option in the
578 container config is ignored in this case.
582 specialArgs = mkOption {
583 type = types.attrsOf types.unspecified;
586 A set of special arguments to be passed to NixOS modules.
587 This will be merged into the `specialArgs` used to evaluate
588 the NixOS configurations.
592 ephemeral = mkOption {
596 Runs container in ephemeral mode with the empty root filesystem at boot.
597 This way container will be bootstrapped from scratch on each boot
598 and will be cleaned up on shutdown leaving no traces behind.
599 Useful for completely stateless, reproducible containers.
601 Note that this option might require to do some adjustments to the container configuration,
602 e.g. you might want to set
603 {var}`systemd.network.networks.$interface.dhcpV4Config.ClientIdentifier` to "mac"
604 if you use {var}`macvlans` option.
605 This way dhcp client identifier will be stable between the container restarts.
607 Note that the container journal will not be linked to the host if this option is enabled.
611 enableTun = mkOption {
615 Allows the container to create and setup tunnel interfaces
616 by granting the `NET_ADMIN` capability and
617 enabling access to `/dev/net/tun`.
621 privateNetwork = mkOption {
625 Whether to give the container its own private virtual
626 Ethernet interface. The interface is called
627 `eth0`, and is hooked up to the interface
628 `ve-«container-name»`
629 on the host. If this option is not set, then the
630 container shares the network interfaces of the host,
631 and can bind to any port on any interface.
635 interfaces = mkOption {
636 type = types.listOf types.str;
638 example = [ "eth1" "eth2" ];
640 The list of interfaces to be moved into the container.
644 macvlans = mkOption {
645 type = types.listOf types.str;
647 example = [ "eth1" "eth2" ];
649 The list of host interfaces from which macvlans will be
650 created. For each interface specified, a macvlan interface
651 will be created and moved to the container.
655 extraVeths = mkOption {
656 type = with types; attrsOf (submodule { options = networkOptions; });
659 Extra veth-pairs to be created for the container.
663 autoStart = mkOption {
667 Whether the container is automatically started at boot-time.
671 restartIfChanged = mkOption {
675 Whether the container should be restarted during a NixOS
676 configuration switch if its definition has changed.
680 timeoutStartSec = mkOption {
684 Time for the container to start. In case of a timeout,
685 the container processes get killed.
686 See {manpage}`systemd.time(7)`
687 for more information about the format.
691 bindMounts = mkOption {
692 type = with types; attrsOf (submodule bindMountOpts);
694 example = literalExpression ''
695 { "/home" = { hostPath = "/home/alice";
696 isReadOnly = false; };
701 An extra list of directories that is bound to the container.
705 allowedDevices = mkOption {
706 type = with types; listOf (submodule allowedDeviceOpts);
708 example = [ { node = "/dev/net/tun"; modifier = "rw"; } ];
710 A list of device nodes to which the containers has access to.
715 type = types.listOf types.str;
717 example = [ "/var" ];
719 Mounts a set of tmpfs file systems into the container.
720 Multiple paths can be specified.
721 Valid items must conform to the --tmpfs argument
722 of systemd-nspawn. See systemd-nspawn(1) for details.
726 extraFlags = mkOption {
727 type = types.listOf types.str;
729 example = [ "--drop-capability=CAP_SYS_CHROOT" ];
731 Extra flags passed to the systemd-nspawn command.
732 See systemd-nspawn(1) for details.
736 # Removed option. See `checkAssertion` below for the accompanying error message.
737 pkgs = mkOption { visible = false; };
741 # Throw an error when removed option `pkgs` is used.
742 # Because this is a submodule we cannot use `mkRemovedOptionModule` or option `assertions`.
743 optionPath = "containers.${name}.pkgs";
744 files = showFiles options.pkgs.files;
745 checkAssertion = if options.pkgs.isDefined then throw ''
746 The option definition `${optionPath}' in ${files} no longer has any effect; please remove it.
748 Alternatively, you can use the following options:
749 - containers.${name}.nixpkgs
750 This sets the nixpkgs (and thereby the modules, pkgs and lib) that
751 are used for evaluating the container.
753 - containers.${name}.config.nixpkgs.pkgs
754 This only sets the `pkgs` argument used inside the container modules.
758 path = builtins.seq checkAssertion
759 mkIf options.config.isDefined config.config.system.build.toplevel;
764 example = literalExpression
767 { path = "/nix/var/nix/profiles/webserver";
771 { config, pkgs, ... }:
772 { services.postgresql.enable = true;
773 services.postgresql.package = pkgs.postgresql_14;
775 system.stateVersion = "${lib.trivial.release}";
781 A set of NixOS system configurations to be run as lightweight
782 containers. Each container appears as a service
784 on the host system, allowing it to be started and stopped via
785 {command}`systemctl`.
794 warnings = optional (!config.boot.enableContainers && config.containers != {})
795 "containers.<name> is used, but boot.enableContainers is false. To use containers.<name>, set boot.enableContainers to true.";
798 (mkIf (config.boot.enableContainers) (let
800 description = "Container '%i'";
802 unitConfig.RequiresMountsFor = "${stateDirectory}/%i";
804 path = [ pkgs.iproute2 ];
807 root = "${stateDirectory}/%i";
811 preStart = preStartScript dummyConfig;
813 script = startScript dummyConfig;
815 postStart = postStartScript dummyConfig;
817 restartIfChanged = false;
819 serviceConfig = serviceDirectives dummyConfig;
823 (optional (config.virtualisation.containers.enable && versionOlder config.system.stateVersion "22.05") ''
824 Enabling both boot.enableContainers & virtualisation.containers on system.stateVersion < 22.05 is unsupported.
827 systemd.targets.multi-user.wants = [ "machines.target" ];
829 systemd.services = listToAttrs (filter (x: x.value != null) (
830 # The generic container template used by imperative containers
831 [{ name = "container@"; value = unit; }]
832 # declarative containers
833 ++ (mapAttrsToList (name: cfg: nameValuePair "container@${name}" (let
834 containerConfig = cfg // (
835 optionalAttrs cfg.enableTun
837 allowedDevices = cfg.allowedDevices
838 ++ [ { node = "/dev/net/tun"; modifier = "rw"; } ];
839 additionalCapabilities = cfg.additionalCapabilities
840 ++ [ "CAP_NET_ADMIN" ];
844 recursiveUpdate unit {
845 preStart = preStartScript containerConfig;
846 script = startScript containerConfig;
847 postStart = postStartScript containerConfig;
848 serviceConfig = serviceDirectives containerConfig;
849 unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i"
851 (d: if d.hostPath != null then d.hostPath else d.mountPoint)
852 (builtins.attrValues cfg.bindMounts);
853 environment.root = if containerConfig.ephemeral then "/run/nixos-containers/%i" else "${stateDirectory}/%i";
855 optionalAttrs containerConfig.autoStart
857 wantedBy = [ "machines.target" ];
858 wants = [ "network.target" ] ++ (map (i: "sys-subsystem-net-devices-${i}.device") cfg.interfaces);
859 after = [ "network.target" ] ++ (map (i: "sys-subsystem-net-devices-${i}.device") cfg.interfaces);
862 config.environment.etc."${configurationDirectoryName}/${name}.conf".source
864 restartIfChanged = containerConfig.restartIfChanged;
867 )) config.containers)
870 # Generate a configuration file in /etc/nixos-containers for each
871 # container so that container@.target can get the container
874 let mkPortStr = p: p.protocol + ":" + (toString p.hostPort) + ":" + (if p.containerPort == null then toString p.hostPort else toString p.containerPort);
875 in mapAttrs' (name: cfg: nameValuePair "${configurationDirectoryName}/${name}.conf"
878 SYSTEM_PATH=${cfg.path}
879 ${optionalString cfg.privateNetwork ''
881 ${optionalString (cfg.hostBridge != null) ''
882 HOST_BRIDGE=${cfg.hostBridge}
884 ${optionalString (length cfg.forwardPorts > 0) ''
885 HOST_PORT=${concatStringsSep "," (map mkPortStr cfg.forwardPorts)}
887 ${optionalString (cfg.hostAddress != null) ''
888 HOST_ADDRESS=${cfg.hostAddress}
890 ${optionalString (cfg.hostAddress6 != null) ''
891 HOST_ADDRESS6=${cfg.hostAddress6}
893 ${optionalString (cfg.localAddress != null) ''
894 LOCAL_ADDRESS=${cfg.localAddress}
896 ${optionalString (cfg.localAddress6 != null) ''
897 LOCAL_ADDRESS6=${cfg.localAddress6}
900 INTERFACES="${toString cfg.interfaces}"
901 MACVLANS="${toString cfg.macvlans}"
902 ${optionalString cfg.autoStart ''
905 EXTRA_NSPAWN_FLAGS="${mkBindFlags cfg.bindMounts +
906 optionalString (cfg.extraFlags != [])
907 (" " + concatStringsSep " " cfg.extraFlags)}"
909 }) config.containers;
911 # Generate /etc/hosts entries for the containers.
912 networking.extraHosts = concatStrings (mapAttrsToList (name: cfg: optionalString (cfg.localAddress != null)
914 ${head (splitString "/" cfg.localAddress)} ${name}.containers
915 '') config.containers);
917 networking.dhcpcd.denyInterfaces = [ "ve-*" "vb-*" ];
919 services.udev.extraRules = optionalString config.networking.networkmanager.enable ''
920 # Don't manage interfaces created by nixos-container.
921 ENV{INTERFACE}=="v[eb]-*", ENV{NM_UNMANAGED}="1"
924 environment.systemPackages = [
928 boot.kernelModules = [
937 meta.buildDocsInSandbox = false;