Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Deploying flightdeck serve (reference)

FlightDeck stays local-first: this directory is optional packaging for demos, staging, or a trusted private network. Read SECURITY.md before exposing HTTP beyond loopback.

Docker image

Build (from this directory):

docker build -t flightdeck-serve:local .

The image installs flightdeck-ai from PyPI and runs flightdeck serve on 0.0.0.0 using port 8765 by default. On platforms that set PORT (for example Railway), entrypoint.sh binds to $PORT instead.

entrypoint.sh creates a default flightdeck.yaml in /workspace on first start (flightdeck init) if the mounted volume is empty.

Compose (loopback bind on the host)

cd examples/deploy
docker compose up --build
  • UI + API: http://127.0.0.1:8765/ (static UI + /v1/*).
  • Health: GET http://127.0.0.1:8765/health.
  • Compose healthcheck: docker-compose.yml probes /health so orchestrators can mark the service ready (see healthcheck: in that file).
  • Data: named Docker volume fd_workspace (SQLite under .flightdeck/ inside the volume). Remove with docker compose down -v when you want a clean ledger.

Using PostgreSQL

For team or production deployments, add a postgres service alongside flightdeck serve and wire the connection URL via FLIGHTDECK_DATABASE_URL. Create a docker-compose.postgres.yml override (or extend the existing docker-compose.yml):

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: flightdeck
      POSTGRES_USER: flightdeck
      POSTGRES_PASSWORD: changeme
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U flightdeck"]
      interval: 5s
      retries: 5

  flightdeck:
    build: .
    environment:
      FLIGHTDECK_DATABASE_URL: postgresql://flightdeck:changeme@db:5432/flightdeck
      FLIGHTDECK_LOCAL_API_TOKEN: "${FLIGHTDECK_LOCAL_API_TOKEN}"
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8765:8765"

volumes:
  pg_data:

Install the PostgreSQL extra in the image by adding pip install "flightdeck-ai[postgres]" to the Dockerfile, or set it as a build arg. Schema migrations run automatically on startup. Back up with pg_dump flightdeck on your preferred schedule.

SQLite backups

FlightDeck stores the ledger in .flightdeck/flightdeck.db under the workspace root. For a hot copy while the server is stopped or idle, run from the workspace directory:

flightdeck doctor --backup ./backups/flightdeck-$(date -u +%Y%m%dT%H%M%SZ).db

Inside the Compose stack, exec into the running container with /workspace as cwd (same layout as local flightdeck init), or run a one-shot sidecar that mounts the same volume and invokes flightdeck doctor --backup /workspace/backups/snapshot.db. Schedule with cron or your platform scheduler; keep backups off the primary volume when possible.

Optional mutation token

Set FLIGHTDECK_LOCAL_API_TOKEN in your environment before docker compose up (or in an .env file beside docker-compose.yml). Clients must send Authorization: Bearer … for ledger writes: POST /v1/promote*, POST /v1/rollback, and POST /v1/events. With no token configured, those routes accept only loopback callers. POST /v1/diff stays unauthenticated (read-only); still treat network placement as a trust boundary.

For a public HTTPS demo or staging, see Railway or Fly.io below.

Railway

Railway often suits small demos; pricing and free allowances change — confirm Railway pricing before relying on $0/month long term.

Deploy from this repo

  1. Create a new projectDeploy from GitHub (or railway init / railway link with the CLI).
  2. Set the service root directory to examples/deploy so Railway builds Dockerfile and picks up railway.toml (config-as-code).
    If the dashboard root cannot be a subdirectory, set RAILWAY_DOCKERFILE_PATH (service variable) to examples/deploy/Dockerfile and point config as code at examples/deploy/railway.toml per config-as-code.
  3. Networking: enable Public Networking and Generate Domain (HTTPS). Railway routes traffic to the PORT your process listens on; entrypoint.sh uses PORT automatically.
  4. Variables (recommended for any public URL): add FLIGHTDECK_LOCAL_API_TOKEN (random secret). The stock PyPI image does not embed that token in the browser bundle — use read-only UI (VITE_FLIGHTDECK_UI_READ_ONLY=true in a custom image build) or rebuild static assets with VITE_FLIGHTDECK_LOCAL_API_TOKEN so the UI can authenticate when read_auth is bearer-gated — see docs/web-ui.md and SECURITY.md.
  5. Persistent SQLite (optional): add a Railway volume mounted at /workspace so redeploys keep .flightdeck/. Without a volume, the ledger may reset when the container is recreated.

