diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index e1a91f7704e7..b7cb29eaa22a 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -139,6 +139,7 @@ let
--bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
--bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
${optionalString (!cfg.ephemeral) "--link-journal=try-guest"} \
+ ${optionalString (cfg.unprivileged) "-U"} \
--setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
--setenv HOST_BRIDGE="$HOST_BRIDGE" \
--setenv HOST_ADDRESS="$HOST_ADDRESS" \
@@ -238,8 +239,8 @@ let
ExecReload = pkgs.writeScript "reload-container"
''
#! ${pkgs.runtimeShell} -e
- ${pkgs.nixos-container}/bin/nixos-container run "$INSTANCE" -- \
- bash --login -c "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test"
+ ${pkgs.systemd}/bin/machinectl shell "$INSTANCE" \
+ ''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/bin/switch-to-configuration test
'';
SyslogIdentifier = "container %i";
@@ -423,6 +424,7 @@ let
extraVeths = {};
additionalCapabilities = [];
ephemeral = false;
+ unprivileged = false;
allowedDevices = [];
hostAddress = null;
hostAddress6 = null;
@@ -516,6 +518,16 @@ in
'';
};
+ unprivileged = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Run container in unprivileged mode using private users feature of systemd-nspawn.
+ This option is eqvivalent of adding -U parameter to systemd-nspawn command.
+ See systemd-nspawn(1) man page for more information.
+ '';
+ };
+
ephemeral = mkOption {
type = types.bool;
default = false;
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 234609adbc09..943bf12c254a 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -48,6 +48,7 @@ in
colord = handleTest ./colord.nix {};
containers-bridge = handleTest ./containers-bridge.nix {};
containers-ephemeral = handleTest ./containers-ephemeral.nix {};
+ containers-unprivileged = handleTest ./containers-unprivileged.nix {};
containers-extra_veth = handleTest ./containers-extra_veth.nix {};
containers-hosts = handleTest ./containers-hosts.nix {};
containers-imperative = handleTest ./containers-imperative.nix {};
diff --git a/nixos/tests/containers-unprivileged.nix b/nixos/tests/containers-unprivileged.nix
new file mode 100644
index 000000000000..2db6b7e4f022
--- /dev/null
+++ b/nixos/tests/containers-unprivileged.nix
@@ -0,0 +1,56 @@
+# Test for NixOS' container support.
+
+import ./make-test.nix ({ pkgs, ...} : {
+ name = "containers-unprivileged";
+
+ machine = { pkgs, ... }: {
+ virtualisation.memorySize = 768;
+ virtualisation.writableStore = true;
+
+ containers.webserver = {
+ unprivileged = true;
+ privateNetwork = true;
+ hostAddress = "10.231.136.1";
+ localAddress = "10.231.136.2";
+ config = {
+ services.nginx = {
+ enable = true;
+ virtualHosts.localhost = {
+ root = (pkgs.runCommand "localhost" {} ''
+ mkdir "$out"
+ echo hello world > "$out/index.html"
+ '');
+ };
+ };
+ networking.firewall.allowedTCPPorts = [ 80 ];
+ };
+ };
+ };
+
+ testScript = ''
+ $machine->succeed("nixos-container list") =~ /webserver/ or die;
+
+ # Start the webserver container.
+ $machine->succeed("nixos-container start webserver");
+
+ my $ip = $machine->succeed("nixos-container show-ip webserver");
+ chomp $ip;
+ $machine->succeed("ping -n -c1 $ip");
+
+ # Check that container root folder is owned by a new private user
+ $machine->succeed('test $(stat -c "%U" /var/lib/containers/webserver) == "vu-webserver-0"');
+
+ # Check that webserver is working before reload
+ $machine->succeed("curl --fail http://$ip/ > /dev/null");
+
+ # Reload container
+ $machine->succeed('systemctl reload container@webserver');
+
+ # Check that webserver is working after reload
+ $machine->succeed("curl --fail http://$ip/ > /dev/null");
+
+ # Stop the container.
+ $machine->succeed("nixos-container stop webserver");
+ $machine->fail("curl --fail --connect-timeout 2 http://$ip/ > /dev/null");
+ '';
+})