Skip to main content

Answer the Installer Questions

Use this guide when running ./install.sh from a Flow Steward checkout on your computer or VPS. It explains the actual question labels, what to enter, and where to find the values. Start with Installation for obtaining the checkout; use Installer Reference for automation flags. This guide describes application revision 1a66a0490e (version 0.7.27), reviewed against the installer source on 2026-10-26.

Before starting​

Docker is required for both Compact and Scalable. Install Docker Engine and the Compose v2 plugin on a Linux VPS, or Docker Desktop with Linux containers on a desktop. Flow Steward does not install Docker for you. Follow the official Docker Engine installation guide and Compose plugin instructions, or Docker Desktop installation guide.

Use a non-root deployment account with Docker access; ./install.sh refuses root and should not be launched with sudo. Run these checks as that account:

docker --version
docker compose version
docker info
git --version
git rev-parse HEAD
uname -m
df -h .

The Docker daemon must be running and accessible to that account. The installer uses the local Docker socket; a remote Docker context over SSH/TCP is not supported. Run it on the VPS itself. The source must be a real Git checkout (the installer records the checked-out commit), not a copied folder without .git. Git LFS is not needed. The preflight accepts only amd64 (x86_64) and arm64 (aarch64) hosts and stops with unsupported_architecture on anything else; uname -m shows yours. It also requires at least 4 GiB free; that is a refusal threshold, not a production capacity recommendation. Images, builds, artifacts, logs, database growth, and backups need additional space. A Bash/POSIX environment and common system utilities are required; on Windows use Git Bash or WSL rather than PowerShell to launch the script.

For a public deployment, prepare:

  • A hostname such as flow.example.com, with DNS pointing to the VPS or its actual ingress. Use the DNS provider's record list and getent ahosts flow.example.com on Linux to check resolution. Check both A and AAAA records.
  • A decision about who already owns ports 80 and 443. On Linux, sudo ss -ltnp lists listeners; docker ps --format 'table {{.Names}}\t{{.Ports}}' shows published Docker ports. Do not stop an existing website to free a port.
  • A certificate plan and, if there is an existing proxy, its owner/configuration and network details. The installer does not configure DNS, firewall rules, external proxy certificates, or external proxy services.
  • Persistent disk and an off-host backup plan. Local storage on the VPS survives container replacement but does not protect against loss of the VPS.

Choose the route that matches this machine​

Your situationIngress ownerNetwork and TLSOther key answers
First trial on your own computerBundled TraefikLocal/private generated certificatelocalhost, public port 8099, redirect port 8080 if free
Public VPS with no existing web proxyBundled TraefikBundled ACME certificateReal domain, public port 443, redirect port 80, contact and CA directory
Apache or Nginx runs directly on the VPSExisting reverse proxyExisting reverse-proxy TLSHost, correct Proxy kind, loopback backend 127.0.0.1:18099
Apache or Nginx runs in DockerExisting reverse proxyExisting reverse-proxy TLSDocker network, existing shared network; see the readiness limitation below
Existing Traefik runs in DockerExisting TraefikExisting Traefik resolver or Existing Traefik certificateExisting Docker network and exact entrypoint/resolver names
A hosting provider owns routing/TLSHosting platform ingressHosting platform TLSCompact only; follow the provider-specific Installation procedure

An Apache/Nginx service on the host does not make Flow Steward a host-native application. Flow Steward still runs in Docker. Proxy placement describes only your existing proxy.

For a local trial use Production + Compact single-runtime deployment. Production means the minimal runtime preset; it does not require a public domain. Development is the contributor preset and must be paired with Scalable multi-container runtime. Compact requires Production.

Compact or Scalable​

PickWhen
Compact (default)One server, one team, and you want the fewest moving parts. The whole application (web, API, MCP, workers, control plane) runs in one runtime container next to PostgreSQL and RabbitMQ. You scale it by raising Compact worker processes. This is the right answer for most installations and for every first trial.
ScalableYou need each role in its own container: separate worker containers you can add (./flow-steward config set --worker-replicas N), a separate MCP backend, and the full ./flow-steward stack and config command set for changing an installed system. Pick it when you expect to grow the worker pool or change ingress/TLS/storage after installation without reinstalling.

You can switch later with ./install.sh --deployment-profile scalable (or compact) on an installed system; take a complete backup first.

All questions at a glance​

The plain questionnaire asks these in this order. A question appears only when its "Shown when" condition holds. Press Enter to keep the default.

