Development
12 min read
47 views

The Minimalist Edge: Rust and Go Micro-Proxies

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
The Minimalist Edge: Rust and Go Micro-Proxies

Quick answer

Lightweight ngrok Alternatives: Rust & Go Micro-Proxies : localhost tunnel answer

A localhost tunnel gives your local app a public HTTPS URL without opening router ports, which is useful for demos, QA, mobile testing, and provider callbacks.

How do I expose localhost without opening ports?

Use a reverse HTTPS tunnel. Your machine connects outbound to the tunnel service, and the public URL forwards requests back to your local app.

When should I use a localhost tunnel?

Use one for webhook testing, OAuth callbacks, client demos, QA previews, mobile device checks, and short-lived development reviews.

There is a niche but deeply passionate trend running through the infrastructure community: developers are systematically replacing heavy, commercial proxy services with ultra-minimalist, open-source tools written in Rust and Go. For years, the default answer to exposing a local development server or bypassing Carrier-Grade NAT (CGNAT) was to reach for a household name. But as those platforms pivot toward enterprise features, their agents have grown heavier and their free tiers more restrictive.

Enter the micro-proxy.

Writing about open-source tools like bore, rathole, and chisel appeals immensely to home-labbers, IoT hobbyists, and edge computing developers — the engineers running tunnels on low-memory devices like Raspberry Pis, where every megabyte of RAM matters. By leaning on the memory safety of Rust or the static compilation of Go, these micro-proxies offer fast, self-hosted alternatives that put control back in the hands of the developer.

The Hunt for a Lightweight Ngrok Alternative

If you’ve ever needed to show a client a local web app, test a webhook, or reach your home server from a coffee shop, you’ve used a tunneling service. These work by running an agent on your local machine that dials out to a public cloud server, punching through your local firewall. The cloud server hands you a public URL and forwards incoming traffic down that tunnel.

Commercial solutions are polished, but they come with trade-offs:

  • Connection and bandwidth limits. Free tiers frequently throttle bandwidth, limit concurrent connections, or timeout idle sessions.
  • Feature paywalls. Raw TCP tunnels for SSH or a database, or a persistent custom domain, often sit behind a subscription.
  • Agent bloat. Commercial agents bundle compliance features, auto-updaters, and UI components that eat resources on small edge devices.
  • Privacy and control. Routing unencrypted local traffic through a third-party server introduces a point of interception.

This has driven demand for something that can be hosted on a cheap VPS, deployed as a single binary, and left running indefinitely. Let’s look at three tools that fill that niche — and, importantly, at what each one actually guarantees about your traffic once it leaves your machine, since that’s where the marketing copy for these projects tends to get ahead of the defaults.

1. Bore: The Ridiculously Simple Rust TCP Tunnel

If your goal is absolute simplicity, bore is built for it. Created by Eric Zhang, it’s a modern, simple TCP tunnel in Rust that exposes local ports to a remote server, bypassing standard NAT firewalls — intended to be a highly efficient, unopinionated tool for forwarding TCP traffic that is simple to install and easy to self-host, with no frills attached. As of this writing it has 11.4k GitHub stars, 514 forks, and is MIT-licensed, currently at version 0.6.0 on crates.io.

How Bore Works

Bore is aggressively unopinionated. The whole project totals about 400 lines of safe, async Rust code and is trivial to set up — just run a single binary for the client and server. It doesn’t manage TLS certificates, doesn’t offer a dashboard, and doesn’t inspect your HTTP traffic. It forwards bytes from A to B, using an implicit control port at 7835 for negotiating new connections between client and server.

The correction worth making up front: bore does not encrypt your traffic by default, and the draft this article started from implied otherwise by omission. Bore supports an optional --secret flag, but per the official docs, that secret only authenticates the handshake — it does not encrypt the data plane. Read literally from the project’s own authentication section: the protocol requires clients to verify possession of the secret via HMAC challenges on each connection, but “no further traffic is encrypted by default.” If you’re forwarding anything sensitive over bore, you need to layer TLS yourself (see the security section below).

Quick Setup

cargo install bore-cli

To expose a local web server on port 8000:

bore local 8000 --to bore.pub

The terminal returns a randomly assigned remote port at bore.pub. You can pin a specific port with --port, and expose a LAN host other than localhost with --local-host.

