WhatsApp Bot Hosting: How to Run Your Bot 24/7 on a Server

To host a WhatsApp bot 24/7, use the official WhatsApp Business Platform (Cloud API) and run a small webhook server on an always-on VPS with a public HTTPS address. Meta sends each incoming message to your webhook; your server acknowledges it immediately, processes it in the background and replies through the API. Run the process under systemd or Docker with automatic restart, store conversations in PostgreSQL, and add an AI layer for replies if you need one.
Official Cloud API vs unofficial libraries
There are two ways people build WhatsApp bots:
The WhatsApp Business Platform (Cloud API): Meta's official API. You register a business phone number through a Meta developer app, receive messages by webhook and send them with authenticated HTTPS requests. Messaging is charged under Meta's pricing rules.
Unofficial libraries that automate WhatsApp Web or imitate the mobile app. They are tempting because they work with an ordinary number, but automating WhatsApp this way is against WhatsApp's terms, numbers can be banned without warning, and changes on WhatsApp's side can break the bot overnight.
For anything customers depend on, use the official platform; the rest of this guide assumes the Cloud API. Meta changes details such as pricing, limits and API versions from time to time, so confirm specifics in Meta's current developer documentation.
What the webhook server must do
1. Be reachable over public HTTPS
Meta delivers webhooks only to a valid HTTPS URL. On a VPS the usual setup is a subdomain such as bot.example.com pointing at the server, Nginx as a reverse proxy and a free Let's Encrypt certificate. The bot listens on a local port, for example 3000, and Nginx forwards HTTPS traffic to it.
2. Answer the verification handshake
When you register the webhook URL in the app dashboard, you also set a verify token: a secret string of your choosing. Meta then sends a GET request with hub.mode=subscribe, hub.verify_token and hub.challenge. If the token matches yours, respond with status 200 and the challenge value as the body; otherwise return 403.
3. Acknowledge events quickly
Incoming messages and delivery status updates arrive as POST requests with a JSON body. Return 200 as fast as you can, then do the slow work (database writes, AI calls, outgoing API requests) asynchronously. If your endpoint is slow or returns errors, Meta retries the delivery, and you will process the same message twice unless you deduplicate by message ID.
4. Verify the signature
Meta signs webhook payloads with your app secret and sends the result in the X-Hub-Signature-256 header. Compute an HMAC-SHA256 of the raw request body and compare it before trusting the payload, so nobody else can post fake messages to your endpoint.
A minimal webhook in Node.js
This Express example shows the handshake, the signature check and the "acknowledge first, work later" pattern. In production, push the work onto a queue (Redis, or a jobs table in PostgreSQL) instead of handling it in the same process.
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }));
app.get('/webhook', (req, res) => {
const ok = req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === process.env.VERIFY_TOKEN;
return ok ? res.status(200).send(req.query['hub.challenge']) : res.sendStatus(403);
});
app.post('/webhook', (req, res) => {
const sig = req.get('X-Hub-Signature-256') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.APP_SECRET)
.update(req.rawBody).digest('hex');
if (sig.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge immediately
setImmediate(() => handleEvent(req.body)); // replace with a real queue
});
app.listen(3000, '127.0.0.1');Replies are sent as a POST to the Graph API /PHONE_NUMBER_ID/messages endpoint with your access token. For a server bot, use a long-lived system user token rather than the temporary token shown in the dashboard, and keep it in an environment file, not in your code.
Templates and the 24-hour customer service window
WhatsApp treats conversations the customer starts differently from messages the business starts:
When a customer messages you, a customer service window of 24 hours opens. Inside it, your bot can send free-form replies: text, media, buttons and lists.
Outside that window, you can only contact the customer with a message template that was submitted and approved in advance, such as an order update, an appointment reminder or a one-time code.
Each new message from the customer restarts the window.
Design the bot around this. Store the time of each customer's last message, and before sending, check whether you are still inside the window; if not, fall back to an approved template. Template categories, approval rules and pricing change over time, so check Meta's documentation before planning notifications or campaigns.
Running it 24/7
A webhook bot is useless if the process has died. Two reliable options on a Linux server:
systemd starts the bot on boot and restarts it if it crashes. Save this as /etc/systemd/system/whatsapp-bot.service and enable it with sudo systemctl enable --now whatsapp-bot:
[Unit]
Description=WhatsApp bot
Wants=network-online.target
After=network-online.target
[Service]
User=bot
WorkingDirectory=/opt/whatsapp-bot
EnvironmentFile=/opt/whatsapp-bot/.env
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetDocker: run the bot and its database with Docker Compose and restart: unless-stopped, so containers come back after a crash or a reboot. If you already run Node.js apps with PM2, our guide to Node.js hosting with PM2 and Nginx covers that route, including the reverse proxy and SSL.
Add basic monitoring as well: an external uptime check against a health endpoint, and an alert when the webhook starts returning errors.
Storing conversations in PostgreSQL
Keep a record of every message in and out. You need it for context in AI replies, for the 24-hour window logic, for staff who take over a conversation, and for debugging.
CREATE TABLE wa_messages (
id bigserial PRIMARY KEY,
wa_message_id text UNIQUE, -- Meta's message ID, used to deduplicate
phone text NOT NULL,
direction text NOT NULL CHECK (direction IN ('in', 'out')),
body jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX ON wa_messages (phone, created_at DESC);The unique constraint on the message ID makes retried webhooks harmless: insert with ON CONFLICT DO NOTHING and skip processing when no row was inserted. Conversations contain personal data, so restrict database access, back it up and decide how long you keep it.
Adding an AI reply layer
Once messages flow reliably, the AI layer is simply a worker that picks up each incoming message and:
Loads the recent messages for that phone number from PostgreSQL as context.
Optionally retrieves relevant passages from your FAQ, policies or catalogue with pgvector.
Calls a model API with a system prompt that defines scope, tone and when to hand over to a person.
Sends the reply through the Cloud API and stores it.
Always leave a way out: a keyword or button that routes the customer to a person, and a flag that pauses the bot for that customer while staff handle it. Put a timeout on the model call so a slow API doesn't leave customers waiting in silence. Because the model runs at the provider, the bot itself is light; as explained in do you need a GPU to run an AI agent, CPU and RAM are what count. If you are still deciding where to run it, see where to host an AI agent. The architecture is close to a Telegram bot's, covered in hosting a Telegram bot 24/7 on a VPS.
Frequently asked questions
Can I run a WhatsApp bot on my own computer?
For testing, yes, with a tunnel that gives you a temporary HTTPS URL. For production, no: the webhook must be reachable every minute of the day, which a home machine can't guarantee.
Is it safe to use an unofficial WhatsApp library?
Not for a business. Automating WhatsApp outside the official platform is against WhatsApp's terms and can get the number banned. Use the WhatsApp Business Platform.
Why does my webhook receive the same message twice?
Meta retries deliveries it considers failed, often because the endpoint answered slowly. Respond with 200 immediately and deduplicate by message ID.
Can my bot message customers first?
Only with an approved message template when you are outside the 24-hour customer service window. Inside the window, free-form replies are allowed.
Hosting your WhatsApp bot on IM HOST
AI Agent Hosting servers come with Docker, Docker Compose, Node.js, Python and PostgreSQL with pgvector pre-installed, so a WhatsApp webhook bot, its conversation store and an AI reply layer can run together on one always-on machine with free daily backups. If you prefer to build the stack yourself, a Linux VPS gives you an unmanaged KVM server on NVMe storage with full root access.
More from our blog
Discover more practical guides and product insights from the IM Host team.
View all articles