#QuestionShown whenDefaultWhat to pick
1EnvironmentalwaysProductionProduction. Development only for contributors, and only with Scalable.
2Deployment profilealwaysCompactCompact unless the table above says Scalable.
3Compact runtime HTTP portCompact8080Keep 8080; it is the runtime's internal listener, not a public port.
4Ingress owneralwaysBundled TraefikBundled Traefik unless Apache, Nginx, Traefik or a hosting platform already owns ports 80/443.
5Compact worker processesCompact2Keep 2 to start; raise later with ./install.sh --worker-processes N.
6File storagealwaysBundled self-hosted storageCompact: Enter for Local persistent filesystem, or External S3 for a provider bucket; Bundled needs --file-storage bundled (see File storage). Scalable: Local persistent filesystem for one machine, Bundled for an S3-style store on the same host, External S3 for a provider bucket.
7–11S3 endpoint, S3 bucket, S3 region, S3 credentials file, Allow insecure S3 HTTPExternal S3none, flow-steward-artifacts, us-east-1, none, NoYour provider's values; keep insecure HTTP at No.
12Network and TLSalwaysLocal/private generated certificateMust match the ingress owner; see the TLS table.
13Public host (domain or IP)alwayslocalhostlocalhost for a trial on this computer; otherwise the real domain (or the server IP for a test).
14Public portalways8099443 for a public site; 8099 for a local trial.
15Plain-HTTP redirect portBundled Traefik808080 with ACME; any free port otherwise.
16–17Reverse-proxy backend host, Reverse-proxy backend portExisting reverse-proxy TLS127.0.0.1, 18099Keep both unless 18099 is taken.
18Reverse-proxy MCP portExisting reverse proxy18100Keep it (used by Scalable only).
19Proxy placementExisting reverse proxyHostWhere your Apache/Nginx runs: on the host or in Docker.
20Proxy kindExisting reverse proxyNginxNginx or Apache, matching your proxy.
21Trusted proxy CIDRsalways127.0.0.1/32,::1/128Keep the default with Bundled Traefik; see trusted proxy addresses for an existing proxy.
22–24Existing Traefik network, Traefik HTTPS entrypoint, Traefik HTTP entrypointExisting Traefiknone, websecure, webNames from your Traefik configuration.
25Traefik certificate resolverExisting Traefik resolvernoneThe resolver name from your Traefik configuration.
26Existing proxy networkProxy placement is Docker networknoneThe Docker network your proxy container is on.
27–28ACME contact, ACME directory URLBundled ACME certificatenone, noneA monitored email; https://acme-v02.api.letsencrypt.org/directory.
29Extension installer originalwayshttp://fs-extension-installer:8099Keep the default.
30–31Certificate path, Private key pathalways.ssl/cert.pem, .ssl/key.pemKeep the defaults unless you chose Operator-provided certificate.

After the last question the installer prints Review pending change: with the final values and asks Apply this change? (default No).

What the installer does not ask​

The questionnaire covers only how the platform runs and is reached. These are set up later, in the browser or with ./flow-steward:

  • Administrator account. No email or password is asked. The installer prints a one-time setup link at the end; you create the first administrator there. See Review, install, and create the first administrator.
  • Outgoing email. There is no SMTP question. After you sign in, install the Outgoing Email extension and create a connection with your SMTP server; password-reset and notification mail use it.
  • AI provider, API key and model. Not needed to install. After you sign in, an administrator adds a provider account in the application.
  • Database and broker passwords and internal secrets. Generated by the installer and kept in the installation's environment file; never typed.
  • Memory or CPU size. There is no memory profile question. Capacity is the worker count: Compact worker processes, or worker containers on Scalable after installation.

How the questions work​

Run from the checkout directory:

./install.sh --plain

Plain mode is also the default for ./install.sh. For a numbered choice, enter the number printed beside the label, not the internal option name. Press Enter to accept the displayed default. Boolean questions accept yes/no. Values passed as command-line options are already supplied and are skipped in the plain questionnaire.

The installer asks visible questions in the order below. A question marked advanced is still asked in plain mode; in ./install.sh --tui, expand Show advanced to see it. Visibility follows previous answers, but the Network and TLS list shows all eight choices: it does not filter out incompatible choices. Choose the pair in the table above. The final Review pending change: shows normalized values; Apply this change? defaults to No. Confirm only when the host, ports, storage and routing match your intended installation.

Compact storage. The File storage question proposes Bundled self-hosted storage, the Scalable default. On Compact that default is recorded as Local persistent filesystem. Answering Local persistent filesystem or External S3-compatible storage keeps your answer and its S3 settings. For bundled storage on Compact, start the installer with ./install.sh --file-storage bundled. The review screen shows the value that will be used. Scalable keeps the answer you give.

1. Environment and runtime​

