Migrating to Bahriya
Moving an application to Bahriya follows the same shape whatever you are coming from. Your app becomes a container, your configuration becomes environment variables and secrets, and your public URL is served automatically over HTTPS with your own domain layered on top. This overview walks the general path; the platform-specific guides linked at the end fill in the details for where you are today.
Moving an application to Bahriya follows the same shape whatever you are coming from. Your app becomes a container, your configuration becomes environment variables and secrets, and your public URL is served automatically over HTTPS with your own domain layered on top. This overview walks the general path; the platform-specific guides linked at the end fill in the details for where you are today.
The mental model
Most platforms wrap three things together: a build step, a running process, and some managed add-ons (a database, a cache). Bahriya keeps the same pieces but makes each one explicit:
| What you have now | On Bahriya |
|---|---|
| A web app or service | An HTTP container |
| A background process | A worker container |
| A scheduled task | A cron job |
| Config values | Environment variables |
| Secret values | Secrets (encrypted, injected as env vars) |
| A managed cache | Bahriya Memcached, or an external cache reached via secrets |
| A managed database | An external database reached via a connection secret |
| A build from source | A Dockerfile producing an image |
The one meaningful shift is that Bahriya runs a container image rather than building from your source on every push. You produce an image — usually with a Dockerfile — push it to a registry, and deploy that image. This makes builds reproducible and keeps the runtime independent of any single provider's build system.
The migration path
Containerise. Write a Dockerfile that builds and runs your app, and make sure it listens on a single port. If you already have a Dockerfile, you are most of the way there. Build the image and push it to a registry — Docker Hub, GitHub Container Registry (
ghcr.io), or your own.Move configuration. Split your existing config into non-sensitive values (environment variables) and sensitive values (secrets). Create the secrets at the organisation level and wire them into the container by env-var name. See Environment Variables.
Handle stateful add-ons. Point your app at a database over the network using a connection string stored as a secret. For caching, create a Bahriya Memcached instance or connect to an external cache the same way.
Deploy. Create the container from the Console or with the Reis CLI, choosing your regions, resources, and replicas. Your container comes up on its default hostname with automatic TLS.
Point your domain and cut over. Add your custom domain, verify it, then move production DNS across once you have confirmed the new deployment is healthy.
Containerise your app
If your current platform builds from a buildpack or a Procfile, translate that into a Dockerfile. The key requirements are that the image starts your app with a single command and listens on one port. A minimal Node example:
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]Bind your server to 0.0.0.0 and read the port from an environment variable so it stays portable. Bahriya sends traffic to the port you declare with --port (default 8080).
Move configuration and secrets
List every config value your app reads today. Non-sensitive values (log level, feature flags, public URLs) become plain environment variables. Anything sensitive (database passwords, API keys, tokens) becomes a secret: create it once, attach it to the project, then wire it to a variable name your app already expects.
Deploy
With the image pushed and secrets in place, deploy from the Console (see 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 \
--regions falkenstein-1 \
--env NODE_ENV=production \
--secrets DATABASE_URL=database-urlPoint your domain and cut over
Your container is reachable immediately at https://<handle>.<region>.x.on.bahriya.app. Test against that hostname first. When you are satisfied, add your production domain, verify it, and update DNS. Keep the old deployment running until traffic has fully drained to Bahriya, then decommission it. See Custom Domain Setup.