• Operand
  • # (b)ring mi - belles.

gram:build

> ./nixos/module/lxd.nix

Lenses
(coming soon!)


# See:
# https://discourse.nixos.org/t/howto-setup-lxd-on-nixos-with-nixos-guest-using-unmanaged-bridge-network-interface/21591
{ config, lib, pkgs, ...}:
let
preseed = pkgs.writeText "`lxd-preseed.yml" ''
config:
  images.auto_update_interval: "0"
networks: {}
storage_pools:
- config:
    source: /var/lib/lxd/storage-pools/default
  description: ""
  name: default
  driver: dir
profiles:
- config: {}
  description: Default LXD profile
  devices:
    root:
      path: /
      pool: default
      type: disk
  name: default
projects:
- config:
    features.images: "true"
    features.networks: "true"
    features.profiles: "true"
'';

launch = pkgs.writeScriptBin "lxd-launch" ''
${pkgs.lxd-lts}/bin/lxd init --preseed < ${preseed}
'';

load = pkgs.writeScriptBin "lxd-load" ''
#!${pkgs.nushell}/bin/nu
# nix profile install github:nix-community/nixos-generators
def main [image: path, underlay: path, --label (-l): string = "loaded"] {
  # let underlay = nixos-generate -f lxc-metadata
  ${pkgs.lxc}/bin/lxc image import --alias $label $underlay $image
}
'';

spin = pkgs.writeScriptBin "lxd-spin" ''
#!${pkgs.nushell}/bin/nu
# nix profile install github:nix-community/nixos-generators
def main [ name: string, --label (-l): string = "loaded" ] {
  ${pkgs.lxc}/bin/lxc init $label $name -c security.nesting=true
  ${pkgs.lxc}/bin/lxc config device add $name eth0 nic nictype=bridged parent=lxdbr0
  ${pkgs.lxc}/bin/lxc start lxc-nixos
}
'';

in {
  environment.systemPackages = [ launch load spin pkgs.lxc pkgs.lxd-lts ];
  virtualisation.lxd = { enable = true;
    recommendedSysctlSettings = true; };

  # This enables lxcfs, which is a FUSE fs that sets up some things so that
  # things like /proc and cgroups work better in lxd containers.
  # See https://linuxcontainers.org/lxcfs/introduction/ for more info.
  #
  # Also note that the lxcfs NixOS option says that in order to make use of
  # lxcfs in the container, you need to include the following NixOS setting
  # in the NixOS container guest configuration:
  #
  # virtualisation.lxc.defaultConfig = "lxc.include = ''${pkgs.lxcfs}/share/lxc/config/common.conf.d/00-lxcfs.conf";
  virtualisation.lxc.lxcfs.enable = true;

  # This sets up a bridge called "lxdbr0".
  # This is used to provide NAT'd signal to the guest.
  # This bridge is manipulated directly by lxd,
  # so we don't need to specify any bridged interfaces here.
  networking.bridges = { lxdbr0.interfaces = []; };

  # Add an IP address to the bridge interface.
  networking.localCommands = ''
    ip address add 192.168.57.1/24 dev lxdbr0
  '';

  # Firewall commands allowing traffic to go in and out of the bridge interface
  # (and to the guest LXD instance).  Also sets up the actual NAT masquerade rule.
  networking.firewall.extraCommands = ''
    iptables -A INPUT -i lxdbr0 -m comment --comment "a rule for LXD network lxdbr0" -j ACCEPT

    # These three technically aren't needed, since by default the FORWARD and
    # OUTPUT firewalls accept everything everything, but lets keep them in just
    # in case.
    iptables -A FORWARD -o lxdbr0 -m comment --comment "a rule for LXD network lxdbr0" -j ACCEPT
    iptables -A FORWARD -i lxdbr0 -m comment --comment "a rule for LXD network lxdbr0" -j ACCEPT
    iptables -A OUTPUT -o lxdbr0 -m comment --comment "a rule for LXD network lxdbr0" -j ACCEPT

    iptables -t nat -A POSTROUTING -s 192.168.57.0/24 ! -d 192.168.57.0/24 -m comment --comment "a rule for LXD network lxdbr0" -j MASQUERADE
  '';

  # ip forwarding is needed for NAT'ing to work.
  boot.kernel.sysctl = {
    "net.ipv4.conf.all.forwarding" = true;
    "net.ipv4.conf.default.forwarding" = true;
  };

  # kernel module for forwarding to work
  boot.kernelModules = [ "nf_nat_ftp" ];
}