Build a DN42 setup from scratch
Find a file
2026-03-04 15:48:35 +01:00
assets Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
group_vars Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
host_vars Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
roles fixed Roa file paths 2026-03-03 14:49:26 +01:00
.gitignore Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
bootstrap.yml Update bootstrap.yml 2026-02-06 20:25:03 +01:00
inventory-bootstrap.yml Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
inventory.yml Do you want to build a gateway? 2026-02-06 18:57:44 +01:00
README.md Update README.md 2026-03-04 15:48:35 +01:00
router.yml Do you want to build a gateway? 2026-02-06 18:57:44 +01:00

What does this repo do?

It provides a collection of playbooks and roles that make it easy to deploy a DN42 gateway fully automated.

Featureset as of now:

  • create a gateway from a blank VM
  • add new peers
  • create a more complex setup with gateways and routers

Build from scratch

To make a Gateway out of a blank VM, edit the host_vars and group_vars files, rename them appropriately and edit the inventory files.
Once this happened, decide if you have a simple or complex setup in mind.

Decisions, decisions . . .

Simple means:

  • A local gateway
  • Peers connected directly to this gateway
  • No drop pods (aka separate routers)
  • Clients are connected directly to this gateway

Complex means:

  • Separate routers and gateways
  • peers are connected to gateways
  • routers connect to gateways and only route internal traffic
  • clients connect to routers

Image Description Network Graph for a complex setup - development env this collection was created in

Bill of materials and prerequisites

For a successful deployment, the following things are required:

  • Hashicorp Vault or OpenBao
  • Local Python environment with these packages:
    • ansible
    • hvac
    • passlib

Complex Setup:

  • 2 VPS Instances (this Ansible collection was developed and tested with Debian)
  • 1 Machine that acts as a local router
    Note: this is a separate VM or machine, not an OPNsense or FritzBox or anything like that
  • 2 Domains or Subdomains
  • 7 Wireguard configs and thus 7 keypairs for:
    • 2x Communication between gateways ("east-west")
    • 2x Communication "down" from gateway to router ("north-south")
    • 2x Communication "up" from router to gateways ("north-south")
    • 1x for clients on the router
  • Management wireguard tunnel for monitoring and metrics

Simple Setup:

  • VM
  • 1 wireguard config for clients
  • Optional: Domain

Aides

How to make it yours

This lump of yaml files was written with universal usage in mind. This means that you only have to change the variable files in group_vars and host_vars plus the inventory files.

Wireguard configs

Here is a template to create a new wg config for infra components:

[Interface]
PrivateKey = 
ListenPort = PORT
PostUp = /sbin/ip addr add dev %i TUNNEL_ADDR/64 peer PEER_TUNNEL_ADDR/64
Table = off


[Peer]
# friendly_name = new-u-station
PublicKey = 
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepAlive = 5

You can generate keys in stdout without writing any files like this:
wg genkey --> copy this privatekey
wg pubkey --> paste key in here, press enter and then ctrl-d

Vault/OpenBao structure

Due to the rather many secrets in need of storing for the complex setup, a well-structured directory tree helps a lot to find things. An idea for how this could be structured is this:

DN42:
  passwords:
    machine1:
      initial_root_pw
      root_pw
      remote
    machine2:
      initial_root_pw
      root_pw
      remote
    machine3:
      initial_root_pw
      root_pw
      remote
  wireguard_configs:
    gateways:
      machine1:
        to_2
        to_router
        management
      machine2:
        to_1
        to_router
        management
    routers:
      router1:
        to_1
        to_2
        clients
        (management)
    peers:
      peer1
      peer2
      peer3
Misc:
  ssh_keys:
    authorized_keys

Commands

To create a simple setup, execute this:

ansible-playbook bootstrap.yml -i inventory-bootstrap.yml --skip-tags complex

For a complex setup, run these commands in order:

ansible-playbook bootstrap.yml -i inventory-bootstrap.yml --skip-tags simple
ansible-playbook router.yml -i inventory-bootstrap.yml --skip-tags simple

Lifecycle

A setup lives and breathes over time. Two situations are covered by this repo as of now:
adding new peers running tasks after the initial setup

The other inventory file

Since some properties about the hosts change after the initial setup (namely passwords and ssh ports), this needs to be reflected in the inventory. To avoid editing an inventory file over and over again back and forth, this repo contains two inventory files. One for the initial setup and one for after that. Look at the file and check if the password, paths in Vault, users, ssh ports and so on changed.

Adding a new peer

The most regular change is most likely the addition of a new peer.
This step is still half manual, due to the fact that the wireguard config needs to be in Vault for this playbook to work.

Here is a template to create a new wg config:

[Interface]
PrivateKey = MY_PRIVKEY
PostUp = /sbin/ip addr add dev %i MY_TUNNEL_ADDR/128 peer PEER_TUNNEL_ADDR/128
Table = off
ListenPort = PORT

[Peer]
# friendly_name = PEERNAME
PublicKey = PEER_PUBKEY
Endpoint = PEER_ENDPOINT:PEER_PORT
AllowedIPs = 172.16.0.0/12, 10.0.0.0/8, fd00::/8, fe80::/10
PersistentKeepAlive = 10

You can generate keys in stdout without writing any files like this:
wg genkey --> copy this privatekey
wg pubkey --> paste key in here, press enter and then ctrl-d

Once this is done, edit the host vars of your gateway and add the ASN, peer tunnel address and Port of your new peer. Afterward execute this command:

ansible-playbook bootstrap.yml -i inventory.yml --tags new_peer

Adding a new client

Fortunately, a client needs very little config. Normally, all it should take is this wireguard config.

[Interface]
PrivateKey = 
PostUp = /sbin/ip addr add dev %i DN42_ADDR/128 peer ROUTER_AREA_IP/56

[Peer]
PublicKey = ROUTER_PUBKEY
Endpoint = [fd00:ULA_ADDR_OF_ROUTER]:9000
AllowedIPs = 172.16.0.0/12, 10.0.0.0/8, fd00::/8, fe80::/10
PersistentKeepalive = 10

Troubleshooting

If the client isn't able to ping for example door.cccda.de, these troubleshooting ideas may help:

  • check if client and router report a handshake with wg or wg show $INTERFACE_NAME
    • if not, make sure both can ping each other (VLAN, routing)
  • check routing on the client with ip r g $IP_ADDR to make sure the kernel chooses the correct route. Add static routes if necessary
  • use tcpdump -ni $INTERFACE along the way to find out what gets lost where
  • check firewalls