← all posts

the best ways to run an AI agent on a VPS from telegram

Telegram is the cheapest remote control ever built for a server: a chat box you already have on your phone, wired to a bot that runs anything on your VPS. The four real ways to build that, from least to most powerful: self-hosted n8n, a headless CLI agent (like the Claude Agent SDK), roll-your-own with the Bot API, or a code-first framework like LangGraph. Pick by how much the agent needs to do on the box versus how fast you want it live.

approach what it actually is best for the catch
n8n (self-hosted) visual workflow: Telegram Trigger → AI Agent node → reply shipping a useful bot in an afternoon, wiring APIs/tools with little code it’s a workflow engine, not a long-lived reasoning loop — genuinely agentic behavior gets awkward
headless CLI agent (Claude Agent SDK / claude -p) a thin bot that hands each message to an agent with real tools on the server an agent that operates the box — files, shell, cron, deploys it can run commands. Unsandboxed, that’s a remote shell for anyone who reaches the bot
roll-your-own (Bot API + a script) python/node script talking to Telegram with an LLM call inside control, learning the plumbing, cheapest possible you write and babysit every piece: retries, state, memory, deploy
framework agent (LangGraph / PydanticAI + bot) a code-first agent graph wrapped in a Telegram bot custom multi-step logic, your own tools and memory the most code to own end to end, and you own every bug in it

how do I run an AI agent on a VPS through telegram?

Every one of these is the same three moving parts: Telegram delivers the message, an agent thinks, something keeps the process alive. What changes is who writes the middle part. n8n draws it for you. A CLI agent is the middle part, pre-built, with tools attached. Roll-your-own means you are the middle part. The choice isn’t “which is best” — it’s how much of that middle you want to own.

n8n: the fastest thing that actually works

Self-hosted n8n is the shortest path from zero to a working bot. Drop a Telegram Trigger node, connect it to the AI Agent node, wire the reply back to a Telegram send node — done, and you can bolt on tools (HTTP calls, a database, a scraper) by dragging more nodes in. It runs as a Docker container on your VPS and survives reboots if you set restart: always.

The honest ceiling: n8n is a workflow engine wearing an agent hat. For “summarize this, hit that API, reply,” it’s perfect. For an agent that loops, re-plans, and holds a real conversation across turns, you’ll be fighting the canvas. Reach for it when the job is orchestration, not open-ended reasoning.

headless CLI agent: when the bot needs to actually do things

This is the one people underestimate. Instead of an LLM that answers, you run an agent that acts — the Claude Agent SDK, or claude -p in headless mode, wrapped in a tiny bot that pipes each Telegram message in as a prompt and pipes the result back. Now “restart the service” or “check the logs and tell me what broke” isn’t a metaphor; the agent runs the command on your VPS and reports back.

That’s also exactly why it’s the dangerous one. An agent with shell access, reachable from a chat box, is a remote shell with extra steps. Two non-negotiables: lock the working directory so it can’t wander off into /etc or your keys, and allowlist your chat ID so only you can talk to it. Do both and it’s the most capable option here by a wide margin. Skip either and you’ve published a root prompt to the internet.

roll-your-own: the most control, the most babysitting

python-telegram-bot or telegraf (Node), an LLM call in the handler, and you own the whole thing. This is the right call when you’re learning how the plumbing fits together, or when the logic is specific enough that every framework feels like fighting a straitjacket. You’ll also personally implement retries, conversation state, rate limits, and error handling — all the boring parts the other options hide. Cheapest to run, most expensive in your hours.

framework agent: for custom logic you’ll maintain

LangGraph, PydanticAI, or the agent framework of the month, wrapped in a Telegram bot. This is roll-your-own with the reasoning loop already solved — graphs, tool-calling, memory, retries handled by the library. Pick it when your agent genuinely needs multi-step planning you’d otherwise hand-code, and you’re willing to own a heavier dependency. Overkill for a bot that answers questions; right-sized for one that runs a real multi-tool process.

how do I keep the bot alive on the VPS?

The bot that dies when you close SSH isn’t a bot, it’s a demo. tmux and nohup survive a logout but not a reboot or a crash. Use one of two things:

  • systemd — write a unit file, systemctl enable --now yourbot, and it restarts on crash and on reboot. This is the default for a bare script.
  • Docker with restart: always — the same guarantee, and it’s how n8n and the Claude/Ollama containers already run.

While you’re there: webhook vs polling. Long-polling (getUpdates) needs no open ports and is the easy default — fine for a personal bot. A webhook is lighter and instant but needs a public HTTPS endpoint (a reverse proxy or a tunnel). For one user driving one VPS, polling is the boring correct answer.

the one rule that matters more than the stack

A Telegram bot token is not a password. It ends up in logs, in docker inspect, in a screenshot — and the moment someone has it, they can message your bot. So the security boundary is never the token; it’s the chat-ID allowlist: on every incoming message, check chat.id against your own and drop everything else on the floor. Then, if the agent can run commands, jail it — a fixed working directory, no ambient credentials, least privilege.

The bot is the easy 20%. Keeping it alive and making sure a stranger who guesses your bot’s @handle gets silence instead of a shell — that’s the 20% that’s actually the whole job. Build the allowlist before you build anything clever.