Deploy to Fly.io
Ship your Petal Pro app to production on Fly.io.
Before you start
There are a few things to think about before deploying — see Deployment fundamentals for the full checklist.
If you’re using Claude Code, the easiest path is to ask:
help me deploy this app to Fly.io
Claude knows the patterns from the CLAUDE.md files and will walk you through the steps below. The rest of this guide is the same flow, in case you want to do it yourself.
Dev scripts
Petal Pro ships with a few convenience scripts in /scripts/:
sh scripts/server.sh # Start Phoenix + IEx in a tmux session named petal_pro
sh scripts/reset_db.sh # Drop, create, migrate, and seed the database
sh scripts/kill_db.sh # Kill stuck Postgres connections (handy when migrations hang)
Launch on Fly.io
Fly.io is the cheapest, easiest place to host a Phoenix app. Petal Pro is configured to deploy there with minimal fuss.
Install the Fly.io CLI, then sign in.
Create a new app with:
fly launch
ℹ️ Information: Fly will prompt you with default settings and ask if you want to tweak them. Hit Y — it opens a browser configuration UI.
In the configuration UI:
- Give your app a name (you can’t change it later).
- Under Database, choose Fly Postgres.
- Pick the cheapest server size to start.
- Leave Redis as none.
- Hit Confirm.
The Dockerfile
Petal Pro v4 ships a production-ready Dockerfile in the repo root — you don’t need to generate one with mix phx.gen.release --docker. It’s a multi-stage build:
- Builder stage: Elixir 1.17.2 / OTP 27 on Debian Bookworm. Compiles deps, runs the npm asset pipeline, produces an Elixir release.
- Runner stage: Lean Debian Bookworm slim with only the compiled release — no Elixir or build tools in the production image.
fly launch detects the existing Dockerfile and uses it. If it tries to generate a new one, skip that step — the included Dockerfile already has nodejs and npm for the asset pipeline.
Environment variables
fly launch automatically creates these secrets:
-
SECRET_KEY_BASE -
DATABASE_URL
The generated fly.toml also sets:
-
PHX_HOST -
PORT
Required
# Email — required for auth flows (confirmation, password reset, etc.)
fly secrets set RESEND_API_KEY="re_..."
Optional
# Sentry error tracking — auto-activates when set, no code changes needed
fly secrets set SENTRY_DSN="https://..."
# Admin MCP API bearer token (for AI tool access)
fly secrets set MCP_ADMIN_TOKEN="your_secure_token"
# Slack notifications (new signups, billing events, daily digest)
fly secrets set SLACK_OAUTH_TOKEN="xoxb-..."
fly secrets set SLACK_CHANNEL_ID="C0123456789"
Auto-deploy on push to main
Petal Pro v4 includes a GitHub Actions workflow at .github/workflows/fly.yml that auto-deploys on push to main:
name: Deploy to Fly.io
on:
push:
branches:
- main
concurrency:
group: fly-deploy
cancel-in-progress: false
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
To enable it:
-
fly tokens create deploy -x 999999hto generate a long-lived token - In your GitHub repo: Settings → Secrets and variables → Actions
-
Add a secret called
FLY_API_TOKENwith the token value
cancel-in-progress: false queues deploys instead of cancelling them — so you don’t end up half-deployed if you push twice in a row.
Manual deploy
You can also deploy at any time with:
fly deploy
ℹ️ Information: If deployment fails, you may need to add a payment method — Fly only allows 1 machine per app on the free tier.
After deploying, run fly open to view it in the browser. You’re live.