islandflow/deployment/native
2026-05-18 19:55:27 -04:00
..
config Implement native public edge cutover 2026-05-18 19:55:27 -04:00
systemd Implement native public edge cutover 2026-05-18 19:55:27 -04:00
bootstrap-infra.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
check-native-health.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
check-native-infra.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
cutover.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
full-rollback.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
install-infra-units.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
install-user-units.sh Implement native fast iterative deploy workflow 2026-05-18 03:36:01 -04:00
README.md Implement native public edge cutover 2026-05-18 19:55:27 -04:00
rollback.sh Implement native fast iterative deploy workflow 2026-05-18 03:36:01 -04:00
start-infra.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
stop-infra.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00
switch-npm-edge.sh Implement native public edge cutover 2026-05-18 19:55:27 -04:00

Native Deployment

This directory documents the host-native Islandflow rollout path used by:

./deploy main --runtime native
./deploy current-branch --runtime native

Current operating model

Native runtime is now intended for a phased VPS cutover. Docker remains the supported rollback runtime, but Docker and native app services must not own the same Islandflow scope at the same time because the workers and API use durable JetStream consumers.

Today, the recommended split is:

  • Nginx Proxy Manager remains the public :80/:443 edge
  • Native system services own NATS, Redis, and ClickHouse after infra cutover
  • Native user services own web, api, and workers after app cutover
  • Docker Compose remains available as the rollback runtime
  • local development stays:
    • Docker infra: bun run dev:infra
    • native backend services: bun run dev:services
    • native web: bun run dev:web

What native deploy means here

The checked-in deploy helper assumes:

  • the live repo checkout is /home/delta/islandflow
  • Bun is installed on the VPS
  • app processes are managed by systemd --user
  • infrastructure services such as NATS, ClickHouse, and Redis are reachable from the host
  • the web app runs from apps/web and is served with next start -p 3000

The deploy script updates the repo checkout, optionally runs bun install --frozen-lockfile, optionally rebuilds the web app, restarts the target user units, verifies local health, and then runs public verification when the selected scope includes the public edge.

Live audit status on 2026-05-18

The plan assumptions were audited on the VPS:

  • bun is installed and available at /home/delta/.bun/bin/bun
  • systemctl --user is available and the delta user has lingering enabled
  • /home/delta/islandflow/.env exists
  • public https://flow.deltaisland.io/replay/options routing is healthy again
  • the previously reported duplicate islandflow compose project is not currently present in docker compose ls
  • native Islandflow user units were not installed at the start of the audit; this change now provides and installs the checked-in user unit files, but they remain disabled until an operator enables a scope intentionally

That means native worker deploy support is now provisioned on the host, but native runtime should still be enabled scope-by-scope rather than started wholesale.

Checked-in native ops assets

Infra system units

Checked-in system service units and config live under:

  • deployment/native/systemd/system/islandflow-nats.service
  • deployment/native/systemd/system/islandflow-redis.service
  • deployment/native/systemd/system/islandflow-clickhouse.service
  • deployment/native/config/redis.conf
  • deployment/native/config/clickhouse-listen.xml

Install and start them on the VPS with:

./deployment/native/bootstrap-infra.sh

Or install and start manually:

sudo ./deployment/native/install-infra-units.sh
sudo ./deployment/native/start-infra.sh
./deployment/native/check-native-infra.sh

The native infra services bind to loopback and use stable host data paths:

  • NATS JetStream: /var/lib/islandflow/nats
  • Redis: /var/lib/islandflow/redis
  • ClickHouse: /var/lib/islandflow/clickhouse

The Docker fallback compose file uses the same ISLANDFLOW_DATA_ROOT default of /var/lib/islandflow, so rollback can preserve durable state when only one runtime is active.

User unit templates

Checked-in unit files live under:

  • deployment/native/systemd/user/islandflow-web.service
  • deployment/native/systemd/user/islandflow-api.service
  • deployment/native/systemd/user/islandflow-compute.service
  • deployment/native/systemd/user/islandflow-candles.service
  • deployment/native/systemd/user/islandflow-ingest-options.service
  • deployment/native/systemd/user/islandflow-ingest-equities.service

These are written for the current VPS layout:

  • repo root: /home/delta/islandflow
  • Bun binary: /home/delta/.bun/bin/bun
  • env file: /home/delta/islandflow/.env

Install the units

./deployment/native/install-user-units.sh
./deployment/native/install-user-units.sh workers
systemctl --user start islandflow-compute.service

Install script behavior:

  • copies the checked-in unit files into ~/.config/systemd/user
  • reloads the user systemd daemon
  • enables only the scope you explicitly request
  • defaults to installing without enabling anything yet

Smoke test helper

./deployment/native/check-native-health.sh workers
./deployment/native/check-native-health.sh services
./deployment/native/check-native-health.sh full

This validates:

  • native infra health for full, api, services, and workers
  • systemctl --user is-active for the selected units
  • local API health at http://127.0.0.1:4000/health when API scope is included
  • local web health at http://127.0.0.1:3000/ when web scope is included

App cutover and edge switch helpers

