feat: add Rathole Cloudron package (Infrastructure) [#650]

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
This commit is contained in:
2026-09-01 19:02:51 -05:00
parent 8d0b0f42f6
commit f918a90c3b
12 changed files with 415 additions and 13 deletions
@@ -0,0 +1,95 @@
# Rathole — Cloudron Package
[Rathole](https://github.com/rathole-org/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_token` is generated into `/app/data/server.toml` on 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 |
| 52005299 | `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:
```toml
[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):
```toml
[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
```bash
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.0
- `CloudronManifest.json` — manifestVersion 2, httpAuth proxy, tcpPorts (control + 100-port service range)
- `start.sh` — config seeding, status page, exec rathole server mode
- `status.html` — auth-proxied landing/health page
- `.env.example` — runtime knobs
- `logo.png` — 256x256, padded from upstream wordmark