rustunnel: a self-hosted tunnel server in Rust, with an AGPL boundary you need to read first
Self-hosted, secure tunnel server in Rust. Expose local HTTP/HTTPS/TCP/UDP services to the public internet via TLS-encrypted WebSocket. Open-source, pay-as-you-go managed option, MCP server for AI agents.
At a glance
- What is it?
- rustunnel exposes local HTTP, HTTPS, TCP and UDP services through a public server over TLS-encrypted WebSocket streams, and it ships an MCP server so AI agents can drive it. The interesting question is not whether it works but where the AGPL-3.0 line falls if you fork the server.
- Who is it for?
- Adopt rustunnel if you want the tunnel server on your own hardware and you are comfortable with AGPL-3.0 obligations on the server code you deploy, or if you want an agent to open tunnels through the hosted edge at eu, us or ap. Do not adopt it if your organisation cannot accept AGPL-3.0 on a network-facing daemon, or if you need a documented mTLS story for client identities, which the README does not describe.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem rustunnel solves, and who actually has that problem
A webhook provider needs to reach a service running on a laptop. A payment processor needs a callback URL that is not localhost. A developer wants to show a colleague a build that only exists on their machine. The usual answer is a hosted tunnel service, and the usual objection is that the traffic passes through someone else's infrastructure on someone else's terms. rustunnel addresses that objection by making the server side installable. The README describes it as a self-hosted tunnel server that exposes local HTTP, HTTPS, TCP and UDP services to the public internet over TLS-encrypted WebSocket connections, with HTTP/TCP proxying, a live dashboard, Prometheus metrics and audit logging. The audience is therefore narrower than a general developer tool: it is people who are willing to run a daemon on a public host, terminate TLS there, and manage the certificate lifecycle. If you only need an occasional tunnel for a demo, the operational surface here is larger than the problem. If you need a tunnel for production webhook traffic and you cannot send that traffic through a third party, the self-hosted path is the point of the project. The hosted option exists too, with regions in Helsinki, Hillsboro and Singapore, and a free tier capped at three tunnels, so the same client binary serves both modes.
What the architecture diagram actually tells you about the data path
The README includes an ASCII diagram of the server, and it is the most informative part of the document. The server listens on five distinct surfaces. Port 80 returns a 301 redirect to HTTPS. Port 443 terminates TLS for public traffic and then forwards it over a yamux stream to the connected client. Port 4040 carries the control-plane WebSocket, also over TLS. Port 8443 serves the dashboard UI and the REST API. Port 9090 exposes Prometheus metrics. TCP tunnels get their own listening ports starting at 20000, one port per tunnel, which is a design choice with consequences: a TCP tunnel is not multiplexed behind 443, so every TCP tunnel you open consumes a port that must be reachable from the internet and accounted for in your firewall rules. The multiplexing happens over yamux, a stream multiplexer, which means the client holds one connection to the control plane and individual tunnels are streams on top of it. That is the mechanism that lets the client print a public URL as soon as the tunnel is established. It also means the control-plane connection is a single point of failure for every tunnel on that client: if the WebSocket drops, the streams riding it drop with it. The README does not describe reconnection behaviour, backoff, or what happens to in-flight requests during a control-plane restart, so treat that as unverified.
Getting a tunnel running: the commands and config keys in the README
The fastest path is the setup wizard, which writes your region and token into the client config. Running rustunnel setup prompts for a region, defaulting to auto, and the README shows the wizard measuring latency to each edge and selecting the nearest. It then prompts for an auth token, which you create in the hosted dashboard under API Keys. After that, exposing a service is a single command per protocol: rustunnel http 3000 for HTTP, rustunnel tcp 5432 for a database, rustunnel udp 27015 for a game server. Flags shown in the README include --region to pin an edge, --subdomain to request a custom subdomain, and --json for machine-readable output. There is also a peer-to-peer mode that does not involve a public URL at all: rustunnel p2p 27015 --name my-game --secret "shared-secret" exposes a service, and rustunnel p2p 8000 --target my-game --secret "shared-secret" connects to it. That is a genuinely different use case from public tunnelling and worth noting, because the secret is a shared string rather than a certificate, so the security of a P2P tunnel rests on that string staying private. For self-hosting, the README walks through an Ubuntu and systemd deployment in nine numbered steps: install dependencies, build release binaries, create a system user and directories, install the server binary, write the server config file, obtain TLS certificates via Let's Encrypt and Cloudflare, set up the systemd unit, open firewall ports, and verify. A Docker deployment guide is linked separately at docs/docker-deployment.md. The client requires Rust 1.76 or newer according to the badge.
The port budget is the real self-hosting constraint
Most tunnel tools hide their complexity behind a single ingress port. rustunnel does not. The diagram allocates 80, 443, 4040, 8443, 9090, and then a range from 20000 upward for TCP tunnels. On a small VPS that is fine. On a host behind a corporate firewall, or on a cloud provider where ingress rules are managed by a separate team, that is five fixed ports plus a dynamic range to justify. The dashboard and metrics ports are the ones to think about hardest. Port 8443 serves the dashboard UI and the REST API, and port 9090 serves Prometheus metrics. Neither is described in the README as authenticated, and the README does not state whether either binds to localhost by default or to all interfaces. If you deploy this on a public host and leave 8443 open, you are exposing an administrative interface. The README's firewall step is the place to handle that, and anyone reading this should treat the default binding behaviour as something to confirm in the server config file rather than assume. The same applies to 9090: Prometheus metrics endpoints commonly leak internal hostnames, tunnel counts and request volumes, which is exactly the kind of inventory you do not want public.
AGPL-3.0 on a network daemon is a decision, not a formality
rustunnel is licensed AGPL-3.0, and the README links to the LICENSE file and shows the badge. The AGPL differs from the GPL in how it treats network use: running modified software to provide a service over a network is generally treated as distribution for the purpose of source disclosure. For a tunnel server, that framing lands directly on the deployment model. If you fork rustunnel-server, modify it, and run it as a hosted tunnel service that other people connect to, the licence's network clause is the thing your legal team will want to read, not the GPL comparison. Self-hosting an unmodified build for your own internal use is a different situation from operating a modified build as a service for third parties. This article is not legal advice and cannot tell you where your specific deployment falls. What it can say is that the licence choice is consistent with the project's commercial structure: there is a hosted service with a free tier and a pay-as-you-go tier at $3 per month minimum plus $0.10 per GB, and AGPL-3.0 on the server is the standard way to keep a commercial hosted offering viable while the code stays open. If your organisation has a blanket ban on AGPL dependencies in network-facing services, this project is out of scope for you before any technical evaluation begins.
The MCP server is the most distinctive part, and the least documented here
rustunnel ships an MCP server, which means an AI agent can open and manage tunnels as tool calls rather than by shelling out to a CLI. The README provides a Cursor deep link that installs the MCP server with a config specifying the command rustunnel-mcp, arguments pointing at eu.edge.rustunnel.com on port 4040 and the API endpoint on 8443, and an environment variable RUSTUNNEL_TOKEN for the auth token. For Claude Code, Claude Desktop and Windsurf, the README points to an agent integration guide at rustunnel.com/docs/guides/agent-integration and an agent manual at rustunnel.com/agents.md. There is also an OpenClaw skill mentioned in the table of contents. The security shape of this deserves a moment. An agent holding RUSTUNNEL_TOKEN can open tunnels, which means it can expose internal services to the public internet. That is a meaningful capability to hand to a model, and the README does not describe scoping, per-token permissions, or an approval step before a tunnel opens. The token is created in the dashboard and shown once. If you are evaluating this for an agent workflow, the question to answer first is whether the token you issue can be limited to specific protocols or subdomains, and the supplied material does not say that it can.
Where rustunnel is the wrong tool, and what to compare it against
The clearest alternative is ngrok, and the repository itself lists ngrok-alternative as a topic. The difference in approach is architectural rather than cosmetic. ngrok's agent connects outbound to ngrok's edge and you consume a hosted product; the tunnel endpoint is theirs, the TLS certificate is theirs, and the operational burden is near zero. rustunnel inverts that: you can run the edge yourself, which means you own the certificate, the port allocation, the systemd unit, the upgrade cycle and the metrics endpoint. That inversion is the entire value proposition and the entire cost. frp is the other obvious point of comparison for people who want self-hosted tunnelling, and it is a long-standing project in Go with a different configuration model; the README does not benchmark against it, so any comparison on throughput or connection handling would be invented here. Where rustunnel is plainly the wrong tool: if you need a tunnel for thirty seconds during a pairing session, the setup wizard and token flow are more ceremony than the problem deserves. If you cannot open port 4040 outbound from the client's network, the control plane will not connect. If you need per-client mTLS identity rather than a bearer token, the README describes tokens and shared secrets, not client certificates, and you should confirm that gap before designing around it.
Maintenance cost and what to verify before you deploy
The release cadence visible in the supplied material is three releases in roughly six weeks: v0.8.3 on 23 July 2026, v0.8.4 on 26 July 2026, v0.8.5 on 3 September 2026. That is a pre-1.0 project moving at a steady clip, and the practical consequence is that self-hosters should expect to track releases rather than install once. The README includes an Updating the server section, which suggests the maintainers expect self-hosted deployments to be upgraded in place. Budget for that: a systemd service, a config file whose keys may change between minor versions, and TLS certificates that renew on their own schedule via the Let's Encrypt and Cloudflare path described. The client and server are versioned together in the release tags, so a mismatch between a client from one release and a server from another is a compatibility question the supplied material does not answer. Before deploying, verify four concrete things: whether the dashboard on 8443 and metrics on 9090 bind to localhost or to all interfaces in your server config file, what the client does when the control-plane WebSocket on 4040 drops, whether your token scopes to a single deployment, and whether the TCP port range starting at 20000 fits inside your provider's ingress rules. Each of those is answerable by reading the config file reference and the source, and none of them is answered by the README as supplied.
Editorial conclusion
Adopt rustunnel if you want the tunnel server on your own hardware and you are comfortable with AGPL-3.0 obligations on the server code you deploy, or if you want an agent to open tunnels through the hosted edge at eu, us or ap. Do not adopt it if your organisation cannot accept AGPL-3.0 on a network-facing daemon, or if you need a documented mTLS story for client identities, which the README does not describe. Before committing, verify three things on your own copy: that the control-plane port 4040 and the dashboard port 8443 are both reachable only from where you intend, that the TCP tunnel port range starting at 20000 matches your firewall and NAT rules, and that your client token was generated on the same deployment you are pointing the client at, since the README states the token is shown only once and is not recoverable from the dashboard.
Community notes