One image for the whole app: engine, API and dashboard on one port
The backend image now builds the SPA and serves it on the API's own origin (fluksio/spa.py), so an instance is a single container with no proxy, DNS, port 80 or .env: `docker compose up -d` with the new compose.yml runs it on localhost:8080. It starts on fluksio serve (persisted secret key, first admin printed once) and brings its own Redis when REDIS_HOST is unset. Slimmer: python:3.13-slim, no dev group, uv once, fastapi without the cloud CLI. Optional features are per-feature extras (mqtt, influx, email, sentry, ml, server for all) picked with the EXTRAS build argument; numpy moved to `ml`. ffmpeg left the image for imageio-ffmpeg via the Modules screen. The operator stack runs the same image with app. and api. routed to it; the nginx frontend service, the LAN nginx proxy and DOMAIN in the backend are gone, and the MCP issuer is FRONTEND_HOST. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+7
-4
@@ -5,13 +5,16 @@ and run flows with the permissions of the user who authorizes it.
|
||||
|
||||
## Connect an agent
|
||||
|
||||
Set `MCP_ENABLED=true` in the engine's environment and restart it. The Python
|
||||
package defaults to off; the Docker template enables it.
|
||||
Set `MCP_ENABLED=true` in the engine's environment and restart it, under
|
||||
`environment` in `compose.yml` for the Docker container. It defaults to off.
|
||||
|
||||
Configure your MCP client with an HTTP endpoint:
|
||||
|
||||
- Local Docker stack: `http://api.localhost/mcp`
|
||||
- Deployment: `https://api.<your-domain>/mcp`
|
||||
- Docker container: `http://localhost:8080/mcp`
|
||||
- Deployment: `https://<your-domain>/mcp`
|
||||
|
||||
The endpoint has to be the address in `FRONTEND_HOST`, which is also the
|
||||
issuer of the client's tokens.
|
||||
|
||||
The client registers, opens browser authorization, and receives an OAuth
|
||||
token after you approve access. The issuer and browser redirects use
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ export FLUKSIO=http://127.0.0.1:8000/api/v1
|
||||
```
|
||||
|
||||
Use the port printed by `fluksio serve`. For Docker, use
|
||||
`http://api.localhost/api/v1`, `http://<host-ip>:8080/api/v1` on a LAN stack,
|
||||
or `https://api.<your-domain>/api/v1` for a deployment.
|
||||
`http://localhost:8080/api/v1`, or `https://<your-domain>/api/v1` for a
|
||||
deployment.
|
||||
All paths below are relative to this base. Timestamps in responses are
|
||||
ISO 8601 and always carry their UTC offset.
|
||||
|
||||
|
||||
+5
-4
@@ -11,8 +11,9 @@ For the browser dashboard, sign up at [fluksio.com](https://fluksio.com), add
|
||||
an instance, then run `fluksio enroll <code>` in the same directory.
|
||||
|
||||
Use `fluksio --help` or `fluksio COMMAND --help` for command options.
|
||||
`pip install 'fluksio[server]'` adds MQTT, InfluxDB, outbound mail and error
|
||||
reporting. A machine that only executes remote nodes can install
|
||||
`pip install 'fluksio[server]'` adds MQTT, InfluxDB, outbound mail, error
|
||||
reporting and numpy, or name only what you need, such as `fluksio[mqtt]`. A
|
||||
machine that only executes remote nodes can install
|
||||
[`fluksio-worker`](workers.md).
|
||||
|
||||
## Where an instance lives
|
||||
@@ -123,7 +124,7 @@ Starts the same agent as the standalone `fluksio-worker` command:
|
||||
|
||||
```sh
|
||||
FLUKSIO_WORKER_TOKEN=your-token fluksio worker \
|
||||
--url wss://api.example.com/api/v1/workers/attach --labels gpu
|
||||
--url wss://fluksio.example.com/api/v1/workers/attach --labels gpu
|
||||
```
|
||||
|
||||
Create the worker token on the engine first. See [Remote workers](workers.md)
|
||||
@@ -140,7 +141,7 @@ is a fallback.
|
||||
### `fluksio login`
|
||||
|
||||
```sh
|
||||
fluksio login --url https://api.example.com
|
||||
fluksio login --url https://fluksio.example.com
|
||||
```
|
||||
|
||||
Prompts for credentials and saves an API token for a remote engine.
|
||||
|
||||
+6
-5
@@ -144,6 +144,7 @@ import subprocess
|
||||
import tempfile
|
||||
|
||||
import fluksio
|
||||
import imageio_ffmpeg
|
||||
|
||||
# H.264 Constrained Baseline, at most 640x360 and 15 fps, mono AAC.
|
||||
PANEL = [
|
||||
@@ -157,10 +158,11 @@ PANEL = [
|
||||
|
||||
def process(clip):
|
||||
source = fluksio.load_artifact(clip)
|
||||
ffmpeg = imageio_ffmpeg.get_ffmpeg_exe()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
target = os.path.join(tmp, "panel.mp4")
|
||||
subprocess.run(
|
||||
["ffmpeg", "-nostdin", "-loglevel", "error", "-i", source, *PANEL, target],
|
||||
[ffmpeg, "-nostdin", "-loglevel", "error", "-i", source, *PANEL, target],
|
||||
check=True,
|
||||
timeout=600,
|
||||
)
|
||||
@@ -169,10 +171,9 @@ def process(clip):
|
||||
```
|
||||
|
||||
Use it only for clips headed for such a panel. Browsers play the originals,
|
||||
and the result plays there too, just smaller. The node needs `ffmpeg` on the
|
||||
`PATH`. The Docker image includes it only when built with
|
||||
[`WITH_FFMPEG=true`](../reference/configuration.md#image-options) in `.env`.
|
||||
Otherwise run the node on a [remote worker](workers.md) that has it.
|
||||
and the result plays there too, just smaller. Add `imageio-ffmpeg` on the
|
||||
**Modules** screen first. It brings a static `ffmpeg` build for Linux on x86
|
||||
and ARM, so nothing has to be installed into the image.
|
||||
|
||||
### Speech to and from a panel
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ WebSocket. Keep one engine; add workers where the hardware lives.
|
||||
On the engine, use a superuser access token. In these examples:
|
||||
|
||||
- `API_URL` is the engine's API base, including `/api/v1`, such as
|
||||
`https://api.example.com/api/v1` or `http://localhost:8080/api/v1` for a LAN stack.
|
||||
`https://fluksio.example.com/api/v1` or `http://localhost:8080/api/v1` for a Docker container.
|
||||
- `TOKEN` is your superuser bearer token. The login endpoint
|
||||
`POST /api/v1/login/access-token` accepts form fields `username` and `password`.
|
||||
|
||||
@@ -36,7 +36,7 @@ pip install fluksio-worker
|
||||
export FLUKSIO_WORKER_TOKEN='<token from the engine>'
|
||||
|
||||
fluksio-worker \
|
||||
--url wss://api.example.com/api/v1/workers/attach \
|
||||
--url wss://fluksio.example.com/api/v1/workers/attach \
|
||||
--labels gpu,cuda12 \
|
||||
--python /opt/torch-venv/bin/python
|
||||
```
|
||||
@@ -163,7 +163,7 @@ in `$DATA_DIR/provisioners.json`, replacing the example addresses and paths:
|
||||
"name": "hpc",
|
||||
"login": "me@login.cluster",
|
||||
"ssh_key": "/secrets/hpc_ed25519",
|
||||
"engine_url": "wss://api.example.com/api/v1/workers/attach",
|
||||
"engine_url": "wss://fluksio.example.com/api/v1/workers/attach",
|
||||
"max_idle_s": 300,
|
||||
"provision_timeout_s": 900,
|
||||
"profiles": [{
|
||||
|
||||
@@ -3,40 +3,43 @@
|
||||
Build a small temperature flow, then connect a real sensor when you're ready.
|
||||
No hardware required for the first lap.
|
||||
|
||||
## Start the Docker stack
|
||||
## Start Fluksio
|
||||
|
||||
You need Git, Docker with Compose v2, `make`, and `openssl`. Port 80 must be
|
||||
free. Clone the public app repository and run its commands from the repo root:
|
||||
You need Git and Docker with Compose v2. Clone the app repository and start
|
||||
its single container:
|
||||
|
||||
```sh
|
||||
git clone https://git.stroblme.de/Fluksio/app.git fluksio
|
||||
cd fluksio
|
||||
make init
|
||||
make dev-local
|
||||
docker compose up -d
|
||||
docker compose logs fluksio
|
||||
```
|
||||
|
||||
`make init` creates `.env`, generates secrets, creates the `proxy` network,
|
||||
and prints your admin login. It is safe to run again: existing secrets stay
|
||||
as they are.
|
||||
The first build takes a few minutes. The log shows the admin account and its
|
||||
password once, on the first start. Open [http://localhost:8080](http://localhost:8080)
|
||||
and sign in. Adding Python code requires that superuser account.
|
||||
|
||||
Give the containers a moment to start on the first build, then open
|
||||
[http://app.localhost](http://app.localhost). Sign in with the admin login:
|
||||
adding Python code requires a superuser account. The API is at
|
||||
[http://api.localhost](http://api.localhost), and the docs are at
|
||||
[http://docs.localhost](http://docs.localhost).
|
||||
Everything runs in that one container on one port: the engine, its API and the
|
||||
dashboard. To use another port, change the left side of `ports` in
|
||||
`compose.yml`, for example `"9000:8000"`. From another machine on your network,
|
||||
open `http://<host-ip>:8080`. Set `FRONTEND_HOST` in `compose.yml` to the
|
||||
address you open, since links for wall panels and mails are built from it.
|
||||
|
||||
For a Docker instance reached from another machine on your network, use:
|
||||
The image starts minimal. MQTT, InfluxDB, outbound mail and the rest are
|
||||
[extras](../reference/configuration.md#image-options). Add the ones you need to
|
||||
`EXTRAS` in `compose.yml` and rebuild:
|
||||
|
||||
```yaml
|
||||
args:
|
||||
EXTRAS: "mqtt,influx"
|
||||
```
|
||||
|
||||
```sh
|
||||
make dev-lan
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Open `http://<host-ip>:8080`. Choose another port with
|
||||
`make dev-lan APP_PORT=8081`. This is a development stack; see
|
||||
[running it long term](#run-it-long-term) before using it for a deployment.
|
||||
|
||||
When you are done, stop the stack with `make down`. Your data volumes stay
|
||||
in place for the next start.
|
||||
Stop the container with `docker compose down`. Your data stays on the `data`
|
||||
volume for the next start.
|
||||
|
||||
## Your first flow
|
||||
|
||||
@@ -97,10 +100,8 @@ checking the payload format your device expects. A relay may need `ON` and
|
||||
and **Step** let you inspect queued messages one at a time. A real heating
|
||||
controller also needs appropriate limits and hysteresis.
|
||||
|
||||
Docker development stacks include a test broker at `mosquitto:1883`; it has
|
||||
no published host port, so your physical sensors cannot reach it directly.
|
||||
For real sensors, use your own broker. The Docker image includes the MQTT
|
||||
and InfluxDB connector dependencies.
|
||||
The MQTT node needs the `mqtt` extra. Fluksio does not run a broker, so point
|
||||
the node at your own, such as Mosquitto.
|
||||
|
||||
## Show it on a dashboard
|
||||
|
||||
@@ -112,53 +113,38 @@ See [Dashboards and panels](../interface/dashboards.md) for widgets and pairing
|
||||
a wall tablet.
|
||||
|
||||
For longer-term history, add an **InfluxDB** node that consumes
|
||||
`living_temperature`. Configure your server URL, organization, bucket, token
|
||||
`living_temperature`. It needs the `influx` extra. Configure your server URL, organization, bucket, token
|
||||
and `writes` mapping. Store the token under **Secrets** and select it in the
|
||||
node's credential field. [Node types](../reference/node-types.md#influxdb)
|
||||
has the write and query formats.
|
||||
|
||||
The Docker development stack includes an InfluxDB test service at
|
||||
`http://influxdb:8086`, with organization and bucket `fluksio` and token
|
||||
`fluksio-dev-token`. It is for testing; configure a persistent InfluxDB server
|
||||
for data you want to keep. The production stack includes neither InfluxDB nor
|
||||
an MQTT broker.
|
||||
Fluksio does not run an InfluxDB server either. Use your own.
|
||||
|
||||
## Run it long term
|
||||
|
||||
For a Docker deployment, run `make init`, then edit the repository's `.env`:
|
||||
The container from `compose.yml` is fit for long-term use. It restarts with
|
||||
Docker, and `/data` holds everything it keeps: the database, the flows,
|
||||
secrets, artifacts and its Redis. Back up that volume. Compose names it
|
||||
`fluksio_data`.
|
||||
|
||||
| Setting | Example |
|
||||
|---|---|
|
||||
| `DOMAIN` | `example.com` |
|
||||
| `ENVIRONMENT` | `production` |
|
||||
| `FRONTEND_HOST` | `https://app.example.com` |
|
||||
| `VITE_API_URL` | `https://api.example.com` |
|
||||
| `BACKEND_CORS_ORIGINS` | `https://app.example.com` |
|
||||
| `FIRST_SUPERUSER` | your administrator email |
|
||||
| `TZ` | your timezone, such as `Europe/Berlin` |
|
||||
The container speaks plain HTTP. For access from outside your network, put a
|
||||
reverse proxy with HTTPS and WebSocket support in front of it, such as Caddy,
|
||||
Traefik or nginx, or [enroll with the portal](../interface/portal.md). A
|
||||
Caddyfile for `fluksio.example.com` is one line:
|
||||
|
||||
Keep the generated secrets. Stop any development stack with `make down`.
|
||||
Set up DNS and a reverse proxy with HTTPS and WebSocket support before running
|
||||
`make up`. That target starts the application services; it requires a proxy
|
||||
on the Docker `proxy` network. Route
|
||||
`app.example.com` to `fluksio-app:80`, `api.example.com` to `fluksio-api:8000`
|
||||
and, optionally, `docs.example.com` to `fluksio-docs:80`.
|
||||
```text
|
||||
fluksio.example.com {
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
`docker/compose.traefik.yml` is an optional proxy configuration. It also needs
|
||||
`EMAIL`, `USERNAME` and `HASHED_PASSWORD` for certificates and dashboard
|
||||
authentication; `make init` does not set these up.
|
||||
Set `FRONTEND_HOST` to `https://fluksio.example.com` and `TZ` to your
|
||||
timezone, such as `Europe/Berlin`. See [Configuration](../reference/configuration.md)
|
||||
for the other settings, which go under `environment` in `compose.yml`.
|
||||
|
||||
The published port from `make dev-lan` uses HTTP. For access outside your
|
||||
network, use HTTPS or [enroll with the portal](../interface/portal.md).
|
||||
To update, pull the repository and rebuild:
|
||||
|
||||
Back up `.env` and both persistent volumes: `app-flow-data` holds the database,
|
||||
flows, secrets and artifacts; `app-redis-data` holds message values, node state
|
||||
and queued work. Compose prefixes volume names with the project name
|
||||
`fluksio-app`. Also back up any external MQTT or InfluxDB data you need.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Flows, nodes and messages](../concepts/flows.md): how the graph works.
|
||||
- [Secrets, modules and alerts](../interface/operations.md): credentials and notifications.
|
||||
- [Remote workers](../code/workers.md): run node code on another machine.
|
||||
- [Configuration](../reference/configuration.md): settings and storage paths.
|
||||
```sh
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
@@ -42,9 +42,10 @@ Docker stores instance data under `/data` on the `app-flow-data` volume.
|
||||
Docker uses `managed`. When Fluksio adopts your own venv, the Modules screen
|
||||
is read-only; install packages into that environment yourself.
|
||||
|
||||
Back up the whole data directory and the persistent `SECRET_KEY`. In Docker,
|
||||
keep `.env` and `app-flow-data`; back up `app-redis-data` too when preserving
|
||||
live state. Compose prefixes volume names with the project name `fluksio-app`.
|
||||
Back up the whole data directory and the persistent `SECRET_KEY`. The single
|
||||
container keeps both, and its Redis, on the `/data` volume. The operator stack
|
||||
under `docker/` keeps `.env` and `app-flow-data`, plus `app-redis-data` for
|
||||
live state. Compose prefixes volume names with the project name.
|
||||
Keep runtime files on persistent storage so rebuilds preserve credentials,
|
||||
pairings and subscriptions.
|
||||
|
||||
@@ -52,13 +53,15 @@ pairings and subscriptions.
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `REDIS_HOST` | unset | unset uses memory; a Redis host enables persistent flow state |
|
||||
| `REDIS_HOST` | unset | unset uses memory, or the image's own Redis in Docker; a Redis host enables persistent flow state |
|
||||
| `REDIS_PORT` | `6379` | Redis port |
|
||||
|
||||
Live state includes message values, node memory and queued work. In-memory
|
||||
state is lost on restart. The Docker stack uses Redis with append-only
|
||||
persistence on its own `app-redis-data` volume. Its default sync policy may
|
||||
lose about a second of recent writes after an unclean shutdown.
|
||||
state is lost on restart. The Docker image starts a Redis of its own with
|
||||
append-only persistence in `/data/redis` whenever `REDIS_HOST` is unset. Set
|
||||
`REDIS_HOST` to use an external one instead, as the operator stack does with
|
||||
its `app-redis-data` volume. The default sync policy may lose about a second of
|
||||
recent writes after a power cut.
|
||||
|
||||
## Accounts and access
|
||||
|
||||
@@ -68,8 +71,7 @@ lose about a second of recent writes after an unclean shutdown.
|
||||
| `ACCESS_TOKEN_EXPIRE_MINUTES` | `11520` (8 days) | session-token lifetime |
|
||||
| `FIRST_SUPERUSER` | unset | initial administrator email; the CLI creates an account if needed |
|
||||
| `FIRST_SUPERUSER_PASSWORD` | unset | initial password; the CLI generates and prints one if needed |
|
||||
| `DOMAIN` | `localhost` | API hostname and OAuth issuer; Docker also uses it for routing |
|
||||
| `FRONTEND_HOST` | `http://localhost:5173` | interface URL for links and metadata |
|
||||
| `FRONTEND_HOST` | `http://localhost:5173`, `http://localhost:8000` in Docker | the address people and devices reach the instance at; panel links, mails and the OAuth issuer use it |
|
||||
| `BACKEND_CORS_ORIGINS` | `[]` | allowed origins, as comma-separated URLs or a JSON list; `FRONTEND_HOST` is also allowed |
|
||||
| `FORWARDED_ALLOW_IPS` | `127.0.0.1` | trusted proxies; Docker adds `172.16.0.0/12` |
|
||||
| `SIGNUP_ENABLED` | `false` | allows account creation from the login page; otherwise use **Admin → Users** |
|
||||
@@ -79,32 +81,31 @@ lose about a second of recent writes after an unclean shutdown.
|
||||
Changing `SECRET_KEY` signs everyone out and makes existing encrypted
|
||||
secrets unreadable. Back it up with your data.
|
||||
|
||||
## Interface API address
|
||||
## Interface address
|
||||
|
||||
`VITE_API_URL` is a frontend **build argument**, so changing it requires
|
||||
rebuilding the frontend image.
|
||||
|
||||
| Setup | Value |
|
||||
|---|---|
|
||||
| Production Docker | set `.env` to `https://api.<your-domain>` |
|
||||
| `make dev-local` | overlay sets `http://api.localhost` by default |
|
||||
| `make dev-lan` | overlay sets an empty value, using `/api` on the page's own origin |
|
||||
|
||||
Without an explicit value, the production Compose file falls back to
|
||||
`https://api.${DOMAIN}`. Set `FRONTEND_HOST` and `BACKEND_CORS_ORIGINS` to
|
||||
match your deployment as well; `make init` generates secrets, not deployment
|
||||
URLs.
|
||||
|
||||
The LAN overlay also configures nginx to proxy `/api` and WebSocket requests
|
||||
to the backend. An empty value needs that proxy when the frontend and backend
|
||||
are served separately. See [facility automation](../getting-started/facility-automation.md#run-it-long-term)
|
||||
for deployment settings.
|
||||
The image serves the interface and the API on one origin, so the interface
|
||||
calls the API as a path on whatever address served it. One build works behind
|
||||
any port, hostname or reverse proxy. `FRONTEND_DIST` points at the built
|
||||
interface and is set by the image. A checkout leaves it empty and runs the Vite
|
||||
dev server, which needs its origin in `BACKEND_CORS_ORIGINS`.
|
||||
|
||||
## Image options
|
||||
|
||||
`WITH_FFMPEG=true` in `.env` installs `ffmpeg` into the backend image on the
|
||||
next build, for node code that transcodes video. It is off by default because
|
||||
it adds about 400 MB.
|
||||
The `EXTRAS` build argument picks the optional features built into the image,
|
||||
comma separated. Empty, the default, is the minimal engine.
|
||||
|
||||
| Extra | Adds |
|
||||
|---|---|
|
||||
| `mqtt` | the MQTT node |
|
||||
| `influx` | the InfluxDB node |
|
||||
| `email` | outbound mail, such as password resets |
|
||||
| `sentry` | error reporting to `SENTRY_DSN` |
|
||||
| `ml` | numpy, for the `mlp` node |
|
||||
| `server` | all of the above |
|
||||
|
||||
A node whose extra is missing says so on the canvas. The same names work as
|
||||
pip extras, such as `pip install 'fluksio[mqtt]'`. Connector packages built
|
||||
with `make connectors` are installed into the image too.
|
||||
|
||||
## Environment
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ settings in the node panel; use a **Function** node for your own Python.
|
||||
`GET /flows/node-types` returns this list with each type's full parameter
|
||||
schema, including any [connectors](#connectors) installed on your instance.
|
||||
|
||||
MQTT and InfluxDB need `pip install 'fluksio[server]'` on a Python installation.
|
||||
The Docker image includes these dependencies. Run the broker and database
|
||||
separately, or use the development stack's test services.
|
||||
MQTT and InfluxDB need their [extras](configuration.md#image-options): `mqtt`
|
||||
and `influx` in the image's `EXTRAS`, or `pip install 'fluksio[mqtt,influx]'`
|
||||
on a Python installation. Run the broker and database separately.
|
||||
|
||||
## Function
|
||||
|
||||
|
||||
Reference in New Issue
Block a user