How to host Evolution API (WhatsApp)

Evolution API is an open source REST API for WhatsApp. To host it you need Node.js (or Docker), PostgreSQL or MySQL, Redis and a process that stays on all the time.

Updated 6 min read

Learning objectives

After reading this article you will be able to:

  • Understand what Evolution API needs to run in production
  • Start the API with Docker Compose and configure the .env file
  • Create an instance, scan the QR code and send the first message
On this page

Evolution API turns a WhatsApp account into a REST API. Your system (a CRM, a chatbot, an admin panel) sends a POST and the message goes out; when a message arrives, it notifies you by webhook. That is why many teams use it instead of building a bot from scratch with a library.

Hosting it is different from running it on your laptop. The API keeps an open connection to WhatsApp and stores sessions and messages in a database. If the process stops, the connection drops. The steps below follow the repository's README; check the releases before installing, because scripts and variables can change between versions.

YoursystemapikeywebhookEvolution APIone per numberWhatsAppPostgreSQLsessionsRediscacheinternal network, no public port
Only the API is exposed, guarded by the apikey; PostgreSQL and Redis stay on the internal network.

What does Evolution API need to run?#

According to the official README:

  • The current Active LTS of Node.js (if you run it without Docker).
  • PostgreSQL or MySQL, chosen in DATABASE_PROVIDER.
  • Redis, recommended for caching.
  • A process that stays on all the time, listening on port 8080 by default.

There is also a Docker image, evoapicloud/evolution-api:latest. The repository ships a docker-compose.yaml with the API, Redis and PostgreSQL.

How do you start it with Docker Compose?#

Create a folder with two files. First the .env, with your own values (don't reuse the repository's sample key):

bash
SERVER_PORT=8080
SERVER_URL=http://localhost:8080
AUTHENTICATION_API_KEY=replace-with-a-long-random-key
DATABASE_PROVIDER=postgresql
DATABASE_CONNECTION_URI=postgresql://evolution:change-the-password@postgres:5432/evolution_db?schema=evolution_api
CACHE_REDIS_ENABLED=true
CACHE_REDIS_URI=redis://redis:6379/6
CACHE_REDIS_PREFIX_KEY=evolution
POSTGRES_DB=evolution_db
POSTGRES_USER=evolution
POSTGRES_PASSWORD=change-the-password

Then the docker-compose.yaml, trimmed down from the official file:

yaml
services:
  api:
    image: evoapicloud/evolution-api:latest
    restart: always
    depends_on: [redis, postgres]
    ports:
      - "8080:8080"
    env_file: .env
    volumes:
      - evolution_instances:/evolution/instances

  redis:
    image: redis:latest
    restart: always
    command: redis-server --port 6379 --appendonly yes
    volumes:
      - evolution_redis:/data

  postgres:
    image: postgres:15
    restart: always
    env_file: .env
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  evolution_instances:
  evolution_redis:
  postgres_data:

Start it with docker compose up -d. The official file publishes the API only on 127.0.0.1; the example above exposes it on every interface, so put a reverse proxy with HTTPS in front and never leave the port open without the key.

How do you run it without Docker?#

This is for environments that run Node.js directly. The repository's steps are:

bash
git clone https://github.com/EvolutionAPI/evolution-api.git
cd evolution-api
npm install
cp .env.example .env   # edit database, Redis and AUTHENTICATION_API_KEY
npm run db:generate
npm run db:deploy
npm run build
npm run start:prod

db:deploy applies the migrations for the provider set in DATABASE_PROVIDER, so define that variable first. start:prod runs the compiled dist/main.

db:generate generates the Prisma client for the chosen provider; without it, the API does not start. If the environment installs only dependencies (with NODE_ENV=production), two scripts break: build, because tsc is a devDependency, and prepare, because husky is one too. In that case, compile elsewhere and change prepare to husky || true, as the Husky docs suggest.

How do you create an instance and connect WhatsApp?#

Each WhatsApp number is an instance. The global key (AUTHENTICATION_API_KEY) goes in the apikey header:

bash
curl -X POST http://localhost:8080/instance/create \
  -H "apikey: $AUTHENTICATION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"instanceName":"my-instance","qrcode":true,"integration":"WHATSAPP-BAILEYS"}'

The response carries the QR code in qrcode.base64. If you need a new one, request it with GET /instance/connect/my-instance. On your phone, open WhatsApp, go to Linked devices, Link a device, and scan the code. Then check the state:

bash
curl http://localhost:8080/instance/connectionState/my-instance \
  -H "apikey: $AUTHENTICATION_API_KEY"

How do you send the first message?#

bash
curl -X POST http://localhost:8080/message/sendText/my-instance \
  -H "apikey: $AUTHENTICATION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"number":"15551234567","text":"Hello from Evolution API"}'

The number includes the country code and the full number, without +. If the response returns the sent message's data and the text shows up on the phone, it worked. To receive messages, configure the instance's webhook to point at a URL of yours.

