If you’re reading this, you’re probably leaving Railway this week. Maybe it’s the October 21 security incident and the paused deploys. Maybe it’s a usage bill you didn’t expect. Either way, the good news is that Railway doesn’t lock you in much. Your code is in GitHub, your database speaks standard Postgres, and your config is a list of env vars.

This guide moves a typical Railway app (a web service plus Postgres) to InstaPods, step by step. Most of it applies to any host you pick.

Short version: list your variables, dump Postgres with pg_dump, deploy the repo with instapods deploy --repo, add a database and restore, set fresh keys with instapods env set, move your domain, then revoke the old keys and delete the Railway project.

Make the migration your secret rotation

Don’t copy your old API keys across. If you’re moving because of the incident, those keys are the problem.

Do it in this order instead:

  1. Create new keys at each provider (OpenAI, Stripe, AWS, and so on).
  2. Put the new keys only on the new host.
  3. Cut over.
  4. Revoke the old keys.

You end up rotated and migrated in one pass, and the old values that may have leaked stop working once you revoke them in step 4. If you can’t cut over today, revoke your AI and cloud keys first anyway: a few hours of downtime is cheaper than a leaked key. The rotation checklist has the full list of what to rotate, including the JWT and session secrets people forget.

What you’re actually moving

PieceWhere it is on RailwayHow it travels
CodeYour GitHub repoPoint the new host at the same repo
Env varsEach service’s Variables tabRe-enter (with new values for secrets)
Postgres / MySQL dataA Railway database servicepg_dump / mysqldump, then restore
RedisA Railway database serviceUsually a cache: start empty
Files on a volumeA Railway volumeCopy them out with railway ssh or your app’s own export
Custom domainDNS pointing at RailwayRe-point the CNAME
Cron jobsA cron serviceA cron entry on the new server

Step 1: Write down your variables

Open each Railway service’s Variables tab, or run railway variable list in the linked project. Copy the names into a file. For each one, note whether it’s:

Step 2: Dump your Postgres database

Railway’s backup guide gives two ways in. The simplest uses the database’s public URL (find DATABASE_PUBLIC_URL on the Postgres service):

pg_dump "$DATABASE_PUBLIC_URL" --format=plain --no-owner --no-acl --file=railway.sql

Railway bills traffic over the public proxy as egress, so for a big database the tunnel below is cheaper.

If you don’t want to enable the public proxy, open a tunnel instead. Run railway login first (Railway invalidated old sessions), then run this in a linked project directory and leave it open:

railway connect postgres --tunnel-only

It prints a local host, port, user and password. Run pg_dump against those in a second terminal.

Check the version before you go further. InstaPods runs PostgreSQL 16, and Postgres only guarantees that dumps restore into the same or a newer major version. Run SELECT version(); on your Railway database:

I’d rather you hear that here than halfway through a cutover.

Step 3: Deploy your repo

Install the CLI and log in:

curl -fsSL https://instapods.com/install.sh | sh
instapods login

Then deploy straight from GitHub. You need the Build plan ($7/mo) or higher for a database:

instapods deploy my-app --repo https://github.com/you/your-repo --plan build

InstaPods detects the stack from the repo (Node.js, Python, PHP, Go or static), creates the pod, builds it and follows the first build to completion. Every push to the branch redeploys it after that, the same way Railway did. For a monorepo, add --subdir services/api. For a branch other than the default, add --branch.

No Dockerfile needed. It runs as a normal service on a real Linux server, and you can instapods ssh my-app into it any time.

Railway service runs a Docker image? Run the same image

If your Railway service deploys an image you already publish (say your CI pushes to ghcr.io), skip the repo build and run that image as is:

instapods deploy my-app --image ghcr.io/you/app:1.2 --plan build

Or use Import → Docker image in the dashboard. If you start from the Railway import tab instead, its Deploy the image link takes you there.

What to know before you do it:

Not supported yet: private images that need a registry login, docker-compose setups with several services, arm64-only images, more than one public port, UDP, and anything that needs --privileged. The Docker image guide has the full details.

Step 4: Add Postgres and restore

instapods services add my-app -s postgresql -w
instapods services creds my-app -s postgresql

That installs PostgreSQL in the same pod as your app (about 10 seconds) and prints the password. The database is on localhost, so there’s no public port to leak.

Upload the dump and restore it:

instapods files upload my-app ./railway.sql --remote /tmp/railway.sql
instapods exec my-app -- sh -c "PGPASSWORD='<password>' psql -h localhost -U instapod -d instapod -f /tmp/railway.sql"

Read the output. Errors about roles mean the dump was made without --no-owner --no-acl, so re-dump with those flags. Errors about syntax or unknown features mean the version step above bit you.

Then delete the dump from the server:

instapods exec my-app -- rm /tmp/railway.sql

MySQL: same pattern with mysqldump on the Railway side and instapods services add my-app -s mysql -w. Redis: if it’s a cache or a job queue you can drain, start fresh with instapods services add my-app -s redis -w.

Step 5: Set your env vars, with new secrets

instapods env set my-app \
  NODE_ENV=production \
  DATABASE_URL='postgres://instapod:<password>@localhost:5432/instapod' \
  OPENAI_API_KEY='<new key>' \
  STRIPE_SECRET_KEY='<new key>' \
  SESSION_SECRET="$(openssl rand -base64 32)"

env set writes to /home/instapod/app/.env, puts the values in your app’s process environment and restarts the app. You don’t need dotenv or a redeploy. Check them with instapods env list my-app.

That .env is a normal file on your own server. You can read it, edit it, and back it up.

Now open the pod’s URL (instapods pods get my-app shows it) and click around. Log in, hit a page that reads from the database, trigger whatever calls your AI or payment provider.

Step 6: Move your domain

Lower the TTL on your DNS record a few hours ahead if you can. Then:

instapods domains add my-app app.example.com

It prints a CNAME target. Change your DNS record from the Railway target to that one, wait for it to resolve, then:

instapods domains verify my-app app.example.com

That issues a Let’s Encrypt certificate and starts serving the domain. A root domain (example.com with no subdomain) works if your DNS provider supports CNAME flattening.

Step 7: Cron jobs and workers

A Railway cron service becomes a cron entry on your server (push your SSH key first with instapods ssh-keys add my-app):

instapods ssh my-app
crontab -e

A background worker (a queue consumer, a bot) depends on what it talks to. The database listens on localhost inside your app’s pod, so a worker that needs it is simplest as a second service on the same server (SSH in and add a systemd unit). A worker that only needs outside APIs can go in its own pod: deploy it with instapods deploy my-worker --repo ... --subdir worker, then convert it to a worker pod in its Settings tab so it has no public URL.

Step 8: Revoke the old keys and shut Railway down

Once traffic is on the new host and you’ve watched it for a day:

  1. Revoke every old key at the provider that issued it. This is the step that actually protects you.
  2. Delete the Railway project, including any staging and PR environments that held copies of the same keys.
  3. Remove RAILWAY_TOKEN from your CI secrets.

What you give up, honestly

I’d rather you move once than twice, so here’s what InstaPods doesn’t do that Railway does:

What you get instead: a flat price ($3/mo for a small app, $7/mo with a database), a full Linux server with SSH, storage included in the plan, and no usage meter. There’s a fuller side by side on InstaPods vs Railway.

Not ready to move?

That’s fair. If you’re staying on Railway, the rotation checklist is the part that matters today. Do it whether or not Railway emails you.