Exact questionDefault and visibilityWhat to enter
EnvironmentProduction; alwaysProduction for ordinary use, including a local trial. Development only for contributing/testing with Scalable.
Deployment profileCompact single-runtime deployment; alwaysCompact for the initial single-runtime setup. Scalable separates app services into containers and is appropriate when you deliberately need that topology.
Compact runtime HTTP port8080; Compact only, advancedUsually keep 8080. This is the runtime's internal HTTP listener, not your public HTTPS port. A Docker proxy must target this value. With Hosting platform ingress this port is published on the host for the platform's router.
Ingress ownerBundled Traefik; alwaysChoose the owner from the route table above. Hosting platform ingress is only for a Compact host that sits behind a provider's own HTTPS load balancer: it publishes the runtime's plain HTTP port on the host and starts no proxy. Do not choose it on an ordinary VPS.
Compact worker processes2; Compact onlyUsually keep 2 initially. This is the number of queue workers inside the one runtime, not the number of runtime replicas. Raise it when jobs wait in the queue and the server has spare CPU and memory; change it later with ./install.sh --worker-processes N.

Compact still needs PostgreSQL and RabbitMQ containers. Selecting bundled storage adds SeaweedFS. “Single runtime” does not mean the complete deployment is one container. Do not run multiple Compact replicas against the same database and broker as a way to scale it.

2. File storage​

File storage offers:

  1. Local persistent filesystem (local_fs): a simple choice for one machine. Compact stores artifacts under /data/artifacts in its persistent data volume; Scalable uses its persistent artifacts directory. Include this data in backups.
  2. Bundled self-hosted storage (bundled, the prompt default): the installer starts and configures SeaweedFS. You do not supply S3 credentials for this option. Its persistent data and generated credentials need backup.
  3. External S3-compatible storage (external_s3): bring an endpoint, bucket, region, and credentials from your storage administrator/provider.

Recommendation: Local persistent filesystem for a single server (this is what Compact uses by default, see the note above). Choose External S3-compatible storage when files must live off the server, for example on a provider bucket with its own backups. Bundled adds a SeaweedFS container on the same host; it gives an S3 interface but not off-host safety.

The following five questions appear only for External S3-compatible storage:

Exact questionDefaultWhat to enter / where to find it
S3 endpointNone; requiredProvider's HTTPS S3 API endpoint, such as https://s3.example.com; not a bucket's browser console or download URL.
S3 bucketflow-steward-artifactsThe actual artifact bucket name from the provider's bucket list. Arrange its existence/access with the storage owner before installing.
S3 regionus-east-1Region expected by that endpoint; use the provider's documented value even for a non-AWS service.
S3 credentials fileNone; requiredPath to a regular private JSON file described below. Enter a path, never the key itself.
Allow insecure S3 HTTPNoKeep No on a VPS. HTTP is allowed only with Development and an explicit Yes; Production rejects HTTP.

For the installer, the JSON keys are exactly:

{
"access_key": "REPLACE_WITH_YOUR_ACCESS_KEY",
"secret_key": "REPLACE_WITH_YOUR_SECRET_KEY"
}

Create the file privately, do not commit it, and restrict its permissions to 0600 or stricter. It must not be a symbolic link. The installer reads it, keeps credentials out of the configuration review, and later probes storage with a write/read/delete cycle; read-only bucket access is insufficient. The later storage-transition interface has a different credential-file format; use the format documented for the command you are running.

A file selected during the questionnaire must be inside the checkout, for example .private/s3.json. If the file lives elsewhere, supply its absolute path when launching, so the launcher can mount it read-only:

./install.sh --plain --file-storage external_s3 \
--s3-credentials-path /home/deploy/private/flow-steward-s3.json

Replace the example path with your existing file. Do not paste literal ~ or use ../ to escape the checkout. The remaining S3 questions are still asked.

3. Public address and TLS​

Network and TLS offers these exact choices:

ChoiceCompatible ownerUse it when
Local/private generated certificate (local, default)Bundled TraefikLocal/private trial; generated certificate is not publicly trusted.
Hostname generated certificate (self_signed)Bundled TraefikYou need a generated certificate for the supplied hostname/IP and control how clients trust it.
Operator-provided certificate (provided)Bundled TraefikYou supply a matching PEM certificate chain and private key. You own renewal.
Bundled ACME certificate (acme)Bundled TraefikBundled Traefik obtains/renews the public certificate using HTTP-01.
Existing reverse-proxy TLS (reverse_proxy)Existing reverse proxyYour Apache/Nginx terminates HTTPS and forwards private HTTP to Flow Steward.
Existing Traefik resolver (external_resolver)Existing TraefikYour Traefik already has a named certificate resolver.
Existing Traefik certificate (external_certificate)Existing TraefikYour Traefik already has the matching certificate loaded. No resolver is selected.
Hosting platform TLS (platform_managed)Hosting platform ingressThe hosting platform terminates HTTPS for Compact.

