---
title: "Deploy Multi-Client WhatsApp API — Self-Hosted Evolution"
description: "Run many WhatsApp numbers from one Evolution API — per-instance keys"
category: "Bots"
url: https://railway.com/deploy/evolution-api-multi-instance
---

# Deploy Multi-Client WhatsApp API — Self-Hosted Evolution

Run many WhatsApp numbers from one Evolution API — per-instance keys

**[Deploy Multi-Client WhatsApp API — Self-Hosted Evolution on Railway](https://railway.com/template/evolution-api-multi-instance)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/evolution-api-multi-instance/manifest.json

- **Creator:** SB
- **Category:** Bots
- **Total deploys:** 1

## Template content

### Postgres https://devicons.railway.app/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### Evolution API https://res.cloudinary.com/asset-cloudinary/image/upload/v1772629067/evolution_api_rgbwhh.png

- **Image:** evoapicloud/evolution-api:latest
- **Public domain:** Yes

### Redis https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg

- **Image:** redis:8.2
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

## Documentation

# Deploy and Host Evolution API on Railway

Evolution API turns WhatsApp numbers into REST endpoints, and one deployment runs many of them. Each client, brand or region is its own instance with its own QR login, webhook target and API key — no Meta verification, no per-message billing. This template deploys it with Postgres, Redis and a session volume, configured for the case quickstarts skip: more than one number on one box.

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| `evolution-api` | REST API and Manager UI on port `8080`. The only public service. |
| `Postgres` | Instance records, contacts, chats and messages for every number. |
| `Redis` | Session cache and instance state. |
| Volume | `/evolution/instances` — one WhatsApp auth directory per connected number. |

Everything stateful is split: Postgres holds application data, while each number's WhatsApp credentials are files on the volume under its instance name. You need both, together.

## About Hosting

Running one number is straightforward. Running twenty for twenty clients changes which mistakes matter, and the defaults are built for one.

**Instances share a deployment, not an isolation boundary.** `AUTHENTICATION_API_KEY` is global: it authenticates every request to every instance on the box. Hand it to a client so they can integrate and you have given them the ability to read, send from and delete every other client's number. Generate a per-instance key for each, and keep the global key for administration only. That one decision separates a usable multi-tenant deployment from a liability.

**Memory scales with connected numbers, not traffic.** Each instance holds an open socket and its session state inside the same Node process. A deployment sized for one number falls over at ten, and the symptom is instances dropping offline rather than an obvious out-of-memory error. Budget per number.

**One volume means one service, so no horizontal scaling.** Session directories live on a Railway volume, and a volume attaches to one service — replicas cannot share them. Growth is a bigger box, not more boxes; plan the ceiling before you sell past it.

**`DEL_INSTANCE` can delete a client while you are not looking.** Set to a number of minutes, it removes instances disconnected that long. Tidy on a single-user box; on an agency box it destroys a client's session because their phone was off, and reconnecting means a fresh QR scan with them on the line. Set it to `false`.

**Every instance needs its own webhook target.** Inbound messages are useless if twenty clients' events land on one endpoint. Configure the webhook per instance at creation, subscribing only to events you consume.

**One deployment, one reputation.** Numbers are banned individually, so one client's bulk sending does not take the others down directly — but they share your server and egress address, and patterns across numbers are visible. Agree in writing what clients may send, because you cannot enforce it technically from here.

Typical cost: **~$15–30/month** for the API, Postgres and Redis at a handful of numbers, on rates of $10/GB/month RAM, $20/vCPU/month CPU and $0.15/GB/month volumes. Memory dominates, and it rises with each connected number.

## How It Compares

| | Evolution API | Meta Cloud API | Twilio | One deploy per client |
| --- | --- | --- | --- | --- |
| Numbers per deployment | Many instances | Per WABA setup | Per project | One |
| Isolation between clients | Logical, by key | Account-level | Account-level | Full |
| Cost at ten clients | One server | Per conversation | Per message | Ten servers |

The honest edge: one deployment per client gives real isolation, and for regulated work or clients who will ask, that is the correct answer and worth the extra servers. The Cloud API is the supported path if they can wait on verification. This wins on economics and simplicity at small scale — one box, one upgrade, one thing to monitor — and the price is that isolation is a key you issue, not a boundary the platform enforces.

## Deploy in Under 5 Minutes

1. Click **Deploy** and pick a workspace. The API, Postgres and Redis come up wired, with a global `AUTHENTICATION_API_KEY` generated.
2. Confirm the volume is mounted at `/evolution/instances` and set `DEL_INSTANCE=false` before connecting anyone.
3. Open `/manager`, sign in with the global key, and create your first instance named for the client.
4. Generate a per-instance key for that client and give them only that one.
5. Set the instance's webhook to the client's endpoint, scan the QR, and send a test message.

> Verify before you rely on it: connect two instances, then redeploy. Both should reconnect without new QR scans. If only one does, the volume layout is wrong and you will discover it at the worst time with a client on the phone.

## Common Use Cases

- **Agency client management** — one deployment, one instance per client, each with its own key and webhook.
- **Multi-brand support** — separate numbers for separate brands or regions, with inbound events routed to different inboxes.
- **Staging beside production** — a test number on the same box as live ones, isolated by instance rather than by another deployment.

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `AUTHENTICATION_API_KEY` | Generated | Global admin key. Authenticates every instance — never give it to a client. |
| `SERVER_URL` | Required | Public HTTPS domain. Webhook callbacks and media URLs are built from it. |
| `DATABASE_PROVIDER` | Required | `postgresql`. Selects the Prisma schema applied at boot. |
| `CACHE_REDIS_ENABLED`, `CACHE_REDIS_URI` | Auto | Redis holds instance and session state. |
| `DEL_INSTANCE` | Recommended | `false`. A number of minutes here deletes disconnected clients automatically. |
| Storage volume | Pre-set | `/evolution/instances` — one auth directory per number. |

> **Issue per-instance keys to clients.** The global key is not scoped to an instance; anyone holding it controls every number on the deployment.

> **Back up the volume and the database together.** The database knows an instance exists; the volume holds the credential that keeps it logged in. Restore one alone and you get twenty instances all asking for a QR scan.

## Dependencies for Evolution API Hosting

- **Railway account** — ~$15–30/month at a handful of numbers; memory rises with each one connected.
- **Bundled services** — Postgres for application data, Redis for instance state, both wired over private networking.
- **Volume** — required at `/evolution/instances`. Each number's WhatsApp auth lives in its own directory there.
- **Optional** — S3 or MinIO for media offload, and RabbitMQ or WebSocket if you want events streamed rather than posted.

### Deployment Dependencies

- [Evolution API on GitHub](https://github.com/EvolutionAPI/evolution-api)
- [Evolution API documentation](https://doc.evolution-api.com/)
- [Baileys library](https://github.com/WhiskeySockets/Baileys)
- [Railway volumes](https://docs.railway.com/volumes)

### Implementation Details

The API runs on a pinned tag behind Railway's HTTPS edge on port `8080`, Manager UI at `/manager` on the same domain. Postgres and Redis are reached by private hostname through reference variables, and Prisma applies the schema on first boot — which is why `DATABASE_PROVIDER` must be set before the container starts.

Multi-instance is a naming convention rather than a tenancy model, and that shapes how you operate it. Every instance is a row in Postgres and a directory on the volume keyed by its name, served by one process under one global key. There is no per-tenant resource limit, no process-level isolation, no database partition. What you get is per-instance keys and per-instance webhooks, enough to keep clients out of each other's data provided the global key never leaks. Name instances for the client from the start; renaming later means reconnecting.

Capacity planning is simple because one variable dominates. Each connected number costs memory continuously whether busy or not, so your ceiling is memory divided by per-number cost and barely moves with message volume. The volume grows slowly with session files and quickly with media — offload media to S3 before that becomes a problem. Outgrowing one box means a second deployment with clients moved across, and moving an instance means a new QR scan.

## Frequently Asked Questions

**Can one deployment run many WhatsApp numbers?** Yes. Each is an instance with its own QR login, webhook and API key, sharing one API process, one database and one volume.

**Is one client isolated from another?** Logically, by API key. There is no process or database partition, and the global key controls every instance — so key hygiene is the boundary.

**How many numbers can one box handle?** Memory is the limit and it scales per connected number, not per message. Watch usage as you add instances rather than assuming a figure.

**What happens when a client's phone goes offline?** The instance disconnects. With `DEL_INSTANCE` set to a duration it is eventually deleted along with its session; set it to `false` so reconnection does not need a new QR scan.

**Can I scale this across replicas?** No. The session volume attaches to one service, so growth is a larger instance or a second deployment.

## Why Deploy Evolution API on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Evolution API on Railway you get the configuration multi-number use actually needs — a session volume so every instance survives a redeploy, auto-deletion turned off so a disconnected client is not erased, Postgres and Redis on the private network, and a global key you keep rather than hand out.

## Similar templates

- [Swarm](https://railway.com/deploy/swarm) — Named LLM bots join channels, take jobs, run routines on your Railway box
- [Telegram JavaScript Bot](https://railway.com/deploy/5lRkWa) — A template for Telegram bot in JavaScript using grammY
- [Cobalt Tools [Updated Oct ’26]](https://railway.com/deploy/cobalt) — Cobalt Tools [Oct ’26] (Media Downloader, Converter & Automation) Self Host

Open this page in a browser: https://railway.com/deploy/evolution-api-multi-instance
