Skip to content

HAProxy load balancer setup with netns namespaces

This example configures HAProxy with dedicated network namespaces for listener and server access. This gives a hard isolation between the public Internet, the backend servers and the management access.

interfaces:
  # bonding interface used for VLAN sub-interfaces
  bond0:
    link:
      state: up
      kind: bond
      bond_mode: 802.3ad
      bond_ad_lacp_rate: fast
      bond_xmit_hash_policy: layer3+4
      bond_miimon: 100
      bond_updelay: 300
  # physical interfaces for bond0
  lom1:
    link:
      state: up
      kind: physical
      master: bond0
    identify:
      parent_dev_name: "0000:06:00.0"
      parent_dev_bus_name: pci
  lom2:
    link:
      state: up
      kind: physical
      master: bond0
    identify:
      parent_dev_name: "0000:06:00.1"
      parent_dev_bus_name: pci

  # management access in VLAN 100
  mgmt:
    addresses:
      - "192.0.2.80/24"
    link:
      state: up
      kind: vlan
      vlan_protocol: 802.1q
      vlan_id: 100
      link: bond0
routing:
  routes:
    - to: 0.0.0.0/0
      via: 192.0.2.1

namespaces:
  # namespace for HAProxy listener
  public:
    interfaces:
      bond0.600:
        addresses:
          - 198.51.100.2/29
          - 2001:db8:dead:c0de::10/64
        link:
          kind: vlan
          state: up
          vlan_id: 600
          link: bond0
          link_netns: null
    routing:
      routes:
        - to: 0.0.0.0/0
          via: 198.51.100.1
        - to: ::/0
          via: fe80::defa
          dev: bond0.600

  # namespace for HAProxy server access
  backend:
    interfaces:
      bond0.900:
        addresses:
          - fd00:4242:dead:c0de::1:80::/64
        link:
          kind: vlan
          state: up
          vlan_id: 900
          link: bond0
          link_netns: null
    routing:
      routes:
        - to: ::/0
          via: fe80::defa
          dev: bond0.900
{
  networking.ifstate = {
    enable = true;
    settings = {
      interfaces = {
        # bonding interface used for VLAN sub-interfaces
        bond0 = {
          link = {
            state = "up";
            kind = "bond";
            bond_mode = "802.3ad";
            bond_ad_lacp_rate = "fast";
            bond_xmit_hash_policy = "layer3+4";
            bond_miimon = 100;
            bond_updelay = 300;
          };
        };
        # physical interfaces for bond0
        lom1 = {
          link = {
            state = "up";
            kind = "physical";
            master = "bond0";
          };
          identify = {
            parent_dev_name = "0000:06:00.0";
            parent_dev_bus_name = "pci";
          };
        };
        lom2 = {
          link = {
            state = "up";
            kind = "physical";
            master = "bond0";
          };
          identify = {
            parent_dev_name = "0000:06:00.1";
            parent_dev_bus_name = "pci";
          };
        };
        # management access in VLAN 100
        mgmt = {
          addresses = [ "192.0.2.80/24"; ];
          link = {
            kind = "vlan";
            link = "bond0";
            vlan_id = 42;
            state = "up";
          };
        }; 
      };
      routing.routes = [
        {
          to = "0.0.0.0/0";
          via = "192.0.2.1";
        }
      ];
      # namespace for HAProxy listener
      namespaces = {
        public = {
          interfaces = {
            "bond0.600" = {
              addresses = [ "198.51.100.2/29", "2001:db8:dead:c0de::1:80/64" ];
              link = {
                kind = "vlan";
                link = "bond0";
                link_netns = null;
                vlan_id = 600;
                state = "up";
              };
            };
          };
          routing.routes = [
            {
              to = "0.0.0.0/0";
              via = "198.51.100.1";
            }
            {
              to = "::/0";
              via = "fe80::defa";
              dev = "bond0.600";
            }
          ];
        };
        # namespace for HAProxy server access
        backend = {
          interfaces = {
            "bond0.900" = {
              addresses = [ "fd00:4242:dead:c0de::1:80::/64" ];
              link = {
                kind = "vlan";
                link = "bond0";
                link_netns = null;
                vlan_id = 900;
                state = "up";
              };
            };
          };
          routing.routes = [
            {
              to = "::/0";
              via = "fe80::defa";
              dev = "bond0.900";
            }
          ];
        };
      };
    };
  };
}

HAProxy

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    setcap cap_sys_admin
    daemon

listen frontend
    mode http
    bind :80 namespace public
    use_backend app

backend app
    mode http
    default-server namespace backend
    server server1 10.0.0.11:8000
    server server2 10.0.0.12:8000
{
    services.haproxy = {
        enable = true;
        config = ''
          global
              log /dev/log local0
              log /dev/log local1 notice
              chroot /var/lib/haproxy
              user haproxy
              group haproxy
              setcap cap_sys_admin
              daemon

          listen frontend
              mode http
              bind :80 namespace public
              use_backend app

          backend app
              mode http
              default-server namespace backend
              server server1 10.0.0.11:8000
              server server2 10.0.0.12:8000
        '';
    };
}