Fly.io skill for Codex

Machines, volumes and regions without surprises. Codex sets up Fly.io apps with a fly.toml that has real readiness checks, sensible auto stop and start, release commands for migrations and a deliberate deploy strategy. It treats volumes as single-host disks that need off-platform backups, routes writes to the primary region, connects services over .internal or Flycast, and records the rollback image before anything risky ships.

  • Cloud Platforms
  • $fly-io
  • 187 lines
  • 2 files
  • ~1,700 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- fly-io

Installs to ~/.agents/skills/fly-io/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $fly-io, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Deploys and runs apps on Fly.io with flyctl and fly.toml - Machines, http_service and auto stop/start, health checks, release commands, deploy strategies, secrets, volumes and snapshots, multi-region placement, private networking over .internal and Flycast, scaling and rollback. Use when launching an app on Fly, a deploy hangs on health checks, machines will not stop or start, data on a volume is at risk, you are adding regions, or connecting services privately.

Use it when

  • Launching or migrating an app onto Fly.io
  • Deploys fail on health checks or machines do not auto stop and start
  • An app stores data on a Fly volume
  • Adding regions or connecting apps over the private network

Use something else when

  • You want a simpler managed PaaS with built-in databases: use paas-deploys
  • You are deploying containers to your own servers: use kamal-deploys

How to check the result

fly checks list shows passing checks on every Machine, the public health URL returns 200 over HTTPS, and a backup of any volume data has been restored once.

The mistake it prevents

Assuming a Fly volume is replicated; it lives on one host, so a host failure loses data that has no off-platform backup.

~/.agents/skills/fly-io/SKILL.md

--- name: fly-io description: Deploys and runs apps on Fly.io with flyctl and fly.toml - Machines, http_service and auto stop/start, health checks, release commands, deploy… license: MIT ---

On Fly, an app is a set of Machines (fast-booting VMs) built from your image. A sound setup has health checks that reflect real readiness, at least two Machines for anything user-facing, volumes treated as single-host disks with their own backup plan, and secrets set through fly secrets, never baked into the image.

Inspect first

  1. Read AGENTS.md, fly.toml, Dockerfile and the app’s listen address and port.
  2. fly status, fly machine list and fly volumes list show what is actually running. All fly commands need network and fly auth login or FLY_API_TOKEN; in a sandbox without network, prepare files and hand commands to the user.
  3. Check which Postgres the app uses: Fly Managed Postgres (fly mpg), an older self-managed Fly Postgres app, or an external provider. They are operated differently.

Launch

fly launch --no-deploy          # detects framework, writes fly.toml and Dockerfile
fly secrets set DATABASE_URL=... SESSION_SECRET=... --stage   # stage, apply on next deploy
fly deploy

The process must listen on 0.0.0.0 (or ::) at internal_port. Binding to 127.0.0.1 is the most common cause of “no healthy machines”.

fly.toml baseline

app = "acme-api"
primary_region = "iad"

[build]
  dockerfile = "Dockerfile"

[env]
  NODE_ENV = "production"
  PORT = "8080"

[deploy]
  release_command = "npm run migrate"   # runs once in a temporary Machine before rollout
  strategy = "rolling"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = "stop"
  auto_start_machines = true
  min_machines_running = 1
  [http_service.concurrency]
    type = "requests"
    soft_limit = 200
    hard_limit = 250

  [[http_service.checks]]
    grace_period = "10s"
    interval = "15s"
    timeout = "3s"
    method = "GET"
    path = "/healthz"

[[vm]]
  size = "shared-cpu-1x"
  memory = "512mb"
SettingGuidance
auto_stop_machines"stop" saves money; "suspend" resumes faster; "off" for always-on workers
min_machines_runningApplies to the primary region; set at least 1 for anything latency-sensitive
concurrencyrequests for HTTP apps, connections for raw TCP or WebSockets
release_commandMigrations only; it has no volume and a failed run aborts the deploy
Health check pathReturn 200 only when the app can serve: DB pool ready, config loaded

Deploy strategies

StrategyWhen
rolling (default)Replaces Machines one at a time; fine for most stateless apps
bluegreenBoots a full new set, waits for health checks, then switches; needs checks defined; not for Machines with volumes
canaryOne new Machine first, then rolling; not for Machines with volumes
immediateReplaces everything at once; accept downtime

Roll back by redeploying a previous image:

fly releases --image                  # lists releases with image refs
fly deploy --image registry.fly.io/acme-api:deployment-01J...   # confirm with user first

Schema migrations do not roll back with the image. Write migrations that the previous release can still run against (expand, then contract).

Volumes

A volume is a slice of NVMe on one physical host, attached to exactly one Machine.

fly volumes create data --region iad --size 10     # GB
fly volumes list
fly volumes snapshots list <volume-id>
fly volumes extend <volume-id> --size 20           # grow only, never shrink
[mounts]
  source = "data"
  destination = "/data"

Rules:

  • Volumes are not replicated. If the host dies, that volume is gone until restored from a snapshot. Daily snapshots exist but are short-retention; for real data run your own backups off Fly (for SQLite, Litestream or LiteFS backups to object storage).
  • Two Machines need two volumes; data does not sync between them. Scaling a volume-backed app horizontally needs replication in the application layer.
  • Deleting a volume is permanent. Never run fly volumes destroy without explicit user confirmation and a verified snapshot.

Regions and scaling

fly platform regions
fly scale count 2                      # in primary region
fly scale count 2 --region fra        # Machines in an additional region
fly scale vm shared-cpu-2x --memory 1024
fly scale show

Put Machines where the database is. Read replicas in other regions help reads; writes should go to the primary region (replay a request there with the fly-replay response header when a non-primary Machine receives a write).

Private networking

  • Every app in an organization shares a private IPv6 network.
  • <app>.internal resolves to all Machines of an app; <region>.<app>.internal narrows to a region. These addresses bypass the Fly proxy, so autostart does not apply.
  • Flycast (fly ips allocate-v6 --private, then <app>.flycast) goes through the proxy, so stopped Machines wake up and load balancing applies. Use it for internal HTTP services that scale to zero.
  • fly proxy 5432 -a acme-db forwards a private port to your laptop for one-off access.

Debugging

fly logs -a acme-api
fly status --all
fly machine status <id>
fly checks list
fly ssh console -s            # pick a Machine and open a shell
fly doctor
SymptomLikely cause
Deploy waits then fails health checksWrong internal_port, bound to localhost, check path slow or needs auth
Machines never stopOpen connections, background traffic, or min_machines_running too high
First request slowCold start after auto stop; raise min_machines_running or use suspend
OOM kills in logsRaise memory; Node may also need --max-old-space-size set below it
App cannot reach another appUsing public hostname instead of .internal/.flycast, or listening on IPv4 only

Verification

  • fly deploy completes and fly checks list shows passing checks on every Machine.
  • curl -I https://<app>.fly.dev/healthz returns 200 over HTTPS.
  • At least two Machines for user-facing apps (fly scale show).
  • Volume-backed data has a backup that has been restored at least once.
  • Rollback image reference recorded before risky deploys.

Gotchas

  • fly secrets set without --stage restarts Machines immediately.
  • fly launch may create extra Machines for high availability; check fly scale show after the first deploy before assuming one instance.
  • The release command Machine has no access to volumes; do not run SQLite migrations there. Run them at boot in the app instead.
  • Shared CPU Machines get throttled under sustained load; move CPU-bound work to performance sizes.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Fly.io"
  short_description: "Machines, volumes and regions without surprises"
  default_prompt: "$fly-io Deploy this Node API to Fly.io with health checks and two machines"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem