diff --git a/profiles/default.nix b/profiles/default.nix
index 841ac25..087804c 100644
--- a/profiles/default.nix
+++ b/profiles/default.nix
@@ -7,6 +7,7 @@
     ./common-dns
     ./common-networking
     ./cybercluster-vm
+    ./dn42-router
     ./fem-net
     ./hetzner-cloud
     ./mercury-vm
diff --git a/profiles/dn42-router/default.nix b/profiles/dn42-router/default.nix
new file mode 100644
index 0000000..ddbb64f
--- /dev/null
+++ b/profiles/dn42-router/default.nix
@@ -0,0 +1,272 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.profiles.clerie.dn42-router;
+
+  myAsn = 4242422574;
+  ospf6Table = 1337;
+  bgp6Table = 2342;
+
+in {
+
+  options.profiles.clerie.dn42-router = {
+    enable = mkEnableOption "DN42 router base config";
+    loopbackIp = mkOption {
+      type = types.str;
+      description = "IPv6 lookback IP";
+    };
+    routerId = mkOption {
+      type = types.str;
+      description = "IPv6 lookback IP";
+    };
+    ospfInterfaces = mkOption {
+      type = with types; listOf str;
+      default = [];
+    };
+    ibgpPeers = mkOption {
+      type = with types; listOf (submodule ({ ... }: {
+        options = {
+          remoteAddress = mkOption {
+            type = types.str;
+          };
+          peerName = mkOption {
+            type = types.str;
+          };
+        };
+      }));
+      default = {};
+      description = "External bgp peers";
+    };
+    bgpPeers = mkOption {
+      type = with types; listOf (submodule ({ ... }: {
+        options = {
+          localAddress = mkOption {
+            type = types.str;
+          };
+          remoteAddress = mkOption {
+            type = types.str;
+          };
+          peerName = mkOption {
+            type = types.str;
+          };
+          remoteAsn = mkOption {
+            type = types.str;
+          };
+        };
+      }));
+      default = {};
+      description = "External bgp peers";
+    };
+    wireguardPeers = mkOption {
+      type = with types; listOf (submodule ({ ... }: {
+        options = {
+          interfaceName = mkOption {
+            type = types.str;
+          };
+          localAddress = mkOption {
+            type = types.str;
+          };
+          #localAddressPrefixlen = ;
+          remoteAddress = mkOption {
+            type = types.str;
+          };
+          #remoteAddressPrefixlen = ;
+          #localPrivateKey = ;
+          #remotePublicKey = ;
+          #localListenPort = ;
+          #remoteEnpoint = ;
+          peerName = mkOption {
+            type = types.str;
+          };
+          remoteAsn = mkOption {
+            type = types.str;
+          };
+        };
+      }));
+      default = [];
+      description = "External bgp peers";
+    };
+    birdExtraConfig = mkOption {
+      type = types.str;
+      default = "";
+    };
+  };
+
+  config = mkIf config.profiles.clerie.dn42-router.enable {
+
+    systemd.network.config.routeTables = {
+      bgp6 = bgp6Table;
+      ospf6 = ospf6Table;
+    };
+    systemd.network.config.addRouteTablesToIPRoute2 = true;
+
+    systemd.network.netdevs."10-lo-dn42" = {
+      netdevConfig = {
+        Kind = "dummy";
+        Name = "lo-dn42";
+      };
+    };
+
+    systemd.network.networks."10-lo-dn42" = {
+      matchConfig.Name = "lo-dn42";
+      address = [ "${ cfg.loopbackIp }/128" ];
+      linkConfig.RequiredForOnline = "no";
+      routingPolicyRules = [
+        {
+          Priority = 10000;
+          Family = "ipv6";
+          To = "fd56:4902:eca0::/48";
+          Table = "ospf6";
+        }
+        {
+          Priority = 11000;
+          Family = "ipv6";
+          Table = "bgp6";
+        }
+        {
+          Priority = 15000;
+          Family = "ipv6";
+          From = "fd56:4902:eca0::/48";
+          Type = "unreachable";
+        }
+        {
+          Priority = 16000;
+          Family = "ipv6";
+          To = "fd56:4902:eca0::/48";
+          Type = "unreachable";
+        }
+        {
+          Priority = 20000;
+          Family = "both";
+          Table = "main";
+        }
+      ];
+    };
+
+    services.bird.enable = true;
+    services.bird.package = pkgs.bird2;
+    services.bird.config = ''
+      router id ${ cfg.routerId };
+  
+      ipv6 table ospf6;
+      ipv6 table bgp6;
+  
+      protocol direct {
+        interface "lo-dn42";
+        ipv6 {
+          table ospf6;
+        };
+      }
+  
+      protocol static {
+        ipv6 {
+          table bgp6;
+        };
+        route fd56:4902:eca0::/48 via "lo-dn42";
+      }
+  
+      protocol kernel {
+        ipv6 {
+          table ospf6;
+          export filter {
+            krt_prefsrc=${ cfg.loopbackIp };
+            accept;
+          };
+          import none;
+        };
+        kernel table ${ toString ospf6Table };
+      }
+  
+      protocol kernel {
+        ipv6 {
+          table bgp6;
+          export filter {
+            krt_prefsrc=${ cfg.loopbackIp };
+            accept;
+          };
+          import none;
+        };
+        kernel table ${ toString bgp6Table };
+      }
+
+      protocol device {
+        scan time 10;
+      }
+
+      protocol ospf v3 {
+        ipv6 {
+          table ospf6;
+          import all;
+          export all;
+        };
+        area 0 {
+          ${ concatMapStringsSep "\n" (interfaceName: ''
+          interface "${interfaceName}" {
+            cost 80;
+            type broadcast;
+          };
+          '') cfg.ospfInterfaces}
+        };
+      }
+    
+      template bgp ibgp_peer {
+        local as ${ toString myAsn };
+        graceful restart on;
+        source address ${ cfg.loopbackIp};
+        ipv6 {
+          table bgp6;
+          igp table ospf6;
+          next hop self;
+          import keep filtered;
+          import all;
+          export all;
+        };
+      }
+    
+      ${concatMapStringsSep "\n" ( peerConfig: ''
+      protocol bgp ${peerConfig.peerName} from ibgp_peer {
+        neighbor ${peerConfig.remoteAddress} as ${ toString myAsn };
+      }
+      '') cfg.ibgpPeers}
+
+      template bgp bgp_peer {
+        local as ${ toString myAsn };
+        graceful restart on;
+        ipv6 {
+          table bgp6;
+          next hop self;
+          import keep filtered;
+          import filter {
+            if net ~ [fd00::/8{48,64}] then accept;
+            reject;
+          };
+          export filter {
+            if net ~ [fd00::/8{48,64}] then accept;
+            reject;
+          };
+        };
+      }
+
+      ${concatMapStringsSep "\n" ( peerConfig: ''
+      protocol bgp ${peerConfig.peerName} from bgp_peer {
+        neighbor ${peerConfig.remoteAddress} as ${peerConfig.remoteAsn};
+        source address ${peerConfig.localAddress};
+      }
+      '') cfg.bgpPeers}
+
+      ${concatMapStringsSep "\n" ( peerConfig: ''
+      protocol bgp ${peerConfig.peerName} from bgp_peer {
+        neighbor ${peerConfig.remoteAddress}%${peerConfig.interfaceName} as ${peerConfig.remoteAsn};
+        source address ${peerConfig.localAddress};
+      }
+      '') cfg.wireguardPeers}
+
+      ${ cfg.birdExtraConfig }
+
+    '';
+  
+  };
+}