CLI sketch (from examples/deploy after railway link):

railway login
cd examples/deploy
railway variable set FLIGHTDECK_LOCAL_API_TOKEN="$(openssl rand -hex 24)"
railway up
railway domain   # generate .railway.app URL if needed

Fly.io

Deploy the same Docker image to Fly Machines. This gives you a URL you can open from any browser; treat it as trusted or lock it down with FLIGHTDECK_LOCAL_API_TOKEN (see SECURITY.md).

One-time setup

  1. Install flyctl and run fly auth login.
  2. From examples/deploy/:
    • Edit fly.toml: set app to a unique name (or run fly apps create <name> and match).
    • Optional persistent ledger: create a volume in the same region as primary_region:
      fly volumes create fd_workspace --region iad --size 1
      Uncomment the [mounts] block at the bottom of fly.toml (source = "fd_workspace", destination = "/workspace").
  3. Secrets (recommended once you expose the app on the internet):
    fly secrets set FLIGHTDECK_LOCAL_API_TOKEN="$(openssl rand -hex 24)"
    The server then expects Authorization: Bearer … for ledger writes from non-loopback clients. The stock examples/deploy image does not embed a browser token; use either read-only UI (VITE_FLIGHTDECK_UI_READ_ONLY=true in a custom image build — see docs/web-ui.md) or rebuild the image with VITE_FLIGHTDECK_LOCAL_API_TOKEN matching your secret so the bundled UI can call promote/diff when read_auth is bearer-gated.

Deploy

cd examples/deploy
fly deploy --remote-only

Open https://<app>.fly.dev/ — static UI and /v1/* on the same origin.

Notes

  • Cold starts: fly.toml allows min_machines_running = 0; first request may wake the Machine.
  • Demo-only UI: ship a build with VITE_FLIGHTDECK_UI_READ_ONLY=true if you only want read-only navigation (rebuild web/ and static bundle per docs/web-ui.md).
  • Maintainers: this repo cannot run fly deploy for you; use your own Fly org and the steps above.

Helm (optional single-replica chart)

A minimal chart lives under chart/flightdeck/. It runs one replica of flightdeck serve with an emptyDir workspace (ephemeral); for a persistent ledger, replace the volume in templates/deployment.yaml with a PVC or mount your own image init.

docker build -t flightdeck-serve:local .
helm install fd ./chart/flightdeck --namespace flightdeck --create-namespace

Tune values.yaml (image, resources, service.type) for your cluster.

Bind-mounting a host workspace

To reuse an existing directory that already contains flightdeck.yaml and .flightdeck/, replace the volumes entry with:

volumes:
  - /path/on/host/my-workspace:/workspace

Use an absolute path on Linux/macOS; on Windows Docker Desktop, use a path Docker can mount.

Process supervision

Compose sets a healthcheck on /health plus restart: unless-stopped on the service; for systemd/Kubernetes, reuse the same image and run /entrypoint.sh (or invoke flightdeck serve directly with a prepared workspace directory).

Operator checklist

  • Logs: docker compose logs -f flightdeck (or your platform log stream) when debugging ingest or policy failures.
  • State: one flightdeck serve instance per workspace SQLite file; do not run two writers against the same volume.
  • Upgrades: rebuild the image on semver bumps; keep /workspace mounted so the ledger survives container recreation.

Related