<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jagoum</title>
    <description>The latest articles on DEV Community by Jagoum (@jagoum).</description>
    <link>https://dev.to/jagoum</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2563774%2F3e35a9fb-3434-48d7-9152-c301036f8d51.jpg</url>
      <title>DEV Community: Jagoum</title>
      <link>https://dev.to/jagoum</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jagoum"/>
    <language>en</language>
    <item>
      <title>How Two Processes Fighting Over One WireGuard Interface Broke Our NetBird Mesh in Kubernetes</title>
      <dc:creator>Jagoum</dc:creator>
      <pubDate>Wed, 15 Jul 2026 13:25:18 +0000</pubDate>
      <link>https://dev.to/jagoum/how-two-processes-fighting-over-one-wireguard-interface-broke-our-netbird-mesh-in-kubernetes-1b4o</link>
      <guid>https://dev.to/jagoum/how-two-processes-fighting-over-one-wireguard-interface-broke-our-netbird-mesh-in-kubernetes-1b4o</guid>
      <description>&lt;h2&gt;
  
  
  How Two Processes Fighting Over One WireGuard Interface Broke Our NetBird Mesh in Kubernetes
&lt;/h2&gt;

&lt;p&gt;We run &lt;a href="https://netbird.io/" rel="noopener noreferrer"&gt;NetBird&lt;/a&gt; as a WireGuard mesh overlay across our OpenStack Kubernetes cluster. Three router pods (DaemonSet) advertise K8s service and pod CIDRs to remote agents over the mesh. One proxy pod forwards agent traffic to K8s ClusterIPs.&lt;/p&gt;

&lt;p&gt;Last week, all three routers went unstable — relays disconnected, peers dropped to 0/0, and the engine entered a restart loop with 256+ restarts. Here's how we found and fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Symptoms
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Management: Connected
Signal: Connected  
Relays: 0/1 Available    ← only 1 relay, none connected
Networks: -              ← CIDRs not advertised
Peers: 0/0 Connected     ← nobody can reach us
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meanwhile, the proxy pod on the same cluster was rock-solid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Management: Connected
Relays: 3/3 Available
Peers: 7/14 Connected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both were running the same NetBird version (0.73.2), same setup key, same management URL. But the routers were dying and the proxy wasn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigation: Layer by Layer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Layer 1: Version Mismatch (Red Herring)
&lt;/h3&gt;

&lt;p&gt;The original symptom was &lt;code&gt;failed to handle new offer: relay connection is not established&lt;/code&gt; and relay WebSocket connections dying with &lt;code&gt;EOF&lt;/code&gt; every ~1.6 seconds. We'd recently upgraded the routers from 0.73.2 to 0.74.2, but the self-hosted relay server was still 0.73.x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Downgraded routers back to 0.73.2. The relay connection storms stopped. But the instability remained.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: Stale WireGuard Interfaces
&lt;/h3&gt;

&lt;p&gt;After the downgrade, two routers couldn't bind port 51820 — the old WireGuard interface (&lt;code&gt;wt0&lt;/code&gt;) persisted on the node from the previous pod. We deleted the stale interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; netbird-system &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; ip &lt;span class="nb"&gt;link &lt;/span&gt;delete wt0
kubectl delete pod &lt;span class="nt"&gt;-n&lt;/span&gt; netbird-system &amp;lt;pod&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Workers 2 and 3 recovered. Worker-1 didn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: The Dual-Process Bug
&lt;/h3&gt;

