RA

rathole

Lightweight and high-performance reverse proxy for NAT traversal

Remote Access & VPN ★ 14.3k stars Medium setup Apache-2.0

rathole is a secure, stable, and high-performance reverse proxy for NAT traversal written in Rust. It is a lightweight alternative to frp with a small binary and low memory use.

Key features

  • NAT traversal tunneling
  • Tiny memory footprint
  • Noise protocol encryption
  • High connection capacity

Pros & cons

Strengths

  • Tiny binary and memory use
  • Simple TOML config
  • Encrypted transport

Trade-offs

  • Fewer features than frp
  • No web dashboard

rathole replaces

Last reviewed Sep 13, 2026 · 886 words

Pick rathole over frp when you have a handful of services behind CGNAT, a cheap VPS with a public IP, and no interest in a web dashboard. It is a single Rust binary of a few megabytes, configured by one short TOML file on each end, and the catalogue's 64 MB RAM figure is a comfortable ceiling rather than a working number. frp does more; rathole does the 80 percent case with less to read, less to patch, and encryption that is on by choice rather than bolted on.

Two files, one binary, no database

rathole runs in two roles from the same executable. The server sits on the machine with the public address and the client sits next to the thing you want to expose. The server config is this small:

[server]
bind_addr = "0.0.0.0:2333"

[server.services.nas_web]
token = "a-long-random-string"
bind_addr = "0.0.0.0:5202"

And the client mirrors it:

[client]
remote_addr = "vps.example.com:2333"

[client.services.nas_web]
token = "a-long-random-string"
local_addr = "127.0.0.1:8080"

Start each with rathole server.toml and rathole client.toml. Traffic to the VPS on port 5202 now lands on the NAS at 8080. Port 2333 is the control channel; every service gets its own public port on the server side, and the client can carry as many services as you list. The config file is hot-reloaded, so adding a service is an edit, not a restart. There is no state anywhere else to back up, which is the whole appeal.

Turn on Noise before anything real goes through it

The default transport is plain TCP with a token handshake, which authenticates the client but does not encrypt what follows. The fix costs two lines and a key pair. Run rathole --genkey once, then put the private half on the server:

[server.transport]
type = "noise"

[server.transport.noise]
local_private_key = "server-private-key-here"

and the public half on the client under [client.transport.noise] remote_public_key. That gives you the Noise protocol framework end to end, the same family of handshake WireGuard uses, with no certificate to renew. TLS is also available if you already have certificates to hand, but Noise is the lower-maintenance choice for a tunnel you set up once and forget. Whatever you pick, the token on its own is not a secret worth trusting: anyone who can read the control port can see it in the clear.

What frp has that rathole does not

frp, the much larger project rathole was written as a lighter answer to, offers HTTP and HTTPS virtual hosting on one port, a web dashboard, bandwidth limits, load balancing across clients, plugin auth, and a much longer list of knobs. rathole covers TCP and UDP forwarding, Noise or TLS transport, and hot reload. If you want ten HTTP services routed by hostname on a single public port 443, frp does that natively; with rathole you put Caddy on the VPS in front of a set of rathole ports and let it do the hostname routing, which is honestly the cleaner design anyway, because the reverse proxy is where TLS certificates and access rules belong. See frp if you know you need the extras; otherwise the smaller tool is the safer one to operate.

The tunnel you might not need

A tunnel solves exactly one problem: reaching a service on a network you cannot open ports into. If your real goal is reaching your own machines from your own devices, a mesh VPN is a better fit than any port-forwarder, because nothing is exposed to the public internet at all. Tailscale or a self-hosted control plane like Headscale gets you there in fewer steps than a rathole pair and needs no VPS. rathole earns its place when the audience is not you: a public game server, a friend's access to your Jellyfin, a webhook endpoint that must resolve from anywhere. The broader trade-offs between VPN, tunnel, and reverse proxy are laid out in remote access three ways.

Running it without babysitting

Ship the binary from the GitHub release page or use the rapiz1/rathole Docker image with the config mounted at /app/config.toml. On the VPS, put the server behind a systemd unit with Restart=always; on the home side, the client reconnects on its own when the link drops, with backoff, so a flaky uplink does not need a watchdog. Memory on both ends sits in the low tens of megabytes even with several services active. The one operational chore is remembering that the public ports on the VPS are open to the world: firewall them to the reverse proxy, or to a source IP range if the consumer is fixed.

What I'd do

For a home behind CGNAT that needs 1 to 5 public services, rathole with the Noise transport, a $4-a-month VPS, and Caddy on the VPS terminating TLS and routing by hostname. For anything that is really "let me reach my own stuff", skip the tunnel and use Tailscale. Reach for frp only when you have already hit a feature rathole lacks, because until then the smaller config file is the better one.

Compare rathole

12 head-to-head comparisons.

Similar remote access & vpn apps