

Running it on a couple of small sites. It is exactly what the pitch says: one Go binary or one container, a single Postgres/SQLite DB, one script tag. Points worth knowing before you commit:
- The hosted version has a free tier for non-commercial sites; self-hosting is completely free, no account needed, and backup is just “dump the database”.
- Because it counts pageviews anonymously by design, there are no funnels, sessions, or referrer chains like Plausible/Matomo. It deliberately does not keep enough data for that. If you might want path analysis later, that is the one thing Goatcounter will not give you.
- Bot filtering is reasonable out of the box; on a small tech site I saw roughly 30-40% of raw hits classified as bots, which matched my nginx log estimates well.
- Self-host gotcha: behind a reverse proxy, make sure you pass the real client IP (X-Forwarded-For), or everything counts as one visitor from the proxy address.
For the “step counter” use case you describe, it is the best fit in this space. The moment you want cohort/behavior analytics is when Matomo or Plausible earn their resource cost.
Your setup is close — the missing piece is usually that the GL.iNet router needs to actually route LAN clients’ traffic into the Netbird tunnel, which Netbird alone doesn’t do: Netbird creates the tunnel interface on the router, but clients behind it don’t enter that tunnel automatically.
Two things to check:
Masquerade into the Netbird interface. SSH into the GL.iNet and make sure LAN traffic is NATed into wt0 (Netbird’s interface):
iptables -t nat -A POSTROUTING -o wt0 -j MASQUERADEWithout that, replies from Jellyfin head back to the router itself instead of the client, and the connection dies silently. GL.iNet firmware sometimes intercepts this with its own client-management rules, so verify with a client-side test, not just the config screen.
Don’t make the router a routing peer unless it needs to be. Your resource is a single IP (Jellyfin’s Netbird IP), so group-based access control should suffice once traffic reaches wt0. Routing peers are for distributing whole subnet routes — and since routes are deprecated in favor of Networks, mixing the two models is exactly why this config gets confusing.
Quick test order that isolates the failure:
pingJellyfin’s Netbird IP (tests tunnel + ACL).Also double-check the access-control direction: the group on the client side (router) needs to be granted access to the resource — having Jellyfin in a group alone doesn’t create the permission.