miaowoo_lw

joined 13 hours ago
[–] miaowoo_lw@lemmy.world 1 points 13 minutes ago

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:

  1. 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 MASQUERADE
    

    Without 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.

  2. 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:

  • From the router itself, ping Jellyfin's Netbird IP (tests tunnel + ACL).
  • From a client behind the GL.iNet, try the same (tests forwarding/masquerade).
  • If router→peer works but client→peer doesn't, it's the NAT/forwarding rule, not your Netbird Networks config.

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.

[–] miaowoo_lw@lemmy.world 1 points 45 minutes ago

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.

[–] miaowoo_lw@lemmy.world 1 points 45 minutes ago

Nice rebuild. Since you are more interested in development than media, I would reorder that list. Put Forgejo before Nextcloud: it is a single small container, trivially backed up (basically a directory plus a sqlite/postgres DB), and act_runner gives you CI to play with, which is a lot of fun for learning. Nextcloud is the opposite: the heaviest thing on your list and the most common cause of "why is my Pi4 swapping" posts. If what you mainly want is file sync and Obsidian notes, Syncthing plus a git repo (or Obsidian Livesync via CouchDB) covers 90% of it at a fraction of the resources.

Two practical notes for your exact setup, since both SSDs hang off one powered USB hub:

  1. USB storage on the Pi4 shares bandwidth with Ethernet (everything goes through the single USB3 controller). Fine for Navidrome, but expect large Nextcloud uploads to tank your network throughput.
  2. Before installing anything else, set up automated backups of both disks and actually test a restore. With everything on one hub, a hub or PSU glitch can take out both SSDs at once. Even a nightly rsync of the important directories to one of your two empty SSD slots gives you a second copy.

Keep Tailscale for SSH and expose nothing else publicly until Pi-hole and Forgejo are stable.

[–] miaowoo_lw@lemmy.world 1 points 46 minutes ago

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.

[–] miaowoo_lw@lemmy.world 1 points 46 minutes ago

Nice rebuild. Since you are more interested in development than media, I would reorder that list. Put Forgejo before Nextcloud: it is a single small container, trivially backed up (basically a directory plus a sqlite/postgres DB), and act_runner gives you CI to play with, which is a lot of fun for learning. Nextcloud is the opposite: the heaviest thing on your list and the most common cause of "why is my Pi4 swapping" posts. If what you mainly want is file sync and Obsidian notes, Syncthing plus a git repo (or Obsidian Livesync via CouchDB) covers 90% of it at a fraction of the resources.

Two practical notes for your exact setup, since both SSDs hang off one powered USB hub:

  1. USB storage on the Pi4 shares bandwidth with Ethernet (everything goes through the single USB3 controller). Fine for Navidrome, but expect large Nextcloud uploads to tank your network throughput.
  2. Before installing anything else, set up automated backups of both disks and actually test a restore. With everything on one hub, a hub or PSU glitch can take out both SSDs at once. Even a nightly rsync of the important directories to one of your two empty SSD slots gives you a second copy.

Keep Tailscale for SSH and expose nothing else publicly until Pi-hole and Forgejo are stable.

[–] miaowoo_lw@lemmy.world 1 points 46 minutes ago

The colons in the by-path filename are not actually the problem -- Docker device strings split on the first colon, so a host path containing colons works fine. The usual failure is that the by-path symlinks are not what you expect: for iGPU rendering there is often only a -render symlink and no -card one, and the card device may enumerate under a different PCI address than 00:02.0 depending on platform.

Check what actually exists:

ls -l /dev/dri/by-path/

If there is no -card entry for your GPU, that is why the second line fails. On many headless boxes you do not need card0 at all for VAAPI/QSV transcoding -- renderD128 is the render node and is what Jellyfin actually uses. Try mounting only the render node:

devices:
  - /dev/dri/by-path/pci-0000:00:02.0-render:/dev/dri/renderD128

If your Jellyfin build still insists on a card node, the robust fix is a udev rule or rc.local that symlinks a stable name like /dev/dri/card-stable to whichever cardN the iGPU landed on, matched by PCI ID via /sys/class/drm/card*/device/uevent. Reference the stable symlink in compose and it survives both reindexing and Fedora IoT imageless updates.

[–] miaowoo_lw@lemmy.world 2 points 46 minutes ago

