fly-io
Use when deploying to Fly.io or configuring flyctl, fly.toml, Fly.io secrets, databases, or GitHub Actions.
How do I install this agent skill?
npx skills add https://github.com/fellowship-dev/dogfooded-skills --skill fly-ioIs this agent skill safe to install?
- Gen Agent Trust Hubfail
The skill provides comprehensive instructions for deploying applications to Fly.io, including CLI installation, database management, and CI/CD integration. It correctly follows security best practices such as environment variable encryption. Security findings relate to the standard use of remote installation scripts from a well-known service and the interpolation of user-provided names into shell commands.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Fly.io
This skill provides comprehensive guidance for deploying applications to Fly.io, including initial setup, database management, CI/CD integration, and production operations.
When to Use
This skill activates automatically when working with:
- Fly.io-specific tasks ("fly.io", "deploy to fly", "fly.io setup", "flyctl")
- Fly.io configuration ("fly.toml", "fly app", "fly launch")
- Fly.io database operations ("fly postgres", "fly pg")
- Fly.io environment management ("fly secrets", "fly env")
- Fly.io monitoring ("fly logs", "fly status", "fly dashboard")
- Fly.io GitHub Actions ("fly deploy github action", "flyctl in CI/CD")
Core Principles
- Security First: Always encrypt sensitive data, never commit unencrypted secrets
- Database Safety: Use proxying for database access, maintain regular backups
- Environment Isolation: Separate development, staging, and production configurations
- Cost Awareness: Optimize resource allocation, monitor usage regularly
- Automation: Leverage CI/CD for consistent, repeatable deployments
- Monitoring: Implement comprehensive logging and health checks
Prerequisites
Before beginning Fly.io deployment:
- Fly.io Account: Active account with credit card attached (required for PostgreSQL)
- CLI Installation:
flyctlcommand-line tool installed and authenticated - Environment Variables: Project-specific configuration ready
- Application Ready: Application configured for production deployment
Instructions
1. Initial Setup and Authentication
Install Fly.io CLI:
# Standard installation
curl -L https://fly.io/install.sh | sh
# Add to PATH (adjust based on your environment)
export FLYCTL_INSTALL="/home/user/.fly"
export PATH="$FLYCTL_INSTALL/bin:$PATH"
# Verify installation
flyctl version
Authenticate with Fly.io:
flyctl auth login
This opens a browser for authentication. After successful login, your credentials are stored locally.
2. Environment Variable Management
Encryption for Security:
Fly.io deployments should use encrypted environment files to protect sensitive data:
# Decrypt environment file (requires ENV_PASS variable)
openssl enc -aes-256-cbc -pbkdf2 -salt -d -in .env.enc -out .env -k $ENV_PASS
# After modifying .env, re-encrypt
openssl enc -aes-256-cbc -pbkdf2 -salt -in .env -out .env.enc -k $ENV_PASS
# For production environment
openssl enc -aes-256-cbc -pbkdf2 -salt -in .env -out .env.enc.prod -k $ENV_PASS
IMPORTANT Security Notes:
- Never commit unencrypted
.envfiles - Store
ENV_PASSsecurely (GitHub secrets, password manager) - Use different encryption passwords for staging/production
- Add
.envto.gitignoreif not already present
3. Database Setup (PostgreSQL)
Create PostgreSQL Database:
# Create new PostgreSQL database on Fly.io
flyctl postgres create
# When prompted, use naming convention: {project-name}-db
# Example: myapp-db
Important database creation options:
- Choose region closest to your users
- Select appropriate resource tier (start small, scale up)
- Note the database credentials provided
- Database name typically matches app name + "-db" suffix
Attach Database to Application:
# Attach database to your application
flyctl pg attach {project-name}-db -a {project-name}
# If attachment fails, set DATABASE_URL manually
flyctl secrets set DATABASE_URL=postgres://user:pass@host:5432/dbname -a {project-name}
Verify database connection:
# Check database status
flyctl status -a {project-name}-db
# Test connection via proxy
flyctl proxy 5433 -a {project-name}-db
# In another terminal: psql -h localhost -p 5433 -U {username} -d {dbname}
4. Application Creation and Configuration
Launch New Application:
# Create application (don't deploy yet)
flyctl launch
# Follow prompts:
# - Choose app name (matches ENV_NAME variable)
# - Select region (same as database for best performance)
# - Choose resource allocation
# - Decline immediate deployment (configure first)
Configure Application:
After flyctl launch, review and customize fly.toml:
app = "your-app-name"
[build]
# Adjust based on your application type
[env]
PORT = "8080"
HOST = "::"
# Add other non-secret environment variables
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
Set Secrets:
# Set individual secrets
flyctl secrets set APP_KEYS="your-app-keys" -a {project-name}
flyctl secrets set API_TOKEN_SALT="your-salt" -a {project-name}
# Import from .env file (ensure it's decrypted first)
flyctl secrets import -a {project-name} < .env
5. Deployment Workflow
Pre-Deployment Checklist:
- Environment variables configured (production values)
- Database created and attached
-
fly.tomlreviewed and customized - Secrets set via
flyctl secrets - Application builds successfully locally
- Dependencies are production-ready
Initial Deployment:
# Deploy application
flyctl deploy -a {project-name}
# Monitor deployment
flyctl logs -a {project-name}
# Check status
flyctl status -a {project-name}
Post-Deployment Verification:
# Open application in browser
flyctl open -a {project-name}
# Check health endpoint
curl https://{project-name}.fly.dev/health
# Review logs for errors
flyctl logs -a {project-name}
6. Domain and SSL Configuration
Add Custom Domain:
# Add certificate for custom domain
flyctl certs create yourdomain.com -a {project-name}
# Check certificate status
flyctl certs show yourdomain.com -a {project-name}
DNS Configuration:
- Point your domain's A/AAAA records to Fly.io
- Wait for DNS propagation
- Verify certificate issuance
- Update
APP_URLenvironment variable to custom domain - Re-deploy with updated configuration
7. Database Management
PostgreSQL Dump (Backup):
# Standard dump format (custom format, compressed)
pg_dump -Fc --no-acl --no-owner -h HOST -U USERNAME -d DATABASE_NAME > dump_file.dump
# Example for local database
pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -d strapi > backup.dump
PostgreSQL Restore:
# Standard restore
pg_restore --verbose --clean --no-acl --no-owner -h HOST -p PORT -U USERNAME -d "DATABASE_NAME" dump_file.dump
# Example for local database
pg_restore --verbose --clean --no-acl --no-owner -h localhost -U postgres -d strapi backup.dump
Upload Local Database to Fly.io:
# 1. Export local database
pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -d {dbname} > latest.dump
# 2. Proxy production database (run in separate terminal)
flyctl proxy 5433 -a {project-name}-db
# 3. In another terminal, restore to production
DB_USER={check_fly_dashboard} # Get from Fly.io dashboard
DB_NAME={check_fly_dashboard} # Get from Fly.io dashboard
pg_restore --verbose --clean --no-acl --no-owner -h localhost -p 5433 -U $DB_USER -d "$DB_NAME" latest.dump
# 4. Clean up
rm latest.dump
Download Production Database from Fly.io:
# 1. Proxy production database (run in separate terminal)
flyctl proxy 5433 -a {project-name}-db
# 2. In another terminal, dump production database
DB_USER={check_fly_dashboard}
DB_NAME={check_fly_dashboard}
pg_dump -Fc --no-acl --no-owner -h localhost -p 5433 -U $DB_USER -d "$DB_NAME" > production.dump
# 3. Restore to local database
pg_restore --verbose --clean --no-acl --no-owner -h localhost -U postgres -d {dbname} production.dump
# 4. Clean up
rm production.dump
Database Proxy for Direct Access:
# Proxy database to local port
flyctl proxy 5433 -a {project-name}-db
# Connect with psql
psql -h localhost -p 5433 -U {username} -d {dbname}
# Connect with GUI tools (PgAdmin, DBeaver, etc.)
# Host: localhost
# Port: 5433
# User: {from Fly.io dashboard}
# Database: {from Fly.io dashboard}
8. GitHub Actions CI/CD Integration
Setup Continuous Deployment:
-
Generate Fly.io API token:
flyctl auth token -
Add GitHub repository secrets:
FLY_API_TOKEN: Your Fly.io API tokenENV_PASS: Environment encryption password (if using encrypted .env)
-
Create
.github/workflows/deploy.yml:
name: Deploy to Fly.io
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Fly.io CLI
uses: superfly/flyctl-actions/setup-flyctl@master
- name: Decrypt environment variables
run: |
openssl enc -aes-256-cbc -pbkdf2 -salt -d \
-in .env.enc.prod -out .env -k ${{ secrets.ENV_PASS }}
- name: Deploy to Fly.io
run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
Best Practices for CI/CD:
- Use
--remote-onlyflag to build on Fly.io servers - Separate staging and production workflows
- Implement smoke tests after deployment
- Configure Slack/Discord notifications for deployment status
- Use GitHub environments for approval gates on production deploys
9. Monitoring and Troubleshooting
Essential Monitoring Commands:
# Check application status
flyctl status -a {project-name}
# View real-time logs
flyctl logs -a {project-name}
# View logs with filtering
flyctl logs -a {project-name} --region iad
# Check database status
flyctl status -a {project-name}-db
# View metrics
flyctl metrics -a {project-name}
# SSH into application
flyctl ssh console -a {project-name}
Common Issues and Solutions:
-
Port Configuration Problems:
- Verify
fly.tomlinternal_port matches application PORT - Ensure HOST is set to "::" for IPv6 compatibility
- Check APP_URL matches deployed domain/URL
- Verify
-
Database Connection Failures:
- Verify DATABASE_URL format and credentials
- Check database is in same region as app
- Test connection via proxy:
flyctl proxy 5433 -a {project-name}-db - Review database logs:
flyctl logs -a {project-name}-db
-
Environment Variable Issues:
- Verify secrets are set:
flyctl secrets list -a {project-name} - Check production values in .env before encryption
- Ensure ENV_PASS is correct when decrypting
- Re-import secrets after changes:
flyctl secrets import
- Verify secrets are set:
-
Deployment Failures:
- Review build logs:
flyctl logs -a {project-name} - Check Dockerfile or buildpack configuration
- Verify all dependencies in package.json/requirements.txt
- Test build locally before deploying
- Increase build timeout if needed
- Review build logs:
-
Application Crashes:
- Check logs for error messages:
flyctl logs -a {project-name} - Verify health check endpoint is responding
- Review resource allocation (memory, CPU)
- Check for database connection issues
- SSH into container to debug:
flyctl ssh console -a {project-name}
- Check logs for error messages:
10. Scaling and Performance
Vertical Scaling (Resource Allocation):
# Scale VM resources
flyctl scale vm shared-cpu-1x --memory 512 -a {project-name}
# Available VM sizes:
# shared-cpu-1x (256MB, 512MB, 1GB, 2GB)
# dedicated-cpu-1x (2GB, 4GB, 8GB)
# dedicated-cpu-2x (4GB, 8GB, 16GB)
Horizontal Scaling (Machine Count):
# Scale number of machines
flyctl scale count 2 -a {project-name}
# Auto-scaling configuration in fly.toml:
[http_service]
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0 # Scale to zero when idle
Regional Deployment:
# Add machines in multiple regions
flyctl regions add iad lhr syd -a {project-name}
# View current regions
flyctl regions list -a {project-name}
# Remove regions
flyctl regions remove lhr -a {project-name}
11. Cost Optimization
Strategies for Reducing Costs:
- Auto-stop/Auto-start: Enable in fly.toml to scale to zero during idle periods
- Right-size Resources: Start with smallest VM size, scale up only if needed
- Database Optimization: Choose appropriate PostgreSQL tier, monitor usage
- Regional Strategy: Deploy only in regions with active users
- Monitoring: Set up billing alerts in Fly.io dashboard
Cost Monitoring:
# View current usage and costs
flyctl dashboard
# Check resource allocation
flyctl status -a {project-name}
flyctl status -a {project-name}-db
Supporting Files
This skill includes supporting templates:
- fly.toml.template: Basic Fly.io configuration template
- deployment-checklist.md: Pre-deployment verification checklist
- github-actions-workflow.yml: Sample CI/CD workflow
Access these via: .claude/skills/flyio-deployment/templates/
Common Deployment Patterns
Pattern 1: Initial Production Deployment
# 1. Setup and authenticate
flyctl auth login
# 2. Create database
flyctl postgres create # Use {project-name}-db
# 3. Launch application
flyctl launch # Don't deploy yet
# 4. Attach database
flyctl pg attach {project-name}-db -a {project-name}
# 5. Set secrets
flyctl secrets import -a {project-name} < .env
# 6. Deploy
flyctl deploy -a {project-name}
# 7. Verify
flyctl open -a {project-name}
flyctl logs -a {project-name}
Pattern 2: Database Migration
# Export from source
pg_dump -Fc --no-acl --no-owner -h {source-host} -U {user} -d {db} > migration.dump
# Proxy Fly.io database
flyctl proxy 5433 -a {project-name}-db # Separate terminal
# Import to Fly.io
pg_restore --verbose --clean --no-acl --no-owner \
-h localhost -p 5433 -U {user} -d {db} migration.dump
# Verify
flyctl ssh console -a {project-name}
# Inside container: run database query to verify data
Pattern 3: Rollback Deployment
# List recent releases
flyctl releases -a {project-name}
# Rollback to previous version
flyctl releases rollback -a {project-name}
# Or rollback to specific version
flyctl releases rollback {version-number} -a {project-name}
# Monitor rollback
flyctl logs -a {project-name}
Security Best Practices
- Environment Encryption: Always encrypt .env files before committing
- Database Access: Use database proxying instead of exposing publicly
- API Tokens: Store Fly.io API tokens in GitHub secrets, never in code
- SSL Certificates: Always enable force_https in fly.toml
- Database Backups: Implement automated backup strategy (S3, external storage)
- Secrets Rotation: Regularly rotate API tokens, database passwords, encryption keys
- Access Control: Use Fly.io organizations for team access management
- Network Security: Configure firewall rules, restrict database access
Validation Checklist
Before considering deployment complete:
- Application accessible via public URL
- Health check endpoint responding correctly
- Database connection working
- All environment variables set correctly
- SSL certificate issued and active
- Logs showing no errors
- CI/CD pipeline configured and tested
- Database backups configured
- Monitoring and alerting set up
- Documentation updated with deployment URLs and procedures
Real-World Gotchas (learned the hard way)
High-Risk Account Lock
Fly.io flags dormant accounts as "high risk". Creating apps/DBs fails with:
Your account has been marked as high risk. Please go to https://fly.io/high-risk-unlock
Fix: Must visit the URL in a browser logged into the Fly account. CLI cannot bypass this.
Auto-Stop Is Aggressive
With auto_stop_machines = "stop" and min_machines_running = 0, machines stop after ~60s idle. Some frameworks take 5-10s to cold boot. This means:
- First request after idle gets a slow response (wake + boot)
- Rapid sequential API calls may hit a stopped machine between calls
- Always hit
/_healthand wait for 204 before running batch operations
Fly Creates 2 Machines by Default
Even with min_machines_running = 0, fly deploy creates 2 machines for "HA". For dev/staging, destroy the second one:
fly status --app <app> # Find both machine IDs
fly machine stop <second-id> --app <app>
fly machine destroy <second-id> --app <app> --force
DATABASE_SSL Must Be False on Internal Network
fly postgres attach sets DATABASE_URL with sslmode=disable. If your app has a DATABASE_SSL env var, set it to false:
[env]
DATABASE_SSL = "false"
DNS + Cert Setup (Cloudflare)
When using Cloudflare for DNS:
- Records must be unproxied (
proxied=false) — Fly needs direct traffic for TLS termination - Check for stale records — old deployments may have left proxied A/AAAA records. Delete them first.
- ACME CNAME —
fly certs setupgives you a_acme-challengeCNAME target. Create/update it for Let's Encrypt validation. - Cert issuance is fast (~30s) once DNS is correct.
Deploy Flag: No --region
Use --primary-region or set primary_region in fly.toml. The flag --region does not exist on fly deploy.
Bash Token Piping Bug
Long API tokens (256+ chars) cause empty stdout when piped through bash variable expansion + curl. Workarounds:
- Store token in a file:
echo -n "TOKEN" > /tmp/.token && TK=$(cat /tmp/.token) - Use curl with
-o fileinstead of piping - Use Python
urllib.request(most reliable in sandbox environments)
Additional Resources
- Fly.io Official Documentation
- Fly.io CLI Reference
- Fly.io Pricing
- Fly.io Community Forum
- GitHub Actions Integration
Notes
- Always test deployments in staging environment before production
- Keep flyctl CLI updated:
flyctl version update - Monitor Fly.io status page for platform incidents
- Join Fly.io community for support and best practices
- Consider using Fly.io's managed PostgreSQL for production workloads
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/fellowship-dev/dogfooded-skills/fly-io">View fly-io on skillZs</a>