cashmere

cashmere

NixOS Container

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.

  1. 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

    1. 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 privateNetwork is not set, the container shares the network with the host, enabling it to bind any port on any interface. However, when privateNetwork is set to true, the container gains its private virtual eth0 and ve- 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  =  {  };
       };
  2. Usage

    List containers

    # machinectl  list

    Checking the status of the container

    # systemctl  status  container@webserver

    Login into the container

    # nixos-container  root-login  webserver

    Start or stop a container

     # nixos-container  start  webserver
    # nixos-container  stop  webserver

    Destroy a container including its file system

    # nixos-container  destroy  webserver

    View log for container

    # journalctl  -M  webserver

    Further informations are available in the NixOS Manual, NixOS manual.

Tips and tricks

  1. Define and create nixos-container from a Flake file

    We can define and create a custom container called container from a file stored as flake.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.nix file 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
  2. Use agenix secrets in container

    To add agenix secrets to a container bind mount the ssh-host.key and import the agenix.nixosModule and set age.identityPaths Source

     { 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

  1. 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.stateVersion option 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.stateVersion to your container, rebuild, and possibly stop/start the container.

See also

Retrieved from " https://wiki.nixos.org/w/index.php?title=NixOS_Containers&oldid=23589"