Recommendation: on your own computer keep Local/private generated certificate. On a public VPS with a domain and nothing else on ports 80/443, pick Bundled ACME certificate. If you already have a certificate from your CA, pick Operator-provided certificate. If Apache, Nginx or Traefik already serves the domain, pick the matching "Existing" choice so the certificate stays where it is. Hostname generated certificate is for a temporary test by IP.

Public host (domain or IP) defaults to localhost. Enter only the hostname or IP: flow.example.com, not https://flow.example.com/, a path, or a hostname with a port. A public VPS normally needs its real domain. localhost refers to the computer running the browser; it does not identify a remote VPS. The selected host feeds the product URL and generated certificate names.

Public port defaults to 8099. Enter the externally visible HTTPS port, usually 443 for production. It is not the backend's HTTP port. For port 443, the product URL is https://flow.example.com; for 8099 it includes :8099.

Plain-HTTP redirect port defaults to 8080, is advanced, and appears only for Bundled Traefik. Use a free port for local work; use 80 for the ordinary public ACME setup. This port and the public HTTPS port are separate host listeners. Changing Compact runtime HTTP port does not free a conflicting redirect port.

4A. Bundled Traefik on a public VPS​

Use Bundled Traefik, Bundled ACME certificate, your domain, public port 443, and Plain-HTTP redirect port 80. DNS and inbound TCP 80/443 must reach this machine and these listeners must be free. If another proxy owns those ports, choose its existing-proxy branch instead.

Two questions appear for ACME:

  • ACME contact has no default. Enter a monitored email address owned by your deployment operator.
  • ACME directory URL has no default and is advanced, but is required for ACME. For Let's Encrypt production use https://acme-v02.api.letsencrypt.org/directory. Its testing directory is https://acme-staging-v02.api.letsencrypt.org/directory; staging certificates are not trusted by ordinary browsers and are unsuitable as a finished public setup. The installer has no staging-certificate trust bypass.

The bundled configuration uses HTTP-01, so a public CA must reach port 80; a private 8080 listener without forwarding from public port 80 is insufficient. See Traefik's ACME requirements.

To supply your own certificate instead, choose Operator-provided certificate and provide Certificate path / Private key path in the final advanced questions. See Certificate and internal settings.

4B. Apache or Nginx already runs on the VPS host​

Choose Existing reverse proxy and Existing reverse-proxy TLS. The installer does not install a second public proxy. Answer:

Exact questionAnswer
Reverse-proxy backend hostKeep 127.0.0.1; the validator requires this exact value.
Reverse-proxy backend portKeep 18099 if free, or choose a different free local port.
Reverse-proxy MCP portKeep 18100 if free for Scalable. Asked for either profile, advanced; Compact routes MCP through its one backend and does not need a separate MCP port.
Proxy placementHost
Proxy kindNginx (default) or Apache, matching your existing service.
Trusted proxy CIDRsSee Discover trusted proxy addresses.

Find the existing site's configuration through your server management records. Useful read-only checks on a Linux host are:

sudo ss -ltnp
sudo nginx -t
sudo apachectl -t -D DUMP_VHOSTS
sudo apachectl -M

Run only the checks for software you use. On Debian/Ubuntu the Apache command may be apache2ctl; on other distributions it may be httpd. The virtual-host listing identifies the relevant config file. Nginx commonly includes sites from /etc/nginx/sites-enabled/ or /etc/nginx/conf.d/; Apache commonly uses /etc/apache2/sites-enabled/ or /etc/httpd/conf.d/. These locations vary. Read the existing site configuration locally; do not paste private keys or a complete configuration dump into a support ticket.

The installer publishes private HTTP on loopback. Your existing HTTPS virtual host must send requests to these destinations:

Placement/profileApp, API and /ws/ backend/mcp, /mcp/… and /.well-known/oauth-protected-resource… backend
Host + Compact127.0.0.1:18099Same backend
Host + Scalable127.0.0.1:18099127.0.0.1:18100
Docker + Compactflow-steward-compact-proxy:8080Same backend
Docker + Scalableflow-steward-app-proxy:8099flow-steward-mcp-proxy:8100

Replace host ports with your answers. Docker aliases use your installation's Compose project prefix; flow-steward is the fallback prefix. Compact's Docker port follows Compact runtime HTTP port. Docker destinations work only inside the shared proxy network.

