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.
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.io | Bahriya |
|---|---|
| App | A project (with one or more containers) |
| Machine / process | A container — HTTP, worker, or cron job |
fly.toml | Container settings (Console fields or Reis flags) |
[build] / Dockerfile | The image you build and push to a registry |
internal_port / [[services]] port | The port you declare with --port |
fly secrets set | Secrets (encrypted, injected as env vars) |
[env] in fly.toml | Environment variables |
| Regions | Regions — the same concept, chosen per container |
min_machines_running / autoscaling | Replicas and autoscaling |
| Fly Postgres | An 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.0If 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 to0.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:
| Region | Location |
|---|---|
helsinki-1 | Helsinki, Finland |
falkenstein-1 | Falkenstein, Germany |
virginia-1 | Ashburn, Virginia, USA |
singapore-1 | Singapore |
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.
Related
From the blog