Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Example: complex

Main view (click to enlarge)

Network view (click to enlarge)

flake.nix

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nix-topology.url = "github:oddlama/nix-topology";
    nix-topology.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs =
    {
      self,
      nixpkgs,
      nix-topology,
      ...
    }:
    {
      nixosConfigurations.host1 = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          {
            networking.hostName = "host1";

            # Network interfaces from systemd are detected automatically:
            systemd.network.enable = true;
            systemd.network.networks.wan = {
              matchConfig.Name = "wan";
              address = [ "192.168.178.100/24" ];
            };
            systemd.network.networks.lan = {
              matchConfig.Name = "lan";
              address = [ "192.168.1.1/24" ];
            };

            # Hosts a DHCP server with kea, this will become a network automatically
            services.kea.dhcp4 = {
              # ... (skipped unnecessary options for brevity)
              enable = true;
              settings = {
                interfaces-config.interfaces = [ "lan" ];
                subnet4 = [
                  {
                    interface = "lan-self";
                    subnet = "192.168.1.0/24";
                  }
                ];
              };
            };

            # We can change our own node's topology settings from here:
            topology.self.name = "🧱  Small Firewall";
            topology.self.interfaces.wg0 = {
              addresses = [ "10.0.0.1" ];
              network = "wg0"; # Use the network we define below
              virtual = true; # doesn't change the immediate render yet, but makes the network-centric view a little more readable
              type = "wireguard"; # changes the icon
            };

            # You can add stuff to the global topology from a nixos configuration, too:
            topology = {
              # Let's say this node acts as a wireguard server, so it would make sense
              # that it defines the related network:
              networks.wg0 = {
                name = "Wireguard network wg0";
                cidrv4 = "10.0.0.0/24";
              };
            };
          }
          nix-topology.nixosModules.default
        ];
      };
      nixosConfigurations.host2 = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          (
            { config, ... }:
            {
              networking.hostName = "host2";

              # This host has a wireless connection, as indicated by the wlp prefix
              systemd.network.enable = true;
              systemd.network.networks.eth0 = {
                matchConfig.Name = "eth0";
                address = [ "192.168.1.100/24" ];
              };

              # Containers will automatically be rendered if they import the topology module!
              containers.vaultwarden.macvlans = [ "vm-vaultwarden" ];
              containers.vaultwarden.config = {
                imports = [ nix-topology.nixosModules.default ];
                networking.hostName = "host2-vaultwarden";
                # This node host's a vaultwarden instance, which nix-topology
                # will automatically pick up on
                services.vaultwarden = {
                  enable = true;
                  config = {
                    rocketAddress = "0.0.0.0";
                    rocketPort = 8012;
                    domain = "https://vault.example.com/";
                    # ...
                  };
                };
              };

              services.vaultwarden = {
                enable = true;
                config = {
                  rocketAddress = "0.0.0.0";
                  rocketPort = 8012;
                  domain = "https://anothervault.example.com/";
                  # ...
                };
              };

              containers.test.config = {
                imports = [ nix-topology.nixosModules.default ];
                networking.hostName = "host2-test-with-a-long-name";
              };

              # We can change our own node's topology settings from here:
              topology.self = {
                name = "☄️  Powerful host2";
                hardware.info = "2U Server with loads of RAM and a really long description";
                interfaces.wg0 = {
                  addresses = [ "10.0.0.2" ];
                  # Rendering virtual connections such as wireguard connections can sometimes
                  # clutter the view. So by hiding them we will only see the connections
                  # in the network centric view
                  renderer.hidePhysicalConnections = true;
                  virtual = true; # doesn't change the immediate render yet, but makes the network-centric view a little more readable
                  type = "wireguard"; # changes the icon
                  # No need to add the network wg0 explicitly, it will automatically be propagated via the connection.
                  physicalConnections = [ (config.lib.topology.mkConnection "host1" "wg0") ];
                };
              };
            }
          )
          nix-topology.nixosModules.default
        ];
      };
      nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          {
            networking.hostName = "desktop";

            # This host has a wireless connection, as indicated by the wlp prefix
            systemd.network.enable = true;
            systemd.network.networks.eth0 = {
              matchConfig.Name = "eth0";
              address = [ "192.168.1.123/24" ];
            };

            topology.self = {
              name = "🖥️ Desktop";
              hardware.info = "AMD Ryzen 7850X, 64GB RAM";
            };
          }
          nix-topology.nixosModules.default
        ];
      };
      nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          {
            networking.hostName = "laptop";

            # This host has a wireless connection, as indicated by the wlp prefix
            systemd.network.enable = true;
            systemd.network.networks.eth0 = {
              matchConfig.Name = "eth0";
              address = [ "192.168.1.142/24" ];
            };
            systemd.network.networks.wlp1s1 = {
              matchConfig.Name = "wlp1s1";
            };

            topology.self = {
              name = "💻  Laptop";
              hardware.info = "Framework 16";
            };
          }
          nix-topology.nixosModules.default
        ];
      };
    }
    // (
      let
        forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
      in
      {
        topology = forAllSystems (
          system:
          let
            pkgs = import nixpkgs {
              inherit system;
              overlays = [ nix-topology.overlays.default ];
            };
          in
          # This is the global topology module.
          import nix-topology {
            inherit pkgs;
            modules = [
              (
                { config, ... }:
                let
                  inherit (config.lib.topology)
                    mkInternet
                    mkRouter
                    mkSwitch
                    mkConnection
                    ;
                in
                {
                  inherit (self) nixosConfigurations;

                  # Add a node for the internet
                  nodes.internet = mkInternet { connections = mkConnection "router" "wan1"; };

                  # Add a router that we use to access the internet
                  nodes.router = mkRouter "FritzBox" {
                    info = "FRITZ!Box 7520";
                    image = ./images/fritzbox.png;
                    interfaceGroups = [
                      [
                        "eth1"
                        "eth2"
                        "eth3"
                        "eth4"
                      ]
                      [ "wan1" ]
                    ];
                    connections.eth1 = mkConnection "host1" "wan";
                    interfaces.eth1 = {
                      addresses = [ "192.168.178.1" ];
                      network = "home-fritzbox";
                    };
                  };

                  networks.home-fritzbox = {
                    name = "Home Fritzbox";
                    cidrv4 = "192.168.178.0/24";
                  };

                  networks.host1-kea.name = "Home LAN";
                  nodes.switch-main = mkSwitch "Main Switch" {
                    info = "D-Link DGS-1016D";
                    image = ./images/dlink-dgs1016d.png;
                    interfaceGroups = [
                      [
                        "eth1"
                        "eth2"
                        "eth3"
                        "eth4"
                        "eth5"
                        "eth6"
                      ]
                    ];
                    connections.eth1 = mkConnection "host1" "lan";
                    connections.eth2 = mkConnection "host2" "eth0";
                    connections.eth3 = mkConnection "switch-livingroom" "eth1";
                  };

                  nodes.switch-livingroom = mkSwitch "Livingroom Switch" {
                    info = "D-Link DGS-105";
                    image = ./images/dlink-dgs105.png;
                    interfaceGroups = [
                      [
                        "eth1"
                        "eth2"
                        "eth3"
                        "eth4"
                        "eth5"
                      ]
                    ];
                    connections.eth2 = mkConnection "desktop" "eth0";
                    connections.eth3 = mkConnection "laptop" "eth0";
                  };
                }
              )
            ];
          }
        );
      }
    );
}