After installation configuration exists and its CLI is ready, obtain the exact recorded fragment with this read-only command (available in both profiles):

./flow-steward proxy-fragment --json

The JSON result includes app_backend, mcp_backend, and fragment. With jq, extract the text using:

./flow-steward proxy-fragment --json | jq -r '.result.fragment'

The generated fragment is an HTTP port-80 routing example without certificate material. Do not replace your working HTTPS configuration with it unchanged. Merge its route rules into your existing HTTPS site, retain your certificate and renewal configuration, preserve forwarded host/protocol and authorization, and test the proxy configuration before using your normal reload procedure. The installer neither writes nor reloads that external proxy configuration.

Nginx example​

For Compact on the host, this is a routing example to adapt inside your existing TLS site. The paths shown for certificates are placeholders. The upstream and upgrade headers follow the application's renderer; the TLS listener and forwarded headers are operator additions for an HTTPS front end.

server {
listen 443 ssl;
server_name flow.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;

location / {
proxy_pass http://127.0.0.1:18099;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Authorization $http_authorization;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
}
}

Compact's one HTTP router serves all paths, including MCP and WebSockets. For Scalable, retain location / for the app, and add the three more-specific locations produced by proxy-fragment: location = /mcp, location ^~ /mcp/, and location ^~ /.well-known/oauth-protected-resource. Each must use the MCP backend (http://127.0.0.1:18100 for the default Host answers), and each must include the same proxy headers and proxy_buffering off shown above. Do not add a trailing / to these proxy_pass backend URLs: the route must preserve the original request path. Repeat the forwarded headers inside those locations; Nginx header inheritance can change when a location defines its own headers.

Keep your HTTP-to-HTTPS redirect in the external proxy. Check with sudo nginx -t before reloading. For a Docker proxy the equivalent check is docker exec YOUR_NGINX_CONTAINER nginx -t. Nginx requires explicit upgrade forwarding for WebSockets; see its WebSocket documentation and proxy module reference.

Apache example​

The following is the renderer's routing arrangement adapted to an existing TLS virtual host for Scalable on the host. Keep the specific paths before /. For Compact, replace every 127.0.0.1:18100 below with 127.0.0.1:18099.

<VirtualHost *:443>
ServerName flow.example.com
SSLEngine on
SSLCertificateFile /path/to/fullchain.pem
SSLCertificateKeyFile /path/to/privkey.pem
ProxyRequests Off
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"

ProxyPass "/mcp" "http://127.0.0.1:18100/mcp" nocanon
ProxyPassReverse "/mcp" "http://127.0.0.1:18100/mcp"
ProxyPass "/.well-known/oauth-protected-resource" "http://127.0.0.1:18100/.well-known/oauth-protected-resource" nocanon
ProxyPassReverse "/.well-known/oauth-protected-resource" "http://127.0.0.1:18100/.well-known/oauth-protected-resource"
ProxyPass "/ws/" "ws://127.0.0.1:18099/ws/" nocanon
ProxyPassReverse "/ws/" "ws://127.0.0.1:18099/ws/"
ProxyPass "/" "http://127.0.0.1:18099/" nocanon
ProxyPassReverse "/" "http://127.0.0.1:18099/"
</VirtualHost>

This requires mod_proxy, mod_proxy_http, mod_proxy_wstunnel, plus mod_ssl and mod_headers for the shown TLS/header additions. Inspect apachectl -M to see loaded modules. Enable missing modules through your distribution's normal configuration procedure. Check apachectl configtest before your normal reload. The explicit ws:// route carries job-progress WebSockets. Do not put a blanket HTTP / rule first: Apache matches proxy rules in configuration order. See the Apache proxy reference and WebSocket tunnel module.

4C. Apache or Nginx already runs in Docker​

Choose Existing reverse proxy, Existing reverse-proxy TLS, and Proxy placement → Docker network. Choose the actual Proxy kind. Existing proxy network then appears with no default: supply the exact existing Docker network shared with the proxy. It is not a domain, a bridge interface name, or a Compose service name.

Find the running proxy and its network without dumping environment variables:

docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
docker network ls
docker inspect YOUR_PROXY_CONTAINER --format '{{range $name, $net := .NetworkSettings.Networks}}{{printf "%s IP=%s gateway=%s\n" $name $net.IPAddress $net.Gateway}}{{end}}'
docker network inspect YOUR_NETWORK --format '{{range .IPAM.Config}}{{printf "subnet=%s gateway=%s\n" .Subnet .Gateway}}{{end}}'
docker network inspect YOUR_NETWORK --format '{{range .Containers}}{{printf "%s %s\n" .Name .IPv4Address}}{{end}}'

