---
title: "Deploy WAHA [Updated Oct '26]"
description: "WhatsApp HTTP API. No per-message fees. Sessions survive redeploys."
category: "Automation"
url: https://railway.com/deploy/waha-whatsapp-api
---

# Deploy WAHA [Updated Oct '26]

WhatsApp HTTP API. No per-message fees. Sessions survive redeploys.

**[Deploy WAHA [Updated Oct '26] on Railway](https://railway.com/template/waha-whatsapp-api)**

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

- **Creator:** shruistic
- **Category:** Automation

## Template content

### WAHA https://raw.githubusercontent.com/devlikeapro/waha/refs/heads/core/logo.png

- **Image:** devlikeapro/waha
- **Health check:** /ping
- **Public domain:** Yes

## Documentation

# Deploy and Host WAHA on Railway

[WAHA](https://github.com/devlikeapro/waha) (WhatsApp HTTP API) turns WhatsApp into a REST API — send and receive messages, manage groups and contacts, wire up webhooks, run multiple sessions — without per-message fees or Meta Business approval. It's Apache-2.0, actively maintained, and has over 7,500 GitHub stars. This template deploys the official `devlikeapro/waha` image directly and fixes two real bugs found in Railway's own official WAHA template: a session-restart variable that doesn't exist in WAHA's codebase, and a healthcheck path that would 401 on every single probe.

## About Hosting WAHA

This template runs `devlikeapro/waha` unmodified — no Dockerfile, no forked code, no custom start command. Everything this template adds is configuration: a pinned port that matches the domain's target port, a healthcheck path that's actually reachable without authentication, and the correct variable name for automatic session recovery after a redeploy.

Those sound like small details, but they're the difference between a template that *looks* configured and one that's actually been checked against the app's real behavior. Railway's reference `waha-api` template sets `WAHA_RESTART_ALL_SESSIONS=True` — a variable that doesn't exist anywhere in WAHA's source. It's silently ignored, which means a redeploy drops your WhatsApp session and nobody's told. This template uses the real variable, `WHATSAPP_RESTART_ALL_SESSIONS`, confirmed against WAHA's `config.service.ts` and verified live in deploy logs.

## Common Use Cases

- **Business messaging automation**: order confirmations, appointment reminders, and support replies sent straight from your own backend, no per-message platform fee
- **Chatbots and AI assistants**: wire WAHA's webhooks into an LLM or workflow tool (n8n, Zapier, your own code) to auto-respond to incoming messages
- **CRM and support-inbox integration**: sync WhatsApp conversations into your existing ticketing or CRM system via REST calls and webhooks
- **Multi-session WhatsApp gateways**: run several WhatsApp numbers from one deployment, each as an independent session

## Dependencies for WAHA Hosting

Running this template needs nothing beyond the container and one persistent volume — WAHA has no external database or separate services to wire up for the Core (free) tier used here. You bring a WhatsApp number to scan into a session via the dashboard, and whatever downstream system (webhook receiver, CRM, chatbot) you want WAHA to talk to.

### Deployment Dependencies

- [WAHA's Source Code](https://github.com/devlikeapro/waha) — Apache-2.0
- [WAHA's Official Documentation](https://waha.devlike.pro/docs/overview/quick-start/)
- [WAHA's Official Docker Image](https://hub.docker.com/r/devlikeapro/waha)

### Implementation Details

WAHA's `Dockerfile` exposes port 3000, and its `config.service.ts` resolves the actual listening port by checking `PORT` first, falling back to `WHATSAPP_API_PORT` (default `3000`). Railway's reference template leaves `PORT` unset and hardcodes the domain's target port to 8080 instead, relying entirely on Railway's post-boot port auto-detection to reconcile the two. It happens to work, but it's one platform quirk away from a silent mismatch. This template sets `PORT=3000` explicitly and generates the domain against that exact same port.

The healthcheck took closer reading. WAHA has a `HealthController` that does real work — checking free disk space on the media and session volumes — which made `/health` look like the obvious choice. Reading `app.module.core.ts` showed otherwise: the `health` route is registered with `authApiKey: true`, which wires WAHA's API-key middleware onto it. Since this template (like any sane deployment) sets `WAHA_API_KEY`, an unauthenticated request — exactly what Railway's healthcheck prober sends — gets rejected with `401` before the health logic ever runs. A healthcheck that always fails is worse than none at all. The one route registered with zero auth anywhere is `/ping` (confirmed in `ping.controller.ts` — no guards, just a static `{"message": "pong"}`), so that's what this template points the healthcheck at instead.

## Why Deploy WAHA on Railway?

Railway removes the infrastructure WAHA would otherwise need you to manage yourself: TLS, a reverse proxy, a place for session data to survive a restart. Generate a domain and you have HTTPS; mount a volume and session data outlives every redeploy.

Beyond the platform, this template specifically fixes what breaks when you actually rely on the reference template's claims. "Sessions restart automatically" only means something if the variable it's wired to is real. "Healthy" only means something if Railway's probe can actually reach the endpoint it's checking. Both were broken in the official template and are fixed here, verified against the running app rather than assumed from the variable names.

## What Was Verified

This wasn't verified by watching the deploy log turn green — it was verified by hitting the live endpoints directly. `GET /ping` returns `200 {"message":"pong"}` with no headers, confirming the healthcheck path actually works pre-auth. `GET /health` returns `401 Unauthorized` without an API key and `200` with one (its deep check reporting both the media and session volumes as healthy) — proof that using it as the healthcheck path, as the obvious choice would suggest, would have failed Railway's probe on every single deploy. `GET /` serves Swagger UI gated by the Swagger credentials; `GET /dashboard` serves the QR-login dashboard gated by its own credentials; `GET /api/version` (with the API key) confirms the WEBJS engine and its Chromium binary are both present and running.

The session-restart fix was verified in the deploy logs themselves: `Restarting sessions with delay of 0 seconds... STOPPED sessions have been restarted.` — a line that only appears because `WHATSAPP_RESTART_ALL_SESSIONS` is a variable WAHA's code actually reads. The reference template's `WAHA_RESTART_ALL_SESSIONS` produces no such line, because nothing in WAHA is listening for it.

## Frequently Asked Questions

### Why isn't `/health` used as the healthcheck path?
Because it requires the `x-api-key` header — it's registered with `authApiKey: true` in WAHA's own route configuration. Railway's healthcheck prober sends a plain, unauthenticated request, so pointing it at `/health` means every deploy gets marked unhealthy regardless of whether the app is actually fine. `/ping` is the one endpoint with no auth requirement anywhere in the app.

### What's wrong with `WAHA_RESTART_ALL_SESSIONS`?
It isn't a real variable — a full search of WAHA's source code returns zero references to it anywhere. Setting it does nothing. The variable that actually controls automatic session restart after a redeploy is `WHATSAPP_RESTART_ALL_SESSIONS`, which this template uses instead.

### Does this template modify WAHA's code?
No. It's the unmodified official `devlikeapro/waha` image — every difference from a bare `docker run` is in the environment variables and service configuration, not the application itself.

### Which WhatsApp engine does this template use?
`WEBJS` (headless Chromium) by default, matching the reference template's proven-working behavior. If you're on a memory-constrained plan, WAHA's own docs recommend `NOWEB` — a lighter, browser-free engine — as a one-variable swap (`WHATSAPP_DEFAULT_ENGINE=NOWEB`).

### Will my WhatsApp sessions survive a redeploy?
Yes — session data lives on a persistent volume mounted at `/local`, and `WHATSAPP_RESTART_ALL_SESSIONS=True` (the real variable, not the reference template's dead one) automatically reconnects stopped sessions once the new deployment boots.

### Where can I download WAHA?
Source is on GitHub at [github.com/devlikeapro/waha](https://github.com/devlikeapro/waha). Use this template to deploy the official Core image with the healthcheck and session-restart bugs already fixed, in one click.

Source for this template's docs: https://github.com/shruti060701/waha-railway

## Similar templates

- [N8N Main + Worker](https://railway.com/deploy/n8n-main-worker) — Deploy and Host N8N with Inactive worker.
- [Evolution API with n8n](https://railway.com/deploy/evolution-api-with-n8n) — Automate WhatsApp workflows with Evolution API, n8n, and Postgres.
- [Postgres Backup](https://railway.com/deploy/postgres-s3-backups) — Cron-based PostgreSQL backup to bucket storage

Open this page in a browser: https://railway.com/deploy/waha-whatsapp-api
