Migrate from Fly.io to Bahriya

If you are running on Fly.io you are already most of the way to Bahriya: you have a Dockerfile, you deploy an image, and you think in terms of regions. The move is largely a matter of translating your fly.toml into Bahriya container settings, recreating your secrets, and choosing which regions to run in. This guide maps the pieces and walks the cutover.

Updated 3 Aug 20263 min read

If you are running on Fly.io you are already most of the way to Bahriya: you have a Dockerfile, you deploy an image, and you think in terms of regions. The move is largely a matter of translating your fly.toml into Bahriya container settings, recreating your secrets, and choosing which regions to run in. This guide maps the pieces and walks the cutover.

What maps to what

Fly.ioBahriya
AppA project (with one or more containers)
Machine / processA container — HTTP, worker, or cron job
fly.tomlContainer settings (Console fields or Reis flags)
[build] / DockerfileThe image you build and push to a registry
internal_port / [[services]] portThe port you declare with --port
fly secrets setSecrets (encrypted, injected as env vars)
[env] in fly.tomlEnvironment variables
RegionsRegions — the same concept, chosen per container
min_machines_running / autoscalingReplicas and autoscaling
Fly PostgresAn external database via a connection secret

1. The Dockerfile is already there

Fly deploys a container image, so your existing Dockerfile carries straight over. Build and push it to a registry Bahriya can pull from:

docker build -t ghcr.io/myorg/api:v1.0.0 .
docker push ghcr.io/myorg/api:v1.0.0

If the image is private, add the registry credentials to your project once — see Registries — and reference the registry handle when you deploy.

2. Translate fly.toml

Map the fields you rely on:

  • internal_port — the port your app listens on becomes --port. Keep binding to 0.0.0.0.
  • [http_service] / [[services]] — an HTTP service becomes an HTTP container; a process with no public port becomes a worker.
  • [checks] / health checks — set the health check path with --healthcheck (default /healthz). See Health Checks.
  • [env] — plain environment variables move across unchanged.
  • [[vm]] sizing — set minimum CPU (millicores) and memory (MB) on the container.

3. Secrets

Fly stores sensitive values with fly secrets set and injects them as environment variables. Bahriya secrets work the same way from your app's point of view: create the secret at the organisation level, attach it to the project, and wire it to the variable name your app already reads. Encrypted at rest, decrypted only at deploy time.

4. Regions map directly

Regions are the concept the two platforms share most closely. On Bahriya you choose which regions a container runs in, and each region is billed independently — three regions at two replicas each is six replicas. Pick the regions closest to your users from the four that are live:

RegionLocation
helsinki-1Helsinki, Finland
falkenstein-1Falkenstein, Germany
virginia-1Ashburn, Virginia, USA
singapore-1Singapore

See Regions for tiers and how multi-region deploys work.

5. Databases

If you use Fly Postgres, provision an equivalent database — a managed provider or your own instance — reachable over the network, store its connection string as a secret, and wire it to DATABASE_URL. Provision and load the new database, verify connectivity from a Bahriya container, then cut over. For a Memcached-compatible cache, use Bahriya Memcached.

6. Deploy

From the Console follow Deploy Your First Container, or with Reis:

reis container:create \
  --type http \
  --name "Web API" \
  --handle web-api \
  --image ghcr.io/myorg/api:v1.0.0 \
  --registry ghcr \
  --port 8080 \
  --healthcheck /healthz \
  --replicas 2 \
  --max_replicas 8 \
  --regions falkenstein-1 \
  --regions virginia-1 \
  --env NODE_ENV=production \
  --secrets DATABASE_URL=database-url

--max_replicas above --replicas enables autoscaling between the two.

7. Point your domain and cut over

Your container comes up at https://web-api.<region>.x.on.bahriya.app with automatic TLS. Test there, then add your production domain, verify it, and move DNS — see Custom Domain Setup. Keep the Fly app running until traffic has drained across, then scale it down and remove it.

From the blog