./deployment/native/cutover.sh full
./deployment/native/switch-npm-edge.sh native
./deployment/native/full-rollback.sh

The edge switch helper updates the Nginx Proxy Manager database entries for flow.deltaisland.io and api.flow.deltaisland.io, preserving the same-origin Islandflow API location matcher:

^/(ws|replay|prints|joins|nbbo|dark|flow|candles|history)/

For native cutover, the helper targets the NPM bridge gateway IP by default, not host.docker.internal. NPM generates proxy_pass with a runtime-resolved $server variable, so Docker's /etc/hosts alias is not sufficient for these proxy hosts. On the current VPS that native target resolves to 172.18.0.1, which reaches the host-native 3000 and 4000 listeners from the NPM container.

Switching back to Docker restores upstreams to the Compose service names web:3000 and api:4000.

Rollback helper

./deployment/native/rollback.sh <git-ref> workers
./deployment/native/rollback.sh <git-ref> services

Rollback helper behavior:

  • requires a clean repo state
  • fetches refs
  • switches the checkout to a detached target ref
  • reruns bun install --frozen-lockfile
  • rebuilds the web app only when web scope is included
  • restarts the selected user units
  • runs the native smoke checks

Expected unit names

Default unit names used by scripts/deploy.ts:

  • islandflow-web
  • islandflow-api
  • islandflow-compute
  • islandflow-candles
  • islandflow-ingest-options
  • islandflow-ingest-equities

Override them from your local shell before running ./deploy if the server uses different names:

export DEPLOY_NATIVE_WEB_UNIT=my-web-unit
export DEPLOY_NATIVE_API_UNIT=my-api-unit

Available overrides:

  • DEPLOY_NATIVE_WEB_UNIT
  • DEPLOY_NATIVE_API_UNIT
  • DEPLOY_NATIVE_COMPUTE_UNIT
  • DEPLOY_NATIVE_CANDLES_UNIT
  • DEPLOY_NATIVE_INGEST_OPTIONS_UNIT
  • DEPLOY_NATIVE_INGEST_EQUITIES_UNIT

systemctl invocation

For the checked-in user units, use:

export DEPLOY_NATIVE_SYSTEMCTL_PREFIX="systemctl --user"

The deploy helper defaults to sudo -n systemctl, but that is only appropriate if you intentionally install matching system units.

Partial native rollouts

Examples:

./deploy main --runtime native --workers-only
./deploy main --runtime native --fast
./deploy main --runtime native --services-only
./deploy main --runtime native --web-only
./deploy current-branch --runtime native --workers-only --no-build

Scope behavior:

  • default: restart web + API + worker services
  • --web-only: rebuild/restart only the web unit
  • --api-only: restart only the API unit
  • --services-only: restart API + worker units without touching the web unit
  • --workers-only: restart only compute, candles, ingest-options, and ingest-equities
  • --fast: when no explicit scope flag is provided, native deploys now default to --workers-only
  • --no-build: skip bun install --frozen-lockfile and skip the web build step

Edge-cutover guardrail

Native deploys that touch the public web or API edge are intentionally blocked unless you acknowledge cutover readiness:

export DEPLOY_NATIVE_EDGE_READY=1

Without that variable, these commands are refused:

  • ./deploy main --runtime native
  • ./deploy main --runtime native --web-only
  • ./deploy main --runtime native --api-only
  • ./deploy main --runtime native --services-only

This keeps native app ownership explicit until infra, app health, and proxy routing are switched deliberately.

Running deploy from the VPS itself

If you run ./deploy from /home/delta/islandflow on the live server, the deploy helper now executes the remote steps locally instead of SSHing back into the same machine.

That means:

  • no SSH key is required for on-server deploy execution
  • timing and verification behavior stay the same
  • you can still force SSH with DEPLOY_FORCE_SSH=1
  • you can override the SSH key path with DEPLOY_SSH_KEY_PATH=/path/to/key

Validation matrix

Area Native workers-only Native edge cutover
Bun installed required required
systemctl --user works required required
Islandflow user units installed worker units only all units
Host access to NATS/ClickHouse/Redis required required
Proxy routes updated for /prints, /history, /replay, /nbbo, /ws, /flow, /candles not required required
Public app check not required required
Public API route suite not required required

Staged cutover plan

  1. Stage 1: native workers only
    • install user units
    • validate ./deployment/native/check-native-health.sh workers
    • use ./deploy main --runtime native --fast
  2. Stage 2: native API behind local-only verification
    • start islandflow-api.service
    • confirm curl http://127.0.0.1:4000/health
    • do not switch public routing yet
  3. Stage 3: deliberate public edge cutover
    • update proxy routing to native web/api
    • export DEPLOY_NATIVE_EDGE_READY=1
    • run full native deploy
    • validate bun run scripts/check-public-api-routes.ts https://flow.deltaisland.io
  4. Stage 4: decide final default runtime
    • keep Docker as fallback until native edge has proven stable

Fast backend iteration before edge cutover:

export DEPLOY_NATIVE_SYSTEMCTL_PREFIX="systemctl --user"
./deploy main --runtime native --fast

Supported production path today:

./deploy main --runtime docker