DEV Community

ChenXX
ChenXX

Posted on

Tunneling From a Raspberry Pi: How FRP Actually Behaves on Low-Power ARM Hardware

A Raspberry Pi is the most common way people first meet FRP. You've got Home Assistant, a small web dashboard, maybe a Minecraft server for the kids — all sitting on the Pi, all needing to be reachable from outside the house.

So you install FRP on the Pi and expose it. Then you open a second terminal and think: is this really what I need every time? And whether you should run frpc from a config file, or a tray-based GUI client that assumes someone's sitting at the machine.

Here's what actually happens on real hardware.

The short version

FRP's client (frpc) is a single static Go binary. On a Pi it's cheap — it's a Go daemon with no runtime dependencies, near-zero CPU when idle, and it doesn't need a desktop environment. For a headless Pi you SSH into, frpc is genuinely the right tool and I'd keep using it.

The friction starts when the Pi isn't yours alone. Family members, a partner, or yourself two weeks later — now the SSH + edit + restart loop is the thing that costs time.

What the Pi actually costs you

The tunnel itself is cheap. The process management around it is what isn't:

  • It doesn't survive a reboot. Your SSH session is gone, so nothing restarts frpc unless you wrote a systemd unit.
  • It doesn't tell you it's dead. If frpc crashes, your public address just starts refusing connections, and you find out when a user complains.
  • Changing one port means editing TOML over SSH. Fine for you. Not fine for someone who isn't sure what localPort vs remotePort means.
  • There's no status you can glance at. On a headless box you'd run systemctl status frpc or journalctl — which is a terminal, every time.

None of this is a criticism of FRP. frpc is a great tool. It's that the operating model assumes you live in a terminal, and a Pi sitting under a desk is precisely a machine nobody sits at.

The ARM reality check

People assume a GUI will be too heavy for a Pi. The tradeoffs to weigh:

frpc (headless) Tauri GUI client
Desktop required No Yes — needs a display
Survives reboot Only via systemd Native launch-at-login
Crash visibility journalctl On-screen state + health polling
Edit a tunnel Edit TOML over SSH Click
Memory Modest — a static Go daemon Higher — GUI + webview runtime

The important line in that table: a desktop GUI needs a desktop. A headless Pi with no monitor has no window to click into — in that case frpc + a systemd unit genuinely is the better engineering choice, and MoonProxy isn't meant to replace it.

MoonProxy runs on macOS and Windows, not Linux/Pi. So think of it as the answer for the machine that has a screen — your laptop, a desktop in the homelab, the box you actually sit down at — rather than for the Pi itself.

The pattern that actually works

The setup that's held up well across homelab setups:

  1. The Pi keeps the service, and runs headless frpc — it's a single binary plus a systemd unit. Lean and scriptable.
  2. The machine with a screen runs MoonProxy to manage tunnels in a form instead of a file.

You end up with one tunnel config in two places, which sounds like duplication — but in practice each side only owns the tunnels it actually needs, and you get both: unattended reliability on the Pi, and no-SSH convenience at the desk.

If you only have the Pi, keep using frpc. Nothing below changes that recommendation.

If you're on a Pi and tired of journalctl

Three options, roughly in order of how much I'd recommend them:

  • Write the systemd unit properly. Restart=always, RestartSec=5, and a WantedBy=multi-user.target. This is the fix that makes frpc boring in the best way. Smallest possible change.
  • Use a lightweight web UI for frpc if you genuinely want a browser interface on the Pi — that's a real category (see FRP's own docs and community projects).
  • Use MoonProxy on a machine that has a display if your tunnels mostly live on laptops/desktops rather than the Pi.

What this looks like in MoonProxy, concretely

On a machine with a screen, the tunnel is a form instead of a file:

  • Add a tunnel by filling fields — local port, remote port, type, token. No TOML, no syntax to get wrong.
  • Four-state start button — stopped / connecting / connected / error. "Connected" is derived from real frpc output, not an optimistic flag, so you can trust the green state.
  • Health polling every 3 seconds — it checks whether your local port is actually reachable, so you find out your service is down before the person using it does.
  • Tray-resident — close the window and the tunnel keeps running. Launch-at-login brings it back after a reboot.
  • Scheduled connect — set weekdays and a time window, so a dev tunnel isn't exposed at 3am.
  • Engine self-update — pulls new frpc releases, SHA256-verifies, and swaps the binary atomically without reinstalling the app.

You bring your own frps — MoonProxy is strictly the client side, and it doesn't relay your traffic through anyone's infrastructure.

Bottom line

On a Raspberry Pi, FRP works well and frpc is the correct tool. Don't reach for a GUI to solve a problem a systemd unit solves.

But if the machine that runs your tunnels is one you actually sit at — a laptop, a desktop — the GUI layer earns its place, because the thing it removes isn't complexity, it's SSH.

If you've already run FRP on a Pi, I'd genuinely like to hear what numbers you got — CPU and memory on a Pi 4 vs a Pi 5 is exactly the kind of detail I'd like to add to the article. 👋

Top comments (0)