FL

Fly.io

infrastructure vLatest

Fly.io

Version: Latest

Overview

Fly.io is the deployment platform for the Prismatic Platform's production and staging environments. It provides globally distributed application hosting with automatic TLS, private networking, and native support for BEAM clustering -- enabling the platform to run distributed Elixir nodes across multiple regions with transparent inter-node communication. Fly.io was selected specifically for its first-class Elixir and BEAM support, which eliminates the infrastructure complexity that other platforms require for distributed Erlang clustering.

The Prismatic Platform runs on Fly.io at prismatic-prod.fly.dev (production) and prismatic-staging.fly.dev (staging). Fly's support for BEAM distribution means the platform's Erlang/OTP applications can form clusters across regions, sharing agent state and real-time events through Distributed Erlang with zero additional infrastructure. This is a significant architectural advantage: features like Phoenix PubSub broadcasting, distributed ETS replication, and global process registration work natively across Fly.io machines without requiring external message brokers or service meshes.

Fly.io's Machines API enables the platform to scale dynamically -- spinning up additional compute for intensive security scanning operations and scaling down during quiet periods, optimizing cost while maintaining responsiveness. The auto-start and auto-stop capabilities mean the platform pays only for active compute, with machines hibernating during periods of inactivity and waking within seconds when requests arrive.

Key Features

  • BEAM Clustering: Native Distributed Erlang support across regions via WireGuard-encrypted 6PN private networking
  • Global Distribution: Deploy to 30+ regions worldwide with automatic request routing to the nearest healthy instance
  • Automatic TLS: Free SSL certificates with automatic renewal via Let's Encrypt, supporting custom domains
  • Private Networking: WireGuard-encrypted inter-machine communication on the fly.internal DNS domain
  • Machines API: Programmatic VM management for auto-scaling with sub-second start times for pre-built images
  • Volume Storage: Persistent NVMe-backed storage volumes for database files and application state
  • Health Checks: HTTP, TCP, and script-based health checks with automatic machine replacement on failure
  • Secrets Management: Encrypted environment variable storage accessible only to application machines

Platform Integration

Fly.io hosts the platform with BEAM-native clustering, enabling distributed GenServer processes to communicate transparently across machines.

defmodule PrismaticWeb.Release do
  @moduledoc """
  Release configuration for Fly.io deployment with BEAM clustering.
  """

  def start do
    # Connect to other Fly.io machines for clustering
    topologies = [
      fly6pn: [
        strategy: Cluster.Strategy.DNSPoll,
        config: [
          polling_interval: 5_000,
          query: System.get_env("FLY_APP_NAME") <> ".internal",
          node_basename: System.get_env("FLY_APP_NAME")
        ]
      ]
    ]

    {:ok, _} = Supervisor.start_link(
      [{Cluster.Supervisor, [topologies, [name: Prismatic.ClusterSupervisor]]}],
      strategy: :one_for_one
    )
  end

  def migrate do
    for repo <- Application.fetch_env!(:prismatic, :ecto_repos) do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
    end
  end
end

The clustering configuration uses DNS polling on the .internal domain that Fly.io provides for all machines in an application. Every 5 seconds, the cluster supervisor queries DNS for peer machines and establishes Distributed Erlang connections to any new nodes.

Architecture

Fly.io provides the entire production infrastructure stack for the Prismatic Platform, from edge routing to persistent storage.

LayerFly.io ComponentPlatform Usage
EdgeAnycast routingGlobal request distribution to nearest region
TLSAutomatic certificatesHTTPS termination with TLSv1.3
ProxyFly ProxyHTTP/2, WebSocket upgrade, connection pooling
ComputeFly MachinesPhoenix application instances
Networking6PN (WireGuard)BEAM cluster communication, inter-service calls
StorageFly VolumesPostgreSQL data, KuzuDB graph files
DNS.fly.devPublic hostname, internal service discovery
SecretsEncrypted vaultAPI keys, database credentials, signing keys

The deployment topology places the primary application in the fra (Frankfurt) region, with the ability to add read replicas and edge workers in additional regions as traffic demands. Frankfurt was chosen for its proximity to the Czech Republic, where the platform's primary users and OSINT data sources are located.

Performance Characteristics

Fly.io's infrastructure meets the platform's strict performance requirements enforced by the quality gates.

MetricTargetMeasuredStatus
Cold start time< 5s~3sPass
Warm request latency (fra)< 50ms~15msPass
WebSocket connection setup< 100ms~40msPass
Inter-node message latency< 10ms~2ms (same region)Pass
Machine wake time (auto-start)< 3s~1.5sPass
TLS handshake< 100ms~30msPass
Volume I/O (NVMe)> 100 MB/s~400 MB/sPass