For self-hosting, run bore server on your VPS (optionally with --secret for handshake authentication, and --min-port/--max-port to restrict the exposed range), then point your local client’s --to flag at your VPS’s address. It’s a drop-in tool when you need a tunnel immediately and don’t want to write a config file.

2. Rathole: High-Performance NAT Traversal in Rust

While bore is great for quick, ephemeral testing, rathole targets something more permanent: exposing a home NAS or an IoT sensor network securely and continuously. One repo note worth flagging — the project has moved organizational homes, from rapiz1/rathole to rathole-org/rathole (the old URL still resolves via GitHub’s redirect). It currently sits at roughly 14k stars, 809 forks, and is Apache-2.0 licensed, describing itself as a lightweight and high-performance reverse proxy for NAT traversal, written in Rust, an alternative to frp and ngrok.

The Security Model — and a Correction

This is the second place the original draft overstated things. Rathole’s README does advertise Noise Protocol support: tokens of services are mandatory and service-wise, and with the optional Noise Protocol, encryption can be configured at ease, with no need to create a self-signed certificate — TLS is also supported. But two details matter here that the earlier draft collapsed into one:

  1. The token field is service authentication, not transport encryption. It proves a client is allowed to bind a given service; it does nothing to the bytes on the wire.
  2. Encryption is opt-in, not automatic. Unless you explicitly add a [client.transport] / [server.transport] block with type = "noise" (or "tls"), rathole defaults to plain type = "tcp" — meaning traffic between your client and server is unencrypted by default, same as bore. The Noise block also needs a local_private_key/remote_public_key pair (or rathole’s default pattern, Noise_NK_25519_ChaChaPoly_BLAKE2s) — it isn’t turned on just because you set a token.

So the earlier claim that “traffic is automatically end-to-end encrypted” once you set a shared token is inaccurate. Here’s what a config that actually enables encryption looks like.

Configuration via TOML

server.toml on your VPS:

[server]
bind_addr = "0.0.0.0:2333"

[server.transport]
type = "noise"

[server.services.my_ssh]
token = "super_secret_string"
bind_addr = "0.0.0.0:5202"

client.toml on your home server:

[client]
remote_addr = "vps_ip_address:2333"

[client.transport]
type = "noise"

[client.services.my_ssh]
token = "super_secret_string"
local_addr = "127.0.0.1:22"

With no [transport] block on either side, this falls back to raw, unauthenticated-at-the-transport-layer TCP — fine for a quick local test, not fine for crossing the public internet. Rathole also supports UDP services (type = "udp" under a service block) and hot-reloading of the config file without restarting the process. Per its own benchmark docs, rathole can achieve much higher throughput than frp and is more stable handling large connection volumes, while consuming far less memory, with binaries as small as ~500KiB.

3. Chisel: The Versatile Go-Based SSH Tunnel

For deeply restrictive corporate environments or complex proxying needs, chisel is the Go option. It’s currently at v1.11.5 (released March 2026), with 16.1k stars, 1.6k forks, MIT-licensed, and describes itself plainly: a fast TCP/UDP tunnel, transported over HTTP, secured via SSH, single executable including both client and server, written in Go.

Unlike bore and rathole, chisel gets its security story right out of the box — this is the one place the original draft’s confidence was actually justified, and it’s worth stating clearly since the other two aren’t: encryption is always on. When a chisel server starts, it generates an in-memory ECDSA key pair (or loads one from --keyfile) and secures all traffic with it via Go’s crypto/ssh. The server prints its public key fingerprint on startup; clients should pin that fingerprint with --fingerprint to prevent MITM.

Bypassing Restrictive Firewalls

The trick is the transport layer. Many corporate networks block raw TCP or drop SSH traffic outright, but almost never block standard HTTP/HTTPS. Chisel wraps its TCP/UDP tunnel inside HTTP, upgrading to WebSockets — so to a restrictive firewall, a chisel tunnel looks like ordinary web traffic. Once it reaches the chisel server, the payload is secured with the SSH protocol underneath.

Setup

chisel server -p 8080 --reverse

On the restricted local machine:

chisel client https://your-vps-domain.com R:80:localhost:3000

