feat: add FX Cloudron package (DevOps-Tools) [#640]
FX 0.9.48 ("poor man's function as a service") as the 13th package:
pre-compiled goreleaser release binary with sha256 pin on
cloudron/base:4.0.0. fx is a CLI with no user concept, so the package
is a workstation: pinned binary + persistent workspace
(functions/ssh/kube) driven from the Cloudron web terminal, with an
auth-proxied landing page as the only HTTP surface (httpAuth proxy).
Deploys target remote Docker hosts over key-based SSH or Kubernetes
via FX_KUBECONF. Build green; runtime smoke (landing page, workspace
seeding, fx -v) green. Docs gardened to 13 packages.
Ticket: https://projects.knownelement.com/issues/640
This commit is contained in:
+71
-1
@@ -4,7 +4,7 @@
|
|||||||
**Project**: TSYSDevStack-SupportStack-Cloudron
|
**Project**: TSYSDevStack-SupportStack-Cloudron
|
||||||
**Goal**: Package ~57 applications for Cloudron PaaS platform
|
**Goal**: Package ~57 applications for Cloudron PaaS platform
|
||||||
**Start Date**: 2025-01-24
|
**Start Date**: 2025-01-24
|
||||||
**Current Status**: 12/~57 packages completed (~21%)
|
**Current Status**: 13/~57 packages completed (~23%)
|
||||||
|
|
||||||
## Completed Packages
|
## Completed Packages
|
||||||
|
|
||||||
@@ -966,6 +966,76 @@ PostgreSQL databases (OIDC login, OPA-authorized queries, cached results)
|
|||||||
|
|
||||||
**Commit**: `feat: add Database-Gateway Cloudron package (Infrastructure) [#639]`
|
**Commit**: `feat: add Database-Gateway Cloudron package (Infrastructure) [#639]`
|
||||||
|
|
||||||
|
### 13. FX (DevOps-Tools) ✅
|
||||||
|
**Date**: 2026-09-01
|
||||||
|
**Application**: FX — "poor man's function as a service" (metrue/fx): a CLI
|
||||||
|
that turns a stateless function file (JS, Python, Go, Ruby, Java, PHP,
|
||||||
|
Perl, Crystal, Rust, Julia, D) into a running HTTP service on your own
|
||||||
|
Docker host or Kubernetes cluster
|
||||||
|
**Package Size**: 3.55GB (cloudron/base 4.0.0 dominates)
|
||||||
|
**Ports**: 8000 (HTTP landing/health page only — fx itself listens on
|
||||||
|
nothing)
|
||||||
|
**Addons**: localstorage (auth proxy, no database)
|
||||||
|
|
||||||
|
**Key Learnings**:
|
||||||
|
- **Auth gate verdict**: NO user concept — fx is a terminal tool: no UI,
|
||||||
|
no accounts, no SSO hooks → `httpAuth.type = proxy` gates the only
|
||||||
|
HTTP surface (the landing page), the Rathole/Easy-Gate pattern for
|
||||||
|
user-less apps. Terminal + workspace access is Cloudron's app access
|
||||||
|
list; the SSH keys under /app/data/ssh are target credentials
|
||||||
|
- **First pure "CLI workstation" package**: fx has no daemon, so the
|
||||||
|
landing-page server (python3 -m http.server) is the ONLY long-running
|
||||||
|
process; the fx binary runs on demand from the Cloudron web terminal.
|
||||||
|
Package value = pinned binary + persistent workspace
|
||||||
|
(/app/data/{functions,ssh,kube})
|
||||||
|
- **No Docker daemon in Cloudron apps** (and no host socket access):
|
||||||
|
fx's local-docker mode is unusable in-app; deploys target remote
|
||||||
|
Docker hosts over SSH (Go-native ssh library, key-based — no
|
||||||
|
openssh binary needed in the image) or Kubernetes via FX_KUBECONF
|
||||||
|
- **Release pinning on a quiet upstream**: last published release is
|
||||||
|
0.9.48-alpha.d91a7a0 (2021-06-10) while master sits at 2023-10-24;
|
||||||
|
packaged the release (what official scripts/install.sh installs; the
|
||||||
|
binary self-reports 0.9.48), not master
|
||||||
|
- **glibc trap, Rathole side**: the goreleaser `Tux` asset is
|
||||||
|
glibc-built → Ubuntu base (cloudron/base:4.0.0); the mirror image of
|
||||||
|
Database Gateway's musl/alpine pairing
|
||||||
|
- **Starter functions must match upstream shapes exactly**: JS =
|
||||||
|
Koa-style `(ctx) => { ctx.body = ... }`, Python = plain
|
||||||
|
`def fx(request)` — copied from upstream examples verbatim
|
||||||
|
|
||||||
|
**Build Process**:
|
||||||
|
- Pre-compiled-binaries pattern (JOURNAL pattern #5): release tarball
|
||||||
|
`fx_0.9.48-alpha.d91a7a0_Tux_64-bit.tar.gz` downloaded in-Dockerfile
|
||||||
|
behind a sha256 pin taken from the upstream checksums.txt; `fx -v`
|
||||||
|
runs inside the build as an executability gate
|
||||||
|
- Logo: 256x256 "fx" monogram generated in a throwaway alpine:3.20
|
||||||
|
container (upstream ships no logo asset)
|
||||||
|
- start.sh: seeds the /app/data workspace (functions/ssh/kube + two
|
||||||
|
starter functions) then execs the landing-page server in the
|
||||||
|
foreground — committed executable
|
||||||
|
|
||||||
|
**Validation**:
|
||||||
|
- `docker build --cgroup-parent ukrrs-batch.slice -t fx-cloudron:test`
|
||||||
|
→ green (sha256 gate OK, `fx version 0.9.48` printed in-build)
|
||||||
|
- Runtime smoke: container up, `GET /` → 200 with the FX landing page,
|
||||||
|
workspace dirs + hello.js/hello.py seeded, startup banner in logs;
|
||||||
|
container removed after test
|
||||||
|
|
||||||
|
**Files Created**:
|
||||||
|
- Dockerfile (pre-compiled binary, sha256-pinned, cloudron/base:4.0.0)
|
||||||
|
- CloudronManifest.json (manifestVersion 2, httpAuth proxy, httpPort
|
||||||
|
8000, localstorage only)
|
||||||
|
- start.sh (workspace seed + landing-page server, exec) — committed
|
||||||
|
executable
|
||||||
|
- status.html (auth-proxied landing/usage page)
|
||||||
|
- README.md (auth story, terminal workflow, remote/K8s usage)
|
||||||
|
- CHANGELOG.md
|
||||||
|
- .env.example (FX_HOST / FX_KUBECONF knobs)
|
||||||
|
- .dockerignore (excludes the cloned repo/ from the build context)
|
||||||
|
- logo.png (256x256 monogram)
|
||||||
|
|
||||||
|
**Commit**: `feat: add FX Cloudron package (DevOps-Tools) [#640]`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Packaging Pattern: Download Pre-Compiled Binaries
|
## Packaging Pattern: Download Pre-Compiled Binaries
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
repo/
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# FX Cloudron package — environment knobs
|
||||||
|
#
|
||||||
|
# Set via App -> Configure -> Environment; they are visible to fx when
|
||||||
|
# run from the app's web terminal. Not secrets.
|
||||||
|
|
||||||
|
# Default deploy target for fx up/list/down/image: <user>@<host> of a
|
||||||
|
# Docker host reachable over SSH. Leave unset to pass --host per
|
||||||
|
# command. The SSH key itself is a file, not env: put it in
|
||||||
|
# /app/data/ssh/ and pass --ssh_key (fx authenticates with keys only).
|
||||||
|
#FX_HOST=deploy@docker.example.com
|
||||||
|
|
||||||
|
# Path to a kubeconfig for Kubernetes deploys (or pass -C per command).
|
||||||
|
# /app/data/kube/config is the persistent home for it.
|
||||||
|
#FX_KUBECONF=/app/data/kube/config
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Changelog — FX Cloudron Package
|
||||||
|
|
||||||
|
## 1.0.0 (2026-09-01)
|
||||||
|
|
||||||
|
Initial Cloudron package for fx 0.9.48 (poor man's function as a
|
||||||
|
service).
|
||||||
|
|
||||||
|
- Pre-compiled-binaries pattern: upstream goreleaser release
|
||||||
|
`fx_0.9.48-alpha.d91a7a0_Tux_64-bit.tar.gz` (linux/amd64) downloaded
|
||||||
|
at build time behind a sha256 pin taken from the upstream
|
||||||
|
checksums.txt; `fx -v` runs inside the build as an executability gate.
|
||||||
|
- fx is a CLI with no daemon or UI: the package is an fx workstation —
|
||||||
|
pinned binary + persistent workspace (`functions/`, `ssh/`, `kube/`
|
||||||
|
under /app/data, with two upstream-shaped starter functions) — driven
|
||||||
|
from the Cloudron web terminal.
|
||||||
|
- No user concept → `httpAuth.type = proxy` gates a static landing/usage
|
||||||
|
page served on the HTTP port (also the platform health check); the
|
||||||
|
page server is the only long-running process.
|
||||||
|
- Deploys target remote Docker hosts over key-based SSH (Go-native SSH,
|
||||||
|
no openssh binary needed in the image) or Kubernetes via kubeconfig
|
||||||
|
(`FX_KUBECONF`); documented limitation: the app container has no
|
||||||
|
Docker daemon, so functions never run inside this app.
|
||||||
|
- Addons: `localstorage` only (workspace persistence; no database).
|
||||||
|
- Logo: 256x256 monogram generated for this package (upstream ships no
|
||||||
|
logo asset).
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"manifestVersion": 2,
|
||||||
|
"type": "app",
|
||||||
|
"id": "io.cloudron.fx",
|
||||||
|
"title": "FX",
|
||||||
|
"description": "fx is 'poor man's function as a service': a CLI that turns a stateless function file (JavaScript, Python, Go, Ruby, Java, PHP, Perl, Crystal, Rust, Julia, D) into a running HTTP service on your own Docker host or Kubernetes cluster in seconds. This package is an fx workstation: the pinned fx binary plus a persistent workspace, driven from the Cloudron web terminal. Deploy targets are remote Docker hosts (SSH key auth) or a Kubernetes cluster (kubeconfig); the app container itself has no Docker daemon, so functions always run on their target, not inside this app.",
|
||||||
|
"author": "metrue",
|
||||||
|
"website": "https://github.com/metrue/fx",
|
||||||
|
"documentationUrl": "https://github.com/metrue/fx/blob/master/README.md",
|
||||||
|
"contactEmail": "cloudron@tsys.dev",
|
||||||
|
"tagline": "Poor man's Function as a Service — deploy function files from the terminal",
|
||||||
|
"version": "0.9.48",
|
||||||
|
"upstreamVersion": "0.9.48",
|
||||||
|
"healthCheckPath": "/",
|
||||||
|
"httpPort": 8000,
|
||||||
|
"httpAuth": {
|
||||||
|
"type": "proxy"
|
||||||
|
},
|
||||||
|
"memoryLimit": 268435456,
|
||||||
|
"addons": {
|
||||||
|
"localstorage": {}
|
||||||
|
},
|
||||||
|
"postInstallMessage": "FX is a CLI, not a web app: there is nothing to click through. Open the app's **web terminal** and run `fx -v`. Drop an SSH key into **/app/data/ssh/** (or a kubeconfig into **/app/data/kube/**), put function sources in **/app/data/functions/** (two starters are already there), then `fx up --host <user>@<host> --ssh_key /app/data/ssh/id_rsa --name hello /app/data/functions/hello.js`. The landing page on the app URL is an auth-proxied usage guide.",
|
||||||
|
"mediaLinks": [],
|
||||||
|
"changelog": "Initial Cloudron package for fx 0.9.48 ('poor man's function as a service'). Pre-compiled upstream release binary with sha256 pin, persistent workspace at /app/data (functions/, ssh/, kube/) with two starter functions, and an auth-proxied landing page on the HTTP port (fx has no daemon or UI of its own). Driven from the Cloudron web terminal; deploys go to remote Docker hosts over SSH or to Kubernetes via kubeconfig.",
|
||||||
|
"icon": "file://logo.png"
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# FX Cloudron Package
|
||||||
|
#
|
||||||
|
# fx (metrue/fx) is "poor man's function as a service": a CLI that turns a
|
||||||
|
# stateless function file (JavaScript, Python, Go, Ruby, Java, PHP, Perl,
|
||||||
|
# Crystal, Rust, Julia, D) into a running HTTP service on your own Docker
|
||||||
|
# host or Kubernetes cluster, in seconds. fx is a DRIVER-side tool: it
|
||||||
|
# packages the function, ships it to the target over SSH (key-based) or
|
||||||
|
# the K8s API, and the TARGET runs the container.
|
||||||
|
#
|
||||||
|
# Cloudron app containers have no Docker daemon, so this package is the
|
||||||
|
# operator's fx WORKSTATION: the pinned fx binary plus a persistent
|
||||||
|
# workspace (/app/data/functions, /app/data/ssh, /app/data/kube), driven
|
||||||
|
# from the Cloudron web terminal. Deploy targets are remote Docker hosts
|
||||||
|
# (--host user@host --ssh_key ...) or a Kubernetes cluster (FX_KUBECONF
|
||||||
|
# or -C kubeconf).
|
||||||
|
#
|
||||||
|
# Authentication: fx has NO user concept — no web UI, no accounts, no
|
||||||
|
# SSO hooks — so the auth-gate verdict is the proxy row (AGENTS.md
|
||||||
|
# matrix). The manifest declares httpAuth.type = proxy: Cloudron's auth
|
||||||
|
# proxy gates the landing page, the only HTTP surface this app has.
|
||||||
|
# Access to the terminal/workspace itself is Cloudron's app access list.
|
||||||
|
#
|
||||||
|
# Upstream: https://github.com/metrue/fx
|
||||||
|
# - Release 0.9.48-alpha.d91a7a0 (2021-06-10) is the latest published
|
||||||
|
# release and what the official scripts/install.sh installs; the
|
||||||
|
# binary reports version 0.9.48. Repo master (2023) has no newer
|
||||||
|
# release.
|
||||||
|
# - Ships goreleaser tarballs; the linux/amd64 asset is
|
||||||
|
# fx_<tag>_Tux_64-bit.tar.gz, glibc-built -> needs an Ubuntu base.
|
||||||
|
FROM cloudron/base:4.0.0
|
||||||
|
|
||||||
|
ARG FX_TAG=0.9.48-alpha.d91a7a0
|
||||||
|
ARG FX_SHA256=1ed8a40f81038ca9e33aa09dba2184448b2efa3ed6373936e9f849f50200910f
|
||||||
|
|
||||||
|
# Pre-compiled-binaries pattern (JOURNAL pattern #5): pinned release
|
||||||
|
# download behind a sha256 gate (checksum taken from the upstream
|
||||||
|
# checksums.txt asset). Building the 2021-era codebase (go 1.12 modules
|
||||||
|
# + packr assets) from source would buy nothing over the official
|
||||||
|
# release binary.
|
||||||
|
RUN curl -fsSL -o /tmp/fx.tar.gz \
|
||||||
|
"https://github.com/metrue/fx/releases/download/${FX_TAG}/fx_${FX_TAG}_Tux_64-bit.tar.gz" \
|
||||||
|
&& echo "${FX_SHA256} /tmp/fx.tar.gz" | sha256sum -c - \
|
||||||
|
&& tar -xzf /tmp/fx.tar.gz -C /usr/local/bin --exclude='*.md' --exclude='LICENSE*' \
|
||||||
|
&& chmod +x /usr/local/bin/fx \
|
||||||
|
&& rm -f /tmp/fx.tar.gz \
|
||||||
|
&& /usr/local/bin/fx -v
|
||||||
|
|
||||||
|
# Static landing page served on the Cloudron HTTP port (platform health
|
||||||
|
# check + auth-proxied usage guide). fx itself has no daemon, so the
|
||||||
|
# page server is the only long-running process. start.sh seeds the
|
||||||
|
# /app/data workspace on first run; it 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
|
||||||
|
|
||||||
|
CMD ["/bin/bash", "/app/start.sh"]
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# FX — Cloudron Package
|
||||||
|
|
||||||
|
[fx](https://github.com/metrue/fx) is "poor man's function as a service":
|
||||||
|
a CLI that turns a stateless function file (JavaScript, Python, Go, Ruby,
|
||||||
|
Java, PHP, Perl, Crystal, Rust, Julia, D) into a running HTTP service on
|
||||||
|
your own Docker host or Kubernetes cluster, in seconds. fx packages the
|
||||||
|
function, ships it to the target over SSH (key-based) or the K8s API, and
|
||||||
|
the target runs the container.
|
||||||
|
|
||||||
|
This package is an **fx workstation**: the pinned fx binary plus a
|
||||||
|
persistent workspace, driven from the Cloudron web terminal. Cloudron app
|
||||||
|
containers have no Docker daemon (and no access to the host's), so
|
||||||
|
deploys always target a **remote** Docker host or a Kubernetes cluster —
|
||||||
|
never the app container itself.
|
||||||
|
|
||||||
|
## Packaging overview
|
||||||
|
|
||||||
|
| Aspect | Choice |
|
||||||
|
|--------|--------|
|
||||||
|
| Pattern | Pre-compiled binaries (JOURNAL pattern #5) |
|
||||||
|
| Base image | `cloudron/base:4.0.0` (Ubuntu 22.04; the goreleaser binary is glibc-built) |
|
||||||
|
| Upstream binary | `fx_0.9.48-alpha.d91a7a0_Tux_64-bit.tar.gz` (linux/amd64), sha256-pinned in the Dockerfile (checksum from upstream `checksums.txt`) |
|
||||||
|
| Addons | `localstorage` only (workspace persistence; no database) |
|
||||||
|
| Auth | No user concept → `httpAuth.type = proxy` (see below) |
|
||||||
|
| Runtime | `start.sh` seeds the workspace and serves the landing page; fx runs on demand from the terminal |
|
||||||
|
|
||||||
|
Why pre-compiled: the last published release is `0.9.48-alpha.d91a7a0`
|
||||||
|
(2021-06-10) — the same artifact the official `scripts/install.sh`
|
||||||
|
installs, and the binary reports version `0.9.48`. Repo master (2023) has
|
||||||
|
no newer release; building the go 1.12-era, packr-using codebase from
|
||||||
|
source would buy nothing over the official binary.
|
||||||
|
|
||||||
|
## Authentication (auth gate verdict: proxy)
|
||||||
|
|
||||||
|
- fx has **no user concept**: no web UI, no accounts, no SSO hooks — it
|
||||||
|
is a terminal tool.
|
||||||
|
- The manifest declares `httpAuth: {"type": "proxy"}`: Cloudron's auth
|
||||||
|
proxy gates the landing page, which is the only HTTP surface this app
|
||||||
|
has. Access to the terminal (and therefore the workspace and SSH keys)
|
||||||
|
is Cloudron's app access list — restrict the app to the admins who
|
||||||
|
should wield it.
|
||||||
|
- The SSH keys stored in `/app/data/ssh/` are the credentials for the
|
||||||
|
*deploy targets*; guard them with the app's access list and file
|
||||||
|
permissions.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Open the app's **web terminal** (or `cloudron exec`).
|
||||||
|
2. Drop an SSH private key into `/app/data/ssh/` (e.g. via the file
|
||||||
|
manager) for your Docker target, or a kubeconfig into
|
||||||
|
`/app/data/kube/` for a Kubernetes target.
|
||||||
|
3. Deploy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fx up --host deploy@example.com --ssh_key /app/data/ssh/id_rsa \
|
||||||
|
--name hello /app/data/functions/hello.js
|
||||||
|
|
||||||
|
fx list --host deploy@example.com # deployed services
|
||||||
|
fx down --host deploy@example.com hello
|
||||||
|
```
|
||||||
|
|
||||||
|
Kubernetes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export FX_KUBECONF=/app/data/kube/config
|
||||||
|
fx up --name hello /app/data/functions/hello.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The two seeded starters (`hello.js`, `hello.py`) use the exact upstream
|
||||||
|
example shapes: a Koa-style `ctx` handler for JS, a plain `fx(request)`
|
||||||
|
callable for Python.
|
||||||
|
|
||||||
|
Knobs: `FX_HOST` (default deploy target, `<user>@<host>`) and
|
||||||
|
`FX_KUBECONF` (path to kubeconfig) can be set once via Cloudron's
|
||||||
|
environment settings instead of per-command flags — see `.env.example`.
|
||||||
|
|
||||||
|
## Ports
|
||||||
|
|
||||||
|
| Port | Type | Purpose |
|
||||||
|
|------|------|---------|
|
||||||
|
| 8000 | `httpPort` | Landing/usage page + platform health check (behind Cloudron auth proxy) |
|
||||||
|
|
||||||
|
fx itself listens on nothing; deployed functions listen on their target
|
||||||
|
host, outside this app.
|
||||||
|
|
||||||
|
## Build & test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --cgroup-parent ukrrs-batch.slice -t fx-cloudron:test Package-Workspace/DevOps-Tools/fx/
|
||||||
|
docker run --rm --entrypoint /usr/local/bin/fx fx-cloudron:test -v # -> 0.9.48
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `Dockerfile` — pinned release download + sha256 gate on cloudron/base:4.0.0
|
||||||
|
- `CloudronManifest.json` — manifestVersion 2, httpAuth proxy, localstorage only
|
||||||
|
- `start.sh` — workspace seeding + landing-page server (committed executable)
|
||||||
|
- `status.html` — auth-proxied landing/usage page
|
||||||
|
- `.env.example` — FX_HOST / FX_KUBECONF knobs
|
||||||
|
- `.dockerignore` — excludes the cloned `repo/` from the build context
|
||||||
|
- `logo.png` — 256x256 monogram (fx ships no logo asset)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
Executable
+40
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# fx is a CLI, not a daemon: it has nothing to serve. The long-running
|
||||||
|
# process of this package is therefore the auth-proxied landing page on
|
||||||
|
# the Cloudron HTTP port (health check + usage guide). The fx binary and
|
||||||
|
# the persistent workspace below are driven interactively from the
|
||||||
|
# Cloudron web terminal (App -> terminal, or `cloudron exec`).
|
||||||
|
#
|
||||||
|
# Workspace layout seeded on first run:
|
||||||
|
# /app/data/functions/ function sources (two starter functions)
|
||||||
|
# /app/data/ssh/ SSH keys for remote Docker targets
|
||||||
|
# /app/data/kube/ kubeconfig for Kubernetes targets
|
||||||
|
|
||||||
|
mkdir -p /app/data/functions /app/data/ssh /app/data/kube
|
||||||
|
|
||||||
|
# Starter functions, exactly the upstream example shapes (Koa-style ctx
|
||||||
|
# for JavaScript, plain callable for Python).
|
||||||
|
if [[ ! -f /app/data/functions/hello.js ]]; then
|
||||||
|
cat > /app/data/functions/hello.js <<'EOF'
|
||||||
|
module.exports = (ctx) => {
|
||||||
|
ctx.body = 'hello world'
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f /app/data/functions/hello.py ]]; then
|
||||||
|
cat > /app/data/functions/hello.py <<'EOF'
|
||||||
|
def fx(request):
|
||||||
|
return "hello world"
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "fx $(/usr/local/bin/fx -v) ready - open the app's web terminal to use it."
|
||||||
|
echo "Workspace: /app/data/functions (sources), /app/data/ssh (keys), /app/data/kube (kubeconfig)"
|
||||||
|
echo "Deploy example: fx up --host <user>@<host> --ssh_key /app/data/ssh/id_rsa --name hello /app/data/functions/hello.js"
|
||||||
|
|
||||||
|
# Landing page (health check + auth-proxied usage guide) is the only
|
||||||
|
# long-running process - fx itself runs on demand from the terminal.
|
||||||
|
exec python3 -m http.server "${CLOUDRON_HTTP_PORT:-8000}" --directory /app/code/status
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>FX</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>FX <span class="ok">▲ fx 0.9.48 ready</span></h1>
|
||||||
|
<p class="tagline">Poor man's function as a service</p>
|
||||||
|
|
||||||
|
<p>fx is a <strong>CLI, not a web app</strong> — this page exists so
|
||||||
|
Cloudron has a health endpoint and you have a landing spot (gated by the
|
||||||
|
Cloudron auth proxy). You drive fx from the app's <strong>web
|
||||||
|
terminal</strong>: open the terminal and run <code>fx -v</code> to confirm,
|
||||||
|
then deploy function files to your own Docker hosts or Kubernetes
|
||||||
|
clusters. Cloudron app containers have no Docker daemon, so functions
|
||||||
|
always run on the <em>target</em> you point fx at, never inside this
|
||||||
|
app.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Path</th><th>Purpose</th></tr>
|
||||||
|
<tr><td><code>/app/data/functions/</code></td><td>Function sources (<code>hello.js</code> + <code>hello.py</code> starters seeded)</td></tr>
|
||||||
|
<tr><td><code>/app/data/ssh/</code></td><td>SSH keys for remote Docker targets (fx logs in with a key, no passwords)</td></tr>
|
||||||
|
<tr><td><code>/app/data/kube/</code></td><td>kubeconfig for Kubernetes targets</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>Deploy to a remote Docker host (JS example):</p>
|
||||||
|
<pre>fx up --host deploy@example.com --ssh_key /app/data/ssh/id_rsa \
|
||||||
|
--name hello /app/data/functions/hello.js
|
||||||
|
fx list --host deploy@example.com
|
||||||
|
fx down --host deploy@example.com hello</pre>
|
||||||
|
|
||||||
|
<p>Deploy to Kubernetes (copy your kubeconfig to
|
||||||
|
<code>/app/data/kube/config</code> first):</p>
|
||||||
|
<pre>export FX_KUBECONF=/app/data/kube/config
|
||||||
|
fx up --name hello /app/data/functions/hello.py</pre>
|
||||||
|
|
||||||
|
<p style="color:#7f8c9b;font-size:0.85rem;">Supported languages: Go,
|
||||||
|
JavaScript, Python, Ruby, Java, PHP, Perl, Crystal, Rust, Julia, D.
|
||||||
|
Upstream docs:
|
||||||
|
<a style="color:#9ecbff" href="https://github.com/metrue/fx">github.com/metrue/fx</a></p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -9,9 +9,9 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
### 📊 Current Progress
|
### 📊 Current Progress
|
||||||
|
|
||||||
- **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt))
|
- **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt))
|
||||||
- **Completed Packages**: 12/~57 (~21%)
|
- **Completed Packages**: 13/~57 (~23%)
|
||||||
- **Packaging Templates**: Created ✅
|
- **Packaging Templates**: Created ✅
|
||||||
- **Packages Committed & Pushed**: 12 ✅
|
- **Packages Committed & Pushed**: 13 ✅
|
||||||
- **Build Tickets**: 46 filed (#633-#678, umbrella
|
- **Build Tickets**: 46 filed (#633-#678, umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
||||||
grist-core excluded (packaged upstream)
|
grist-core excluded (packaged upstream)
|
||||||
@@ -34,6 +34,7 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
| 10 | Easy-Gate | Infrastructure | 3.18GB | 8080 | localstorage (auth proxy) | ✅ 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 |
|
| 11 | Rathole | Infrastructure | 3.51GB | 8000, 2333, 5200-5299 | localstorage (auth proxy) | ✅ Committed |
|
||||||
| 12 | Database Gateway | Infrastructure | 93.7MB | 8080 | localstorage, postgresql | ✅ Committed |
|
| 12 | Database Gateway | Infrastructure | 93.7MB | 8080 | localstorage, postgresql | ✅ Committed |
|
||||||
|
| 13 | FX | DevOps-Tools | 3.55GB | 8000 | localstorage (auth proxy) | ✅ Committed |
|
||||||
|
|
||||||
### 📦 Packages in Development
|
### 📦 Packages in Development
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ None currently in development.
|
|||||||
|
|
||||||
### ⚡ Productivity Metrics
|
### ⚡ Productivity Metrics
|
||||||
|
|
||||||
- **Packages Completed**: 12/~57 (~21%)
|
- **Packages Completed**: 13/~57 (~23%)
|
||||||
- **Average Package Time**: ~30 minutes
|
- **Average Package Time**: ~30 minutes
|
||||||
- **Success Rate**: 100% (all packages built successfully)
|
- **Success Rate**: 100% (all packages built successfully)
|
||||||
- **Commits Pushed**: 100% (all packages pushed to remote)
|
- **Commits Pushed**: 100% (all packages pushed to remote)
|
||||||
@@ -88,7 +89,7 @@ Applications are organized by function rather than programming language:
|
|||||||
| **Communication** | Messaging and communication platforms | 2 | 0/2 (0%) |
|
| **Communication** | Messaging and communication platforms | 2 | 0/2 (0%) |
|
||||||
| **Data-Management** | Data processing and management tools | 2 | 0/2 (0%) |
|
| **Data-Management** | Data processing and management tools | 2 | 0/2 (0%) |
|
||||||
| **Development** | Development tools and platforms | 4 | 2/4 (50%) |
|
| **Development** | Development tools and platforms | 4 | 2/4 (50%) |
|
||||||
| **DevOps-Tools** | DevOps and infrastructure tooling | 2 | 0/2 (0%) |
|
| **DevOps-Tools** | DevOps and infrastructure tooling | 1 | 1/1 (100%) ✅ |
|
||||||
| **Documentation-Tools** | Documentation and diagramming tools | 3 | 1/3 (33%) |
|
| **Documentation-Tools** | Documentation and diagramming tools | 3 | 1/3 (33%) |
|
||||||
| **Financial-Payments** | Payment processing and financial infrastructure | 1 | 0/1 (0%) |
|
| **Financial-Payments** | Payment processing and financial infrastructure | 1 | 0/1 (0%) |
|
||||||
| **Financial-Trading** | Trading and financial algorithm platforms | 1 | 0/1 (0%) |
|
| **Financial-Trading** | Trading and financial algorithm platforms | 1 | 0/1 (0%) |
|
||||||
@@ -116,7 +117,7 @@ Applications are organized by function rather than programming language:
|
|||||||
| [Pimcore](https://github.com/pimcore/pimcore) | [GitHub](https://github.com/pimcore/pimcore) | Open-source digital experience platform | Business-Apps |
|
| [Pimcore](https://github.com/pimcore/pimcore) | [GitHub](https://github.com/pimcore/pimcore) | Open-source digital experience platform | Business-Apps |
|
||||||
| [Database-Gateway](https://github.com/kazhuravlev/database-gateway) | [GitHub](https://github.com/kazhuravlev/database-gateway) | Database gateway and connection management | Infrastructure | ✅ Packaged |
|
| [Database-Gateway](https://github.com/kazhuravlev/database-gateway) | [GitHub](https://github.com/kazhuravlev/database-gateway) | Database gateway and connection management | Infrastructure | ✅ Packaged |
|
||||||
| [Webhook](https://github.com/adnanh/webhook) | [GitHub](https://github.com/adnanh/webhook) | Lightweight webhook receiver | API-Gateway | ✅ Packaged |
|
| [Webhook](https://github.com/adnanh/webhook) | [GitHub](https://github.com/adnanh/webhook) | Lightweight webhook receiver | API-Gateway | ✅ Packaged |
|
||||||
| [FX](https://github.com/metrue/fx) | [GitHub](https://github.com/metrue/fx) | Function as a Service platform | DevOps-Tools |
|
| [FX](https://github.com/metrue/fx) | [GitHub](https://github.com/metrue/fx) | Function as a Service platform | DevOps-Tools | ✅ Packaged |
|
||||||
| [Fonoster](https://github.com/fonoster/fonoster) | [GitHub](https://github.com/fonoster/fonoster) | Open-source CPaaS for communications | Communication |
|
| [Fonoster](https://github.com/fonoster/fonoster) | [GitHub](https://github.com/fonoster/fonoster) | Open-source CPaaS for communications | Communication |
|
||||||
| [Rundeck](https://github.com/rundeck/rundeck) | [GitHub](https://github.com/rundeck/rundeck) | Job scheduling and automation platform | Automation |
|
| [Rundeck](https://github.com/rundeck/rundeck) | [GitHub](https://github.com/rundeck/rundeck) | Job scheduling and automation platform | Automation |
|
||||||
| [HyperSwitch](https://github.com/juspay/hyperswitch) | [GitHub](https://github.com/juspay/hyperswitch) | Open-source payment switch | Financial-Payments |
|
| [HyperSwitch](https://github.com/juspay/hyperswitch) | [GitHub](https://github.com/juspay/hyperswitch) | Open-source payment switch | Financial-Payments |
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
> **Human read-only. Agents maintain this file automatically after each work
|
> **Human read-only. Agents maintain this file automatically after each work
|
||||||
> session.** Do not edit by hand — the next agent run will overwrite it.
|
> session.** Do not edit by hand — the next agent run will overwrite it.
|
||||||
>
|
>
|
||||||
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — Database Gateway
|
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — FX packaged (#640,
|
||||||
> packaged (#639, Infrastructure, 12th package); auth gate verdict: native
|
> DevOps-Tools, 13th package); auth gate verdict: no user concept —
|
||||||
> OIDC (preferred) — platform provider wired via CLOUDRON_OIDC_* env.
|
> httpAuth proxy gates the landing page (CLI-workstation pattern).
|
||||||
|
|
||||||
## Current State: STABLE (packaging phase, ongoing)
|
## Current State: STABLE (packaging phase, ongoing)
|
||||||
|
|
||||||
Cloudron packaging pipeline is operational. 12 of ~57 upstream applications are
|
Cloudron packaging pipeline is operational. 13 of ~57 upstream applications are
|
||||||
packaged, committed, and pushed. Packaging templates exist for the core
|
packaged, committed, and pushed. Packaging templates exist for the core
|
||||||
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
||||||
All remaining apps now carry build tickets (#633-#678) under umbrella
|
All remaining apps now carry build tickets (#633-#678) under umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
||||||
ready for the sequential grind-driver pattern.
|
ready for the sequential grind-driver pattern.
|
||||||
|
|
||||||
## Completed Packages (12)
|
## Completed Packages (13)
|
||||||
|
|
||||||
| # | Application | Category | Pattern | Port(s) | Addons |
|
| # | Application | Category | Pattern | Port(s) | Addons |
|
||||||
|---|-------------|----------|---------|---------|--------|
|
|---|-------------|----------|---------|---------|--------|
|
||||||
@@ -32,6 +32,7 @@ ready for the sequential grind-driver pattern.
|
|||||||
| 10 | Easy-Gate | Infrastructure | Multi-stage (Go) + auth proxy | 8080 | localstorage |
|
| 10 | Easy-Gate | Infrastructure | Multi-stage (Go) + auth proxy | 8080 | localstorage |
|
||||||
| 11 | Rathole | Infrastructure | Pre-compiled binaries + auth proxy | 8000, 2333, 5200-5299 | localstorage |
|
| 11 | Rathole | Infrastructure | Pre-compiled binaries + auth proxy | 8000, 2333, 5200-5299 | localstorage |
|
||||||
| 12 | Database Gateway | Infrastructure | Multi-stage (Go, CGO) | 8080 | localstorage, postgresql |
|
| 12 | Database Gateway | Infrastructure | Multi-stage (Go, CGO) | 8080 | localstorage, postgresql |
|
||||||
|
| 13 | FX | DevOps-Tools | Pre-compiled binaries + auth proxy | 8000 | localstorage |
|
||||||
|
|
||||||
Each package lives in `Package-Workspace/<Category>/<app>/` and contains a
|
Each package lives in `Package-Workspace/<Category>/<app>/` and contains a
|
||||||
`Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`,
|
`Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`,
|
||||||
@@ -117,7 +118,7 @@ Full write-ups of each pattern + challenges are in [`JOURNAL.md`](JOURNAL.md).
|
|||||||
| Collaboration | 2 | 0/2 | |
|
| Collaboration | 2 | 0/2 | |
|
||||||
| Communication | 1 | 0/1 | |
|
| Communication | 1 | 0/1 | |
|
||||||
| Data-Management | 2 | 0/2 | |
|
| Data-Management | 2 | 0/2 | |
|
||||||
| DevOps-Tools | 1 | 0/1 | |
|
| DevOps-Tools | 1 | 1/1 (100%) ✅ | fx done |
|
||||||
| Financial-Payments | 1 | 0/1 | |
|
| Financial-Payments | 1 | 0/1 | |
|
||||||
| Financial-Trading | 1 | 0/1 | |
|
| Financial-Trading | 1 | 0/1 | |
|
||||||
| Infrastructure | 6 | 3/6 | easy-gate, rathole, database-gateway done |
|
| Infrastructure | 6 | 3/6 | easy-gate, rathole, database-gateway done |
|
||||||
@@ -134,7 +135,7 @@ Auth capability is a hard gate before packaging (see
|
|||||||
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
||||||
(unacceptable / blocked-on-auth).
|
(unacceptable / blocked-on-auth).
|
||||||
|
|
||||||
### Completed packages (12)
|
### Completed packages (13)
|
||||||
|
|
||||||
| App | OIDC | LDAP | Verdict | Note |
|
| App | OIDC | LDAP | Verdict | Note |
|
||||||
|-----|------|------|---------|------|
|
|-----|------|------|---------|------|
|
||||||
@@ -150,6 +151,7 @@ LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
|||||||
| Easy-Gate | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` (no user concept; IP-subnet groups only) |
|
| 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) |
|
| 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) |
|
||||||
| Database Gateway | yes | no | ✅ preferred | **Packaged**; native OIDC-only app — platform provider env (`CLOUDRON_OIDC_*`) seeded into config.json; roles from the `groups` claim |
|
| Database Gateway | yes | no | ✅ preferred | **Packaged**; native OIDC-only app — platform provider env (`CLOUDRON_OIDC_*`) seeded into config.json; roles from the `groups` claim |
|
||||||
|
| FX | n/a | n/a | 🔄 proxy | **Packaged**; CLI-only FaaS tool with no user concept — pinned binary + workspace driven from the Cloudron terminal; landing page gated by `httpAuth.type=proxy` |
|
||||||
|
|
||||||
### Candidates researched
|
### Candidates researched
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user