frp
Fast reverse proxy to expose local servers behind NAT
frp is a fast reverse proxy that exposes a local server located behind a NAT or firewall to the internet. It supports TCP, UDP, HTTP, and HTTPS tunneling.
Key features
- Expose services behind NAT
- TCP, UDP, and HTTP tunnels
- Single binary
- Encryption and compression
Pros & cons
Strengths
- Single lightweight binary
- TCP UDP HTTP tunneling
- Battle-tested and popular
Trade-offs
- Needs a public server
- Manual config file editing
frp replaces
Last reviewed Aug 26, 2026 · 859 words
frp requires something the marketing rarely says out loud: a second server. It is a reverse proxy that punches out of NAT, which means a machine with a public IP must terminate the tunnel — in practice a $4–6/month VPS. Budget that in and the rest is pleasingly small: one Go binary on each end, a config file measured in lines, 64 MB of RAM, and tunnels for TCP, UDP, HTTP, and HTTPS. With 109,000 GitHub stars and a first release back in 2016, frp is the boring, proven answer to "how do I reach my homelab without opening ports on my router" — provided you actually want raw port exposure rather than a VPN.
The VPS is a feature, not a flaw
Hosted tunnel services put a third party in the path of your traffic and meter you: ngrok's free tier rotates your URL and caps bandwidth, and the paid tiers climb fast if you expose several services. With frp, the relay is a VPS you control. Your traffic transits infrastructure you rent, your domains point where you choose, and there are no per-tunnel or per-request charges — the cost is flat and tiny, since the frp server (frps) idles at a few tens of megabytes on the cheapest instance any provider sells. If you are leaving a hosted service for exactly this reason, the ngrok alternatives page covers the wider field; frp is the most battle-tested option on it.
Two TOML files and you have a tunnel
On the VPS, frps.toml:
bindPort = 7000
auth.method = "token"
auth.token = "use-a-long-random-string-here"
On the machine behind NAT, frpc.toml:
serverAddr = "203.0.113.10"
serverPort = 7000
auth.method = "token"
auth.token = "use-a-long-random-string-here"
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6022
Run frps on the VPS, frpc at home, and ssh -p 6022 [email protected] now lands on the hidden machine. Each additional service is another [[proxies]] block; HTTP services can share ports 80/443 on the server via virtual hosts if you set vhostHTTPPort and vhostHTTPSPort in frps.toml and give each proxy a customDomains entry. This manual config editing is the whole reason the catalogue rates frp "Medium" rather than "Easy" — there is no web UI walking you through it, just files and a restart.
Skip the token and you are running a public relay
An frps with no auth.token accepts connections from any frpc on the internet, and port 7000 gets scanned constantly. That means strangers can tunnel their traffic through your VPS — at best your bandwidth bill, at worst abuse complaints with your name on them. Set a long random token on both sides before the first real tunnel, restrict bindPort in the VPS firewall if you can pin your home IP, and if you enable the optional dashboard (webServer block, conventionally on port 7500), give it a real password and never expose it publicly. frp also supports TLS on the control connection and per-proxy encryption plus compression; turn encryption on for anything that is not already TLS itself.
When a VPN beats a tunnel
frp publishes services to the internet. If what you actually want is to reach your own machines from your own devices, a mesh VPN is safer and easier: Tailscale needs no VPS, no port math, and nothing exposed. And if your services are HTTP-only and you already keep DNS at Cloudflare, Cloudflare Tunnel removes the VPS from the bill entirely, at the price of a third party in the request path. frp earns its place in the gaps those two leave: raw TCP and UDP to the public internet — game servers, SSH for collaborators, Minecraft for your kids' friends, a mail submission port — under a domain and IP you control. The full decision tree lives in remote access three ways.
Run it as a service, then forget it
Both binaries ship for Linux, macOS, and Windows (frp is Apache-2.0, written in Go, cross-platform by nature), and Docker images exist, though a tunnel daemon is one of the few things I still run as a plain systemd unit — fewer layers between the network and the process. Two units, Restart=always, and frpc reconnects on its own after ISP blips. My oldest frps instance has survived several VPS reboots and two frp upgrades without config changes; the project is stable enough that new releases rarely demand attention beyond reading the changelog.
What I'd do
Decide the VPN question first: if every consumer of these services is a device you control, install Tailscale and skip frp entirely. If you need true public exposure of TCP or UDP, rent the cheapest VPS with a clean IP reputation, install frps under systemd with a 32-character token, add tunnels one [[proxies]] block at a time, and firewall port 7000 down as far as your home connection allows. Twenty minutes of setup, roughly $60 a year, and no hosted-tunnel invoice ever again.
Compare frp
12 head-to-head comparisons.
Similar remote access & vpn apps
RustDesk
Remote Access & VPNOpen-source remote desktop alternative to TeamViewer
Replaces TeamViewer, AnyDesk
Headscale
Remote Access & VPNOpen-source self-hosted Tailscale control server
Replaces Tailscale
Sunshine
Remote Access & VPNSelf-hosted game-stream host for Moonlight clients
Replaces NVIDIA GameStream, Parsec
Tailscale
Remote Access & VPNZero-config mesh VPN built on WireGuard
Replaces ZeroTier
JumpServer
Remote Access & VPNOpen-source bastion host and PAM platform
Replaces CyberArk, Teleport
Algo VPN
Remote Access & VPNSet up a personal IPsec and WireGuard VPN in minutes
Replaces NordVPN