Running NixOS in a Linux Container

NixOS
is seen as the holy grail of
My favorite configuration stack is Ansible + Shell + Alpine
management and system administration. It’s what many call a
purely functional distribution
[pdf]
. The state is declarative — entire systems, deployment artifacts, or services can be built from a single file.
Let’s try out NixOS in a Linux Container
This is assuming you have a working LXC or LXD setup with networking.
NixOS’
Hydra builds
provide container images but they don’t seem to
Symlinking issues were encountered when extracting the rootfs.
for this use case.
Bootstrapping
The best way to get a NixOS root file system is to bootstrap using nixos-generate
. This will require a live NixOS environment. Download the latest
NixOS minimal image
and boot into the live environment using preferred means.
Inside the live environment bootstrap a Linux container’s rootfs
using nixos-generate
.
nixos-generate -f lxc
If the command nixos-generate
is not found — install nixos-generators
using nix-env
.
nix-env -iA nixos.nixos-generators
Once completed, this command will print a hashed path like /nix/store/3ipfpzhk4dllwhcnldsbfldi1favyxsm-tarball/nix-support/hydra-build-products
. This file contains the location of the rootfs
archive.
$ cat /nix/store/3ipfpzhk4dllwhcnldsbfldi1favyxsm-tarball/nix-support/hydra-build-products
file system-tarball /nix/store/3ipfpzhk4dllwhcnldsbfldi1favyxsm-tarball/tarball/nixos-system-x86_64-linux.tar.xz
Save the generated archive nixos-system-x86_64-linux.tar.xz
and exit the live environment.
Setup the Linux Container
Now that we have a clean rootfs
archive. Create an empty linux container and rootfs
directory. Extract nixos-system-x86_64-linux.tar.xz
to rootfs
.
lxc-create -n nixos -t none
cd /var/lib/lxc/nixos
mkdir rootfs
tar -xvf nixos-system-x86_64-linux.tar.xz -C rootfs/
Let’s massage our
This has been tested on Debian and Arch Linux.
for NixOS at /var/lib/lxc/nixos/config
. Our entry point is /sbin/init
and we must mount /proc
to run nixos-rebuild
.
# Distribution configuration
lxc.include = /usr/share/lxc/config/common.conf
lxc.arch = linux64
# Container specific configuration
lxc.rootfs.path = dir:/var/lib/lxc/nixos/rootfs
lxc.uts.name = nixos
# Network configuration
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:01:77:76
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1
# NixOS configuration
lxc.init.cmd = /sbin/init
lxc.mount.entry = proc mnt/proc proc create=dir 0 0
Setup and Run NixOS
Now
the container and enter the shell using
lxc-attach
.
lxc-start -n nixos
lxc-attach -n nixos
The default /etc/nixos/configuration.nix
is empty. Tell NixOS that we are a container by adding boot.isContainer = true
.
{ config, pkgs, ... }:
{
imports = [ ];
boot.isContainer = true;
}
Now run a
Firewall errors about iptables IPv6 filters mean you either run an old kernel or you need to sudo modprobe ip6table_filter
of the system. The upgrade flag is necessary on the first rebuild to download the channels.
nixos-rebuild switch --upgrade
We now have a base NixOS system in a Linux container. You can build reproducible desktops, servers, deployment artifacts — anything, using your own configuration.nix
and consulting the
NixOS options index.
This approach is great because when you make something it just works — all the time.
Updated 16 August 2020