F7 · chapter overview
Deploy to Fly
F6 left a real, real-time learning platform — the supervised F5 engine, a Phoenix web layer, LiveView, PubSub, auth, and a release that built on a developer’s machine. F7 takes that release live on the internet. The gap between a release that builds and a machine that boots is not one big step; it is a set of faults that only a real boot reveals — and they stack, so fixing one only surfaces the next while the error message barely changes. The first bring-up hit four: a config that named a file the image never shipped, a database name that resolved only when the database was running, an IPv6 flag that was set but never read, and a boot that read the database synchronously and crashed when it could not. None of this touches the engine — deploy is the outermost layer — but all of it has to be right at once, because a wrong value never fails a build; it fails a boot.
Five modules, one bring-up. Each masters one deploy concern and owns the gotcha it produces, ending
with a public health check that returns ok — live, verified, operable.
The four-gotcha spine
This chapter exists because four faults stand between a valid config and a working deploy, and three of the four
produce the same boot symptom — a Postgrex :nxdomain crash-loop — so
a chapter that does not name them teaches nothing the manuals already say. Each gotcha is silent until boot, and
each lands in the module that owns it. Select one.
Four stacked faults · select a gotcha
owning module: F7.1 · the release image
resolves from another machine? no — the file is local to the image
The discriminator that separates gotcha 2 from gotcha 3 — identical
:nxdomain — is to resolve the name from another running machine in the org.
Success there means the fault is the app’s address family, not the network.
The deploy ladder
Read it in order: each module is a narrow operational slice, proven by a probe rather than by inspection, and
each leaves the platform one rung closer to live. The first three assemble a release that boots against a real
database; the last two operate it — deploy with one command, self-heal, verify, and run day-2 operations.
The ladder ends where the chapter does: a public /health that returns
ok over the internet.
Five modules · from a bootable image to a verified-live endpoint
fly.toml and provisions secrets so a
deploy rolls and self-heals; F7.5 verifies curl -fsS https://echo-portal.fly.dev/health returns
ok and names the day-2 operations.Liveness is the only acceptance. A module is done when its concern is demonstrably live — a
curl, a fly status, an applied migration — not when a config
looks right.
Module navigation
Each module links to its hub and lists its three deep dives. The ladder is the build order — start at F7.1, the release image, and end at F7.5, where the Portal answers a public health check.
The release image
A multi-stage Dockerfile that builds the scoped Portal release and ships every file the runtime config points at — owns the missing-inetrc gotcha.
- F7.1.1Multi-stage anatomy & the scoped build
- F7.1.2Toolchain pinning & image coherence
- F7.1.3Shipping config files in
Runtime config & the IPv6 network
runtime.exs resolves secrets, host, and bind at boot, and Postgrex speaks Fly’s IPv6 DNS — owns the AAAA-only address gotcha.
- F7.2.1Runtime vs compile config
- F7.2.2The IPv6 trio & AAAA-only names
- F7.2.3.internal vs .flycast
The database goes live
A reachable, migrated Postgres behind the F5 port, and a release that survives its boot-time read — owns the synchronous-boot gotcha.
- F7.3.1Release-native migration
- F7.3.2The empty-DB trap & fly proxy
- F7.3.3Boot-time DB coupling
fly.toml & the deploy mechanics
A distilled config, provisioned secrets, and a deploy that rolls, self-migrates, and self-heals through the machine lifecycle.
- F7.4.1The distilled fly.toml
- F7.4.2Secrets & env provisioning
- F7.4.3The deploy lifecycle
Portal is live
The verified-live endpoint and the day-2 operations to keep it that way — the four-gotcha triage table as a runbook.
- F7.5.1Liveness verification
- F7.5.2The four-gotcha runbook
- F7.5.3Day-2 operations
The chapter opens with F7.1 — The release image (built) and closes with
F7.5, where curl -fsS https://echo-portal.fly.dev/health returns
ok. It builds on
F6 — Phoenix Framework — F6.08 produced the deploy
artifacts; F7 takes them live — and never touches the engine beneath: deploy is the outermost layer.