Replace the uppercase names with the names from the preceding output. Choose a network containing the proxy that is intended for application ingress. The installer joins that existing network; it does not create your proxy service. Use the Docker backends in the preceding table, not 127.0.0.1:18099 inside the proxy container: that address would refer to the proxy container itself. Host backend questions still appear because visibility follows TLS mode, but this overlay does not publish those host ports.

Current source limitation: the installer's reverse_proxy public-route probe still targets the host backend port even for Docker placement, while this overlay publishes no host port. A correctly connected Docker proxy can therefore still fail installer readiness at public_route. This branch has not been verified end to end for the reviewed revision. Do not publish a private backend on all interfaces to work around the check. Preserve the failed installation and its log for diagnosis; if you need a new installation without this unresolved branch, choose a host proxy or existing Traefik design before starting.

4D. Existing Traefik​

This branch expects an existing Docker-connected Traefik with its Docker provider able to discover the installation's containers. Choose Existing Traefik for Ingress owner. For Network and TLS, choose Existing Traefik resolver if Traefik obtains the certificate, or Existing Traefik certificate if a matching certificate is already loaded.

Answer these questions from the Traefik deployment's existing configuration:

Exact questionDefaultWhat it means
Existing Traefik networkNone; requiredExact Docker network name shared with the running Traefik. Use the network discovery commands above.
Traefik HTTPS entrypointwebsecure; advancedName of the entrypoint receiving HTTPS; not 443 and not the hostname.
Traefik HTTP entrypointweb; advancedExisting HTTP entrypoint used for the redirect route. If your setup deliberately has no HTTP entrypoint, supply an empty value with --traefik-http-entrypoint '' instead of inventing one.
Traefik certificate resolverNone; only with Existing Traefik resolverExact resolver name defined under certificatesResolvers; not an email, certificate filename, or URL.

The installer labels its routes and joins the selected network. It does not create these entrypoints/resolvers, configure the existing Docker provider, change provider constraints, or manage the existing Traefik's certificate store. A network containing one container passes the basic attachment check; that alone does not prove it is a correctly configured Traefik.

To find names, inspect the existing Traefik Compose file or its static traefik.yml / traefik.toml. If you do not know where it is mounted, list only mount paths:

docker inspect YOUR_TRAEFIK_CONTAINER --format '{{range .Mounts}}{{printf "%s -> %s\n" .Source .Destination}}{{end}}'

If configured by command-line flags, this read-only command prints only entrypoint listener flags and resolver names:

docker inspect YOUR_TRAEFIK_CONTAINER --format '{{range .Args}}{{println .}}{{end}}' |
sed -n -E '/^--[Ee]ntry[Pp]oints\.[^.]+\.address=/p; s/^--[Cc]ertificates[Rr]esolvers\.([^.]+)\..*/resolver: \1/p'

For example, these existing settings mean the HTTPS answer is websecure, the HTTP answer is web, and the resolver answer is letsencrypt:

entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
# Existing contact, storage and challenge settings live here.

This is a names-only illustration, not a complete replacement configuration. Do not read or share acme.json: it contains certificate account/private-key material and is not where you obtain the resolver name. An existing dashboard may also show router entrypoints and resolver assignments; do not enable a public dashboard solely for discovery. See Traefik's entrypoint reference and resolver reference.

Discover trusted proxy addresses​

Trusted proxy CIDRs is always visible in plain mode and is advanced in the full-screen form. Its default is 127.0.0.1/32,::1/128. Enter a comma-separated list of IP addresses/CIDRs for the immediate proxy as seen by the Flow Steward backend. This lets the runtime trust forwarded request information from that peer. It is not a list of users allowed to sign in.

For a Docker proxy/Traefik, inspect its IP on the shared network with the commands above. A fixed proxy IP such as 172.23.0.5 can be represented as 172.23.0.5/32. If the IP changes on recreation, arrange stable addressing or use a dedicated, controlled proxy subnet such as 172.23.0.0/24 only when all members of that subnet are trusted to supply forwarded headers. Those are examples; use your inspected values.

For a host proxy using Docker's loopback-published port, the backend may observe a Docker bridge gateway rather than 127.0.0.1. Inspect the relevant network's IPAM.Config gateway and confirm the actual peer from your backend/proxy network observations. Do not assume the loopback default covers traffic translated through Docker. Keep unrelated clients/networks out of the list. The validator rejects 0.0.0.0/0 and ::/0.

There are two distinct trust settings if another load balancer sits in front of Traefik:

  • The Flow Steward question trusts Traefik → Flow Steward. Use Traefik's downstream address/network as observed by Flow Steward.
  • Traefik's own entryPoints.<name>.forwardedHeaders.trustedIPs trusts load balancer → Traefik. Obtain those addresses from the load-balancer owner/provider and inspect the corresponding section in Traefik's static configuration. Flow Steward does not set this external Traefik option.

