跳转至

Deploy

Phase 1 + Phase 2-2a deployment on HK-133 (lab.flytoex.net, 45.145.229.197, ssh port 43475).

Topology

Internet ──:443/:80──> Caddy ──> /admin/proxy/* ── basic_auth ──> relay:7080        (web, bridge-internal)
                               ├ /admin/*      ─────────────────> common:8081       (admin HTTP surface)
                               ├ /api/v1/*     ─────────────────> common:8080       (business REST/SSE -- ADR-0002)
                               └ everything else ──────────────── > logistics:8080  (REST)
                                                                        └─> common:9090 (gRPC, compose bridge)

Internet ──:7000/:7001/:13000-13099──> relay (bridge) ── tunnel ── flyto-proxy (alibaba VPC, 2-2b, not yet deployed)
                                                                        └─> internal DB / HTTP / SSH
  • hub.flytoex.net resolves to HK-133 (grey cloud, DNS-only)
  • Caddy auto-provisions Let's Encrypt certs on first request
  • All services on the compose-default bridge network
  • common gRPC :9090 and admin HTTP :8081 both not exposed to the host -- only reachable through Caddy or from logistics over the compose bridge
  • relay web :7080 is not in compose ports:, so Caddy (reverse_proxy relay:7080) is the only external ingress. Tunnel ports :7000/:7001 plus the rule-listen range :13000-13099 ARE host-exposed, because alibaba-side proxies connect to :7000 and external callers hit the per-rule listen ports that relay binds at runtime. ForwardRule.listen_port values in proxy configs must fall in 13000-13099; outside that range needs a docker-compose.yml update and redeploy.

First-time install on HK-133

ssh -p 43475 root@45.145.229.197
git clone https://git.flytoex.net/yuanwei/Flyto-Agent.git /opt/flyto
cd /opt/flyto/deploy
# After v0.1.0-alpha tag is pushed and Gitea Actions finishes the build:
docker compose pull
docker compose up -d
docker compose logs -f caddy     # watch LE cert issuance

Verify round-trip:

curl https://hub.flytoex.net/health
# => {"status":"STATUS_UNSPECIFIED","version":"","tenantId":""}
# STATUS_UNSPECIFIED is expected in dev mode (no auth, no tenant in ctx).
# Once OIDC is wired, the same call with a valid bearer returns SERVING.

Admin HTTP surface on common (observability only, not business traffic):

curl https://hub.flytoex.net/admin/health   # => {"status":"ok"}
curl https://hub.flytoex.net/admin/version  # => {"version":"v0.1.0-alpha.X"}
curl https://hub.flytoex.net/admin/tenant   # => {"tenant_id":"","subject":""} in dev
# /admin/tenant requires a bearer token once OIDC is wired; in dev it echoes
# empty strings. /admin/health and /admin/version are always open.

Business REST/SSE on common (ADR-0002 -- engine consumption surface):

# Health on the business listener (separate from /admin/health, but same shape)
curl https://hub.flytoex.net/api/v1/health   # => {"status":"ok","timestamp":...}

# Streaming agent run (SSE; requires ANTHROPIC_API_KEY in deploy/.env)
curl -N https://hub.flytoex.net/api/v1/agent/run \
  -H 'Authorization: Bearer <oidc-jwt>' \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"hello"}'
# => streaming text/event-stream chunks (text_delta / tool_use / done)

# Caddy passes SSE through with flush_interval -1; expect first chunk in ms.

Relay web console (flyto-proxy):

# Browser: open https://hub.flytoex.net/admin/proxy/ and enter basic_auth
# credentials (see the "Gitea Actions secrets" section below for where the
# hash is stored; plaintext user/password are in flysafe).

# curl with basic_auth:
curl -u yuanwei:<password> https://hub.flytoex.net/admin/proxy/api/proxies
# => []  (empty until an alibaba-side proxy connects -- that is Phase 2-2b)

Gitea Actions secrets

Go to https://git.flytoex.net/yuanwei/Flyto-Agent/-/settings/actions/secrets and add:

Secret Value
REGISTRY_USER yuanwei
REGISTRY_TOKEN Personal Access Token with write:package scope
ADMIN_BASIC_AUTH_HASH caddy hash-password output for the /admin/proxy/* basic_auth account. Plaintext credentials live in flysafe.
FLYTO_PROXY_TOKEN Shared token between relay and the alibaba-side flyto-proxy (64-hex, openssl rand -hex 32). Same value must be baked into the alibaba proxy config.

Generate the PAT at https://git.flytoex.net/-/user/settings/applications. Note: GITEA_* / GITHUB_* prefixes are reserved by Actions; use REGISTRY_* / ADMIN_* / FLYTO_*.

Release flow

git tag v0.1.0-alpha
git push origin v0.1.0-alpha

Tag push triggers .gitea/workflows/release.yml:

  1. Build git.flytoex.net/yuanwei/flyto-agent-common:<version>
  2. Build git.flytoex.net/yuanwei/flyto-agent-logistics:<version>
  3. Push both plus :latest to Gitea registry

Tag push now triggers auto-deploy via the deploy workflow job (SSH to HK-133, docker compose pull + up -d). Manual roll (skipping the deploy job) is only needed for troubleshooting:

ssh -p 43475 root@45.145.229.197
cd /opt/flyto/deploy
docker compose pull
docker compose up -d

Deploy secrets in the Gitea repo: DEPLOY_HOST, DEPLOY_PORT, DEPLOY_USER, DEPLOY_SSH_KEY (ed25519 key pair; pub already in /root/.ssh/authorized_keys on HK-133, keyed by flyto-deploy@gitea-actions).

Production mode (OIDC)

Once an OIDC issuer is available, override the common service command:

services:
  common:
    command:
      - "--grpc-addr=:9090"
      - "--http-addr=:8081"
      - "--rest-addr=:8080"
      - "--oidc-issuer=https://auth.flytoex.net/realms/flyto"
      - "--oidc-audience=flyto-platform"
      - "--oidc-tenant-claim=tenant_id"

Rolling back to dev mode = remove the last three --oidc-* flags. Leaving --http-addr empty is also legal and disables the admin surface entirely (e.g. for single-purpose gRPC-only builds). Leaving --rest-addr empty disables business REST/SSE without affecting gRPC + admin paths -- the ANTHROPIC_API_KEY ${...:?...} requirement still triggers, so set the env var to any non-empty placeholder when deploying without business REST.