frp is a fast reverse proxy written in Go that builds a tunnel between a machine behind NAT and a public server you already control. The tunnel is outbound, which is the property that makes it work when port forwarding on the router does nothing. The connections come from the inside out, past the CGNAT (carrier-grade NAT, an extra layer of address translation applied by your ISP that blocks inbound traffic) and any other address translation between your home server and the public server. The public server ends up holding the open ports, and your home server ends up holding the actual services.
frp is for the situation where you have a server, you have one or more services on it, and you have no way to give the server a public IP. The shape of that situation is more common than the marketing for cloud hosting suggests. Lots of home labs, small offices, and developer workstations behind CGNAT have services that need to be reachable from the internet, and the only realistic options are a tunnel, a relay, or a cloud VM with a port forwarded to it.
How the tunnel actually works
frp ships two binaries. frps is the server side. It runs on the public machine and holds the open ports. frpc is the client side. It runs on the machine behind NAT and creates the outbound connection. The outbound connection is the working part of the design.
The flow has three steps:
frpcopens a TCP connection from your home server tofrpson the public server, over a control port (usually 7000). Outbound connections can pass through NAT and most firewalls without any special configuration. That is the property the rest of the design relies on.frpsaccepts the control connection, listens on the public ports you configured, and forwards incoming traffic through the established tunnel tofrpc. The local service never sees the public internet directly. It only talks tofrpcon the local machine.- The home server’s
frpchands the traffic to the local service over a local port. Your SSH daemon, your web app, your Minecraft server, or whatever you exposed receives the request through this local hop.
The architecture inverts the direction of the usual setup. The home server does not wait for inbound traffic. It maintains the outbound connection, and the public server reaches back through it. The implication is that any home server can become reachable without changes to the router, the ISP, or the firewall between them.
What frp is not
A tunnel is not a VPN (a virtual private network, software that encrypts all traffic between two endpoints and routes it through a third party). frp does not pretend to be a security boundary. The public server you use is the trust boundary. The token authentication in frp is a guard against unauthorized clients, not a substitute for hardening the services you expose.
When you have a public IP to begin with, frp is not a substitute for a proper VPS (virtual private server) setup. If your router can port forward, that is the simpler path. frp’s value is the situation where the simpler path is unavailable.
The tool is also not a clean solution for high-throughput services. The traffic path goes through the public server twice, and the public server’s bandwidth becomes the bottleneck. For SSH, a small web app, a self-hosted dashboard, or a developer tool, the bandwidth is fine. For a media server with heavy traffic, frp is not the right tool.
The minimum viable setup
The setup that gets a tunnel working on a home server has four pieces:
- A public server running
frpswith a public IP, abindPortfor the control connection, and anauth.tokenfor client authentication. The server runs as a systemd service (a Linux service manager that starts and supervises long-running processes). - A home server running
frpcwith the public server’s address, the matching token, and a list of proxies. Each proxy is one service you want to expose, identified by name, type, and the local IP and port. - A firewall config that allows the control port and user ports. The public server needs these inbound. The home server does not need any inbound ports open. UFW (Uncomplicated Firewall, a Linux firewall configuration tool) or firewalld on the public server is the typical choice.
- A systemd service for both
frpsandfrpcso the tunnel comes back up after a reboot. The unit file pattern is the same for both: a one-lineExecStartpointing at the binary with the config file argument.
The whole setup is reproducible in an hour on a fresh Ubuntu 26.04 or Rocky Linux 10 box. The frp tarball is a static binary (a self-contained executable with no shared library dependencies), so the install is a wget and a cp into /usr/local/bin. The configuration is the part that takes time.
After the install, the test that proves the tunnel is up is the simplest possible command from a third machine on the internet: ssh -p 6000 user@<public-ip>. If the SSH prompt appears, the tunnel is working. If it does not, the error message is the diagnostic.
The hardening you actually need
The default frps.toml allows any authenticated client to claim any port. That is a problem when more than one person uses the same public server, and it is a problem when you run a long-lived tunnel and forget about it. Two settings prevent the worst outcomes:
allowPorts = [{ start = 6000, end = 6100 }]restricts the remote portsfrpccan claim. Without this, a compromised client can request port 22 and expose the public server’s SSH service to the internet.transport.tls.force = truemakesfrpsreject plaintext control connections. Modern frp clients already use TLS (Transport Layer Security, the encryption protocol that wraps HTTP and other TCP traffic) for the control connection by default, so this is a defense-in-depth setting rather than a client-side change.
The hardening story does not end with frp. The service you expose is the service the world can reach. SSH exposed through frp should still have key-based authentication, fail2ban (a service that monitors log files and bans IPs that show malicious signs), and a non-root user. The web app exposed through frp should have HTTPS, a reverse proxy, and whatever auth the production version has. frp is the reachability layer, not the security layer.
Common errors and what they point to
Three error messages show up on the first attempt, and each one points to a specific cause.
login to server failed in the frpc log. The tokens on the client and server do not match. This is usually a trailing whitespace or a copy-paste mistake. Compare the auth.token setting on both sides character by character.
Connection timeout on port 7000. A firewall or cloud security group is blocking the control connection. The frps process is running, but the connection never reaches it. The public server’s security group must allow inbound TCP on the control port. This is not an frp issue.
start proxy error naming a specific port. Either allowPorts does not include the port, or another process is already using it on the public server. sudo ss -tlnp | grep 6000 on the public server shows which process has the port open. The error message names the port that failed.
A fourth error worth knowing about is the antivirus false positive on Windows clients. The frp binaries are sometimes quarantined as malware because reverse proxies look like tunneling tools to security scanners. Adding an exclusion for the frpc directory resolves it. The frp maintainers document this and it is not a defect.
Trade-offs
frp over a cheap VPS is the cheapest way to put a home server on the internet. The cost is the bandwidth of the VPS, which is shared with the public server’s other uses. The cost is also the operational surface: the VPS is a real machine with real updates, and the frp server is a real process with real logs.
The native alternative is a Cloudflare Tunnel, which is similar in concept but operated by Cloudflare. The advantage is no VPS to maintain. The disadvantage is that Cloudflare is in the path of every request, and the privacy posture of routing traffic through a third party is different from routing it through a VPS you control.
Another alternative is Tailscale, a mesh VPN that creates a virtual network between your devices without port forwarding. The advantage is end-to-end encryption and no public server. The disadvantage is that the device you connect to must be running Tailscale, which is fine for personal use and not fine for exposing a service to anyone who does not have your Tailscale account.
frp is the right choice when you want to expose a service to anyone on the internet, without giving the service a public IP of its own. The setup cost is one hour. The maintenance cost is the occasional token rotation and the same updates you would apply to any other internet-facing service.
Bottom line
frp is the lever for the situation where the network is in the way of the service. The setup is straightforward, the documentation is dense, and the failure modes are well-understood. The cost is the public server, which is a small monthly line item. The benefit is the freedom to put a service on any home server, behind any router, on any ISP, and have it reachable from the internet without fighting the network.