This single command opens an HTTP connection, negotiates an SSH-secured session, and reverse-forwards local port 3000 to the server’s port 80. Chisel also supports a SOCKS5 proxy mode (--socks5 on the server, a socks remote on the client), password-based user authentication via an --authfile, and native TLS termination with automatic Let’s Encrypt certificates via --tls-domain — a feature the earlier draft didn’t mention and one that matters if you want chisel itself to terminate HTTPS rather than sitting behind Nginx or Caddy. UDP support landed in v1.7 of the project.

Head-to-Head: bore vs. rathole vs. chisel

The “bore vs rathole” debate is common among Rust enthusiasts; chisel tends to sit in its own category for firewall evasion. The table below is the piece the original draft was missing — a side-by-side on what you get by default, before you configure anything extra:

Bore Rathole Chisel
Language Rust Rust Go
Encrypted by default No No (opt-in via Noise/TLS) Yes (always-on ECDSA/SSH)
Config format CLI flags TOML file CLI flags
UDP support No Yes Yes
Best for Instant, throwaway tunnels Persistent, high-throughput home-lab services Crossing HTTP-only corporate firewalls
License MIT Apache-2.0 MIT

The verdict: use bore for a zero-config, disposable tunnel where you’re comfortable adding your own TLS if the traffic matters. Use rathole for persistent, low-resource home-lab infrastructure — but turn on the Noise transport explicitly. Use chisel when you’re behind a draconian HTTP-only firewall and want encryption without extra configuration.

Tutorial: Setting Up a Raspberry Pi Localhost Tunnel

Millions of hobbyists run personal services on Raspberry Pis. The problem: most residential connections sit behind CGNAT, so there’s no public IP to port-forward. Here’s rathole, used correctly — with the Noise transport enabled this time.

Step 1 — Prepare the server (VPS)

Download the rathole binary from the official releases page. Create server.toml:

[server]
bind_addr = "0.0.0.0:2333"

[server.transport]
type = "noise"

[server.services.pi_web]
token = "MySecureToken123!"
bind_addr = "0.0.0.0:8080"

Run it: ./rathole server.toml

Step 2 — Prepare the client (Raspberry Pi)

Download the ARM binary (Rust cross-compiles cleanly for ARM). Create client.toml:

[client]
remote_addr = "YOUR_VPS_IP:2333"

[client.transport]
type = "noise"

[client.services.pi_web]
token = "MySecureToken123!"
local_addr = "127.0.0.1:80"

Run it: ./rathole client.toml

Because only one of [client] or [server] appears in each file, rathole auto-detects which mode to run in — no --client/--server flag needed unless both blocks live in a single combined file.

Step 3 — Persistence with systemd

Create /etc/systemd/system/rathole.service:

[Unit]
Description=Rathole Client Tunnel
After=network.target

[Service]
Type=simple
User=pi
ExecStart=/home/pi/rathole /home/pi/client.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable and start it:

sudo systemctl enable rathole
sudo systemctl start rathole

(The project also ships ready-made systemd unit examples under examples/systemd in the repo, worth checking against your own if you want extra options like LimitNOFILE.)

Navigating to http://YOUR_VPS_IP:8080 now routes through the Noise-encrypted tunnel down to the Pi.

Security Considerations for Edge Proxies

When you replace commercial tools with self-hosted binaries, you take on the responsibility they used to handle for you. Given the corrections above, this list needs to be more specific than “stay updated”:

  • Don’t assume encryption you haven’t configured. Bore and rathole are both plaintext-on-the-wire by default. If you’re forwarding SSH, that inner protocol is still encrypted — but if you’re forwarding a plain HTTP admin panel or an unencrypted database port, anyone on the path between your VPS and the internet can read it. Chisel is the only one of the three that encrypts by default.
  • Never expose unauthenticated services. If your local app has no login, don’t put it on a public port raw. Bots find open ports within minutes.
  • Put a real reverse proxy in front of the exposed port. Run Nginx or Caddy on your VPS, terminate TLS with Let’s Encrypt on 443, and proxy internally to bore/rathole/chisel rather than exposing their ports directly (chisel’s built-in --tls-domain can substitute for this if you don’t want a separate proxy layer).
  • Pin fingerprints where the tool supports it. Chisel’s --fingerprint flag is the difference between “encrypted” and “encrypted and verified” — skipping it leaves you open to a MITM on first connection.
  • Stay updated. Rust and Go eliminate whole classes of memory-safety bugs, but logic bugs in tunneling code (auth bypass, port-range confusion) still happen. Watch the release pages — chisel, for instance, is on its 35th tagged release as of v1.11.5.

