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
frpcunless you wrote a systemd unit. -
It doesn't tell you it's dead. If
frpccrashes, 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
localPortvsremotePortmeans. -
There's no status you can glance at. On a headless box you'd run
systemctl status frpcorjournalctl— 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:
-
The Pi keeps the service, and runs headless
frpc— it's a single binary plus a systemd unit. Lean and scriptable. - 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 aWantedBy=multi-user.target. This is the fix that makesfrpcboring in the best way. Smallest possible change. -
Use a lightweight web UI for
frpcif 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
frpcoutput, 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
frpcreleases, 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.
- 🌐 Website: moonproxy.app
- 💻 Source (MIT): github.com/MoonProxyHQ/moonproxy-desktop
- ⬇️ Releases: macOS (Apple Silicon + Intel) and Windows x64
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)