Fly.io Deployment¶
Deploy Django Keel projects globally with Fly.io's edge network.
Overview¶
Fly.io runs your application close to users worldwide with:
- Global edge deployment - Deploy to 30+ regions
- Automatic HTTPS - Free SSL certificates
- PostgreSQL included - Managed Postgres clusters
- Redis included - Managed Redis
- Free tier - Generous free allowance
- Near-instant deploys - Deploy in seconds
Prerequisites¶
- Fly.io account (free tier available)
- Fly CLI installed
flyioselected indeployment_targetsduring generation
What's Generated¶
A ready-to-use fly.toml at the project root, plus helper scripts in deploy/flyio/:
deploy.sh- deployment automationsetup_env.sh- interactive secrets setup (walks you throughfly secrets set)manage_db.sh- database management utilities
Installation¶
Install Fly CLI¶
# macOS
brew install flyctl
# Linux
curl -L https://fly.io/install.sh | sh
# Windows
powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"
Authenticate¶
Quick Start¶
1. Launch Application¶
From your project directory:
Django Keel already generated a fly.toml, so let fly launch reuse the existing configuration when prompted. Fly.io will:
- Prompt for app name and region
- Create PostgreSQL database (optional)
- Create Redis instance (optional)
2. Configure fly.toml¶
The generated fly.toml looks like this (Django Keel builds from the project's Dockerfile):
app = "your_project"
primary_region = "iad" # Washington D.C. - change as needed
[build]
[deploy]
release_command = "python manage.py migrate --noinput"
[env]
DJANGO_SETTINGS_MODULE = "config.settings.prod"
PORT = "8000"
[http_service]
internal_port = 8000
force_https = true
auto_stop_machines = "stop"
auto_start_machines = true
min_machines_running = 1
processes = ["app"]
[http_service.concurrency]
type = "connections"
hard_limit = 25
soft_limit = 20
[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
timeout = "5s"
path = "/health/"
[[vm]]
size = "shared-cpu-1x"
memory = "256mb"
[[statics]]
guest_path = "/app/staticfiles"
url_prefix = "/static/"
3. Set Secrets¶
The interactive deploy/flyio/setup_env.sh script can walk you through this. Manually:
# Required
fly secrets set DJANGO_SECRET_KEY=$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')
fly secrets set DEBUG=False
fly secrets set DJANGO_ALLOWED_HOSTS=your-app.fly.dev
# If using AWS S3
fly secrets set AWS_ACCESS_KEY_ID=your-key
fly secrets set AWS_SECRET_ACCESS_KEY=your-secret
fly secrets set AWS_STORAGE_BUCKET_NAME=your-bucket
# If using Sentry
fly secrets set SENTRY_DSN=your-sentry-dsn
# If using Stripe
fly secrets set STRIPE_LIVE_PUBLIC_KEY=pk_live_...
fly secrets set STRIPE_LIVE_SECRET_KEY=sk_live_...
fly secrets set STRIPE_LIVE_MODE=True
4. Deploy¶
Your app will be live at https://your-app.fly.dev
Database Setup¶
Create PostgreSQL¶
Options:
- Name: your-app-db
- Region: Same as your app
- Configuration: Development (1GB RAM, 10GB disk)
Attach Database¶
This sets the DATABASE_URL secret automatically.
Create Redis¶
Options: - Plan: Free (256MB) - Region: Same as your app
Attach Redis¶
This sets the REDIS_URL secret automatically.
Multi-Region Deployment¶
Deploy to multiple regions for low latency worldwide:
# Add regions
fly regions add ams # Amsterdam
fly regions add gru # São Paulo
fly regions add syd # Sydney
# Scale to 2 machines per region
fly scale count 2
Fly.io automatically routes users to the nearest region.
Adding Background Workers¶
Celery Worker and Beat¶
Add process groups to fly.toml so worker and beat machines run from the same image:
[processes]
app = "gunicorn config.wsgi:application --bind 0.0.0.0:8000"
worker = "celery -A config worker -l info"
beat = "celery -A config beat -l info"
Make sure [http_service] keeps processes = ["app"] so only web machines receive traffic, then:
Volumes for Persistent Storage¶
If not using S3:
# Create volume
fly volumes create data --size 10 # 10GB
# Update fly.toml
[[mounts]]
source = "data"
destination = "/data"
Update Django settings:
Custom Domains¶
Add Domain¶
Configure DNS¶
Add records to your DNS provider:
A @ 66.241.124.123 # Fly.io IP (check dashboard)
AAAA @ 2a09:8280:1::1 # IPv6
CNAME www your-app.fly.dev
Fly.io automatically provisions SSL certificates.
Monitoring¶
View Logs¶
Metrics¶
Monitoring Dashboard¶
Access at: https://fly.io/apps/your-app/monitoring
- Request rate
- Response time
- Error rate
- CPU/Memory usage
Scaling¶
Vertical Scaling¶
# List available VM sizes
fly platform vm-sizes
# Scale to shared-cpu-2x (2 CPU, 4GB RAM)
fly scale vm shared-cpu-2x
VM Sizes: - shared-cpu-1x: 1 CPU, 256MB RAM (free tier) - shared-cpu-2x: 2 CPU, 4GB RAM - dedicated-cpu-1x: 1 vCPU, 2GB RAM - dedicated-cpu-2x: 2 vCPU, 4GB RAM
Horizontal Scaling¶
# Scale to 3 instances
fly scale count 3
# Scale per region
fly scale count 2 --region sjc
fly scale count 2 --region ams
Auto Start/Stop¶
The generated fly.toml uses Fly's machine auto start/stop:
Machines stop when idle and start on incoming traffic. Raise min_machines_running to keep more machines warm.
Health Checks¶
Fly.io uses your /health/ endpoint (already configured in the generated fly.toml):
[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
timeout = "5s"
path = "/health/"
Django Keel provides this endpoint by default.
Zero-Downtime Deployments¶
Fly.io handles this automatically:
- Deploys new version
- Waits for health checks to pass
- Routes traffic to new version
- Terminates old version
Troubleshooting¶
Build Fails¶
Error: "No Dockerfile found"
Error: "requirements.txt not found"
Database Connection¶
Error: "could not connect to database"
# Check DATABASE_URL is set
fly secrets list | grep DATABASE
# Test connection
fly ssh console
python manage.py dbshell
Memory Issues¶
Error: "OOMKilled"
SSL Certificate Issues¶
Error: "certificate verification failed"
# Check certificate status
fly certs show yourdomain.com
# Recreate certificate
fly certs remove yourdomain.com
fly certs create yourdomain.com
Cost Optimization¶
Free Tier Limits¶
- 3 shared-cpu-1x VMs (256MB RAM each)
- 3GB PostgreSQL storage
- 160GB outbound transfer
- Free HTTPS certificates
Tips¶
- Use shared-cpu for dev/staging
- Auto-scale down during low traffic
- Optimize images - Reduce Docker image size
- Use volumes instead of S3 for small files
- Monitor usage - Set billing alerts
Production Checklist¶
- [ ] Set
DEBUG=False - [ ] Configure
ALLOWED_HOSTSwith your domain - [ ] Set strong
DJANGO_SECRET_KEY - [ ] Enable Sentry for error tracking
- [ ] Set up database backups
- [ ] Configure custom domain with SSL
- [ ] Test Celery workers (if using)
- [ ] Configure auto-scaling
- [ ] Set up monitoring alerts
- [ ] Enable database replication for critical apps
Comparison with Other Platforms¶
| Feature | Fly.io | Render | Heroku |
|---|---|---|---|
| Regions | 30+ | 7 | 2 (US/EU) |
| Free Tier | 3 VMs, 3GB DB | 750 hrs/month | No free tier |
| Auto-scaling | ✅ Yes | ✅ Yes | ✅ Yes |
| SSL | ✅ Free | ✅ Free | ✅ Free |
| Pricing | $1.94+/month | $7+/month | $5-$25+/month |
Best Practices¶
- Deploy to multiple regions - Low latency worldwide
- Use volumes for persistent data (if not using S3)
- Monitor health checks - Ensure endpoints respond
- Enable auto-scaling - Handle traffic spikes
- Regular backups - Snapshot PostgreSQL regularly
- Use Fly CLI - Faster than web dashboard
- Keep fly.toml in version control
Further Reading¶
Support¶
- Community Forum: community.fly.io
- Status: status.fly.io