Back to blog
tutorialtelegramopenclaw

How to Deploy an OpenClaw Bot on Telegram (The Complete Guide)

A 14-step walkthrough to deploy your own OpenClaw AI agent on Telegram — from BotFather to Docker to SSL to monitoring. Every command, every config file, every gotcha.

By ClawPort Team

Telegram is the easiest channel to connect to OpenClaw. No business verification, no API approval process, no monthly fees. Just create a bot with BotFather, paste the token, and go.

"Easy" is relative, though. When you include server setup, Docker, networking, SSL, reverse proxy, firewall, and monitoring — it's about 14 steps and 2-3 hours of work.

This guide covers every step. No hand-waving, no "just figure it out" — every command, every config file, every gotcha we've hit in production.

Before you start

You'll need:

  • A Telegram account
  • A VPS with at least 1 vCPU and 1GB RAM (2GB recommended)
  • A domain name (for SSL)
  • An API key from Anthropic, OpenAI, or OpenRouter
  • Basic comfort with the command line

Total cost: ~$5-15/month for the VPS + your AI API usage.

Step 1: Create a Telegram bot

Open Telegram and message @BotFather.

/newbot

BotFather will ask for:

  1. A name — the display name users see (e.g., "My AI Assistant")
  2. A username — must end in bot (e.g., my_ai_assistant_bot)

BotFather gives you a token that looks like:

7123456789:AAHk8mLx9-VzQPnGfR4mE_D3wKjYt5N2xMo

Save this token. You'll need it in Step 7. Don't share it publicly — anyone with this token can control your bot.

Optional but recommended — set bot commands and description:

/setdescription
/setabouttext
/setuserpic

Step 2: Get a VPS

You need a Linux server. Any provider works. Here's what matters:

SpecMinimumRecommended
CPU1 vCPU2 vCPU
RAM1 GB2 GB
Storage10 GB20 GB
OSUbuntu 22.04+Ubuntu 24.04

Provider pricing (as of March 2026):

ProviderSpecPrice
Hetzner CX222 vCPU, 4GB€3.99/mo
Contabo VPS S4 vCPU, 8GB€5.99/mo
DigitalOcean1 vCPU, 2GB$12/mo
AWS Lightsail1 vCPU, 2GB$12/mo

Hetzner and Contabo give you the most bang for your buck in Europe. DigitalOcean and Lightsail are simpler if you're in the US.

First things after login:

# Update everything
apt update && apt upgrade -y

# Add swap (prevents OOM crashes — ask us how we know)
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# Set up basic firewall
ufw allow 22    # or your SSH port
ufw allow 80
ufw allow 443
ufw enable

The swap part is not optional. OpenClaw with a single agent uses 50-80MB of RAM, but spikes during model calls. Without swap, your server will OOM-kill the process at the worst possible moment. We learned this at 3 AM.

Step 3: Install Docker

# Install Docker
curl -fsSL https://get.docker.com | sh

# Verify
docker --version

Don't install Docker from apt — it's usually an ancient version. The official script gets you the latest.

Step 4: Create the project structure

mkdir -p /opt/openclaw/{workspaces/main,config}
cd /opt/openclaw

Your directory will look like this:

/opt/openclaw/
ā”œā”€ā”€ config/
│   └── openclaw.json       # Main configuration
ā”œā”€ā”€ workspaces/
│   └── main/               # Your agent's workspace
│       ā”œā”€ā”€ SOUL.md          # Agent personality
│       ā”œā”€ā”€ AGENTS.md        # Agent instructions
│       └── MEMORY.md        # Persistent memory
└── docker-compose.yml

Step 5: Write the OpenClaw configuration

cat > config/openclaw.json << 'EOF'
{
  "version": "1",
  "gateway": {
    "port": 19001,
    "controlUi": {
      "enabled": false
    },
    "auth": {
      "rateLimit": {
        "maxAttempts": 10,
        "windowSeconds": 60,
        "lockoutSeconds": 300
      }
    },
    "trustedProxies": ["172.16.0.0/12", "127.0.0.1"]
  },
  "agents": [
    {
      "slug": "main",
      "name": "My AI Assistant",
      "model": {
        "provider": "anthropic",
        "model": "claude-sonnet-4-20250514"
      }
    }
  ],
  "channels": [
    {
      "type": "telegram",
      "agentSlug": "main",
      "config": {
        "token": "YOUR_TELEGRAM_BOT_TOKEN_HERE"
      }
    }
  ],
  "session": {
    "dmScope": "per-channel-peer"
  },
  "tools": {
    "profile": "messaging",
    "exec": { "security": "deny" },
    "elevated": { "enabled": false }
  },
  "commands": {
    "bash": false,
    "config": false,
    "restart": false
  },
  "logging": {
    "redactSensitive": true
  }
}
EOF