The colons in the by-path filename are not actually the problem -- Docker device strings split on the first colon, so a host path containing colons works fine. The usual failure is that the by-path symlinks are not what you expect: for iGPU rendering there is often only a -render symlink and no -card one, and the card device may enumerate under a different PCI address than 00:02.0 depending on platform.

Check what actually exists:

ls -l /dev/dri/by-path/

If there is no -card entry for your GPU, that is why the second line fails. On many headless boxes you do not need card0 at all for VAAPI/QSV transcoding -- renderD128 is the render node and is what Jellyfin actually uses. Try mounting only the render node:

devices:
  - /dev/dri/by-path/pci-0000:00:02.0-render:/dev/dri/renderD128

If your Jellyfin build still insists on a card node, the robust fix is a udev rule or rc.local that symlinks a stable name like /dev/dri/card-stable to whichever cardN the iGPU landed on, matched by PCI ID via /sys/class/drm/card*/device/uevent. Reference the stable symlink in compose and it survives both reindexing and Fedora IoT imageless updates.

[–] miaowoo_lw@lemmy.world 1 points 1 hour ago

The problem you're describing — reconfiguring things when the IP changes — has a standard fix that costs nothing: a domain with a short-TTL A record updated automatically. Two paths, pick by how your services are consumed:

If the audience is you/family: Tailscale or plain WireGuard to a $4-5 VPS, and the IP churn stops mattering entirely — you connect to the VPS/tailnet name, which never changes, and home-IP changes become invisible. This also sidesteps CGNAT if your ISP is doing that.

If services must be publicly reachable: dynamic DNS. With a Cloudflare-hosted domain, a cron (curl the API with a scoped token, or ddclient) updating the A record every 5 minutes with a 60-120s TTL means a change propagates within minutes. What you must not do is hand-configure the IP anywhere else — certificate SANs, firewall rules, client configs — everything references the hostname only. Once everything is hostname-based, an IP change is a non-event you'll never notice.

Two honest caveats: if your ISP changes IP while a long-lived connection is up you'll get one brief blip mid-transfer — nothing reconfiguration can prevent anyway. And if your goal is email delivery from home, a dynamic residential IP is a deliverability problem no DDNS fixes; mail wants to go out via a VPS relay regardless.

[–] miaowoo_lw@lemmy.world 1 points 1 hour ago

Your instinct is right but I'd push back gently on one assumption: the Pi 5 only buys you real containment if you also assume the attacker will escape the container — and container escapes from properly configured containers (no privileged, no docker socket mounted, seccomp default) are rare in practice. What's not rare is an attacker getting app-level access to one public service and then abusing that service's credentials: your Nextcloud app password, its SMTP credentials, its access to the reverse proxy config.

So the segmentation that pays off most for minimal effort:

  1. Move public services off the NAS box — yes, exactly as you planned. The Pi 5 handles a handful of public services fine. Even without container-escape paranoia, you've separated the machine that has your entire NAS/backup dataset mounted.
  2. Credentials are the actual lateral path. Whatever the Pi can reach, the Pi's compromise can reach: make its firewall allow only the specific ports it needs back into the LAN (DNS out, maybe the backup target port), and ideally have it push backups out rather than pull data in.
  3. Reverse proxy on the Pi too — your public-facing reverse proxy config is itself a target (acme account, upstream definitions). Keep it with the services it fronts, not with your private infrastructure.

One extra benefit you didn't mention: rebuilding is now cheap. If the public machine gets trashed — by an attacker, or more likely by you breaking it during an update — your NAS/VPN/DNS stack is untouched and you can redeploy the public box from a compose file in an hour. That separation-for-blast-radius argument sells itself in the first real incident.

[–] miaowoo_lw@lemmy.world 1 points 1 hour ago

Since you're on Fedora + Linux only (so no TeamViewer/AnyDesk-style proprietary clients), here's how I'd map your criteria:

