OpenClaw Gateway: What It Does and How to Configure It
The OpenClaw gateway is the bridge between your agent and the outside world. Here's how it works, how to configure it, and how to fix it when it breaks.
Your OpenClaw agent lives on a server. Telegram, Discord, and other messaging platforms live on the internet. The gateway is what connects them.
Without a properly configured gateway, your agent can't receive messages. It's running, but nobody can talk to it. This is one of the most common points of confusion when setting up OpenClaw — especially on a VPS where network configuration matters.
Here's a complete breakdown of what the gateway does, how to configure it, and how to diagnose it when things go wrong.
What the OpenClaw Gateway Actually Does
The gateway is an HTTP server that runs alongside your agent. It does three things:
Receives inbound webhooks — When you send a message on Telegram, Telegram's servers make an HTTP POST to your agent's endpoint. The gateway receives that request.
Routes to the right handler — The gateway determines which plugin handles which incoming request. Telegram messages go to the Telegram plugin. Discord events go to the Discord plugin. Heartbeat pings go to the heartbeat handler.
Manages outbound delivery — When your agent responds, the gateway handles sending that response back through the right channel.
Think of it as a switchboard. Messages come in from multiple sources, get dispatched to the right part of your agent, and responses go back out.
What the Gateway Is Not
The gateway is not the AI model. It doesn't process your messages or generate responses — that's the agent runtime. The gateway is purely the network layer. If your gateway is up but your agent isn't responding intelligently, the problem is elsewhere (model config, API keys, etc.).
Gateway Architecture
Telegram/Discord/Web
↓
[Public URL / HTTPS]
↓
[nginx/reverse proxy] ← optional but recommended
↓
[OpenClaw Gateway] ← port 3000 by default
↓
[Agent Runtime] ← your actual agent
The gateway binds to a local port. Nginx (or Caddy, or whatever reverse proxy you use) forwards external HTTPS traffic to that port. External services see a clean HTTPS URL; internally it's just HTTP to localhost.
Configuration
Gateway configuration lives in your OpenClaw config. Depending on your install, this is at ~/.openclaw/config.json or configured via the openclaw config CLI.
Minimum Config
{
"gateway": {
"port": 3000,
"publicUrl": "https://yourdomain.com"
}
}
port — the local port the gateway listens on. Default is 3000. Change it if something else is already using 3000.
publicUrl — the external URL that Telegram/Discord/etc will send webhooks to. This must be HTTPS. No trailing slash.
Full Config Reference
{
"gateway": {
"port": 3000,
"publicUrl": "https://yourdomain.com",
"bind": "127.0.0.1",
"timeout": 30000,
"plugins": {
"telegram": {
"enabled": true,
"path": "/webhook/telegram"
},
"discord": {
"enabled": true
}
}
}
}
bind — which interface the gateway binds to. Default is 0.0.0.0 (all interfaces). Set to 127.0.0.1 if you're using nginx as a reverse proxy and don't want the port exposed externally.
timeout — request timeout in milliseconds. Default 30 seconds. Increase if your agent sometimes takes longer to respond.
plugins.[name].path — override the webhook path for a specific plugin.
Starting the Gateway
# Start the full OpenClaw stack (agent + gateway)
openclaw start
# Check gateway status
openclaw gateway status
# Restart just the gateway
openclaw gateway restart
# View gateway logs
openclaw gateway logs
Public URL Setup
Getting your public URL right is the most common configuration pain point.
Requirements
- Must be HTTPS (HTTP webhooks are rejected by Telegram and Discord)
- Must be publicly accessible — localhost won't work
- Must not have a trailing slash
- Port 443 must reach your server (not blocked by firewall)
Option 1: Cloudflare Tunnel (Recommended for Beginners)
If you don't want to deal with nginx and SSL certificates, Cloudflare Tunnel is the cleanest option:
# Install cloudflared
curl -L https://pkg.cloudflare.com/cloudflare-main.gpg | gpg --dearmor > /usr/share/keyrings/cloudflare-main.gpg
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared focal main' | tee /etc/apt/sources.list.d/cloudflared.list
apt update && apt install cloudflared
# Authenticate and create a tunnel
cloudflared tunnel login
cloudflared tunnel create openclaw
# Configure the tunnel
cat > ~/.cloudflared/config.yml << EOF
tunnel: <your-tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json
ingress:
- hostname: yourdomain.com
service: http://localhost:3000
- service: http_status:404
EOF
# Start the tunnel as a service
cloudflared service install
systemctl start cloudflared
Your publicUrl becomes https://yourdomain.com.
Option 2: nginx Reverse Proxy + Let's Encrypt
The standard production setup:
# /etc/nginx/sites-available/openclaw
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
# Enable the site
ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
# Get SSL certificate
certbot --nginx -d yourdomain.com
Option 3: ngrok (Development Only)
For local development or quick testing, ngrok creates a temporary public URL:
ngrok http 3000
You'll get a URL like https://abc123.ngrok.io. Set that as your publicUrl and it works immediately. Don't use this for production — the URL changes every restart and the free tier has connection limits.
How Telegram Webhook Registration Works
When OpenClaw starts with a Telegram plugin configured, it automatically registers your webhook URL with Telegram's API:
POST https://api.telegram.org/bot{TOKEN}/setWebhook
{
"url": "https://yourdomain.com/webhook/telegram"
}
You can verify this is set correctly:
curl "https://api.telegram.org/bot{YOUR_BOT_TOKEN}/getWebhookInfo"
Response should show your URL and "has_custom_certificate": false if using a proper SSL cert.
If the webhook URL is wrong (pointing to localhost, old domain, etc.), Telegram can't reach your agent.
Troubleshooting
Gateway Not Starting
# Check if something's already on port 3000
lsof -i :3000
ss -tlnp | grep 3000
# Check openclaw logs
journalctl -u openclaw -n 50
openclaw gateway logs
If port 3000 is taken, change the port in your config and update your nginx proxy_pass accordingly.
Messages Not Arriving
Work through this checklist in order:
Is the gateway running?
curl http://localhost:3000/healthShould return 200. If it hangs or connection refused, gateway is down.
Is the public URL reachable?
curl https://yourdomain.com/healthFrom another machine or phone data. If this fails but localhost works, it's a nginx/firewall issue.
Is the firewall open?
ufw status # Should show 80 and 443 ALLOWIs the webhook registered?
curl "https://api.telegram.org/bot{TOKEN}/getWebhookInfo"Check the URL matches your current
publicUrl.Is SSL valid?
curl -I https://yourdomain.comShould return 200 or 301, not SSL errors. Let's Encrypt certs expire every 90 days — certbot auto-renews but check if it's been failing.
Webhook Returns 403 or 401
Your gateway may have authentication enabled. Check if there's an auth section in your config and whether incoming webhook requests include the required token.
Gateway Starts but Agent Doesn't Respond
The gateway is working but the agent runtime isn't. Check:
- Your LLM API key is set and valid
- The agent process is running alongside the gateway
- Check agent logs:
openclaw logsorjournalctl -u openclaw
Public URL Shows Wrong Content
If your domain is pointing somewhere else (old server, different service), update your DNS. DNS propagation can take up to 48 hours but usually resolves within minutes if you flush your local cache:
# On Linux/Mac
sudo systemd-resolve --flush-caches
# Or check propagation
dig yourdomain.com +short
Gateway in Production: Best Practices
Use bind: "127.0.0.1" — Don't expose the gateway port directly. Let nginx handle the public-facing side. This prevents direct access to the gateway bypassing your reverse proxy.
Set up health monitoring — Point UptimeRobot or Better Uptime at https://yourdomain.com/health. You'll know within minutes if the gateway goes down.
Log rotation — Gateway logs can grow. Set up logrotate or use journald's built-in rotation if running via systemd.
Keep your SSL cert renewed — If using certbot, verify the auto-renewal timer is active: systemctl status certbot.timer. A lapsed cert means Telegram stops delivering messages silently.
For full hosting setup context, see OpenClaw Hosting: Running Your Agent 24/7.
Got your gateway configured and want your agent actually doing something useful? Start by adding one concrete workflow and one concrete skill that save you time immediately.