Installation
On a VPS, the normal path is to clone the repository, run ./install.sh, answer
the guided questions, and wait for readiness. A fresh Git checkout builds the
application images locally and creates its Docker services. Release checks and
upgrades use official release metadata separately.
Railway uses a published Compact image
and three Railway services; the downloadable fresh-project example stages them
in dependency order.
| Destination | Application layout | Entry point |
|---|---|---|
| VPS with Docker | Compact (default) or Scalable | ./install.sh in a Git checkout |
| Railway | One Compact runtime, separate PostgreSQL and RabbitMQ | bash deploy-compact.sh with guided project setup |
| Render | One Compact runtime, separate PostgreSQL and RabbitMQ | One public Blueprint that pulls the Compact image |
| Elestio | Compact, PostgreSQL and RabbitMQ on one dedicated VM | Compose template using the same public images |
| Fly.io | One Compact Machine, separate PostgreSQL and RabbitMQ Machines | Guided installer and three TOML examples |
The Railway, Render, Elestio and Fly.io guides cover Compact. For Scalable, use the VPS installation path until a separate hosted deployment has been tested and documented.
Docker host prerequisites
Before running ./install.sh, install a running Docker Engine with Linux
containers, Docker Compose v2 and Git on the deployment host. Flow Steward
does not install Docker. Use Docker Engine
and the Compose plugin on Linux,
or Docker Desktop for a local desktop trial.
Windows shell launchers require Git Bash or WSL with Linux containers enabled.
The host must be amd64 (x86_64) or arm64 (aarch64): an x86 or ARM
Linux server, or a Mac with Docker Desktop. The installer stops with
unsupported_architecture on anything else. It also needs at least 4 GiB of free disk to start.
From the same non-root deployment account, check:
docker --version
docker compose version
docker info
See Docker's Linux post-install instructions if socket access is unavailable. For detailed answers to all installer questions, including Apache, Nginx and Traefik discovery, use the Installer Walkthrough. Use Platform Deployment for shared provider runtime requirements and Diagnostics and Migration for doctor and Clone.
VPS: guided installation
You need access to the Flow Steward Git repository, Docker Engine, and
the Docker Compose v2 plugin. Run Docker as a regular deployment user, not
root. On a Linux VPS with systemd, the user also needs sudo to set up automatic
startup; the installer requests it after the runtime is ready. The host does not
need Python or Node for the normal installation path;
the launcher runs product commands in Linux containers. Allow enough disk space
for the images and persistent data. For a public HTTPS site, prepare a DNS name
pointing at the VPS and decide whether Flow Steward or an existing reverse proxy
will own TLS.
git clone https://github.com/Flow-Steward/flow-steward-app.git flow-steward
cd flow-steward
./install.sh
Use a full clone, without --depth. Git LFS is not needed. A fresh local
installation uses the checked-out source; it does not require a published
GitHub Release or a version tag. If the repository is private, configure
your normal Git authentication before cloning. The installer does not provision
GitHub access for you.
Select Production. Accept Compact for one runtime container, or select
Scalable when app, workers, MCP, and control services need separate
containers. The wizard also asks who owns ingress and TLS, the public hostname,
artifact storage, and worker capacity; the
Installer Walkthrough lists
every question with a recommended answer. Compact uses the local persistent
filesystem for files unless you choose External S3-compatible storage or start
the installer with --file-storage bundled; Scalable uses the storage you
choose.
The installer does not ask for an administrator account, email (SMTP) settings
or an AI provider: you set those up in the browser after installation.
For a first local trial, the default local certificate and localhost:8099
are enough. For a public VPS, choose the TLS/ingress option that matches the
actual network: bundled ACME with working DNS and ports 80/443, or the existing
proxy/Traefik option and its requested backend/network details. Do not accept
the localhost default for a public domain.
For a temporary test by IP, select Bundled Traefik, Hostname generated
certificate, and enter the server IP in Public host. Set an unused
Public port, for example 18599, and an unused Plain-HTTP redirect
port, for example 18598. Open
https://<server-ip>:18599. The generated certificate is self-signed, so a
browser will warn about its trust; a production public site should use a DNS
name and a trusted certificate. Database, broker, and storage ports remain
private to Docker.
The default line-oriented questionnaire asks each of these in turn. You can also pass them as options, which skips those questions:
./install.sh --plain --public-host <server-ip> \
--public-port 18599 --redirect-http-port 18598
When testing alongside an existing installation, use a separate clone,
unused ports, and a unique Compose project name on the first invocation:
FS_COMPOSE_PROJECT_NAME=fs-demo-test ./install.sh. The installer records that
identity for subsequent commands in that clone. Do not reuse a working
installation's directory, project name, or persistent data.
The first image build and infrastructure image downloads can take time. Leave the installer running until it reports
completion; rerun the same ./install.sh after a recoverable interruption.
Then check the result:
./flow-steward status
./flow-steward doctor
status gives the short readiness summary and doctor the detailed checks.
You can also open https://<your-host>/health/ready in a browser. Run ./flow-steward without
arguments to see the available commands.
To update later, bring the checkout to the new release and run ./install.sh
again; it rebuilds and restarts only what changed and keeps your answers,
secrets and data. See
Update a checkout installation.
DigitalOcean Droplet
A Droplet follows the VPS procedure above: prepare Docker Engine and Compose,
clone the repository as your deployment user, and run ./install.sh.
It does not use an App Platform app.yaml or a separate application image.
The guided Compact installation was checked on an Ubuntu 24.04 x64 Droplet with 4 vCPUs and 8 GB RAM. The check covered the first administrator setup, CLI user management, HTTPS login, systemd stop/start, and rerunning the installer while preserving users. These are the resources used for the check, not a stated minimum. A cold source build and first startup took about 12 minutes on that test machine.
For an IP-only trial, use the explicit public host and ports shown above. Allow the selected HTTPS and redirect ports through the host or cloud firewall; keep PostgreSQL, RabbitMQ and storage ports private. Use a domain and trusted TLS for a production public site.
After a disposable Droplet test, preserve the evidence you need and destroy the Droplet in DigitalOcean. Powering it off alone does not end its billing. Remove any SSH key or other resource created only for that test.
First administrator and CLI
Open the URL printed by the installer and create the first administrator.
For every normal checkout installation, including localhost, the installer
prints an owner-only setup-token location and the complete private
/bootstrap#setup-token=... link. Open the complete link promptly; setup tokens
expire 60 minutes after issuance, not after a resumed installer prints the link.
A plain /bootstrap URL does not bypass installed token checks on loopback.
Keep the token and link private. If it expires while
no administrator exists, rerun ./install.sh to issue a new link. AI provider
credentials are optional at installation and can be configured after login.
Run administrative commands from the clone; the ./flow-steward launcher
selects the installed containers and their configuration:
./flow-steward users list
./flow-steward projects list
./flow-steward jobs list
./flow-steward users create --help
./flow-steward status
stack status and stack restart are Scalable commands. Compact does not retain
the CLI container those commands manage; use status and doctor for its
readiness, and the installer for installation recovery.
Linux VPS automatic startup
For Compact on native Linux with systemd and the system Docker daemon, successful installation
configures flow-steward-<compose-project>.service. The installer prints its exact
name. This service starts the installed containers after a server or Docker
restart, waiting for the database and broker health checks first. It does not
download images, rebuild, or rerun the installation wizard during boot.
The systemd service is a one-time startup action, so active (exited) is normal;
use ./flow-steward status and doctor to check application readiness. Docker
still owns failure retries, including Compact's finite retry policy. This avoids
two supervisors continually restarting the same containers.
Use the service name printed by your installer:
sudo systemctl status flow-steward-<compose-project>.service
# Stop this installation and keep it stopped across reboots:
sudo systemctl disable --now flow-steward-<compose-project>.service
# Restore automatic startup and start the installation:
sudo systemctl enable --now flow-steward-<compose-project>.service
Rerunning the installer refreshes the recorded container IDs but preserves an
explicitly disabled service. That explicit installation starts the application
and restores stop control, but does not re-enable future automatic startup.
Stopping the service drains the application before stopping its database and
broker. If containers were deleted, rerun ./install.sh;
the boot service refuses to silently recreate them. Keep the checkout,
configuration and volumes. Never delete volumes to recover a stopped service.
If system service setup fails because sudo is unavailable, the runtime may already be running, but automatic startup is not configured. Have an administrator provide the required sudo access and rerun the installer. On Mac, Windows, rootless/remote Docker, or managed platforms, follow that platform's startup settings; the installer reports that no host systemd service was configured. Scalable retains its existing Docker restart policies. Switching from Compact to Scalable removes the matching Compact startup service automatically.
The VPS installer link lasts 60 minutes; the Compact provider startup link described below lasts 15 minutes. After a restart, verify that the same user can still sign in. Email delivery and AI execution require their respective provider settings; a successful installation does not configure those services.
The guided path does not currently configure your DNS, an external proxy, or off-host backups. Those remain operator steps. The installer also requires the repository content to be accessible from that host. Before holding real data, verify backups and a restore procedure for your installation.
Railway: Compact in dependency order
Download the Compact installer, then run it from a new directory:
bash deploy-compact.sh
The installer signs you in through Railway's browser flow if needed and creates
the project. Press Enter to accept flow-steward as its name. If your account
belongs to several workspaces, choose the workspace that should pay for the
installation. You do not need to export variables, generate passwords, create
services, or start them in a particular order.
The computer running this helper needs the Railway CLI,
jq, openssl, and curl. These are local installation tools; you do not need
to install Python, Node.js, or Docker to run the image on Railway. On Windows,
use a Bash shell in WSL.
If you already linked an empty project in that directory, the installer uses it.
It refuses to modify a project that already has services. It generates
distinct PostgreSQL and RabbitMQ passwords, creates
the three services and their volumes before connecting images, waits for the
database and broker to become ready, and only then starts Compact. It pins the
2026-09-28 evaluated images, checks /health/ready, and prints the private
first-admin setup link from Compact's deploy logs. Open that link promptly;
it expires 15 minutes after Compact starts. Keep the downloaded file if you need
to review the exact commands;
it is a fresh-install example, not an upgrade tool. If a step fails, inspect
the named Railway services and their logs before deciding whether to remove
the partial installation and start with a new empty project.
Railway's older railway.json configures only one service and is deprecated;
it cannot enforce the PostgreSQL → RabbitMQ → Compact sequence. Railway's
project-level IaC can
describe the graph, but a staged installer still has to wait for the two
dependencies before enabling the app image.
Manual sequence
Railway does not run this repository's Compose file. Create three services in
one project and environment, with private networking enabled. Start the
database first, then the broker, and only then connect the Compact image. Do
not attach an image to an empty Compact service before configuring its volume
and variables: Railway starts image-backed services immediately, so an early
boot can write incomplete state. Use immutable image digests from an evaluated
Flow Steward release, not a mutable latest tag.
1. PostgreSQL
Create an empty service named postgres. Attach a persistent Railway volume at
/var/lib/postgresql/data. Set these service variables before choosing the
image:
PGDATA=/var/lib/postgresql/data/pgdata
POSTGRES_DB=flow_steward
POSTGRES_USER=flow_steward
POSTGRES_PASSWORD=<new strong random password>
PGDATA must be a subdirectory of the volume because a new Railway volume can
contain lost+found, which PostgreSQL refuses as its data directory. Use the
published Flow Steward PostgreSQL 17 image with Apache AGE and pgvector,
ghcr.io/flow-steward/fs-postgres-extended@sha256:47a10afb648b55a29e0422f7944a5eb8f12f99f4fecfbb5a2af721fe42196ce8
for the 2026-09-28 evaluated deployment.
Railway's standard managed PostgreSQL image does not supply the required AGE
extension. Wait until its logs say the database is ready to accept connections.
Keep port 5432 private.
2. RabbitMQ
Create an empty service named rabbitmq. Attach a persistent volume at
/var/lib/rabbitmq so queue data survives replacement. Set:
RABBITMQ_DEFAULT_USER=flow_steward
RABBITMQ_DEFAULT_PASS=<different strong random password>
RABBITMQ_DEFAULT_VHOST=flow
Connect the 2026-09-28 evaluated RabbitMQ image
rabbitmq@sha256:e582c0bc7766f3342496d8485efb5a1df782b5ce3886ad017e2eaae442311f69.
Wait for the AMQP listener on port 5672 and keep it private; the management
port must not be published just to make the app work.
3. Compact runtime
Create an empty service named compact, attach a persistent volume at
/data, and generate a Railway public domain routed to container port 8080.
Set the following variables before adding its image. The ${{...}} strings
are Railway references to the two backing services; keep the service names
exactly as shown or adjust the references accordingly.
FS_DB_DSN=postgresql://${{postgres.POSTGRES_USER}}:${{postgres.POSTGRES_PASSWORD}}@postgres.railway.internal:5432/${{postgres.POSTGRES_DB}}
RABBITMQ_URL=amqp://${{rabbitmq.RABBITMQ_DEFAULT_USER}}:${{rabbitmq.RABBITMQ_DEFAULT_PASS}}@rabbitmq.railway.internal:5672/flow
POSTGRES_HOST=postgres.railway.internal
POSTGRES_DB=${{postgres.POSTGRES_DB}}
POSTGRES_USER=${{postgres.POSTGRES_USER}}
POSTGRES_PASSWORD=${{postgres.POSTGRES_PASSWORD}}
RABBITMQ_HOST=rabbitmq.railway.internal
FS_PUBLIC_BASE_URL=https://<generated-railway-domain>
ARTIFACT_STORAGE_BACKEND=local_fs
PORT=8080
Configure one replica, health check /health/ready, Always restart, zero
deployment overlap, and at least 180 seconds of draining time. Compact is a
single-runtime profile; overlapping two live copies against the same database
and broker is unsupported. Finally connect the 2026-09-28 evaluated Compact
image
ghcr.io/flow-steward/flow-steward-compact@sha256:dee794207e38a4828cadd659cb41cbeaf65a1bdfedd6e4532bcb2a89c77681b1
from source commit 367d5ff885a5b7557cdb0fb712fe754539fa4d09.
Wait for Railway deployment status Success and HTTP readiness. A successful
image upload or a running PostgreSQL service alone does not prove the app is
ready.
The two *_HOST values are required even though the connection URLs already
contain hostnames: Compact checks dependency readiness through those separate
settings. Its LangGraph schema setup also builds a PostgreSQL URI from the
POSTGRES_* components, including the password. The default PostgreSQL
hostname, pg-fs, belongs to the Compose network and does not resolve inside
Railway.
The runtime initializes the empty database, generates its own long-lived app
secrets on /data, and logs a one-time first-admin URL. Open that URL within
15 minutes and create the administrator. If it expires while there is still no
administrator, restart the runtime to receive a new link. Do not copy the
token into tickets, screenshots, or a query string.
First administrator and the Railway container
Opening the public /bootstrap page directly shows a Setup token field:
the public page cannot display the secret. Use the complete URL containing
#setup-token=... instead. The browser removes that fragment from the address
bar and submits the token with the form. The downloaded deployment example
prints this URL when Compact first becomes ready. If you configured Railway
manually, open Compact → Deployments → current deployment → Deploy Logs in
the Railway dashboard and find the line beginning Flow Steward has no administrator yet. Copy the whole URL at the end of that line privately. The
link is issued at startup and lasts 15 minutes, not an hour.
If the link has expired and no user has been created, restart only the Compact service from its deployment menu, then read its fresh Deploy Logs. Keep the PostgreSQL and RabbitMQ services and all three volumes in place. From a local terminal linked to the Railway project, the equivalent commands are:
railway restart --service compact --yes
railway logs --service compact --lines 100 --filter 'Flow Steward has no administrator yet'
The restart mints another link while the user table is empty. If the logs say
a setup link issued earlier is still valid, read the earlier deployment's
log or wait until it expires before restarting. Do not use an old link after a
new one is issued. After you submit the form, sign in at /login with the new
administrator account.
Railway runs a published Docker image, not a Git checkout. Inside the
running Compact container the packaged application is under /app; /data
is the persistent volume, and /project points to /data/projects for user
projects. The service source in Railway therefore need not contain a visible
repository folder. You do not need a shell or a Flow Steward CLI command
to create the first administrator. If you need to inspect the running container,
register an SSH key with Railway and run railway ssh --service compact
from a linked local terminal; pwd there returns /app. railway run runs a
command on your local machine with Railway variables and is not a shell in
the deployed container. On Compact, flow-steward users issue-bootstrap-token
is installer-owned and is not the recovery command; use the restart and log
procedure above.
Administrative commands on Railway
Open the Compact service console in Railway. You start inside the running
container; no repository checkout or local environment variables are needed.
The application is under /app, but you can run its management command from
any directory:
flow-steward --help
flow-steward users list
flow-steward users create --role admin --plain
flow-steward projects list
flow-steward jobs list
flow-steward status
flow-steward users create --help
users create --role admin opens an interactive form in the service terminal;
enter the email and password there. It is an alternative to the one-time setup
link when no administrator exists yet. The built-in command obtains Compact's
saved runtime settings for that command alone, then uses its container-aware
management adapters. Do not read or copy
/data/state/runtime-secrets.json yourself. If flow-steward is not found,
the deployed image predates this command: update the Compact image. Until then,
the legacy Railway command wrapper can
run the packaged CLI over Railway SSH from your computer. That fallback needs
Railway CLI and a registered SSH key; railway ssh --service compact opens the
same running container from a locally linked Railway project.
The command is part of the Compact image, so its invocation is the same in a container console on another provider. Each provider's deployment, persistent storage, and console access still need their own tested installation guide.
For user changes, inspect the command-specific help first. For example,
users create and users set-password accept --password-stdin, so do not
put passwords on the command line. Creating the initial administrator in the
browser using the one-time setup link remains the simplest path.
Compact on Railway has
no Docker daemon, Compose installation, retained fs-cli, fs-audit, or
fs-test-runner services. Host installation, stack/config management, quality
and test commands that require those services are therefore not available
through this runtime shell. The built-in command explains this for unsupported
operations. Use the Railway dashboard/CLI for deployment operations and the
supported product/Compact maintenance commands for app administration.
The 2026-09-28 fresh-project check used the downloadable example and this exact
image: dependency startup, readiness, first administrator, browser sign-in,
users list, projects list, jobs list, and status passed. After restarting
Compact, the same administrator and existing session still worked, and a file
on /data and the saved runtime keys retained their checksums. This was an
installation check, not a test of every CLI command or AI workflow.
Verify the public /health and /health/ready endpoints, the sign-in page,
an authenticated sign-in, and one small workflow. Restart Compact once and
confirm the same login and data still work; this checks that the /data volume
and generated keys survived. Before holding valuable data, arrange backups of
all three persistent stores: PostgreSQL, RabbitMQ, and /data. The
Compose-based Flow Steward restore command is not a Railway restore procedure.
The downloadable example automates the passwords, services, volumes, domain,
variables, and dependency sequence for a fresh project. Manual setup still
requires these steps. PORT=8080 must match the Compact listener because
Railway uses it for its health check; the domain target port alone does not
configure that check. A prebuilt image is required: Railway's native builder
has rejected the source Dockerfile's BuildKit bind mounts in testing. The
Railway CLI and its helper tools are separate from the VPS installer.
Fly.io: Compact with persistent volumes
Fresh guided installation on 2026-09-28 used Compact source
31652e30e9c65b16576e9a4b3d105072c24b8337, image index
sha256:dee794207e38a4828cadd659cb41cbeaf65a1bdfedd6e4532bcb2a89c77681b1.
The actual script generated credentials, deployed dependencies in sequence
and delivered the private bootstrap link. First-administrator setup, browser
login, native CLI administration and user/session/file/key persistence after
restart passed. AI execution, HA and backup/restore were outside this check.
Use the same public Compact, extension-enabled PostgreSQL and RabbitMQ images as the Render and Elestio examples. Fly uses one application per image, so this installation has three TOMLs:
- Compact configuration
- PostgreSQL configuration
- RabbitMQ configuration
- Guided installation script
- Complete installation commands
The same files are in the public deployment configuration repository. They pull pinned images; they do not build a separate Fly-specific image.
Install Fly CLI; the installer also
needs jq, openssl and curl. A paid account is needed for a persistent
installation: the trial stops each Machine after five minutes. Clone the
public configuration repository, then run one installation command:
git clone https://github.com/Flow-Steward/flow-steward-deploy.git
cd flow-steward-deploy
bash fly/install.sh
The script opens Fly sign-in when needed, asks for the billing organization
when there is a choice, an installation name and a region. Press Enter to
accept the suggested name and Frankfurt region. It generates matching
passwords without asking you to enter or export them, creates the three
apps and their volumes, and allocates public IPs only for Compact. It starts
PostgreSQL and checks pg_isready, then RabbitMQ and checks
rabbitmq-diagnostics -q ping, then Compact and checks public readiness.
The final output includes the public URL and, when present in the startup
logs, the private first-administrator link.
Generated TOMLs are saved under fly/generated/<installation-name>/ and
contain no passwords. Existing app names or generated configuration folders
are refused. This script is for a fresh installation, not an upgrade. If it
fails after creating resources, it prints the exact app names and deletion
commands: those resources remain billable until removed. It does not delete
them automatically. The full manual commands remain available above. Keep
--ha=false: these are single-instance stores, without database or broker
replication. Compact also waits for its dependencies before initialization.
The example uses 2 performance CPUs / 4 GB RAM for Compact, 1 shared CPU / 2 GB for each dependency, and 10 GB / 10 GB / 1 GB volumes. These are tested sizes, not a minimum requirement. Review Fly's current estimate. Auto-stop is disabled because workers must run without web traffic; this means ongoing compute charges. PostgreSQL and RabbitMQ stay on the organization's private network.
During testing, 2 shared CPUs started the fresh installation, but a restart did not become ready within ten minutes after CPU burst credits were spent. Linux reported about 76% CPU steal time. Changing only Compact to performance CPUs, keeping the same image, memory and volume, restored readiness in about 2–3 minutes. The template therefore uses performance CPUs for Compact; its price differs from the shared-CPU plans. See Fly's CPU performance explanation.
Wait for public /health/ready to return HTTP 200. Initial role startup can
take several minutes after Fly reports a Machine as started. Read Compact's
logs for the private first-administrator URL; it expires after 15 minutes.
Alternatively, create the first administrator inside the existing Machine:
fly ssh console -a <prefix>-compact --pty -C 'flow-steward users create --role admin --plain'
Enter the email and password interactively, then open
https://<prefix>-compact.fly.dev and sign in. Administrative commands are
already on PATH:
fly ssh console -a <prefix>-compact -C 'flow-steward --help'
fly ssh console -a <prefix>-compact -C 'flow-steward users list'
fly ssh console -a <prefix>-compact -C 'flow-steward status'
fly ssh console -a <prefix>-compact -C 'flow-steward doctor'
Use fly ssh console, which connects to the running installation.
fly console creates a separate temporary Machine. The application is under
/app, persistent files are under /data, and no Git checkout or manual
database-secret exports are needed for administration. As on Railway,
commands that require host Docker/Compose or quality containers are not
available in this runtime shell.
Restart with fly apps restart <prefix>-compact, retaining all volumes.
This interrupts availability. The TOML specifies SIGTERM and time to drain;
keep dependencies running during shutdown. Do not use force-stop. The
fly machine restart --time 180 invocation was rejected by the Machines
API during testing, so use the tested app restart command.
The fresh 2026-09-28 check needed about six minutes to restore public readiness
after restart, including normal role initialization. Fly's restart command
timed out before the application became ready; the same Machine subsequently
recovered and preserved the login session, users, a file and internal keys.
Check /health/ready and flow-steward status before reopening the application.
Before storing valuable data, arrange and test backups of PostgreSQL,
RabbitMQ and /data. These files do not configure high availability or
certify backup/restore or AI-provider execution. Remove disposable test apps
and their volumes when finished; merely stopping Machines retains storage.
Other providers
Compact's provider contract is not Railway-specific: it requires persistent
/data, compatible PostgreSQL 17 with AGE/pgvector, RabbitMQ, a public HTTP
route, and graceful shutdown. Do not treat the Railway walkthrough as proof
that another provider has been tested. Verify each provider's volumes, network,
startup ordering, health checks, and backup/restore path independently.