NixOS Containers - NixOS Wiki
Article
Setup native systemd-nspawn containers, which are running NixOS and are configured and managed by NixOS using the containers directive.
See Docker page for OCI container (Docker, Podman) configuration.
-
Configuration
The following example creates a container called webserver running a httpd web server. It will start automatically at boot and has its private network subnet.
❄︎ /etc/nixos/configuration.nix
networking . nat = { enable = true ; internalInterfaces = [ "ve-+" ]; externalInterface = "ens3" ; # Lazy IPv6 connectivity for the container enableIPv6 = true ; }; containers . webserver = { autoStart = true ; privateNetwork = true ; hostAddress = "192.168.100.10" ; localAddress = "192.168.100.11" ; hostAddress6 = "fc00::1" ; localAddress6 = "fc00::2" ; config = { config , pkgs , lib , ... }: { services . httpd = { enable = true ; adminAddr = "admin@example.org" ; }; networking = { firewall . allowedTCPPorts = [ 80 ]; # Use systemd-resolved inside the container # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 useHostResolvConf = lib .mkForce false ; }; services .resolved . enable = true ; system . stateVersion = "24.11" ; }; };In order to reach the web application on the host system, we have to open Firewall port 80 and also configure NAT through
networking.nat. The web service of the container will be available at http://192.168.100.11-
Networking
☶︎
This article or section needs to be expanded. Further information may be found in the related discussion page. Please consult the pedia article metapage for guidelines on contributing.
By default, if
privateNetworkis not set, the container shares the network with the host, enabling it to bind any port on any interface. However, whenprivateNetworkis set totrue, the container gains its private virtualeth0andve-on the host. This isolation is beneficial when you want the container to have its dedicated networking stack.NAT (Network Address Translation)
Bridge
networking = { bridges .br0 . interfaces = [ "eth0s31f6" ]; # Adjust interface accordingly # Get bridge-ip with DHCP useDHCP = false ; interfaces . "br0" . useDHCP = true ; # Set bridge-ip static interfaces . "br0" .ipv4 . addresses = [{ address = "192.168.100.3" ; prefixLength = 24 ; }]; defaultGateway = "192.168.100.1" ; nameservers = [ "192.168.100.1" ]; }; containers . = { privateNetwork = true ; hostBridge = "br0" ; # Specify the bridge name localAddress = "192.168.100.5/24" ; config = { }; };
-
-
Usage
List containers
# machinectl listChecking the status of the container
# systemctl status container@webserverLogin into the container
# nixos-container root-login webserverStart or stop a container
# nixos-container start webserver # nixos-container stop webserverDestroy a container including its file system
# nixos-container destroy webserverView log for container
# journalctl -M webserverFurther informations are available in the NixOS Manual, NixOS manual.
Tips and tricks
-
Define and create nixos-container from a Flake file
We can define and create a custom container called
containerfrom a file stored asflake.nix. In this case we use the unstable branch of the nixpkgs repository as a source.{ inputs .nixpkgs . url = "nixpkgs/nixos-unstable" ; outputs = { self , nixpkgs }: { nixosConfigurations . container = nixpkgs .lib .nixosSystem { system = "x86_64-linux" ; modules = [ ({ pkgs , ... }: { boot . isContainer = true ; networking .firewall . allowedTCPPorts = [ 80 ]; services . httpd = { enable = true ; adminAddr = "morty@example.org" ; }; }) ]; }; }; }To create and run that container, enter following commands. In this example the
flake.nixfile is in the same directory.# nixos-container create flake-test --flake . host IP is 10.233.4.1, container IP is 10.233.4.2 # nixos-container start flake-test -
Use agenix secrets in container
To add
agenixsecrets to a container bind mount thessh-host.keyand import theagenix.nixosModuleand setage.identityPathsSource{ agenix , ... }: { containers . "withSecret" = { # pass the private key to the container for agenix to decrypt the secret bindMounts . "/etc/ssh/ssh_host_ed25519_key" . isReadOnly = true ; config = { config , lib , pkgs , ... }: { imports = [ agenix .nixosModules .default ]; # import agenix-module into the nixos-container age . identityPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; # isn't set automatically when openssh is not setup # import the secret age .secrets . "secret-name" = { file = ../secrets/secret.age ; }; }; }; }
Troubleshooting
-
I have changed the host's channel and some services are no longer functional
Symptoms:
- Lost data in PostgreSQL database
- MySQL has changed its path, where it creates the database
Solution
If you did not have a = =
system.stateVersionoption set inside your declarative container configuration, it will use the default one for the channel. Your data might be safe, if you did nothing meanwhile. Add the missing = =system.stateVersionto your container, rebuild, and possibly stop/start the container.
See also
- NixOS Manual, Chapter on Container Management
- Blog Article - Declarative NixOS Containers
- NixOS Discourse - Extra-container: Run declarative containers without full system rebuilds
- Nixpkgs - nixos-container.pl
- Nixpkgs - nixos-containers.nix
- nixos-nspawn
- tfc/nspawn-nixos
- MicroVMs as a more isolated alternative, e.g. with https://github.com/astro/microvm.nix
Retrieved from " https://wiki.nixos.org/w/index.php?title=NixOS_Containers&oldid=23589"