本文へスキップ
VPS とサーバー · 6 分

Host a Telegram bot on a VPS so it runs 24/7

A bot that runs on your laptop dies every time the lid closes. On a VPS it runs around the clock and restarts itself after a crash or a reboot. Below: a minimal Python bot, a systemd service that keeps it alive, and logs you can actually read.

What you need

  • A VPS with Ubuntu 24.04 or Debian 12. For a typical bot the smallest plan is more than enough: Pulse has 2 vCPU and 2 GB of RAM for $10/month, and an aiogram bot uses 60–100 MB of it, so there is room for several bots or a small database.
  • A bot token from @BotFather.
  • SSH access to the server (see Connecting over SSH).

Heavier bots are a different story. If yours converts video with ffmpeg, runs a local ML model or keeps a large database, start at Pulse or Drive.

1. A separate user and a virtual environment

Don't run the bot as root. One extra user costs nothing and limits the damage if the bot's code has a hole.

apt update && apt install -y python3-venv
useradd -r -m -d /opt/bot -s /usr/sbin/nologin bot
sudo -u bot python3 -m venv /opt/bot/venv
sudo -u bot /opt/bot/venv/bin/pip install aiogram

2. The bot

/opt/bot/bot.py: replies to /start and echoes messages back. Replace the handlers with your logic.

import asyncio, os
from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.types import Message

dp = Dispatcher()

@dp.message(CommandStart())
async def start(m: Message):
    await m.answer("Hi! I'm running on a VPS.")

@dp.message()
async def echo(m: Message):
    await m.answer(m.text or "…")

async def main():
    await dp.start_polling(Bot(os.environ["BOT_TOKEN"]))

asyncio.run(main())

Keep the token out of the code, in a file only the bot user can read:

echo 'BOT_TOKEN=123456:ABC...' > /opt/bot/.env
chown bot:bot /opt/bot/.env /opt/bot/bot.py && chmod 600 /opt/bot/.env

3. systemd keeps it running

/etc/systemd/system/bot.service:

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

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

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now bot
systemctl status bot

Restart=always brings the bot back five seconds after any crash. enable starts it after a server reboot.

4. Logs and updates

journalctl -u bot -f            # live log
journalctl -u bot --since today # today's output

To deploy a new version, copy the file and run systemctl restart bot. If you keep the code in git, a git pull in /opt/bot followed by the restart is all the deployment most bots ever need.

Polling or webhook?

The example uses polling: the bot asks Telegram for updates itself. It needs no domain, no certificate and no open ports, which is why I'd start with it. A webhook makes sense when the bot handles a lot of traffic or already lives next to a web app with HTTPS. Then Telegram pushes updates to your URL, and you'll need a domain and a certificate (nginx and Let's Encrypt do the job).

One honest caveat: polling keeps a long-lived connection to Telegram open. That's normal, and it costs almost nothing in traffic, which is unlimited on every dedisrv VPS anyway.

Host a Telegram bot on a VPS so it runs 24/7 · dedisrv