Skip to content

Commit 31c0d7b

Browse files
feat(deploy): public Fly.io instance + ghcr one-liner (Task 6) (#261)
## Summary - **fly.toml**: convert from internal-only TCP to public `[http_service]` (HTTPS 443 → :8090); switch build from Dockerfile to pre-built `ghcr.io/hyperpolymath/echidna:full` image - **fly-deploy.yml**: new CI workflow — deploys to `echidna-nesy.fly.dev` on each release and `workflow_dispatch` ## The two delivery forms (both) ### 1. podman one-liner for colleagues (already works — image is live at v2.3.0) ```bash # minimal image (Z3 + Lean) — fastest podman run --rm -p 8081:8081 ghcr.io/hyperpolymath/echidna:latest server --port 8081 --cors # full image (all provers + Julia ML) — for serious colleagues podman run --rm -p 8081:8081 ghcr.io/hyperpolymath/echidna:full server --port 8081 --cors ``` Then in another terminal: ```bash curl -X POST http://localhost:8081/api/prove \ -H 'content-type: application/json' \ -d '{"prover":"Z3","content":"(set-logic QF_LIA)\n(declare-const x Int)\n(assert (and (> x 0) (< x 0)))\n(check-sat)\n","timeout":30}' # → {"success":true,...} ``` ### 2. Fly.io public instance — one-time setup needed ```bash # One-time (you do this once): flyctl apps create echidna-nesy flyctl tokens create deploy -a echidna-nesy # copy the token gh secret set FLY_API_TOKEN -b"<token>" -R hyperpolymath/echidna # Then trigger the workflow (or create a release): gh workflow run fly-deploy.yml --repo hyperpolymath/echidna ``` After deploy: `https://echidna-nesy.fly.dev/api/health` ## Notes - The internal `.flycast` URL (`echidna-nesy.flycast:8090`) still works for `proven-nesy-solver-api` — flycast is automatic and unaffected by adding `[http_service]` - `flyctl` is not installed on the dev WSL machine; hence the CI workflow approach - `FLY_API_TOKEN` must be set as a repo secret before the workflow can run ## Test plan - [ ] Add `FLY_API_TOKEN` repo secret - [ ] Trigger `fly-deploy.yml` via `workflow_dispatch` - [ ] Confirm `https://echidna-nesy.fly.dev/api/health` returns `{"status":"ok",...}` - [ ] Confirm refutation demo returns `success:true` Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6feec89 commit 31c0d7b

2 files changed

Lines changed: 56 additions & 26 deletions

File tree

.github/workflows/fly-deploy.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Deploy to Fly.io — runs after each release (once ghcr-publish.yml has pushed
3+
# ghcr.io/hyperpolymath/echidna:full) and on workflow_dispatch.
4+
#
5+
# Prerequisites:
6+
# 1. App created: flyctl apps create echidna-nesy
7+
# 2. FLY_API_TOKEN secret set in repo:
8+
# flyctl tokens create deploy -a echidna-nesy
9+
# gh secret set FLY_API_TOKEN -b"<token>" -R hyperpolymath/echidna
10+
name: Deploy to Fly.io
11+
on:
12+
release:
13+
types: [published]
14+
workflow_dispatch:
15+
permissions:
16+
contents: read
17+
jobs:
18+
deploy:
19+
name: Deploy echidna-nesy
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v4
26+
- name: Install flyctl
27+
uses: superfly/flyctl-actions/setup-flyctl@ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1 # main 2025-06
28+
- name: Deploy
29+
run: flyctl deploy --remote-only -a echidna-nesy
30+
env:
31+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

fly.toml

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,52 @@
11
# SPDX-License-Identifier: MPL-2.0
2-
# fly.io deployment for echidna (Phase E3 nesy-solver playground backend).
2+
# fly.io deployment for echidna.
33
#
4-
# Deploy:
5-
# flyctl launch --no-deploy --copy-config --name echidna-nesy
6-
# flyctl deploy -c fly.toml -f .containerization/Containerfile.full
4+
# Public HTTPS: https://echidna-nesy.fly.dev/api/health
5+
# Internal: echidna-nesy.flycast:8090 (proven-nesy-solver-api + other Fly apps)
76
#
8-
# Internal-only: echidna is reached via echidna-nesy.flycast:8090 from
9-
# proven-nesy-solver-api; no public http_service.
10-
# Use .flycast (not .internal) so Fly auto-wakes the machine on first connection.
7+
# First deploy (one-time):
8+
# flyctl apps create echidna-nesy
9+
# flyctl secrets set FLY_API_TOKEN=... -a echidna-nesy # (CI sets this)
10+
# flyctl deploy -a echidna-nesy
1111
#
12-
# NB: Container is LARGE (~6-8 GB) — Julia + Idris2 + Agda + Lean + Isabelle.
13-
# Memory must be >=4GB (Isabelle Main heap ~1GB); shared-cpu-2x is the
14-
# cheapest size that fits.
12+
# Subsequent deploys are handled by .github/workflows/fly-deploy.yml on release.
13+
#
14+
# NB: Uses the pre-built ghcr.io/hyperpolymath/echidna:full image (published by
15+
# ghcr-publish.yml on each release) to avoid building the 6-8 GB layer here.
16+
# Memory >=4 GB required: Isabelle Main heap ~1 GB; Julia JIT overhead.
1517

1618
app = "echidna-nesy"
1719
primary_region = "lhr"
1820
kill_signal = "SIGTERM"
1921
kill_timeout = "10s"
2022

2123
[build]
22-
dockerfile = ".containerization/Containerfile.full"
24+
image = "ghcr.io/hyperpolymath/echidna:full"
2325

2426
[env]
25-
# echidna listens on port 8090 when launched with `server --port 8090`.
26-
# The ENTRYPOINT is `/app/bin/echidna`; CMD gets overridden below.
2727
RUST_LOG = "info"
2828
ECHIDNA_HOST = "[::]"
2929
ECHIDNA_PORT = "8090"
3030

3131
[processes]
3232
app = "server --port 8090 --host [::] --cors"
3333

34-
# Internal-only TCP on :8090
35-
[[services]]
36-
protocol = "tcp"
34+
# Public HTTPS — terminates TLS at the Fly edge, forwards to internal :8090.
35+
[http_service]
3736
internal_port = 8090
37+
force_https = true
3838
auto_stop_machines = "stop"
3939
auto_start_machines = true
4040
min_machines_running = 0
4141
processes = ["app"]
42-
43-
[[services.ports]]
44-
port = 8090
45-
handlers = []
46-
47-
# HTTP check on /api/health — tests the server is serving, not just the port.
48-
# grace_period must be generous: Isabelle Main heap maps ~1-2 GB on first load
49-
# and Julia has JIT overhead on first prover call. 90s is the minimum safe value.
50-
[[services.http_checks]]
42+
[http_service.concurrency]
43+
type = "requests"
44+
hard_limit = 25
45+
soft_limit = 20
46+
47+
# Grace period is generous: Isabelle Main heap maps ~1-2 GB on cold start;
48+
# Julia has JIT overhead on first prover call. 90s is the minimum safe value.
49+
[[http_service.checks]]
5150
interval = "30s"
5251
timeout = "10s"
5352
grace_period = "90s"
@@ -56,6 +55,6 @@ kill_timeout = "10s"
5655

5756
[[vm]]
5857
size = "shared-cpu-2x"
59-
memory = "4096mb" # Julia + Agda + Isabelle Main heap need real RAM
58+
memory = "4096mb"
6059
cpu_kind = "shared"
6160
cpus = 2

0 commit comments

Comments
 (0)