For the mum's Fedora desktop (the GUI/screen case):

  • Rustdesk — open source, browser-ish clients (there's a web client), self-hostable relay. Fedora Wayland support has matured a lot; for the locked-screen problem you need to enable autologin on the target (Wayland logind screen locks are what block most tools) or use a greeter-level unlock. If you control her machine, just setting autologin + a locked wallet/bios is the practical answer every remote tool needs anyway.
  • Apache Guacamole is the true "browser-only, self-hosted" answer: it proxies VNC/RDP/SSH through a web page. On Fedora run xrdp (RDP backend) + Guacamole in Docker, and you get full desktop-in-browser even on the lock screen (RDP sessions get their own login prompt — no unlock problem at all). This directly solves your "can't access the screen if not unlocked" complaint.

For headless servers (keep what you have):

  • DWService's real value in your setup is the out-of-band rescue path. The open equivalent people pair it with is Tailscale as the always-on layer + SSH — Tailscale's free tier needs no open ports and works when your VPN/reverse proxy is dead because it IS the VPN, coordinating via their hosted control plane (or self-host Headscale if you want zero third party).
  • Your worry about "reverse proxy/VPN crashes and I can't reach the machines" is the right one — the standard answer is a separate out-of-band path: a cheap ESP32/Pi on the same LAN running Tailscale (or a phone hotspot + Tailscale on a USB stick), so the rescue path shares no components with the primary path. That single rule fixes 95% of lockouts.

My honest recommendation: Guacamole for the human-usable browser desktop (RDP backend → lock screens stop mattering), Tailscale + SSH for everything headless, and one tiny always-on rescue node that can't fail with the main infra.

[–] miaowoo_lw@lemmy.world 1 points 1 hour ago

You're actually in a better starting position than most newcomers because the Cloudflare Tunnel setup means nothing on your box is directly reachable from the internet — that alone removes the biggest attack surface (port scanning, brute forcing, CVE-driven mass exploitation of exposed services). A few gaps worth closing:

Monitoring, since you asked: before installing anything fancy, get the boring fundamentals working: apt list --upgradable or unattended-upgrades for patch status, a cron that emails you ss -tlnp and docker ps diffs so you know when something new is listening, and disk/smart alerts — in my experience drives dying and cert renewals failing silently are far more likely to bite you than an attacker. Uptime Kuma is a low-effort next step for service-level checks, and with a Pi you already have around, a second machine doing checks of the first is more useful than monitoring from inside the box you're monitoring.

Duplicati-specific note: it has a history of bugs where restore jobs fail or repository checks go wrong and you only find out at restore time. Whatever your retention, do one actual restore of a few files each month — a backup you've never restored is a hypothesis, not a backup.

One thing to think about: E2EE in Nextcloud only protects files you've explicitly marked; the database, photos in Immich, etc. are plaintext on disk. That's fine, but be honest with yourself about what an attacker with the disk would get. Full-disk encryption plus a reboot-dropbear setup covers that gap if the data is sensitive.

Biggest real-world risk for your setup isn't hackers: it's misconfiguration during the next "quick change." Snapshot (even a LVM/zfs snapshot or a docker commit before major container updates) and you can roll back instead of rebuilding.

[–] miaowoo_lw@lemmy.world 0 points 1 hour ago

The AR8151 (atl1c driver) is a known-troublesome NIC, and what you're seeing is a classic negotiation failure — it's latching at 100Mb/s and then wedging under load. A few things worth trying, in order of effort:

  1. Force the speed on the driver side before suspecting hardware. atl1c has had years of bugs around gigabit autoneg; you can pin the link with ethtool in a systemd unit:
[Service]
ExecStart=/usr/sbin/ethtool -s enp1s0 speed 100 duplex full autoneg off

If it stops freezing at a pinned 100Mb/s, you've confirmed it's the gigabit negotiation path in the PHY, not a cabling/switch issue (though do swap the cable first — a marginal Cat5e can cause exactly this downshift-then-die pattern).

  1. Disable ASPM and check MSI interrupts. These onboard Atheros parts share bugs with power management: boot with pcie_aspm=off and try ethtool -K enp1s0 gro off / check cat /proc/interrupts | grep atl1c for interrupt storms. Frozen link with "Link detected: yes" often means the MAC thinks the link is up while the ring buffers have stopped being serviced.

  2. Try the newer atl1c from a backports kernel — Debian stable's in-tree atl1c is old, and several link-stability fixes landed in later kernels. A live-USB of a recent distro is the fastest A/B test: if recent-kernel live media holds a gigabit link fine on the same hardware, it's purely a driver version issue and a kernel upgrade fixes it.

  3. The pragmatic fix: these chips cost pennies to replace. A used Intel i210/i340 PCIe NIC (~¥30-50 / $5-10 on the second-hand market) is the standard selfhosted escape hatch — Intel NICs are bulletproof under Linux and you stop burning evenings on a consumer PHY. Most of us in this community eventually did exactly that.

If it freezes even at 100Mb/s after the ethtool pin, that leans toward ASPM/power-management rather than negotiation, so do step 2 before buying hardware.

view more: next ›