Server-mode Rathole 0.5.0 as the 11th package: pinned upstream binary (sha256 gate) on cloudron/base:4.0.0, control port 2333 plus a 100-port tunnel exit range, hot-reloading config in /app/data, auth-proxy verdict (no user concept). Verified end-to-end with a live client tunnel. Docs gardened (STATUS/README/JOURNAL to 11 packages). Ticket: https://projects.knownelement.com/issues/650
Rathole — Cloudron Package
Rathole is a secure, stable and high-performance reverse proxy for NAT traversal (frp/ngrok class, written in Rust). This package runs the server side: the Cloudron box is the public-IP endpoint, rathole clients behind NAT dial the control port, and their local services are exposed through token-authenticated tunnels.
Packaging overview
| Aspect | Choice |
|---|---|
| Pattern | Pre-compiled binaries (JOURNAL pattern #5) |
| Base image | cloudron/base:4.0.0 (Ubuntu 22.04) |
| Upstream binary | rathole-x86_64-unknown-linux-gnu.zip, v0.5.0, sha256-pinned in Dockerfile |
| Addons | localstorage only (config persistence; no database) |
| Auth | No user concept → httpAuth.type = proxy (see below) |
| Runtime | start.sh seeds config, serves status page, execs rathole --server |
Why pre-compiled: upstream ships release binaries and dropped the musl
builds in v0.5.0 (only x86_64-unknown-linux-gnu remains for Linux
amd64). The gnu binary is built on ubuntu-latest, so the runtime needs
glibc >= 2.35 — hence cloudron/base:4.0.0 (22.04) instead of the 3.x
series (20.04). Compiling from source would need a full Rust toolchain
build stage for no benefit.
Authentication (auth gate verdict: proxy)
- Rathole has no user concept: no web UI, no accounts, no SSO hooks.
- Tunnels are authorized by mandatory per-service tokens (a random
default_tokenis generated into/app/data/server.tomlon first start). Transport can additionally be encrypted via Noise or TLS. - The manifest declares
httpAuth: {"type": "proxy"}: Cloudron's auth proxy gates the HTTP status page, which is the only HTTP surface this app has. The raw TCP tunnel ports cannot be HTTP-gated by design; the token layer is their access control.
Ports
| Port | Type | Purpose |
|---|---|---|
| 8000 | httpPort |
Status/health page (behind Cloudron auth proxy) |
| 2333 | tcpPorts |
Control channel — rathole clients connect here |
| 5200–5299 | tcpPorts (100-port range) |
Tunnel exit ports — one per [server.services.*] |
With default install settings Cloudron bridges these 1:1 (external
5200-5299 → container 5200-5299). If the admin picks a different
SERVICE_PORT start value, the container ports stay 5200+ and only the
external numbering shifts — server.toml never needs editing for that.
Configuration
/app/data/server.toml, seeded on first run, hot-reloaded on save
(add/remove services without restarting the app). The seed contains a
placeholder [server.services.example] on :5200 — rathole rejects a
server config with zero services, so keep at least one block. Example
service:
[server.services.my_nas_ssh]
token = "<copy from default_token or set your own>"
bind_addr = "0.0.0.0:5200"
Client side (machine behind NAT):
[client]
remote_addr = "your-cloudron.example.com:2333"
[client.services.my_nas_ssh]
token = "<same token as the server>"
local_addr = "127.0.0.1:22"
Then ssh -p 5200 user@your-cloudron.example.com reaches the NAS.
Knob: RUST_LOG (error|warn|info|debug|trace, default info) via
Cloudron environment settings — see .env.example.
Build & test
docker build --cgroup-parent ukrrs-batch.slice -t rathole-cloudron:test Package-Workspace/Infrastructure/rathole/
docker run --rm --entrypoint /usr/local/bin/rathole rathole-cloudron:test --version
Files
Dockerfile— pinned release download + sha256 gate on cloudron/base:4.0.0CloudronManifest.json— manifestVersion 2, httpAuth proxy, tcpPorts (control + 100-port service range)start.sh— config seeding, status page, exec rathole server modestatus.html— auth-proxied landing/health page.env.example— runtime knobslogo.png— 256x256, padded from upstream wordmark