For example, an existing entryPoints.websecure.forwardedHeaders.trustedIPs list is not automatically the correct answer to Flow Steward's question. If Traefik directly receives browsers, it has no upstream proxy whose forwarded headers should be trusted. Do not enable forwardedHeaders.insecure as a shortcut. See Traefik forwarded headers.

5. Certificate and internal settings​

These final three advanced questions have no visibility condition, so plain mode asks them even when an external proxy owns TLS:

Exact questionDefaultWhat to do
Extension installer originhttp://fs-extension-installer:8099Keep the default unless you maintain a deliberate internal topology. It is an internal HTTP origin, not your public domain; it needs an explicit port and no credentials/path/query. It is not an AI provider setting.
Certificate path.ssl/cert.pemWith provided TLS: path to your PEM certificate/chain. With generated TLS: output location inside the checkout. With ingress-owned TLS, this does not configure the external certificate owner.
Private key path.ssl/key.pemMatching PEM private-key input for provided TLS, or generated key output inside the checkout. Keep the key private.

For provided TLS, the certificate must be valid for the public host and match the key. Inspect certificate metadata without printing the private key:

openssl x509 -in /path/to/fullchain.pem -noout -subject -issuer -dates -ext subjectAltName

For input files outside the checkout, pass absolute paths at launch; merely typing them into the form cannot add the required container mounts:

./install.sh --plain --tls-mode provided \
--certificate-path /home/deploy/tls/fullchain.pem \
--private-key-path /home/deploy/tls/privkey.pem

The launcher mounts those existing inputs read-only. Generated certificate/key output must stay inside the checkout. Relative paths must stay inside it too. The generated local certificate is for controlled local/private use: install appropriate trust on your own client if needed, and do not treat a browser certificate warning as a completed public HTTPS deployment.

Review, install, and create the first administrator​

Review the answers, then answer Yes to Apply this change? The installer checks Docker, disk, network/ports and source material, writes installation state and durable secrets, prepares images, starts dependencies/runtime, checks schema and worker identity, and verifies health, storage and routing. It does not ask for an AI-provider API key or an administrator password during this questionnaire. The first image build can take time; keep the session open.

On a normal checkout installation, including loopback, successful output contains NEXT STEP: CREATE THE FIRST ADMINISTRATOR and a one-time URL ending in /bootstrap#setup-token=.... Open the complete link privately within 60 minutes for this checkout installer. The token is also written to the owner-only .flow-steward/secret-output/bootstrap-token by default. The complete link goes to terminal stderr rather than the JSON result; do not publish terminal recordings containing it. Do not replace the complete link with a plain /bootstrap URL: normal installed bootstrap still requires the setup token on loopback. Create the first administrator in the browser, then sign in at /login.

If no administrator exists and the token expires, rerun the same ./install.sh to issue a replacement. Do not use a stale link after replacement. The 60-minute checkout-installer lifetime is different from the standalone Compact startup link described in provider-specific installation instructions.

On a Linux VPS, review Linux VPS automatic startup for the Compact systemd service, required sudo access, and explicit stop/start policy. Do not run the installer itself as root or with sudo.

Verify from the checkout:

./flow-steward status
./flow-steward doctor

status gives the short readiness summary; doctor lists every core check and separates optional warnings (for example, no AI provider yet) from real problems.

Then check from your browser on another machine, using your real public URL: open https://flow.example.com/ (the sign-in page should load without a certificate warning) and https://flow.example.com/health/ready (it should report ready).

For local generated TLS, use your configured local certificate trust instead of treating an insecure certificate bypass as proof of production readiness. Open the UI, create/sign into the account, and run a small workflow. For an external proxy, also exercise streaming/job-progress WebSockets and, if you use MCP, its authenticated connection and discovery route. A protected MCP request may legitimately require authorization; a proxy-generated 404 on the discovery path indicates a routing problem.

In existing reverse-proxy mode the installer checks the private HTTP backend; it does not prove that your external HTTPS virtual host, public DNS, certificate chain, or firewall is correct. Complete those public checks yourself. Follow the Deployment Checklist before keeping valuable data.

Resume and troubleshoot without discarding data​

Rerun ./install.sh from the same checkout after a recoverable failure. The installer classifies the state before acting. A fresh installation asks questions; a resumable one uses its recorded configuration, asks nothing, and checks each step's postconditions. An installed one verifies the installation, starts stopped services and, when the checkout has moved to a newer commit, rebuilds and updates it (prints Updated from <old> to <new>.). Rerunning is therefore not a read-only diagnostic—use status and doctor to inspect first. See Installation and Updates before updating.