Replace YOUR_TELEGRAM_BOT_TOKEN_HERE with the token from Step 1.

Important config choices:

  • controlUi.enabled: false — don't expose the gateway UI to the internet (see our security guide)
  • dmScope: per-channel-peer — each user gets their own conversation (not shared)
  • tools.profile: messaging — safe tool set for a chatbot
  • exec.security: deny — your bot can't run shell commands
  • trustedProxies — tells OpenClaw to trust the reverse proxy headers

Set your API key as an environment variable (don't put it in the config file):

export ANTHROPIC_API_KEY=sk-ant-your-key-here

Or for OpenAI:

export OPENAI_API_KEY=sk-proj-your-key-here

Step 6: Write your agent's personality

This is where your bot becomes yours. Create the workspace files:

cat > workspaces/main/SOUL.md << 'EOF'
# My AI Assistant

You are a helpful AI assistant for [Your Company].

## Personality
- Friendly and professional
- Concise — keep responses under 3 paragraphs unless asked for detail
- If you don't know something, say so honestly

## What you help with
- Answering questions about [your product/service]
- Providing information and recommendations
- Scheduling and basic support tasks

## What you don't do
- You don't make purchases or financial transactions
- You don't share personal data about other users
- You don't pretend to be human
EOF

This file is the core of your agent's identity. Spend real time on it — the quality of this file directly affects how good your bot is.

Step 7: Set up Docker with proper networking

Don't do this:

# BAD — exposes port to the internet
docker run -d -p 19001:19001 openclaw/openclaw

Do this instead:

cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  openclaw:
    image: openclaw/openclaw:latest
    container_name: openclaw-main
    restart: unless-stopped
    networks:
      - openclaw-net
    ports:
      - "127.0.0.1:19001:19001"
    volumes:
      - ./config/openclaw.json:/app/openclaw.json:ro
      - ./workspaces:/app/workspaces
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.0'

networks:
  openclaw-net:
    driver: bridge
EOF

Key differences:

  • 127.0.0.1:19001:19001 — only accessible from localhost, not the internet
  • openclaw-net bridge network — container is isolated
  • memory: 512M — prevents runaway memory from killing your server
  • Config mounted read-only (:ro)

Start it:

docker compose up -d
docker logs -f openclaw-main

You should see OpenClaw start up and log that it's listening on port 19001. But it's not reachable from the internet yet — that's what the reverse proxy is for.

Step 8: Install and configure a reverse proxy

You need a reverse proxy to:

  1. Handle SSL/TLS (Telegram requires HTTPS for webhooks)
  2. Only expose webhook endpoints (block everything else)
  3. Add rate limiting

We'll use Caddy because it handles SSL automatically:

apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install caddy

Configure it:

cat > /etc/caddy/Caddyfile << 'EOF'
bot.yourdomain.com {
    # Only allow webhook endpoints
    handle /api/telegram/webhook {
        reverse_proxy 127.0.0.1:19001
    }

    # Block everything else
    handle /api/* {
        respond "Forbidden" 403
    }

    handle {
        respond "Forbidden" 403
    }
}
EOF

systemctl restart caddy

Caddy automatically provisions an SSL certificate from Let's Encrypt. No certbot, no cron renewal — it just works.

If you prefer nginx:

server {
    listen 443 ssl;
    server_name bot.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/bot.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bot.yourdomain.com/privkey.pem;

    location /api/telegram/webhook {
        proxy_pass http://127.0.0.1:19001;
        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;

        # Rate limiting
        limit_req zone=webhooks burst=10;
    }

    location / {
        return 403;
    }
}

Step 9: Point your domain

Add a DNS A record:

bot.yourdomain.com → YOUR_SERVER_IP

If you're using Cloudflare, enable the orange cloud (proxy) for free DDoS protection and WAF.

Wait for DNS propagation (usually 1-5 minutes with Cloudflare, up to 48 hours with other providers).

Verify SSL is working:

curl https://bot.yourdomain.com/api/telegram/webhook
# Should return 405 (Method Not Allowed) or similar — that's fine
# If you get a connection error, DNS hasn't propagated or SSL isn't ready

Step 10: Set the Telegram webhook

Tell Telegram where to send messages:

curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=https://bot.yourdomain.com/api/telegram/webhook"

Expected response:

{"ok": true, "result": true, "description": "Webhook was set"}

Verify the webhook is active:

curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getWebhookInfo" | python3 -m json.tool

Check that:

  • url matches your domain
  • has_custom_certificate is false (Let's Encrypt handles it)
  • pending_update_count is 0 or low
  • last_error_message is empty

Step 11: Test the bot

Open Telegram, find your bot by its username, and send a message.

You: Hello!
Bot: Hi there! I'm your AI assistant. How can I help you today?

If nothing happens, check the logs:

docker logs openclaw-main --tail 50

Common issues at this stage:

ProblemCauseFix
Bot doesn't respondWebhook URL wrongRe-run Step 10
"Unauthorized" in logsBot token wrongCheck token in config
"Connection refused"Reverse proxy not reaching containerCheck port binding
SSL error in webhookCertificate not readyWait 2 min, retry
Bot responds but gibberishAPI key invalidCheck ANTHROPIC_API_KEY

Step 12: Set up auto-updates

OpenClaw releases updates frequently. You don't want to SSH in and manually pull new images.

Watchtower monitors your containers and can notify you of available updates:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --monitor-only \
  --label-enable \
  --notifications email \
  --notification-email-from [email protected] \
  --notification-email-to [email protected] \
  --notification-email-server smtp.resend.com \
  --notification-email-server-port 587 \
  --notification-email-server-user resend \
  --notification-email-server-password re_YOUR_RESEND_KEY

Use --monitor-only — you don't want Watchtower to automatically restart your bot during a conversation. Get notified, then update manually when convenient:

docker compose pull
docker compose up -d

Add the label to your OpenClaw container so Watchtower monitors it:

# In docker-compose.yml, add under the openclaw service:
labels:
  - "com.centurylinklabs.watchtower.enable=true"

Step 13: Configure the firewall

You already set up UFW in Step 2, but let's make sure it's right:

ufw status verbose

You should see:

22/tcp     ALLOW IN    Anywhere     # SSH
80/tcp     ALLOW IN    Anywhere     # HTTP (for SSL redirect)
443/tcp    ALLOW IN    Anywhere     # HTTPS

You should NOT see port 19001. That port should only be accessible via the reverse proxy.

If you see it:

ufw delete allow 19001

Remember: Docker bypasses UFW by default. That's why the 127.0.0.1 port binding in Step 7 is critical. UFW alone won't protect you.

Step 14: Ongoing maintenance

Your bot is live. Here's what needs ongoing attention:

Weekly:

  • Check docker logs openclaw-main for errors
  • Verify bot responds to a test message
  • Review any Watchtower notifications

Monthly:

  • apt update && apt upgrade on the server
  • Check disk space: df -h
  • Review memory usage: free -h
  • Run openclaw security audit if available

When things break (and they will):

# Check if container is running
docker ps

# Restart if needed
docker compose restart

# Check resource usage
docker stats openclaw-main

# Nuclear option — recreate
docker compose down
docker compose pull
docker compose up -d

The full picture

Let's count what you just set up:

  1. āœ… Telegram bot (BotFather)
  2. āœ… VPS with swap and firewall
  3. āœ… Docker
  4. āœ… Project structure
  5. āœ… OpenClaw configuration
  6. āœ… Agent personality
  7. āœ… Docker Compose with bridge networking
  8. āœ… Reverse proxy with SSL
  9. āœ… DNS
  10. āœ… Telegram webhook
  11. āœ… Testing
  12. āœ… Auto-update monitoring
  13. āœ… Firewall hardening
  14. āœ… Maintenance plan

That's 14 steps, ~2-3 hours of work for someone who's done it before, and 4-6 hours if you haven't. Plus ongoing maintenance every week.

And this is just one agent on one channel.

Want to add WhatsApp? That's another 22 steps (coming soon). A second agent? More port management, more reverse proxy config, more monitoring.


Or... deploy on ClawPort in 60 seconds. Name your bot, paste the Telegram token, pick your model. We handle Docker, SSL, networking, security hardening, monitoring, and updates. Starting at $10/month. Get started →

Ready to deploy your AI agent?

Get started with ClawPort in 60 seconds. No credit card required.

Get Started Free