These measurements are collected through the platform's telemetry system and validated against the requirement that all pages load under 250ms.

Configuration

The fly.toml configuration file defines the deployment topology, scaling behavior, and health checks for the Prismatic Platform.

# fly.toml - Production deployment configuration
app = "prismatic"
primary_region = "fra"

[build]
  dockerfile = "Dockerfile"

[env]
  PHX_HOST = "prismatic-prod.fly.dev"
  PORT = "8080"
  RELEASE_COOKIE = "prismatic-cluster-cookie"
  ERL_AFLAGS = "-proto_dist inet6_tcp"
  ECTO_IPV6 = "true"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1

  [http_service.concurrency]
    type = "connections"
    hard_limit = 1000
    soft_limit = 800

[[http_service.checks]]
  grace_period = "10s"
  interval = "30s"
  method = "GET"
  timeout = "5s"
  path = "/health"

[[vm]]
  size = "shared-cpu-2x"
  memory = "1gb"

The configuration enforces HTTPS, sets up auto-scaling with at minimum one machine always running, and configures health checks that verify the Phoenix application is responding. The ERL_AFLAGS setting enables IPv6 for Distributed Erlang, which is required for Fly.io's 6PN private networking.

Deployment Pipeline

Deployments to Fly.io are automated through the GitLab CI/CD pipeline. The deployment process follows a blue-green strategy where the new version is deployed alongside the existing one, and traffic is shifted only after health checks pass.

# GitLab CI deployment stage
deploy_staging:
  stage: deploy
  script:
    - flyctl deploy --app prismatic-staging --strategy rolling
    - flyctl status --app prismatic-staging
  only:
    - main
  environment:
    name: staging
    url: https://prismatic-staging.fly.dev

deploy_production:
  stage: deploy
  script:
    - flyctl deploy --app prismatic --strategy rolling
    - flyctl status --app prismatic
  when: manual
  only:
    - main
  environment:
    name: production
    url: https://prismatic-prod.fly.dev

Production deployments require manual approval to ensure that a human reviews the changes before they reach the live system. Staging deployments happen automatically on every merge to main.

Best Practices

  • Use DNS-based clustering -- the Cluster.Strategy.DNSPoll strategy is the most reliable for Fly.io's 6PN networking; avoid libcluster strategies that rely on Kubernetes or AWS APIs
  • Set min_machines_running = 1 -- ensures at least one machine is always warm, preventing cold-start latency for the first request after an idle period
  • Configure ERL_AFLAGS for IPv6 -- Fly.io's internal networking uses IPv6; without this flag, Distributed Erlang connections fail silently
  • Use volumes for database storage -- Fly volumes provide persistent NVMe storage that survives machine restarts; never rely on the ephemeral filesystem for stateful data
  • Run migrations in release commands -- use fly deploy --strategy rolling with a release command that runs PrismaticWeb.Release.migrate() before the application starts
  • Monitor with flyctl status -- regularly check machine health and resource usage to identify scaling needs before they become performance problems

Comparison with Alternatives

FeatureFly.ioAWS ECSHerokuRailwayRender
BEAM ClusteringNativeManual VPC setupNot supportedNot supportedNot supported
Global Distribution30+ regions25+ regions2 regionsLimitedLimited
Auto-scalingMachine-levelTask-levelDyno-levelInstance-levelInstance-level
Cold Start~3s~30s (Fargate)~5s~5s~10s
WebSocket SupportNativeVia ALBSupportedSupportedSupported
Persistent StorageNVMe volumesEBSNone (add-on)NoneDisk
Pricing ModelPer-machine-secondPer-vCPU-hourPer-dyno-hourPer-usagePer-instance
Elixir SupportFirst-classGenericBuildpackNixpackBuildpack

Fly.io was chosen because it is the only platform that provides native BEAM clustering support without requiring custom networking infrastructure, making it the natural deployment target for a distributed Elixir application. The WireGuard-encrypted private network also eliminates the need for application-level encryption between cluster nodes, reducing operational complexity.

  • Docker - Container builds for Fly.io deployment images
  • GitLab CI/CD - Automated deployment pipeline to Fly.io
  • Nginx - Edge routing complement for advanced proxy configurations
  • PostgreSQL - Database hosted on Fly.io volumes
  • BEAM - Virtual machine with native clustering on Fly.io's 6PN network
  • Elixir - Primary application language with first-class Fly.io support
  • prismatic_web - Primary web application deployed to Fly.io
  • prismatic_api - REST API gateway running on Fly.io
  • prismatic_perimeter - EASM service utilizing Fly.io's global distribution
  • All 90 Prismatic Platform applications deploy as a single release to Fly.io

Connect & Contribute

Created by Tomáš Korcak (korczis) | Open Source under GHL