How do you secure the installation?#

AUTHENTICATION_API_KEY grants full access: it creates and deletes instances and sends messages from any connected number. Treat it like a production password.

  • Generate a long random key and keep it in an environment variable, never in the repository (see what environment variables are).
  • Do not expose PostgreSQL or Redis to the internet. In Compose, keep them on the internal network only and remove any ports from those services.
  • Serve the API behind HTTPS and, if you can, restrict callers by IP.
  • Set SERVER_URL to the real public URL, because it appears in responses and webhooks.
  • To understand the packaging better, read how to dockerize an app.

Evolution API is a third-party project: follow the repository's releases before changing the image tag, instead of always relying on latest.

What are the common errors?#

  • Database connection fails: DATABASE_CONNECTION_URI has the wrong host. Inside Compose the host is the service name (postgres), not localhost.
  • Migrations did not run: in a non-Docker install, npm run db:deploy or the DATABASE_PROVIDER variable is missing.
  • TLS error on the database: if the database requires a client certificate, Prisma reads it from DATABASE_CONNECTION_URI itself: sslmode=require, sslcert with the server CA and sslidentity with the client certificate in PKCS12 format (plus sslpassword if it has one). Paths are relative to the prisma folder.
  • redis disconnected in a loop with rediss://: Evolution API's redis client turns on TLS by itself with rediss://, but it only trusts public CAs. If the Redis uses its own CA, point NODE_EXTRA_CA_CERTS at the CA file in the command that starts the process, not in .env: Node reads this variable only at startup.
  • 401 on every call: the apikey header does not match AUTHENTICATION_API_KEY.
  • QR code requested again after a restart: the instance data did not persist. Check volumes and the database, and read why a WhatsApp bot keeps disconnecting.
  • Restricted number: the Baileys integration is unofficial. For commercial use at scale, compare it with the official API.

How to do this on Square Cloud#

Evolution API has to stay online all the time. On Square Cloud, a self-service host, containers are always on with no sleep mode, and automatic restart, which is on by default when you deploy from the dashboard, brings the process back when it exits with an error.

You run Evolution API on the Node.js runtime, using the install-from-source steps above. There is no Dockerfile, Docker Compose or build step, and dependencies are installed with NODE_ENV=production: compile in an external CI such as GitHub Actions, upload the project with the dist folder already built and adjust prepare as described above. Because Evolution API reads its port from SERVER_PORT, a START such as npm run db:generate && npm run db:deploy && SERVER_PORT=$PORT npm run start:prod makes the API listen on the port in the PORT variable, which the platform sets.

Environment variables are per application: the dashboard imports a .env file, and a change applies on the next restart. From the Standard plan up, you can host PostgreSQL, MySQL and Redis in the same datacenter as your applications; the Hobby plan doesn't include databases. The dashboard gives you the full connection URL and the certificate, and TLS is required. On PostgreSQL, the client also presents the downloaded certificate, set in the URL as explained under common errors above. The plan's RAM is a shared pool, with a minimum of 512 MB per web application.

To use a Redis hosted on the platform as the cache, download the Certificate CA (.crt) option on the database page, which saves ca-certificate.crt, put the file at the project root and set:

bash
# application environment variables (the dashboard's connection URL)
CACHE_REDIS_ENABLED=true
CACHE_REDIS_URI=rediss://default:YOUR_PASSWORD@HOST:PORT
# START command
npm run db:generate && npm run db:deploy && NODE_EXTRA_CA_CERTS=./ca-certificate.crt SERVER_PORT=$PORT npm run start:prod

Use the host from the dashboard URL, not an IP, so the name matches the certificate, and don't append /6: this Redis has a single logical database and doesn't ask for a client certificate.

If you'd rather build the bot directly with Baileys, WPPConnect, whatsapp-web.js or the official Cloud API, see WhatsApp bot hosting.

Bot hosting

Keep your bot online 24/7 with automatic restarts

Learn more

FAQs

Is Evolution API free?

The code is open source (Apache 2.0, with additional branding conditions), so there is no license to pay for. You pay for the infrastructure it runs on: server, database and Redis. If you use the official Cloud API, Meta charges per delivered message, depending on the category and the country.

Does Evolution API need a database?

Yes. The README asks for PostgreSQL or MySQL, set in DATABASE_PROVIDER, and recommends Redis for caching. Without a database, instances and messages do not persist.

Can I run Evolution API without Docker?

Yes. Clone the repository, run npm install, configure the .env file, run npm run db:generate and npm run db:deploy, then npm run build and npm run start:prod.

Does Evolution API use the official WhatsApp API?

It supports both. The WHATSAPP-BAILEYS integration uses WhatsApp Web, which is unofficial. The integration with Meta's Cloud API is the official route.

Next articleHow much does it cost to host a Discord bot?The cost of hosting a Discord bot depends on RAM, uptime, database and outside services. Learn how to estimate your own bill and where the money goes.