This content originally appeared on DEV Community and was authored by Quinterabok
Complete Fly.io Deployment Guide for Rails App
A beginner-friendly, step-by-step guide to deploying Ruby on Rails applications to Fly.io with Supabase database, custom domain, and email setup.
Table of Contents
- Prerequisites
- Part 1: Install Fly CLI
- Part 2: Set Up Supabase Database
- Part 3: Deploy to Fly.io (Testing)
- Part 4: Create Admin User
- Part 5: Deploy to Production
- Part 6: Buy and Connect Domain
- Part 7: Set Up Email Forwarding
- Part 8: Managing Your App
- Troubleshooting
Prerequisites
Before starting, ensure you have:
A Rails application ready to deploy
Git installed and your code committed
AWS S3 bucket set up for file storage (or similar)
Terminal/Command line access
Credit/debit card for domain purchase (~$10/year)
Cost Estimate:
- Fly.io hosting: $5-10/month
- Supabase database: FREE
- Domain name: ~$10/year
- Email: FREE (forwarding)
- Total: ~$70-130/year
Part 1: Install Fly CLI
Step 1: Install Fly.io Command Line Tool
For macOS/Linux:
curl -L https://fly.io/install.sh | sh
For Windows (PowerShell):
powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"
Step 2: Sign Up / Login
# Sign up for new account
fly auth signup
# Or login if you have an account
fly auth login
Follow the browser prompts to complete authentication.
Step 3: Verify Installation
fly version
You should see the Fly CLI version number.
Part 2: Set Up Supabase Database
Why Supabase?
FREE tier (500MB database)
Automatic backups
Great dashboard
Saves $38/month vs Fly Postgres
Step 1: Create Supabase Account
- Go to: https://supabase.com
- Click “Start your project”
- Sign up with GitHub, Google, or Email
Step 2: Create Organization (First Time)
- Enter organization name (e.g., “My Company”)
- Click “Create organization”
Step 3: Create New Project
Fill in the form:
-
Name:
your-app-name-prod
(e.g., name-website-prod) -
Database Password: Click refresh icon to generate
- IMPORTANT: Copy and save this password!
- Example:
Kx9mP#vL2nQ8wR5t
-
Region: Choose closest to your users
- Southeast Asia (Singapore)
- West EU (Ireland)
- East US (North Virginia)
- Pricing Plan: FREE (already selected)
Click “Create new project” and wait 1-2 minutes.
Step 4: Get Database Connection String
- Click
Settings (left sidebar)
- Click “Database”
- Scroll to “Connection string”
- Click “URI” tab
- Copy the connection string
- Replace
[YOUR-PASSWORD]
with your actual password from Step 3
Example final URL:
postgresql://postgres.abcdefghijklmno:Kx9mP#vL2nQ8wR5t@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres
Save this URL – you’ll need it soon!
Part 3: Deploy to Fly.io (Testing)
Step 1: Navigate to Your Project
cd /path/to/your-rails-app
Step 2: Initialize Fly.io App
fly launch --no-deploy
You’ll be asked several questions:
Question 1: Copy existing fly.toml?
Answer: N
(No) – Start fresh
Question 2: App name
Enter: your-app-test
(e.g., name-website-test)
Question 3: Organization
Select: Personal (or your organization)
Question 4: Region
Select: Closest to you or your users (e.g., sin
for Singapore)
Question 5: Tweak settings?
Answer: Y
(Yes)
Step 3: Configure Settings in Browser
A browser window opens with configuration form:
Fill in:
-
App name:
your-app-test
(already filled) - Organization: Personal (already selected)
- Region: Keep your selection
-
Internal port:
8080
-
VM Memory:
2GB
(select from dropdown) -
Postgres Provider: Select
none
(we’re using Supabase) -
Tigris Object Storage: Select
Disabled
(using S3) -
Redis: Keep
none
-
Sentry: Keep
Disabled
Click “Confirm Settings”
Step 4: Set Environment Secrets
Back in your terminal, set your secrets:
Generate SECRET_KEY_BASE:
rails secret
Copy the output.
Set Database URL (from Supabase):
fly secrets set DATABASE_URL="postgresql://postgres.abc:yourpassword@aws-0-region.pooler.supabase.com:6543/postgres" --app your-app-test
Set Rails Secret:
fly secrets set SECRET_KEY_BASE="paste-secret-from-rails-secret-command" --app your-app-test
Set AWS S3 Credentials (if using S3):
fly secrets set AWS_ACCESS_KEY_ID="your-aws-key" --app your-app-test
fly secrets set AWS_SECRET_ACCESS_KEY="your-aws-secret" --app your-app-test
fly secrets set AWS_REGION="your-region" --app your-app-test
fly secrets set BUCKET_NAME="your-bucket-name" --app your-app-test
fly secrets set AWS_ENDPOINT_URL_S3="your-s3-endpoint" --app your-app-test
Verify All Secrets:
fly secrets list --app your-app-test
You should see all your secrets listed (shows digests, not actual values).
Step 5: Update fly.toml Configuration
Open fly.toml
in your editor and ensure it looks like this:
app = 'your-app-test'
primary_region = 'sin'
console_command = '/rails/bin/rails console'
[build]
[env]
PORT = '8080'
RAILS_ENV = 'production'
RAILS_LOG_TO_STDOUT = 'true'
[processes]
app = './bin/rake litestream:run ./bin/rails server'
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[http_service.checks]]
interval = '10s'
timeout = '2s'
grace_period = '5s'
method = 'GET'
path = '/up'
protocol = 'http'
tls_skip_verify = false
[http_service.checks.headers]
X-Forwarded-Proto = 'https'
[[vm]]
memory = '2gb'
cpu_kind = 'shared'
cpus = 1
Step 6: Deploy Your App
fly deploy --app your-app-test
Wait 3-5 minutes for the build and deployment to complete.
Watch logs in another terminal:
fly logs --app your-app-test
Step 7: Run Database Migrations
fly ssh console --app your-app-test -C "rails db:migrate"
Step 8: Test Your App
fly open --app your-app-test
Your app opens at: https://your-app-test.fly.dev
Test Environment is Live!
Part 4: Create Admin User
Step 1: SSH into Your App
fly ssh console --app your-app-test
Step 2: Start Rails Console
./bin/rails console
Or:
bundle exec rails console
Step 3: Create Admin
Admin.create!(
email: 'admin@example.com',
password: 'TestPassword123!',
password_confirmation: 'TestPassword123!'
)
Note: Replace Admin
with User
if your model is called User. Adjust fields based on your model.
Step 4: Verify Admin Created
Admin.last
Should show your newly created admin.
Step 5: Exit
exit # Exit Rails console
exit # Exit SSH
Alternative: One-Line Command
From your local terminal:
fly ssh console --app your-app-test -C "./bin/rails runner \"Admin.create!(email: 'admin@example.com', password: 'TestPassword123!', password_confirmation: 'TestPassword123!')\""
Step 6: Test Admin Login
- Visit your app:
https://your-app-test.fly.dev/admin
- Login with credentials you just created
- Verify everything works
Part 5: Deploy to Production
Now that testing works, let’s create a production environment.
Step 1: Create Production App
fly launch --no-deploy
Configuration:
- App name:
your-app-prod
- Region: Same as test or closer to users
- Tweak settings:
Y
(Yes)
Step 2: Configure Production Settings
In the browser form:
-
App name:
your-app-prod
- Region: Choose production region
-
Internal port:
8080
-
VM Memory:
2GB
(more for production) -
Postgres:
none
(using Supabase) -
Tigris:
Disabled
Click “Confirm Settings”
Step 3: Create Production Supabase Database
Option A: Use Same Database
- Use the same Supabase database for production
- Good for small projects
- Cost: FREE
Option B: Create Separate Database (Recommended)
- Go to Supabase dashboard
- Create new project:
your-app-prod
- Get new DATABASE_URL
- Keep test and production data separate
Step 4: Set Production Secrets
# Generate NEW secret for production
rails secret
# Set database URL
fly secrets set DATABASE_URL="your-production-supabase-url" --app your-app-prod
# Set NEW secret key base
fly secrets set SECRET_KEY_BASE="new-secret-from-rails-secret" --app your-app-prod
# Copy AWS credentials (or use different production bucket)
fly secrets set AWS_ACCESS_KEY_ID="your-aws-key" --app your-app-prod
fly secrets set AWS_SECRET_ACCESS_KEY="your-aws-secret" --app your-app-prod
fly secrets set AWS_REGION="your-region" --app your-app-prod
fly secrets set BUCKET_NAME="your-production-bucket" --app your-app-prod
fly secrets set AWS_ENDPOINT_URL_S3="your-s3-endpoint" --app your-app-prod
# Verify
fly secrets list --app your-app-prod
Step 5: Update Production fly.toml
Open fly.toml
and update:
app = 'your-app-prod'
primary_region = 'sin'
[env]
PORT = '8080'
RAILS_ENV = 'production'
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = 'suspend'
auto_start_machines = true
min_machines_running = 1 # Keep 1 always running in production
[[vm]]
memory = '2gb'
cpu_kind = 'shared'
cpus = 2 # More CPU for production
Step 6: Deploy Production
fly deploy --app your-app-prod
Wait for deployment to complete.
Step 7: Run Migrations
fly ssh console --app your-app-prod -C "rails db:migrate"
Step 8: Create Production Admin
fly ssh console --app your-app-prod -C "./bin/rails runner \"Admin.create!(email: 'admin@yourdomain.com', password: 'StrongProductionPassword123!', password_confirmation: 'StrongProductionPassword123!')\""
Save these credentials securely!
Step 9: Test Production App
fly open --app your-app-prod
Visit: https://your-app-prod.fly.dev
Production is Live!
Part 6: Buy and Connect Domain
Step 1: Buy Domain from Namecheap
Why Namecheap?
Cheapest overall (~$10/year)
FREE privacy protection forever
FREE email forwarding
Easy DNS management
Great support
Purchase Process:
- Go to: https://www.namecheap.com
- Search for your desired domain
- Add to cart
- At checkout:
Check: WhoisGuard (Privacy Protection) – FREE
Uncheck: PremiumDNS
Uncheck: Email hosting
Uncheck: Website builder
Uncheck: SSL certificate
- Complete purchase (~$10-13)
Step 2: Get Fly.io IP Addresses
# Get your production app's IPs
fly ips list --app your-app-prod
Output shows:
VERSION IP TYPE REGION
v4 66.241.125.202 public global
v6 2a09:8280:1::a0:a7a4:0 public global
Copy both IPs – you’ll need them next!
Step 3: Add Domain to Fly.io
# Add main domain
fly certs add yourdomain.com --app your-app-prod
# Add www subdomain
fly certs add www.yourdomain.com --app your-app-prod
Example:
fly certs add name.com --app name-website-prod
fly certs add www.noblmed.com --app name-website-prod
Step 4: Configure DNS in Namecheap
Login to Namecheap:
- Go to: https://www.namecheap.com
- Click “Sign In”
- Enter credentials
Go to Domain Management:
- Click “Domain List” (left sidebar)
- Find your domain
- Click “Manage” button
Open Advanced DNS:
- Click “Advanced DNS” tab
Delete Old Records:
Look for and DELETE any existing:
- A Records with @ or blank host
- CNAME Records with @ or blank host
- Parking page records
Add New DNS Records:
Record 1 – A Record (IPv4):
Type: A Record
Host: @
Value: 66.241.125.202 (your IPv4 from Step 2)
TTL: Automatic
Click to save.
Record 2 – AAAA Record (IPv6):
Type: AAAA Record
Host: @
Value: 2a09:8280:1::a0:a7a4:0 (your IPv6 from Step 2)
TTL: Automatic
Click to save.
Record 3 – CNAME Record (WWW):
Type: CNAME Record
Host: www
Target: your-app-prod.fly.dev. (note the dot at end!)
TTL: Automatic
Click to save.
Save All Changes:
Scroll to bottom and click “SAVE ALL CHANGES”
Step 5: Wait for DNS Propagation
Wait 10-30 minutes for DNS changes to spread worldwide.
Check DNS Status:
# Check main domain
dig yourdomain.com
# Check www subdomain
dig www.yourdomain.com
Or check online: https://www.whatsmydns.net/
Step 6: Verify SSL Certificates
After 15-20 minutes:
# Check main domain certificate
fly certs show yourdomain.com --app your-app-prod
# Check www certificate
fly certs show www.yourdomain.com --app your-app-prod
When ready, you’ll see:
The certificate for yourdomain.com has been issued.
Status: Ready ✅
Step 7: Test Your Domain
Open browser and visit:
Both should:
Load your website
Show
padlock (secure HTTPS)
Work perfectly!
Your Custom Domain is Live!
Part 7: Set Up Email Forwarding
Step 1: Enable Email Forwarding
In Namecheap (still on your domain’s management page):
- Look for “Mail Settings” or “Email Forwarding” section
- Click “Add Forwarder” or “Enable Email Forwarding”
Step 2: Add Email Forwards
Create forwarding rules:
Example forwards:
How to add each:
- Click “Add Forwarder”
-
Alias: Enter
admin
(without @domain) - Forward to: Enter your Gmail
- Click “Add” or
- Repeat for other addresses
Step 3: Save Email Settings
Click “Save Changes”
Step 4: Test Email Forwarding
- Send test email to: admin@yourdomain.com
- Check your Gmail inbox
- Should receive within 1-2 minutes
Step 5: Set Up Gmail “Send As” (Optional)
To reply from admin@yourdomain.com:
- Open Gmail
- Click
Settings → “See all settings”
- Click “Accounts and Import” tab
- Find “Send mail as:”
- Click “Add another email address”
- Enter:
- Name: Your Name / Company
- Email: admin@yourdomain.com
- Uncheck “Treat as an alias”
- Click “Next Step”
- For SMTP, you need paid email service (Google Workspace, Zoho, etc.)
Note: Free forwarding only receives emails. To send, you need:
- Google Workspace ($6/month)
- Zoho Mail (free for up to 5 users)
- Or reply from your Gmail (recipient sees Gmail address)
Part 8: Managing Your App
View App Status
# Check if app is running
fly status --app your-app-prod
# List all machines
fly machine list --app your-app-prod
# View recent logs
fly logs --app your-app-prod
Stop App (When Not in Use)
To save costs when not needed:
# Stop all machines
fly scale count 0 --app your-app-prod
What happens:
App stops completely
No compute charges (only storage)
Visitors see “503 Service Unavailable”
Database and files remain safe
Start App Again
# Start 1 machine
fly scale count 1 --app your-app-prod
What happens:
App starts in 10-30 seconds
Website works normally
Everything restored
Auto-Stop Configuration
Edit fly.toml
to automatically stop when idle:
[http_service]
auto_stop_machines = 'stop' # Auto-stop when no traffic
auto_start_machines = true # Auto-start when visitor arrives
min_machines_running = 0 # Allow stopping completely
Benefits:
Automatically stops after 5 minutes of no traffic
Automatically starts when someone visits
Saves money on low-traffic sites
First visitor waits ~10 seconds for startup
For always-on production:
[http_service]
auto_stop_machines = false
auto_start_machines = true
min_machines_running = 1 # Always keep 1 running
Restart App
fly apps restart your-app-prod
View Dashboard
fly dashboard --app your-app-prod
Opens web dashboard in browser.
SSH into App
fly ssh console --app your-app-prod
Run Rails Console
fly ssh console --app your-app-prod -C "./bin/rails console"
Update App
After making code changes:
# Commit changes to git
git add .
git commit -m "Your changes"
# Deploy update
fly deploy --app your-app-prod
# Watch deployment
fly logs --app your-app-prod
Scale Resources
# Add more memory
fly scale memory 4096 --app your-app-prod
# Add more machines
fly scale count 2 --app your-app-prod
# Change VM type
fly scale vm shared-cpu-2x --app your-app-prod
View Costs
fly orgs show
Shows your current usage and estimated costs.
Troubleshooting
Issue: “Database connection failed”
Solution:
# Verify DATABASE_URL is set
fly secrets list --app your-app-prod
# Re-set if needed
fly secrets set DATABASE_URL="your-correct-url" --app your-app-prod
# Restart app
fly apps restart your-app-prod
Issue: “DNS not resolving”
Solution:
- Check DNS records in Namecheap
- Verify IPs match:
fly ips list --app your-app-prod
- Wait 30 more minutes for propagation
- Clear browser cache or try incognito
Issue: “SSL certificate not issued”
Solution:
# Check certificate status
fly certs show yourdomain.com --app your-app-prod
# If stuck, remove and re-add
fly certs remove yourdomain.com --app your-app-prod
fly certs add yourdomain.com --app your-app-prod
# Wait 15 minutes
Issue: “App not starting”
Solution:
# Check logs for errors
fly logs --app your-app-prod
# Common issues:
# - Missing SECRET_KEY_BASE
# - Wrong DATABASE_URL
# - Port configuration (should be 8080)
# Verify secrets
fly secrets list --app your-app-prod
# Check fly.toml port settings
cat fly.toml | grep port
Issue: “Can’t create admin”
Solution:
# SSH into app
fly ssh console --app your-app-prod
# Check your model name
./bin/rails runner "puts User.column_names"
# or
./bin/rails runner "puts Admin.column_names"
# Create with correct fields
./bin/rails console
Admin.create!(email: 'test@example.com', password: 'password123', password_confirmation: 'password123')
Issue: “File uploads not working”
Solution:
# Verify S3 credentials are set
fly secrets list --app your-app-prod
# Should see:
# - AWS_ACCESS_KEY_ID
# - AWS_SECRET_ACCESS_KEY
# - AWS_REGION
# - BUCKET_NAME
# - AWS_ENDPOINT_URL_S3
# Test S3 connection in Rails console
fly ssh console --app your-app-prod -C "./bin/rails console"
# Then test upload
Issue: “Out of memory errors”
Solution:
# Check current memory
fly status --app your-app-prod
# Increase memory
fly scale memory 4096 --app your-app-prod
# Or reduce memory if overprovisioned
fly scale memory 1024 --app your-app-prod
Issue: “Emails not forwarding”
Solution:
- Check Namecheap email forwarding settings
- Verify Gmail isn’t marking as spam
- Wait 30 minutes for DNS changes
- Test with different email provider
Get Help
# Fly.io community forum
# https://community.fly.io
# Fly.io documentation
# https://fly.io/docs
# View all Fly commands
fly help
# Get help for specific command
fly help deploy
Quick Command Reference
Deployment
# Initialize app
fly launch --no-deploy
# Deploy app
fly deploy --app your-app-name
# Deploy with specific fly.toml
fly deploy --app your-app-name --config fly.toml
App Management
# View status
fly status --app your-app-name
# View logs
fly logs --app your-app-name
# Restart app
fly apps restart your-app-name
# Stop app
fly scale count 0 --app your-app-name
# Start app
fly scale count 1 --app your-app-name
# Open app in browser
fly open --app your-app-name
SSH & Console
# SSH into app
fly ssh console --app your-app-name
# Run Rails console
fly ssh console --app your-app-name -C "./bin/rails console"
# Run one-off command
fly ssh console --app your-app-name -C "rails db:migrate"
Secrets
# List secrets
fly secrets list --app your-app-name
# Set secret
fly secrets set KEY="value" --app your-app-name
# Unset secret
fly secrets unset KEY --app your-app-name
Domain & SSL
# Add domain
fly certs add yourdomain.com --app your-app-name
# Check certificate
fly certs show yourdomain.com --app your-app-name
# List all certificates
fly certs list --app your-app-name
# Remove certificate
fly certs remove yourdomain.com --app your-app-name
Scaling
# Scale number of machines
fly scale count 2 --app your-app-name
# Scale memory
fly scale memory 2048 --app your-app-name
# Change VM type
fly scale vm shared-cpu-2x --app your-app-name
Database
# Run migrations
fly ssh console --app your-app-name -C "rails db:migrate"
# Create database
fly ssh console --app your-app-name -C "rails db:create"
# Seed database
fly ssh console --app your-app-name -C "rails db:seed"
# Reset database (CAREFUL!)
fly ssh console --app your-app-name -C "rails db:reset"
Cost Breakdown
Monthly Costs
Service | Cost | Notes |
---|---|---|
Fly.io Compute | $5-10/month | Depends on usage |
Supabase Database | FREE | Up to 500MB |
AWS S3 Storage | $1-5/month | Depends on files |
Domain Name | ~$1/month | $10-13/year |
Email Forwarding | FREE | Via Namecheap |
SSL Certificates | FREE | Via Let’s Encrypt |
Total | $7-16/month | $84-192/year |
Ways to Save
- Use auto-stop: App stops when not in use
- Use free tier Supabase: Instead of paid Postgres
- Share S3 bucket: Use same bucket for test/prod
- Buy domain for multiple years: Slight discount
- Use email forwarding: Instead of Google Workspace
Next Steps
After completing this guide, you can:
- Add monitoring: Set up Sentry or error tracking
- Add analytics: Google Analytics, Plausible, etc.
- Set up CI/CD: GitHub Actions for auto-deploy
- Add custom email: Google Workspace or Zoho
- Scale up: Add more machines, memory, regions
- Add CDN: Cloudflare for better performance
- Set up backups: Automate database backups
- Add staging: Create staging environment
Summary
You’ve learned how to:
Install Fly CLI and set up account
Create FREE Supabase database
Deploy Rails app to Fly.io (test and production)
Create admin users
Buy and connect custom domain
Set up FREE email forwarding
Manage, stop, and start your app
Troubleshoot common issues
Your app is now live with:
- Custom domain with SSL
- Professional email addresses
- Free database
- Scalable hosting
- All for ~$7-16/month!
Congratulations!
Support & Resources
- Fly.io Docs: https://fly.io/docs
- Fly.io Community: https://community.fly.io
- Supabase Docs: https://supabase.com/docs
- Namecheap Support: https://www.namecheap.com/support
- Rails Guides: https://guides.rubyonrails.org
Made with for beginners
This content originally appeared on DEV Community and was authored by Quinterabok