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
+73 -1
View File
@@ -4,7 +4,7 @@
**Project**: TSYSDevStack-SupportStack-Cloudron
**Goal**: Package ~57 applications for Cloudron PaaS platform
**Start Date**: 2025-01-24
**Current Status**: 10/~57 packages completed (~18%)
**Current Status**: 11/~57 packages completed (~19%)
## Completed Packages
@@ -823,6 +823,78 @@ Dockerfile
---
### 11. Rathole (Infrastructure) ✅
**Date**: 2026-09-01
**Application**: Rathole — secure, high-performance reverse proxy for NAT
traversal (frp/ngrok class, Rust); this package runs the **server** side
**Package Size**: 3.51GB (cloudron/base 4.0.0 dominates)
**Ports**: 8000 (HTTP status), 2333 (control), 5200-5299 (tunnel exits)
**Addons**: localstorage (auth proxy, no database)
**Key Learnings**:
- **Auth gate verdict**: NO user concept — no UI, no accounts, no SSO
hooks. Tunnels are authorized by mandatory per-service tokens
(random `default_token` seeded on first run), with optional Noise/TLS
transport encryption → `httpAuth.type = proxy` gates the only HTTP
surface (a static status page), the draw.io/Easy-Gate pattern for
user-less apps
- **Base-image glibc trap**: upstream dropped musl release builds in
v0.5.0 (TLS linking burden); the only linux/amd64 asset is
`x86_64-unknown-linux-gnu`, built on ubuntu-latest → needs glibc
>= 2.35 → `cloudron/base:4.0.0` (22.04). The 3.2.0 (20.04) base used
by earlier packages is too old for this binary
- **Strict TOML schema quirks**: v0.5.0 rejects `nodelay` directly under
`[server.transport]` (must nest under `[server.transport.tcp]`) and
rejects a server config with **zero** `[server.services.*]` blocks —
the seed config must ship one active placeholder service
- **Lazy service binding**: the server binds a service's exit port only
when its client registers — an empty listener table is normal until a
client connects
- **tcpPorts ranges**: CloudronManifest `portCount` allocates sequential
ports from `defaultValue` (max 1000) with `containerPort` bridging —
used for a 100-port tunnel exit range (5200-5299) that survives
admin-chosen external renumbering without touching server.toml
- **httpPort is required** (healthCheckPath too) even for headless TCP
apps: a tiny `python3 -m http.server` sidecar on the status page
satisfies both and gives the auth proxy something to gate
**Build Process**:
- Upstream `rathole-org/rathole` v0.5.0 (rapiz1 redirects) release zip
downloaded in-Dockerfile behind a sha256 pin (pre-compiled-binaries
pattern, JOURNAL pattern #5)
- Logo: upstream wordmark (1080x291) resized/padded to 256x256 PNG via
ImageMagick in a throwaway `alpine:3.20` container (host stays clean)
- start.sh: seeds `/app/data/server.toml` (random default_token via
openssl + placeholder `[server.services.example]` on :5200), starts
the status-page sidecar, `exec rathole --server` (config hot-reloads
on save)
**Validation**:
- `docker build --cgroup-parent ukrrs-batch.slice -t rathole-cloudron:test`
→ green (sha256 gate + `rathole --version` inside the build)
- Runtime smoke: status page HTTP 200, control port :2333 reachable,
hot-reload detected an appended service within 3s
- **End-to-end tunnel test**: second container ran `rathole --client`
against the packaged server; `curl host:15200 → server:5200 →
client → client:9999` returned the client's page — token auth,
control channel, data plane, and lazy bind all proven
**Files Created**:
- Dockerfile (pre-compiled binary, sha256-pinned, cloudron/base:4.0.0)
- CloudronManifest.json (manifestVersion 2, httpAuth proxy, tcpPorts:
CONTROL_PORT 2333 + SERVICE_PORT 5200 x100, localstorage)
- start.sh (config seed + status sidecar + exec) — committed executable
- status.html (auth-proxied landing/health page)
- README.md (auth story, ports, client quickstart)
- CHANGELOG.md
- .env.example (RUST_LOG knob)
- .dockerignore (excludes the whole cloned repo/ from context)
- logo.png (256x256)
**Commit**: `feat: add Rathole Cloudron package (Infrastructure) [#650]`
---
## Packaging Pattern: Download Pre-Compiled Binaries
### When to Use
@@ -0,0 +1 @@
repo
@@ -0,0 +1,8 @@
# Rathole Cloudron package — environment knobs
#
# Cloudron injects these at runtime (App -> Configure -> Environment);
# they are not secrets.
# Log level for the rathole server: error | warn | info | debug | trace.
# Default when unset: info
RUST_LOG=info
@@ -0,0 +1,27 @@
# Changelog — Rathole Cloudron Package
## 1.0.0 (2026-09-01)
Initial Cloudron package for Rathole 0.5.0 (server mode).
- Pre-compiled-binaries pattern: upstream `x86_64-unknown-linux-gnu`
release zip downloaded at build time behind a sha256 pin (musl release
builds were dropped upstream in v0.5.0).
- Runtime `cloudron/base:4.0.0` (Ubuntu 22.04): the gnu binary requires
glibc >= 2.35, too new for the 3.x (20.04) base used by earlier
packages.
- `start.sh` seeds `/app/data/server.toml` on first run with a random
`default_token` (openssl) and a placeholder `[server.services.example]`
binding :5200 — upstream rejects a server config with zero services —
then execs `rathole --server`; the config hot-reloads on save.
- Verified end-to-end at build time: a client container tunneled its own
HTTP server through the packaged server (token auth, lazy service bind,
hot-reload of added services).
- TCP surface: control channel on 2333 + a 100-port tunnel exit range
(5200-5299) declared via `tcpPorts` with `containerPort`/`portCount`.
- No user concept → `httpAuth.type = proxy` gates a small static status
page served on the HTTP port (also serves as the platform health
check); tunnel access itself is controlled by rathole's mandatory
per-service tokens.
- Addons: `localstorage` only (config persistence; no database).
- Logo padded from the upstream wordmark to a 256x256 PNG.
@@ -0,0 +1,43 @@
{
"manifestVersion": 2,
"type": "app",
"id": "io.cloudron.rathole",
"title": "Rathole",
"description": "Rathole is a secure, stable and high-performance reverse proxy for NAT traversal, written in Rust. This package runs the server side: clients behind NAT connect to the control port with per-service token authentication (optionally Noise/TLS encrypted) and expose their local services through tunnels on the reserved port range. Configuration lives in /app/data/server.toml and hot-reloads on save. No database required.",
"author": "rapiz1 / rathole-org",
"website": "https://github.com/rathole-org/rathole",
"documentationUrl": "https://github.com/rathole-org/rathole/blob/main/README.md",
"contactEmail": "cloudron@tsys.dev",
"tagline": "Secure, high-performance reverse-tunnel server for NAT traversal",
"version": "0.5.0",
"upstreamVersion": "0.5.0",
"healthCheckPath": "/",
"httpPort": 8000,
"httpAuth": {
"type": "proxy"
},
"tcpPorts": {
"CONTROL_PORT": {
"title": "Control channel port",
"description": "TCP port that rathole clients connect to in order to establish tunnels. Change only if it collides with another exposed app on this Cloudron.",
"defaultValue": 2333,
"containerPort": 2333,
"portCount": 1
},
"SERVICE_PORT": {
"title": "Tunnel exit ports",
"description": "Start of the sequential port range reserved for tunneled services (100 ports by default: 5200-5299). Each [server.services.*] block in /app/data/server.toml binds one port from this range; the config hot-reloads, so services can be added without a restart.",
"defaultValue": 5200,
"containerPort": 5200,
"portCount": 100
}
},
"memoryLimit": 268435456,
"addons": {
"localstorage": {}
},
"postInstallMessage": "Rathole is headless: there is nothing to click through. Open the **file manager** and edit **/app/data/server.toml** to define tunnel services (a random default token was generated on first start). The config hot-reloads on save. The client-side setup is documented in the package README.",
"mediaLinks": [],
"changelog": "Initial Cloudron package for Rathole 0.5.0 (server mode). Pre-compiled upstream binary with sha256 pin, token-authenticated tunnels on control port 2333 plus a 100-port service range (5200-5299), config with hot reload at /app/data/server.toml, and an auth-proxied status page on the HTTP port.",
"icon": "file://logo.png"
}
@@ -0,0 +1,48 @@
# 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 (2333) and expose their local services
# through token-authenticated tunnels on the 5200+ port range.
#
# Upstream: https://github.com/rathole-org/rathole (v0.5.0)
# - Ships a prebuilt x86_64-unknown-linux-gnu release binary (musl
# release builds were dropped upstream in v0.5.0)
# - No database, no user accounts; per-service tokens are mandatory
#
# Authentication: Rathole has NO user concept (tunnels are authorized by
# per-service tokens, optionally Noise/TLS encrypted at the transport
# layer). The status page on the HTTP port is gated by Cloudron's
# authentication proxy (httpAuth.type = proxy).
#
# Base image: cloudron/base:4.0.0 (Ubuntu 22.04). The upstream gnu binary
# is built on ubuntu-latest, so the runtime needs glibc >= 2.35 —
# cloudron/base:3.2.0 (20.04) is too old for it.
FROM cloudron/base:4.0.0
ARG RATHOLE_VERSION=0.5.0
ARG RATHOLE_SHA256=3e7d0d0f365120cd3cd351d147d1a12ee960c8068b464d4dd533a3821873b80e
# Pre-compiled-binaries pattern (see JOURNAL.md): download the pinned
# upstream release, verify the sha256 gate, install the binary.
RUN curl -fsSL -o /tmp/rathole.zip \
"https://github.com/rathole-org/rathole/releases/download/v${RATHOLE_VERSION}/rathole-x86_64-unknown-linux-gnu.zip" \
&& echo "${RATHOLE_SHA256} /tmp/rathole.zip" | sha256sum -c - \
&& unzip -o /tmp/rathole.zip -d /usr/local/bin \
&& chmod +x /usr/local/bin/rathole \
&& rm -f /tmp/rathole.zip \
&& /usr/local/bin/rathole --version
# Static status page served on the Cloudron HTTP port (platform health
# check + auth-proxied landing page). start.sh seeds /app/data/server.toml
# on first run and execs rathole in server mode. start.sh is made
# executable on the host, not at build time (Cloudron gotcha).
COPY status.html /app/code/status/index.html
COPY start.sh /app/start.sh
WORKDIR /app/data
EXPOSE 8000 2333 5200-5299
CMD ["/bin/bash", "/app/start.sh"]
@@ -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
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
set -euo pipefail
# Rathole runs in SERVER mode on Cloudron: the box has the public IP and
# rathole clients behind NAT dial in on the control port (container port
# 2333, bridged 1:1 by default). Tunneled services bind container ports
# 5200-5299, which Cloudron exposes in sequence from the SERVICE_PORT
# value chosen at install time.
#
# Rathole has no HTTP interface of its own, so a tiny static status page
# is served on the Cloudron HTTP port. That gives the platform a health
# check endpoint and gives the admin an auth-proxied landing page
# (httpAuth.type = proxy gates it at the platform edge).
export RATHOLE_CONFIG="/app/data/server.toml"
if [[ ! -f "${RATHOLE_CONFIG}" ]]; then
default_token="$(openssl rand -hex 24)"
cat > "${RATHOLE_CONFIG}" <<EOF
# rathole server configuration — hot-reloaded on save, no restart needed.
# Full reference: https://github.com/rathole-org/rathole#configuration
[server]
bind_addr = "0.0.0.0:2333"
default_token = "${default_token}"
heartbeat_interval = 30
[server.transport]
type = "tcp"
[server.transport.tcp]
nodelay = true
# At least one service block must exist — rathole rejects a server config
# with no services. This placeholder listens on the first tunnel port and
# forwards whatever the matching client sends. Rename it or add more
# blocks; each bind_addr must use a distinct port from the reserved range
# (5200-5299 with default install settings). Hot-reloads on save.
[server.services.example]
token = "${default_token}"
bind_addr = "0.0.0.0:5200"
#[server.services.my_web_app]
#token = "another_secret"
#bind_addr = "0.0.0.0:5201"
EOF
echo "Seeded default config at ${RATHOLE_CONFIG} (random default_token generated)"
fi
# Status page (health check + auth-proxied landing page) in the background;
# rathole stays in the foreground as PID-friendly main process.
python3 -m http.server "${CLOUDRON_HTTP_PORT:-8000}" --directory /app/code/status &
exec /usr/local/bin/rathole --server "${RATHOLE_CONFIG}"
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rathole (server)</title>
<style>
body { font-family: -apple-system, "Segoe UI", Roboto, sans-serif; background: #14171c; color: #d8dee6; margin: 0; display: flex; min-height: 100vh; align-items: center; justify-content: center; }
main { max-width: 640px; padding: 2rem; }
h1 { color: #ffffff; font-size: 1.6rem; margin-bottom: 0.25rem; }
p.tagline { color: #7f8c9b; margin-top: 0; }
code { background: #1f242c; border: 1px solid #2d3440; border-radius: 4px; padding: 0.1rem 0.35rem; font-size: 0.85rem; color: #9ecbff; }
table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid #2d3440; }
th { color: #7f8c9b; font-weight: 600; }
pre { background: #1f242c; border: 1px solid #2d3440; border-radius: 6px; padding: 1rem; overflow-x: auto; font-size: 0.8rem; line-height: 1.5; }
.ok { color: #6bc46d; }
</style>
</head>
<body>
<main>
<h1>Rathole <span class="ok">&#9650; server running</span></h1>
<p class="tagline">Secure, high-performance reverse-tunnel server for NAT traversal</p>
<p>Rathole is headless &mdash; this page exists so Cloudron has a health
endpoint and you have a landing spot. Configuration is file-based and
<strong>hot-reloads on save</strong>: edit
<code>/app/data/server.toml</code> with the Cloudron file manager to add
or remove tunnel services. A random <code>default_token</code> was
generated on first start; copy it from that file.</p>
<table>
<tr><th>Port</th><th>Purpose</th></tr>
<tr><td>2333</td><td>Control channel &mdash; rathole clients connect here</td></tr>
<tr><td>5200&ndash;5299</td><td>Tunnel exit ports &mdash; one per <code>[server.services.*]</code> block</td></tr>
<tr><td>HTTP (this page)</td><td>Status/health only, gated by the Cloudron auth proxy</td></tr>
</table>
<p>Client side (on the machine behind NAT), with a matching service block on the server:</p>
<pre>[client]
remote_addr = "your-cloudron.example.com:2333"
[client.services.my_nas_ssh]
token = "&lt;same token as the server&gt;"
local_addr = "127.0.0.1:22"</pre>
<p style="color:#7f8c9b;font-size:0.85rem;">Upstream docs:
<a style="color:#9ecbff" href="https://github.com/rathole-org/rathole">github.com/rathole-org/rathole</a></p>
</main>
</body>
</html>
+6 -5
View File
@@ -9,9 +9,9 @@ The Cloudron component focuses on packaging upstream free/libre/open application
### 📊 Current Progress
- **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt))
- **Completed Packages**: 10/~57 (~18%)
- **Completed Packages**: 11/~57 (~19%)
- **Packaging Templates**: Created ✅
- **Packages Committed & Pushed**: 10
- **Packages Committed & Pushed**: 11
- **Build Tickets**: 46 filed (#633-#678, umbrella
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
grist-core excluded (packaged upstream)
@@ -32,6 +32,7 @@ The Cloudron component focuses on packaging upstream free/libre/open application
| 8 | draw.io | Documentation-Tools | — | 8080 | none (auth proxy) | ✅ Committed |
| 9 | Windmill | Automation | ~2GB | 8000 | localstorage, postgresql | ✅ Committed |
| 10 | Easy-Gate | Infrastructure | 3.18GB | 8080 | localstorage (auth proxy) | ✅ Committed |
| 11 | Rathole | Infrastructure | 3.51GB | 8000, 2333, 5200-5299 | localstorage (auth proxy) | ✅ Committed |
### 📦 Packages in Development
@@ -65,7 +66,7 @@ None currently in development.
### ⚡ Productivity Metrics
- **Packages Completed**: 10/~57 (~18%)
- **Packages Completed**: 11/~57 (~19%)
- **Average Package Time**: ~30 minutes
- **Success Rate**: 100% (all packages built successfully)
- **Commits Pushed**: 100% (all packages pushed to remote)
@@ -90,7 +91,7 @@ Applications are organized by function rather than programming language:
| **Documentation-Tools** | Documentation and diagramming tools | 3 | 1/3 (33%) |
| **Financial-Payments** | Payment processing and financial infrastructure | 1 | 0/1 (0%) |
| **Financial-Trading** | Trading and financial algorithm platforms | 1 | 0/1 (0%) |
| **Infrastructure** | Infrastructure and networking tools | 6 | 1/6 (17%) |
| **Infrastructure** | Infrastructure and networking tools | 6 | 2/6 (33%) |
| **Legal** | Legal and compliance applications | 1 | 0/1 (0%) |
| **Low-Code** | Low-code and no-code platforms | 3 | 1/3 (33%) |
| **Monitoring** | Monitoring and observability tools | 6 | 1/6 (17%) |
@@ -127,7 +128,7 @@ Applications are organized by function rather than programming language:
| [Fleet](https://github.com/fleetdm/fleet) | [GitHub](https://github.com/fleetdm/fleet) | Device management and monitoring | Monitoring |
| [NetBox](https://github.com/netbox-community/netbox) | [GitHub](https://github.com/netbox-community/netbox) | IP address management (IPAM) and data center infrastructure management | Infrastructure |
| [SeaTunnel](https://github.com/apache/seatunnel) | [GitHub](https://github.com/apache/seatunnel) | Data integration and streaming platform | Data-Management |
| [Rathole](https://github.com/rapiz1/rathole) | [GitHub](https://github.com/rapiz1/rathole) | Lightweight and high-performance reverse proxy | Infrastructure |
| [Rathole](https://github.com/rapiz1/rathole) | [GitHub](https://github.com/rapiz1/rathole) | Lightweight and high-performance reverse proxy | Infrastructure | ✅ Packaged |
| [Easy-Gate](https://github.com/wiredlush/easy-gate) | [GitHub](https://github.com/wiredlush/easy-gate) | Gateway and proxy solution | Infrastructure | ✅ Packaged |
| [Huginn](https://github.com/huginn/huginn) | [GitHub](https://github.com/huginn/huginn) | Agents that do things for you automatically | Automation |
| [ConsulDemocracy](https://github.com/consuldemocracy/consuldemocracy) | [GitHub](https://github.com/consuldemocracy/consuldemocracy) | Open-source citizen participation platform | Collaboration |
+9 -7
View File
@@ -3,20 +3,20 @@
> **Human read-only. Agents maintain this file automatically after each work
> session.** Do not edit by hand — the next agent run will overwrite it.
>
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — Easy-Gate packaged
> (#651, Infrastructure, 10th package); auth gate verdict: no user concept,
> shipped behind the Cloudron auth proxy.
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — Rathole packaged
> (#650, Infrastructure, 11th package); auth gate verdict: no user concept,
> status page behind the Cloudron auth proxy, tunnels token-authenticated.
## Current State: STABLE (packaging phase, ongoing)
Cloudron packaging pipeline is operational. 10 of ~57 upstream applications are
Cloudron packaging pipeline is operational. 11 of ~57 upstream applications are
packaged, committed, and pushed. Packaging templates exist for the core
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
All remaining apps now carry build tickets (#633-#678) under umbrella
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
ready for the sequential grind-driver pattern.
## Completed Packages (10)
## Completed Packages (11)
| # | Application | Category | Pattern | Port(s) | Addons |
|---|-------------|----------|---------|---------|--------|
@@ -30,6 +30,7 @@ ready for the sequential grind-driver pattern.
| 8 | draw.io | Documentation-Tools | Official-image wrapper + auth proxy | 8080 | none (stateless) |
| 9 | Windmill | Automation | Official-image wrapper + start.sh | 8000 | localstorage, postgresql |
| 10 | Easy-Gate | Infrastructure | Multi-stage (Go) + auth proxy | 8080 | localstorage |
| 11 | Rathole | Infrastructure | Pre-compiled binaries + auth proxy | 8000, 2333, 5200-5299 | localstorage |
Each package lives in `Package-Workspace/<Category>/<app>/` and contains a
`Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`,
@@ -118,7 +119,7 @@ Full write-ups of each pattern + challenges are in [`JOURNAL.md`](JOURNAL.md).
| DevOps-Tools | 1 | 0/1 | |
| Financial-Payments | 1 | 0/1 | |
| Financial-Trading | 1 | 0/1 | |
| Infrastructure | 6 | 1/6 | easy-gate done |
| Infrastructure | 6 | 2/6 | easy-gate, rathole done |
| Legal | 1 | 0/1 | |
| Project-Management | 1 | 0/1 | |
| Scientific-Computing | 2 | 0/2 | |
@@ -132,7 +133,7 @@ Auth capability is a hard gate before packaging (see
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
(unacceptable / blocked-on-auth).
### Completed packages (10)
### Completed packages (11)
| App | OIDC | LDAP | Verdict | Note |
|-----|------|------|---------|------|
@@ -146,6 +147,7 @@ LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
| draw.io | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` (no users, stateless) |
| Windmill | yes | no | ✅ preferred | **Packaged**; OIDC configured via Admin Settings UI (no env vars) |
| Easy-Gate | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` (no user concept; IP-subnet groups only) |
| Rathole | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` on the status page; tunnels secured by mandatory per-service tokens (Noise/TLS optional) |
### Candidates researched