NixOS Containers: Difference between revisions
Fix headings and formatting, fix →Bridge together two nixos-containers with privateNetwork enabled |
|||
| Line 13: | Line 13: | ||
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. | 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. | ||
{{file| | {{file|3=networking.nat = { | ||
networking.nat = { | |||
enable = true; | enable = true; | ||
internalInterfaces = ["ve-+"]; | internalInterfaces = ["ve-+"]; | ||
| Line 48: | Line 47: | ||
system.stateVersion = "24.11"; | system.stateVersion = "24.11"; | ||
}; | }; | ||
}; | };|name=configuration.nix|lang=nix}} | ||
In order to reach the web application on the host system, we have to open [[Firewall]] port 80 and also configure NAT through <code>networking.nat</code>. The web service of the container will be available at http://192.168.100.11 | In order to reach the web application on the host system, we have to open [[Firewall]] port 80 and also configure NAT through <code>networking.nat</code>. The web service of the container will be available at http://192.168.100.11 | ||
| Line 59: | Line 57: | ||
By default, if <code>privateNetwork</code> is not set, the container shares the network with the host, enabling it to bind any port on any interface. However, when <code>privateNetwork</code> is set to <code>true</code>, the container gains its private virtual <code>eth0</code> and <code>ve-<container_name></code> on the host. This isolation is beneficial when you want the container to have its dedicated networking stack. | By default, if <code>privateNetwork</code> is not set, the container shares the network with the host, enabling it to bind any port on any interface. However, when <code>privateNetwork</code> is set to <code>true</code>, the container gains its private virtual <code>eth0</code> and <code>ve-<container_name></code> on the host. This isolation is beneficial when you want the container to have its dedicated networking stack. | ||
===== NAT (Network Address Translation) ===== | |||
{{File|3=networking.nat = { | |||
enable = true; | |||
internalInterfaces = ["ve-+"]; | |||
externalInterface = "ens3"; | |||
# Lazy IPv6 connectivity for the container | |||
enableIPv6 = true; | |||
};|name=configuration.nix|lang=nix}} | |||
===== Bridge ===== | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
networking = { | networking = { | ||
| Line 91: | Line 92: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Without privateNetwork (simpler) ==== | ===== Without privateNetwork (simpler) ===== | ||
If the service can be accessed by changing its port, the private network is not needed necessarily. Be careful to not use occupied ports. This example runs an [[Actual]] server on port 3003. It can be accessed through the host at <code>http://localhost:3003</code>. Since <code>privateNetwork</code> is not defined, it defaults to <code>false</code>. | If the service can be accessed by changing its port, the private network is not needed necessarily. Be careful to not use occupied ports. This example runs an [[Actual]] server on port 3003. It can be accessed through the host at <code>http://localhost:3003</code>. Since <code>privateNetwork</code> is not defined, it defaults to <code>false</code>. | ||
| Line 141: | Line 141: | ||
== Tips and tricks == | == Tips and tricks == | ||
=== Define and create nixos-container from a Flake file === | |||
We can define and create a custom container called <code>container</code> from a file stored as <code>flake.nix</code>. In this case we use the unstable branch of the nixpkgs repository as a source.<syntaxhighlight lang="nix"> | We can define and create a custom container called <code>container</code> from a file stored as <code>flake.nix</code>. In this case we use the unstable branch of the nixpkgs repository as a source.<syntaxhighlight lang="nix"> | ||
{ | { | ||
| Line 173: | Line 174: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Use agenix secrets in container === | |||
To add <code>agenix</code> secrets to a container bind mount the <code>ssh-host.key</code> and import the <code>agenix.nixosModule</code> and set <code>age.identityPaths</code> [https://discourse.nixos.org/t/secrets-inside-nixos-containers/34403/6 Source]<syntaxhighlight lang="nix"> | To add <code>agenix</code> secrets to a container bind mount the <code>ssh-host.key</code> and import the <code>agenix.nixosModule</code> and set <code>age.identityPaths</code> [https://discourse.nixos.org/t/secrets-inside-nixos-containers/34403/6 Source]<syntaxhighlight lang="nix"> | ||
{ agenix, ... }: | { agenix, ... }: | ||
| Line 203: | Line 205: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | === Bridge together two nixos-containers with privateNetwork enabled === | ||
'''Target:''' | '''Target:''' | ||
| Line 217: | Line 219: | ||
'''Configuration:''' | '''Configuration:''' | ||
Create and configure the bridge and the internet connection | |||
{{File|3=# Give containers access to the internet | {{File|3=# Give containers access to the internet | ||
networking.nat = { | networking.nat = { | ||
enable = true; | enable = true; | ||
# Use "ve-*" when using nftables instead of iptables | # Use "ve-*" when using nftables instead of iptables | ||
internalInterfaces = [ "br0" ]; # | internalInterfaces = [ "br0" ]; # Connect the bridge to the internet | ||
externalInterface = "wlp5s0"; # | externalInterface = "wlp5s0"; # Adjust according to your internet interface | ||
# Lazy IPv6 connectivity for the container | # Lazy IPv6 connectivity for the container | ||
enableIPv6 = true; | enableIPv6 = true; | ||
| Line 239: | Line 241: | ||
netdevs = { | netdevs = { | ||
# Create the bridge interface | # Create the bridge interface | ||
# | # Each interface is stored as a seperate file under /etc/systemd/network by default | ||
# | # <number>-name is required so that it is not overwritten by other configurations of the same name | ||
# It is recommended that each filename is prefixed with a number smaller than "70" (e.g. 10-eth0.network). | # It is recommended that each filename is prefixed with a number smaller than "70" (e.g. 10-eth0.network). | ||
# https://www.freedesktop.org/software/systemd/man/latest/systemd. | # https://www.freedesktop.org/software/systemd/man/latest/systemd.netdev.html | ||
"20-br0" = { | "20-br0" = { | ||
netdevConfig = { | netdevConfig = { | ||
Kind = "bridge"; | Kind = "bridge"; | ||
Name = "br0"; | Name = "br0"; | ||
# Sets a pre-determined mac address | # Sets a pre-determined mac address | ||
# Leave empty if you want the system to auto-assign a mac address to the bridge | |||
# MACAddress = "10:00:00:00:00:01"; | # MACAddress = "10:00:00:00:00:01"; | ||
}; | }; | ||
| Line 255: | Line 256: | ||
}; | }; | ||
networks = { | networks = { | ||
# Configure the bridge for its desired function | # Configure the bridge for its desired function | ||
"40-br0" = { | "40-br0" = { | ||
matchConfig.Name = "br0"; | matchConfig.Name = "br0"; | ||
# | # The address of the bridge | ||
# /29 is the netmask, it creates 2^(32-29) = 8 subnets | # /29 is the netmask, it creates 2^(32-29) = 8 subnets | ||
# | # 2 are reserved (first and last), as Network Address and Broadcast Address | ||
# | # The bridge already takes up one subnet, so 3 addresses are already reserved | ||
# | # To bridge 2 networks, you need a netmask of <=29 for IPv4 | ||
# https://www.calculator.net/ip-subnet-calculator.html?cclass=any&csubnet=29&cip=192.168.100.1&ctype=ipv4&x=Calculate | # https://www.calculator.net/ip-subnet-calculator.html?cclass=any&csubnet=29&cip=192.168.100.1&ctype=ipv4&x=Calculate | ||
# 192.168.100.0 - 192.168.100.7 | # 192.168.100.0 - 192.168.100.7 | ||
| Line 288: | Line 271: | ||
"192.168.100.1/29" | "192.168.100.1/29" | ||
]; | ]; | ||
# bridgeConfig = {}; | # bridgeConfig = {}; | ||
# Disable address autoconfig when no IP configuration is required | # Disable address autoconfig when no IP configuration is required | ||
| Line 312: | Line 281: | ||
}; | }; | ||
};|name=configuration.nix|lang=nix}} | };|name=configuration.nix|lang=nix}} | ||
Create and configure <code>containerA</code> | |||
{{File|3=containers.containerA = { | {{File|3=containers.containerA = { | ||
autoStart = true; | autoStart = true; | ||
privateNetwork = true; | privateNetwork = true; | ||
hostBridge = "br0"; | hostBridge = "br0"; | ||
# hostAddress = "192.168.100.1"; # | # hostAddress = "192.168.100.1"; # Not used when using hostBridge | ||
localAddress = "192.168.100.2/29"; # | localAddress = "192.168.100.2/29"; # Should have the netmask if hostBridge is used | ||
config = | config = | ||
{ config, pkgs, lib, ... }: | { config, pkgs, lib, ... }: | ||
| Line 333: | Line 303: | ||
networking = { | networking = { | ||
# Use systemd-resolved inside the container | # Use systemd-resolved inside the container | ||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 | # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 | ||
| Line 347: | Line 311: | ||
}; | }; | ||
};|name=configuration.nix|lang=nix}} | };|name=configuration.nix|lang=nix}} | ||
Create and configure <code>containerB</code> | |||
{{File|3=containers.containerB = { | {{File|3=containers.containerB = { | ||
autoStart = true; | autoStart = true; | ||
privateNetwork = true; | privateNetwork = true; | ||
hostBridge = "br0"; | hostBridge = "br0"; | ||
# hostAddress = "192.168.100.1"; # | # hostAddress = "192.168.100.1"; # Not used when using hostBridge | ||
localAddress = "192.168.100.3/29"; # | localAddress = "192.168.100.3/29"; # Should have the netmask if hostBridge is used | ||
config = | config = | ||
{ config, pkgs, lib, ... }: | { config, pkgs, lib, ... }: | ||
| Line 373: | Line 338: | ||
networking = { | networking = { | ||
firewall | firewall.allowedTCPPorts = [ 80 ]; | ||
# Use systemd-resolved inside the container | # Use systemd-resolved inside the container | ||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 | # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 | ||
| Line 395: | Line 355: | ||
== Troubleshooting == | == Troubleshooting == | ||
=== I have changed the host's channel and some services are no longer functional === | |||
'''Symptoms:''' | '''Symptoms:''' | ||
* Lost data in PostgreSQL database | * Lost data in PostgreSQL database | ||