&lt;p&gt;Worker-1's logs told the real story:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2026-07-14T14:50:14.631Z netbird WireGuard interface monitor: interface wt0 deleted, restarting engine
2026-07-14T14:50:15.354Z netbird stopped Netbird Engine
2026-07-14T14:50:16.098Z netbird new WireGuard interface wt0 has been created
2026-07-14T14:50:18.307Z netbird WireGuard interface monitor: interface wt0 deleted, restarting engine
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;WGIfaceMonitor&lt;/code&gt; was detecting &lt;code&gt;wt0&lt;/code&gt; deletions every few seconds, triggering engine restarts in a loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The root cause&lt;/strong&gt;: The DaemonSet had no explicit &lt;code&gt;command&lt;/code&gt;, so it used the image's default entrypoint. That entrypoint does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NETBIRD_BIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; service run &amp;amp;    &lt;span class="c"&gt;# Process 1: daemon mode&lt;/span&gt;
  wait_for_daemon_startup 30
  connect                           &lt;span class="c"&gt;# Process 2: "netbird up" (foreground)&lt;/span&gt;
  &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;service_pids&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Two independent NetBird engines were running in the same container&lt;/strong&gt;, both managing separate WireGuard interfaces, both fighting for the same management gRPC connection. The &lt;code&gt;service run&lt;/code&gt; daemon would create &lt;code&gt;wt0&lt;/code&gt;, the foreground &lt;code&gt;netbird up&lt;/code&gt; process would see the conflict and interfere, the monitor would detect the interference as a deletion, and the engine would restart.&lt;/p&gt;

&lt;p&gt;The proxy pod was stable because it explicitly sets &lt;code&gt;command: ["netbird", "service", "run"]&lt;/code&gt; — a single process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 4: Cilium WireGuard Port Conflict
&lt;/h3&gt;

&lt;p&gt;Compounding the problem: Cilium has &lt;code&gt;enable-wireguard: true&lt;/code&gt;, which creates &lt;code&gt;cilium_wg0&lt;/code&gt; on every node. The kernel WireGuard module binds UDP port 51820 with no visible userspace process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ss &lt;span class="nt"&gt;-ulnp&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;51820
UNCONN  0  0  0.0.0.0:51820  ← kernel socket, no process owner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NetBird's default WireGuard port is also 51820. With the kernel socket holding the port, NetBird falls back to random ports — which works but adds instability when combined with the dual-process fight.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 5: Missing Hardening
&lt;/h3&gt;

&lt;p&gt;The proxy had these env vars set but the routers didn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NB_DISABLE_NAT_MAPPER=true&lt;/code&gt; — disables UPnP discovery (useless on cloud VMs, clutters logs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NB_DISABLE_EBPF_WG_PROXY=true&lt;/code&gt; — disables eBPF proxy that can hold ports across restarts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Match the proxy's configuration. One command change + two env vars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;netbird&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;netbird"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# ← explicit single process&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_SETUP_KEY&lt;/span&gt;
    &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;setup_key&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;netbird-router-setup-key&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_WIREGUARD_PORT&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;51820"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_MANAGEMENT_URL&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://netbird.vpn.skyengpro.app:443"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_HOSTNAME&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$(NODE_NAME)"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_DISABLE_NAT_MAPPER&lt;/span&gt;           &lt;span class="c1"&gt;# ← new&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NB_DISABLE_EBPF_WG_PROXY&lt;/span&gt;        &lt;span class="c1"&gt;# ← new&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The liveness probe also needed updating to only check for the single process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pgrep&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-f&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'netbird&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;service'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;/dev/null&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;||&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;kill&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  After the Fix
&lt;/h2&gt;

&lt;p&gt;All three routers went from broken to fully stable:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Worker-1&lt;/th&gt;
&lt;th&gt;Worker-2&lt;/th&gt;
&lt;th&gt;Worker-3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0/0 peers, 256 restarts&lt;/td&gt;
&lt;td&gt;0/0 peers, 264 restarts&lt;/td&gt;
&lt;td&gt;3-5/13 peers, flapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7/13 peers, 0 restarts&lt;/td&gt;
&lt;td&gt;7/13 peers, 0 restarts&lt;/td&gt;
&lt;td&gt;7/13 peers, 0 restarts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Management ✅ Signal ✅ Relays: 3/3 ✅ Networks: 10.20.96.0/19 ✅&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The proxy was your best reference implementation.&lt;/strong&gt; It was the only stable component all along. When debugging, compare working vs broken configs line by line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Image entrypoints can surprise you.&lt;/strong&gt; We didn't set a &lt;code&gt;command&lt;/code&gt; in the DaemonSet, so we got the image's default entrypoint — which runs two processes. Always check &lt;code&gt;docker inspect &amp;lt;image&amp;gt;&lt;/code&gt; or read the Dockerfile before deploying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Kernel WireGuard modules don't show in &lt;code&gt;ss -ulnp&lt;/code&gt;.&lt;/strong&gt; The &lt;code&gt;cilium_wg0&lt;/code&gt; socket was invisible because the kernel module owns it, not a userspace process. This caused confusing "port 51820 is in use" messages with no visible process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. HostNetwork pods share the host's WireGuard module state.&lt;/strong&gt; Stale &lt;code&gt;wt0&lt;/code&gt; interfaces survive pod deletion. When rolling out new pods, you may need to clean up old interfaces first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Don't mix &lt;code&gt;service run&lt;/code&gt; and foreground &lt;code&gt;netbird up&lt;/code&gt;.&lt;/strong&gt; They're two independent engines that fight over the same interface name and management connection. Pick one.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The DaemonSet's default entrypoint started &lt;strong&gt;two NetBird engines&lt;/strong&gt; in the same container. They fought over the &lt;code&gt;wt0&lt;/code&gt; WireGuard interface, causing an infinite restart loop. The fix: explicitly set &lt;code&gt;command: ["netbird", "service", "run"]&lt;/code&gt; and add &lt;code&gt;NB_DISABLE_NAT_MAPPER=true&lt;/code&gt; + &lt;code&gt;NB_DISABLE_EBPF_WG_PROXY=true&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you're running NetBird in Kubernetes, check your DaemonSet entrypoint. If it doesn't explicitly set &lt;code&gt;command&lt;/code&gt;, you might have the same dual-process bug hiding in plain sight.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>networking</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>My First Ever Global Hackathan, With MIT Sloan was an amazing experience. Do i did not win, but i got experience.</title>
      <dc:creator>Jagoum</dc:creator>
      <pubDate>Mon, 11 Aug 2025 06:40:40 +0000</pubDate>
      <link>https://dev.to/jagoum/my-first-ever-global-hackathan-with-mit-sloan-was-an-amazing-experience-do-i-did-not-win-but-i-1lk2</link>
      <guid>https://dev.to/jagoum/my-first-ever-global-hackathan-with-mit-sloan-was-an-amazing-experience-do-i-did-not-win-but-i-1lk2</guid>
      <description></description>
      <category>hackathon</category>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>One of My first Programming language I learned.</title>
      <dc:creator>Jagoum</dc:creator>
      <pubDate>Thu, 19 Dec 2024 00:00:38 +0000</pubDate>
      <link>https://dev.to/jagoum/one-of-my-first-programming-language-i-learned-485g</link>
      <guid>https://dev.to/jagoum/one-of-my-first-programming-language-i-learned-485g</guid>
      <description>&lt;p&gt;On the first language I learned in my life was HTML while I was still in secondary school and never even had the idea of becoming a software engineer. It was very fun to learn and to see how website are actually being developed.&lt;br&gt;
I learned C programming language when I was writing my exams to leave secondary school. And go to high school. There I fell in love with it .&lt;/p&gt;

&lt;p&gt;I loved it because I could actually write a program that can solve a problem like calculating numbers when I wrote my first calculator program in C.&lt;br&gt;
After my advanced level I obtained a scholarship into a preemployment training program by adorsys in Cameroon I am currently working.&lt;/p&gt;

&lt;p&gt;I obtained my LPIC-1 there with 100% in both 101 &amp;amp; 102&lt;/p&gt;

&lt;p&gt;So right now I am currently studying rust and java programming languages.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
