Example: complex

Main view (click to enlarge)

Network view (click to enlarge)

flake.nix

{
  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    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,
    flake-utils,
    ...
  }:
    {
      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/";
                    # ...
                  };
                };
              };

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

              # We can change our own node's topology settings from here:
              topology.self = {
                name = "☄️  Powerful host2";
                hardware.info = "2U Server with loads of RAM";
                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
        ];
      };
    }
    // flake-utils.lib.eachDefaultSystem (system: rec {
      pkgs = import nixpkgs {
        inherit system;
        overlays = [nix-topology.overlays.default];
      };

      # This is the global topology module.
      topology = 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";
            };
          })
        ];
      };
    });
}