Conclusion

The infrastructure landscape is going through a minimalist renaissance, and the three tools above are genuinely good options — bore for disposable tunnels, rathole for persistent home-lab infrastructure, chisel for hostile-firewall environments. But “self-hosted” and “secure by default” are not the same claim, and two of these three tools ship with encryption off unless you turn it on. That’s not a knock against them — it’s the trade-off for a 400-line binary with no frills — but it’s the detail worth knowing before you point one at anything that matters.


Changelog

Corrections and additions made to the original draft, verified against official sources (GitHub repositories, READMEs, and release pages) as of August 2026:

  1. Corrected bore’s encryption claims by omission. The original draft didn’t mention that bore has no default traffic encryption; added an explicit correction citing bore’s own Authentication section, which states the optional --secret only covers the handshake (“no further traffic is encrypted by default”). Source: github.com/ekzhang/bore.
  2. Corrected rathole’s core security claim. The draft stated traffic is “automatically end-to-end encrypted” once a shared token is set. This conflates the mandatory service token (authentication only) with the optional Noise Protocol transport (encryption), which must be explicitly configured via a [transport] block with type = "noise" and is off by default. Rewrote the config examples and the Raspberry Pi tutorial to enable Noise correctly. Source: rathole-org/rathole README and docs/transport.md.
  3. Updated rathole’s canonical repo location. The project transferred from rapiz1/rathole to the rathole-org GitHub organization; updated the primary link and noted the redirect.
  4. Added verified current stats. GitHub star/fork counts and license for all three projects: bore (11.4k stars, 514 forks, MIT), rathole (~14k stars, 809 forks, Apache-2.0), chisel (16.1k stars, 1.6k forks, MIT, v1.11.5). Sources: respective GitHub repository pages.
  5. Added chisel’s actual security model. Clarified that chisel is the one tool of the three that encrypts by default (in-memory or file-based ECDSA key pair via crypto/ssh), and added the --fingerprint MITM-prevention detail and --tls-domain Let’s Encrypt automation, none of which were in the original draft. Source: jpillora/chisel README, Security and Usage sections.
  6. Added rathole’s UDP support and hot-reload capability, and chisel’s UDP support history (added in v1.7 per its changelog) — neither was mentioned in the original draft.
  7. Corrected the systemd ExecStart line in the Raspberry Pi tutorial. The original used --client /home/pi/client.toml; since the client config file contains only a [client] block, rathole auto-detects the mode and the flag is unnecessary (only needed when server and client blocks share one file).
  8. Added bore’s control-port and CLI details (7835 control port, --local-host, --min-port/--max-port) directly from the project’s own README rather than paraphrasing.
  9. Rewrote the Security Considerations section to be tool-specific rather than generic, directly reflecting the corrected default-encryption findings above, and added a comparison table summarizing default security posture across all three tools — not present in the original draft.
  10. Stripped all frontmatter/metadata from the original draft; delivered as clean Markdown.

Continue from this article into the most relevant product guides and workflows.

Related Topics

#lightweight ngrok alternative, bore vs rathole, chisel reverse proxy, Raspberry Pi localhost tunnel, Rust micro proxy, Go micro proxy, rust tunneling tool, go tunneling tool, open source reverse proxy, bore proxy, rathole proxy, chisel tunnel, ekzhang bore, rathole rust, jpillora chisel, low memory reverse proxy, homelab tunneling, IoT localhost tunnel, edge computing tunneling, Raspberry Pi proxy, lightweight reverse proxy, minimal tunneling tool, self hosted reverse proxy, bore vs rathole vs chisel, rust reverse proxy, go reverse proxy, fast tcp tunnel, nat traversal rust, nat traversal tool, lightweight port forwarding, single binary reverse proxy, embedded system tunnel, low memory footprint proxy, secure tunneling rust, high performance reverse proxy, chisel socks proxy, chisel ssh tunnel, bore tcp tunnel, rathole nat traversal, homelab port forwarding, edge node proxy, lightweight ngrok replacement, open source ngrok alternative, low resource reverse proxy, custom localhost tunnel, reverse proxy for raspberry pi, iot micro proxy, minimal localhost proxy, fast port forwarding tool, rust networking tools, go networking tools, zero dependency tunnel, lightweight http proxy

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles