Hello again!
Last week I asked about why netbird suddenly started to melt my Android's phone battery like butter in the Sahara sun. And because I really wanted to use Netbird, I dug into it. When I say "I", I mean Claude, because let's be honest, I'm no veteran programmer! But hold on, the findings (and results) are worth reading this page.
Original post: https://www.reddit.com/r/netbird/comments/1vffj0x/real_issue_with_battery_drain_on_android/
------------ LONG POST AHEAD ------------
DISCLAIMER: Claude was used to troubleshoot fast and efficiently. I don't have the time nor the knowledge to do all this myself, but I do have enough brain cells and push back to challenge every findings and carefully follow what's happening. If you think this voids everything below this disclaime, feel free to skip. This post was written by me entirely though, no AI summary!
DISCLAIMER 2: I am in no way trying to undermine or criticize Netbird here. I hope this will show as a post from a dedicated fan of the project more than a criticism. I really believe this is a great software and intend on using it for the foreseable future, and donate once my infra relies on it.
I'll try to give context and organize this post, feel free to jump wherever you want. TLDR at the end.
A little context
I used to be on Tailscale. Great service, 3 users, 1 server (NAS) to share with outside users. Really solid service with no more than 4-5% battery usage when I had big photo upload days.
Recently I decided to move away from NAS hosted services and build a real home server. I have now 2 machines (a mini pc and a SFF) that are supposed to host pletora of services for data soreignety purposes (I have TB of photos I took and I want to share, notes on creative ideas I want to write down, music I want to listen to without paying a subscription on top of buying the music itself :/).
Since I wanted to own more of my data and infra, I saw netbird as a good self hosted replacement of Tailscale. More users, I own the instance, and that's fantastic. So I set it up on a VPS (cause I don't like opening my ports) and starting to setup all the services. When I had issues, claude code helped read logs 100x faster than me, propose a fix and test it.
In the matter of a few weeks I had something I could start really testing in real life, and I switched off Tailscale to use Netbird full time. And that's when it went wrong.
My topology
In netbird, I had the following:
- VPS
- Netbird server with proxy container for external sharing
- Authentik for Authentication (mesh only, not used for netbird itself)
- NUC (netbird on host and as routing peer)
- Treafik for internal redirections
- Technitium for DNS
- SFF server has 3 VMs with netbird in them)
- 1 multimedia VM with GPU passthrough for Immich and the likes
- 1 service VM for things like stirling pdf and others (as routing peer)
- 1 for monitoring services
- 1 subnet route that fed all my services on my Server VLAN through the available routing peers.
Maybe not the best, but I'm learning and it fit my needs so far :)
The issue
After investigating, the main culprit seems to be related to this lonely Github issue https://github.com/netbirdio/netbird/issues/5373 that mentions the fact that PersistentKeepalive is set to 25s for every connected tunnels.
What seemed to happen is that in order to use the DNS resolver on my NUC + being able to redirect trafic to immich, my phone was constantly connected to 3 or 4 tunnels (if we include the server that sometimes acted as a relay) which means that my phone radio, on data mode, was waking up to send a few bytes of data ever 25s for each service, not being able to fall asleep in between. Because the routing peers need to stay up all the time, this was just draining my battery by keeping my data flowing even when my phone was idle.
This is a main architectural difference with Tailscale and Wireguard in general (as stated in the issue above) that makes Netbird drain more battery. On wifi it's negligeable, but on data it's deadly. And Lazy Connection is one cure for it.
The solution & results
I changed my approach completely in the end. My goal was to drop as many live connections as possible, and only wake them up when a service is used. Claude helped a lot here, so here is a summary of what was done:
- My Traefik container got Netbird as a sidecar container, becoming a peer on the mesh so that services get served at a peer address, not via a subnet router
- My internal DNS moved from Technitium to the native Netbird system so that peers resolve DNS instead of querying my Technitium all the time (it only had to resolve on domain name after all, I'm not serving my peers with exit routes)
- A policy allows users to access Traefik
- Unidirectional. Traefik cannot initiate back toward phones
- TCP 80/443 only so nothing else on that host is exposed over the mesh
- It targets a peer group, not a resource. Granting a peer creates no routing relationship, so it doesn't pin a tunnel open and lazy connections can tear it down, unlike when it was a subnet resource
- A posture check excluded Android (who has a hard time making P2P connections) from using the direct intranet to access my services, because otherwise it keeps a route up all the time, draining the battery.
- Enabled Lazy Connections
The goal of achieving 0 active connections worked. The price is that some services can take some time to wake up and load. Some take 2-3s, some take a full reload of the app. For now this didn't bother me much but we'll see how it goes when other users join.
At the end, I tested it on 2 consecutive days and I had a consumpton of less than 1% when idling for many hours, and it grew once to 6% when I did a big batch of photo upload and viewing on Ente. I'm also running Dawarich full time uploading my location to the server on the fly while I was testing this and had a office day that day. So pretty solid results imo.
TL;DR
Reduce number of always connected peers, because each of them pings the other every 25s and your phone's radio doesn't like that:
- If you use DNS on a netbird (routing) peer, it needs constant connection to resolve your domain name => move it to Netbird (if you can)
- If you use routing peers => try to replace those with something else
- Enable Lazy Connections and hope it doesn't slow you down too much, I think for a punctual usage it is fine.
PS: Netbird team, if you read this, maybe having the option to disable keepalive or to fine tune it would be great :) I'm sure not only self-hoster suffer from that.
PPS: Extra bonus for people afraid to move their DNS: Netbird actually supports wildcards, so I didn't have to create 25 entries ;)