Skip to content

Fly.io Deployment

Deploy Navigator on Fly.io with machine suspension, regional distribution, and intelligent routing features.

Quick Start

# 1. Install flyctl
curl -L https://fly.io/install.sh | sh

# 2. Login and create app
flyctl auth login
flyctl apps create myapp

# 3. Deploy Navigator
flyctl deploy

Dockerfile

Navigator works excellently with Fly.io's machine architecture:

Dockerfile
FROM ruby:3.2-slim

# Copy Navigator binary from Docker Hub image
COPY --from=samruby/navigator:latest /navigator /usr/local/bin/navigator
RUN chmod +x /usr/local/bin/navigator

# Install system dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    npm \
    && rm -rf /var/lib/apt/lists/*

# Set up Rails application
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

# Precompile assets
RUN bundle exec rails assets:precompile

# Navigator configuration
COPY config/navigator-fly.yml /app/navigator.yml

EXPOSE 3000

# Start Navigator
CMD ["navigator", "/app/navigator.yml"]

Fly.io Configuration

Basic fly.toml

fly.toml
app = "myapp"
primary_region = "ord"

[build]
  dockerfile = "Dockerfile"

[env]
  RAILS_ENV = "production"
  RAILS_SERVE_STATIC_FILES = "false"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0

  [http_service.checks.alive]
    path = "/up"
    interval = "30s"
    timeout = "5s"

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 512

Production fly.toml

fly.toml
app = "myapp-production"
primary_region = "ord"

[build]
  dockerfile = "Dockerfile"

[env]
  RAILS_ENV = "production"
  RAILS_SERVE_STATIC_FILES = "false"
  LOG_LEVEL = "info"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1  # Keep at least one machine running

  [http_service.checks.alive]
    path = "/up"
    interval = "30s"
    timeout = "5s"
    grace_period = "10s"

  [http_service.checks.readiness]
    path = "/up"
    interval = "30s"
    timeout = "5s"

[[vm]]
  cpu_kind = "shared"
  cpus = 2
  memory_mb = 1024

[machines]
  auto_start = true
  auto_stop = true
  min_machines_running = 1

# Multi-region deployment
[[regions]]
  name = "ord"  # Chicago

[[regions]]  
  name = "fra"  # Frankfurt

[[regions]]
  name = "nrt"  # Tokyo

Basic Navigator Config

config/navigator-fly.yml
server:
  listen: 3000
  public_dir: /app/public

pools:
  max_size: 10
  idle_timeout: 300
  start_port: 4000

# Machine suspension
suspend:
  enabled: true
  idle_timeout: 600        # 10 minutes

applications:
  global_env:
    RAILS_ENV: production
    RAILS_SERVE_STATIC_FILES: "false"
    DATABASE_URL: "${DATABASE_URL}"
    SECRET_KEY_BASE: "${SECRET_KEY_BASE}"

  tenants:
    - name: production
      path: /
      working_dir: /app

Multi-Region Navigator Config

config/navigator-fly.yml
server:
  listen: 3000
  public_dir: /app/public

pools:
  max_size: 15
  idle_timeout: 600        # Longer timeout for production

# Aggressive suspension for cost optimization
suspend:
  enabled: true
  idle_timeout: 900        # 15 minutes
  check_interval: 60

# Fly-Replay routing for optimal performance
routes:
  fly_replay:
    # Route PDF generation to specific region
    - path: "^/api/pdf/"
      region: ord
      status: 307

    # Route European users to Frankfurt
    - path: "^/eu/"
      region: fra
      status: 307

    # Route Asian users to Tokyo  
    - path: "^/asia/"
      region: nrt
      status: 307

applications:
  global_env:
    RAILS_ENV: production
    DATABASE_URL: "${DATABASE_URL}"
    SECRET_KEY_BASE: "${SECRET_KEY_BASE}"
    REDIS_URL: "${REDIS_URL}"

  tenants:
    - name: production
      path: /
      working_dir: /app

Environment Variables

Required Secrets

# Set via flyctl
flyctl secrets set SECRET_KEY_BASE="your-rails-secret-key"
flyctl secrets set DATABASE_URL="postgresql://user:pass@host/db"

# Optional
flyctl secrets set REDIS_URL="redis://host:port"
flyctl secrets set NEW_RELIC_LICENSE_KEY="your-key"

Fly.io-Specific Variables

# Set automatically by Fly.io
FLY_APP_NAME="myapp"
FLY_REGION="ord"
FLY_MACHINE_ID="unique-machine-id"

# Optional for machine control
flyctl secrets set FLY_API_TOKEN="your-fly-api-token"

Database Setup

PostgreSQL on Fly.io

# Create Fly PostgreSQL
flyctl postgres create myapp-db

# Connect to your app
flyctl postgres attach myapp-db

# This sets DATABASE_URL automatically

External Database

# For external PostgreSQL
flyctl secrets set DATABASE_URL="postgresql://user:pass@external-db.com/myapp_production"

Redis Setup

Redis on Fly.io

# Create Fly Redis
flyctl redis create myapp-redis

# Connect to your app  
flyctl redis connect myapp-redis

# This sets REDIS_URL automatically

Deployment Commands

Initial Deployment

# Deploy to Fly.io
flyctl deploy

# Monitor deployment
flyctl logs

# Check app status
flyctl status

Updates and Scaling

# Deploy updates
flyctl deploy

# Scale machines
flyctl scale count 3

# Scale to specific regions
flyctl scale count 2 --region ord
flyctl scale count 1 --region fra

# Update machine size
flyctl scale vm shared-cpu-2x --memory 1024

Machine Management

Machine Suspension

Navigator integrates seamlessly with Fly.io's machine suspension:

# Enable in Navigator config
suspend:
  enabled: true
  idle_timeout: 600

# Allow in Fly.io config  
[machines]
  auto_stop = true
  min_machines_running = 0

Benefits: - Machines suspend automatically during idle periods - Wake in 1-3 seconds on incoming requests
- Significant cost savings for variable traffic

Multi-Machine Deployment

# Deploy to multiple machines
flyctl deploy --ha=false  # Single machine per region

# Or enable high availability  
flyctl scale count 2      # Multiple machines for redundancy

Regional Distribution

Geographic Routing

Navigator configuration
routes:
  fly_replay:
    # North America -> Chicago
    - path: "^/na/"
      region: ord
      status: 307

    # Europe -> Frankfurt  
    - path: "^/eu/"
      region: fra
      status: 307

    # Asia Pacific -> Tokyo
    - path: "^/apac/"
      region: nrt
      status: 307

Regional Deployment

# Deploy to multiple regions
flyctl regions add ord fra nrt

# Check regional status
flyctl regions list

# Scale by region
flyctl scale count 2 --region ord  # Primary region
flyctl scale count 1 --region fra  # Secondary regions  
flyctl scale count 1 --region nrt

Monitoring

Fly.io Monitoring

# View logs
flyctl logs

# Monitor performance
flyctl metrics

# Check machine status
flyctl machine list

# SSH into machine
flyctl ssh console
# Check Navigator processes
flyctl ssh console -C "ps aux | grep navigator"

# View Navigator logs
flyctl ssh console -C "journalctl -u navigator -n 50"

# Check Rails processes
flyctl ssh console -C "ps aux | grep rails"

Performance Optimization

Machine Sizing

# Development
[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 512

# Production
[[vm]]  
  cpu_kind = "shared"
  cpus = 2
  memory_mb = 1024

# High-performance
[[vm]]
  cpu_kind = "performance"
  cpus = 4
  memory_mb = 2048

Process Pool Tuning

# Adjust for machine size
pools:
  max_size: 8      # 512MB machine
  # max_size: 15   # 1GB machine  
  # max_size: 25   # 2GB machine
  idle_timeout: 600

Cost Optimization

Machine Suspension Strategy

# Aggressive suspension (development)
suspend:
  enabled: true
  idle_timeout: 180     # 3 minutes

# Balanced suspension (staging)  
suspend:
  enabled: true
  idle_timeout: 600     # 10 minutes

# Conservative suspension (production)
suspend:
  enabled: true
  idle_timeout: 1800    # 30 minutes

Regional Cost Management

# Use cheaper regions for development
flyctl regions add ord  # Chicago (cheaper)
flyctl regions remove sjc  # San Jose (more expensive)

# Monitor costs
flyctl dashboard

Troubleshooting

Deployment Issues

# Check deployment status
flyctl status

# View deployment logs
flyctl logs

# Debug specific machine
flyctl machine list
flyctl logs --instance machine-id

Machine Won't Start

# Check machine status
flyctl machine list

# Start machine manually
flyctl machine start machine-id

# Check machine configuration
flyctl machine show machine-id

Rails App Issues

# SSH into machine
flyctl ssh console

# Check Navigator status
ps aux | grep navigator

# Check Rails processes  
ps aux | grep rails

# View Navigator logs
journalctl -u navigator -f

Suspension Issues

# Check suspension configuration
flyctl ssh console -C "cat /app/navigator.yml | grep -A5 suspend"

# Monitor suspension activity
flyctl logs | grep -E "(suspend|idle|activity)"

# Check machine auto-stop settings
flyctl config show | grep auto_stop

Advanced Configuration

Custom Health Checks

fly.toml
[http_service.checks.navigator]
  path = "/up"
  interval = "30s" 
  timeout = "5s"
  method = "GET"
  headers = {X-Health-Check = "fly"}

Volume Mounts

fly.toml
[[mounts]]
  source = "myapp_data"
  destination = "/data"

# Create volume
# flyctl volumes create myapp_data --size 10

Custom Entrypoint

# Custom startup script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["navigator", "/app/navigator.yml"]
docker-entrypoint.sh
#!/bin/bash
set -e

# Database migrations
bundle exec rails db:migrate

# Start Navigator
exec "$@"

Integration Examples

CI/CD with GitHub Actions

.github/workflows/deploy.yml
name: Deploy to Fly.io

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: superfly/flyctl-actions/setup-flyctl@master

      - name: Deploy to Fly.io
        run: flyctl deploy --remote-only
        env:
          FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

Multi-Environment Setup

# Production
flyctl apps create myapp-prod
flyctl deploy --app myapp-prod

# Staging
flyctl apps create myapp-staging  
flyctl deploy --app myapp-staging

Best Practices

1. Use Machine Suspension

suspend:
  enabled: true
  idle_timeout: 600    # Adjust based on traffic patterns

2. Optimize for Regions

# Deploy close to users
flyctl regions add ord fra nrt  # Major regions
flyctl regions remove unused-regions

3. Right-Size Machines

# Start small, scale as needed
flyctl scale vm shared-cpu-1x --memory 512  # Start here
flyctl scale vm shared-cpu-2x --memory 1024 # Scale up

4. Monitor Costs

# Regular cost monitoring
flyctl dashboard
flyctl usage --app myapp

5. Security

# Use secrets for sensitive data
flyctl secrets set SECRET_KEY_BASE="..."
flyctl secrets set DATABASE_PASSWORD="..."

# Never hardcode secrets in fly.toml

See Also