A rerun does not ask the questions again and does not change your answers. On an installed Compact the only option it applies is --worker-processes; any other option that differs from the installed value stops with installed_setting_not_applied (--deployment-profile switches the profile).

Do not remove .flow-steward, environment files, or Docker volumes to get past an error. Their relationship identifies your installation and its durable keys. An ambiguous or recovery_required result intentionally preserves resources; read the reported cause and use ./flow-steward doctor before further action.

SymptomWhat to check / next action
Docker missing, unreachable, or Compose missingRepeat the three Docker prerequisite checks under the installer account; start Docker or correct installation/socket permissions.
remote_docker_unsupportedRun on the host with its supported local Docker context.
Port in useInspect ss -ltnp and Docker published ports. For bundled ingress check both Public port and Plain-HTTP redirect port; for a host proxy check private backend ports.
validation_failed for ingress/TLSUse a compatible pair from the route table; the TLS menu itself is not filtered. Compact also requires Production.
unsupported_architectureThe host is not amd64 or arm64. Use a supported server.
insufficient_disk_spaceFree at least 4 GiB in the checkout's file system and rerun.
cancelledYou answered No at Apply this change?, or ran a fresh non-interactive install without --confirm.
installed_setting_not_appliedYou passed an option that a rerun does not change. Rerun without it; on Scalable use ./flow-steward config set and config apply --confirm.
release_migration_requiredThe update carries a database migration; follow Update a checkout installation.
repository_unreadableRequired files of the checkout are missing or unreadable; restore the checkout and rerun.
traefik_network_missing / traefik_network_unattachedVerify the exact existing network and the running proxy's membership. An empty network cannot route the site.
Traefik default certificate or no routerRecheck hostname, DNS, entrypoint spelling, Docker provider/constraints, network selection, and resolver or loaded certificate.
S3 credential failureCheck file path/mount, regular-file status, private permissions, and installer JSON keys; do not print credentials in logs.
S3 probe failureVerify endpoint, region, bucket and write/read/delete permissions; confirm the storage service is reachable from the deployment.
Apache/Nginx 502Verify Host vs Docker placement and backend table. 127.0.0.1 inside a proxy container is not the VPS host.
MCP works poorly or discovery returns 404 on ScalableRoute both /mcp and the OAuth protected-resource discovery prefix to the MCP backend; preserve authorization and streaming.
UI loads but live job progress failsCheck Nginx Upgrade headers or Apache's /ws/ rule and WebSocket tunnel module.
Wrong client/protocol or HTTPS redirect behaviorVerify forwarded headers and Trusted proxy CIDRs using the actual immediate peer, including Docker translation.
public_route failure with Docker external proxySee the known readiness mismatch in the Docker-proxy branch; retain state and log instead of deleting volumes.
Expired first-admin linkIf still no administrator, rerun the installer for a new link.
installer_operation_activeWait for the current operation; do not run two installers or delete its lock manually.

Default operator-relevant paths, relative to the checkout, are:

PathPurpose
.flow-steward/install-state.jsonInstaller journal and completed/failed steps
.flow-steward/logs/install-*.logOwner-only installer logs; use the exact log path printed on failure
.flow-steward/stack.tomlActive non-secret deployment settings (your answers)
.flow-steward/pending-config.jsonPending configuration changes, when present
.flow-steward/compose.envGenerated Compose values; rewritten on every run; can contain sensitive runtime settings
.env.prod / .envProduction/development environment, created by the installer, including generated passwords and keys
.flow-steward/runtime/Runtime material, including bundled-storage/bootstrap state
.flow-steward/secret-output/bootstrap-tokenPrivate first-administrator setup token
.ssl/cert.pem / .ssl/key.pemDefault local/provided certificate paths

Do not edit these by hand. The installer rewrites the keys it owns in .env.prod (or .env) and regenerates compose.env on every run, so a manual change to them is lost or no longer matches the running containers. Change settings with ./flow-steward config set and config apply --confirm (Scalable), ./install.sh --worker-processes N (Compact), or a profile switch. Back up .env.prod together with the database: it holds the keys that decrypt stored secrets.

A deliberately configured FS_INSTALLER_STATE_DIR changes the installer state root; follow the printed paths. Do not include secret files in support messages. Share the error code, failed step, profile, ingress choice and a reviewed/redacted log excerpt.

This walkthrough was checked against the installer source. No fresh VPS installation, external proxy deployment, ACME issuance, or S3 service was operated during this documentation review.