jonnifyelixir
Contents / F7 · Deploy to Fly

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

1 · THE FILE — F7.1 inet_config: file /app/inetrc not found 2 · THE NAME — F7.2 / F7.3 :nxdomain — resolves from another machine 3 · THE ADDRESS — F7.2 · decisive :nxdomain again — AAAA-only host, IPv4 query 4 · THE BOOT — F7.3 failed to start child — exit 1 — suspend after 10

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

7.1 image built 7.2 config 7.3 database 7.4 fly.toml 7.5 live /health → ok boot it live (7.1–7.3) · operate it (7.4–7.5)
Five modules run from a bootable image to a verified-live endpoint. F7.1 builds the image and ships every file the runtime names; F7.2 configures it for Fly’s IPv6-only private network; F7.3 brings a reachable, migrated Postgres behind the F5 port; F7.4 distils 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 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.