corevia_cloud Get started
← Blog

Run your Telegram or AI bot 24/7 on a VPS

Your bot works on your laptop, but it stops the moment you close the lid. To answer users day and night, it needs to run on a machine that is always on. A small Linux VPS is the simplest way to get there.

This guide shows two reliable ways to run a bot around the clock: systemd (built into Linux, no extra software) and Docker (handy if your bot already has a Dockerfile). Examples use a Python Telegram bot, with notes for Node.js.

Before you start

  • A VPS with Ubuntu 24.04 and root SSH access.
  • Your bot's code in a Git repository (private is fine), or ready to copy with scp.
  • Your bot token from BotFather and any API keys (for example, for an AI model).

Polling or webhooks?

Telegram bots receive messages in one of two ways:

  • Long polling: the bot keeps asking Telegram for new messages. It needs no domain and no open ports. This is the easiest choice for a server.
  • Webhooks: Telegram sends each message to your HTTPS address. This needs a domain, a certificate and an open port.

If you are not sure, use polling. Most bot libraries use it by default.

Option 1: systemd

1. Create a separate user

Running the bot as its own user, not as root, limits the damage if something goes wrong:

adduser --disabled-password --gecos "" bot

2. Put the code on the server

apt update && apt install -y git python3-venv
su - bot
git clone https://github.com/you/your-bot.git app
cd app
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

For Node.js, install Node from your preferred source and run npm ci instead.

3. Store secrets in an environment file

Never hard-code the token in the code or commit it to Git. Create /home/bot/app/.env:

TELEGRAM_BOT_TOKEN=123456:your-token-here
OPENAI_API_KEY=your-key-here

Then make it readable only by the bot user and go back to root:

chmod 600 /home/bot/app/.env
exit

Your code reads the values from environment variables, for example os.environ["TELEGRAM_BOT_TOKEN"] in Python or process.env.TELEGRAM_BOT_TOKEN in Node.js. Make sure .env is listed in .gitignore.

4. Create the service

As root, create /etc/systemd/system/bot.service:

[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target

[Service]
User=bot
WorkingDirectory=/home/bot/app
EnvironmentFile=/home/bot/app/.env
ExecStart=/home/bot/app/.venv/bin/python bot.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

For Node.js, use something like ExecStart=/usr/bin/node index.js (check the path with which node).

Restart=always brings the bot back if it crashes; WantedBy=multi-user.target starts it again after a server reboot.

5. Start it

systemctl daemon-reload
systemctl enable --now bot
systemctl status bot

Everyday commands

journalctl -u bot -f          # live logs
systemctl restart bot         # restart after a change
systemctl stop bot            # stop

To deploy a new version:

su - bot -c "cd app && git pull && .venv/bin/pip install -r requirements.txt"
systemctl restart bot

Option 2: Docker

If your bot has a Dockerfile, install Docker (curl -fsSL https://get.docker.com | sh) and create a docker-compose.yml next to it:

services:
  bot:
    build: .
    restart: unless-stopped
    env_file: .env

Start it and follow the logs:

docker compose up -d --build
docker compose logs -f bot

restart: unless-stopped restarts the container after crashes and reboots, unless you stopped it yourself.

Things that break bots in production

  • Two copies running at once. With polling, Telegram allows only one active connection per token. If the bot still runs on your laptop, the server copy gets conflict errors. Stop the local one.
  • Leaked tokens. If a token ever landed in Git or a chat, revoke it in BotFather and issue a new one.
  • Crash loops. If systemctl status bot shows constant restarts, read journalctl -u bot -n 100. The usual causes are a missing environment variable or a missing package.
  • The disk fills up with logs. If your bot writes its own log files, rotate them or log to standard output and let systemd or Docker handle it.
  • Nobody notices it is down. A free uptime monitor, or a tiny scheduled check that messages you when the bot does not respond, saves you from hearing about outages from users first.

Keep the server itself healthy

  • Log in with SSH keys and disable password login once keys work.
  • Enable automatic security updates: apt install -y unattended-upgrades.
  • Open only the ports you need. A polling bot needs no inbound ports besides SSH.

With this setup your bot runs on its own, restarts itself after errors and reboots, and keeps its secrets out of your code.

Need a server for this? Corevia Flow Cloud gives you a VPS with root SSH access and a public IPv4. See current plans and prices on the pricing page.

Get started →