What you'll need
- A VPS on Ubuntu 22.04/24.04 with root or sudo.
- A bot token from @BotFather (open Telegram, message @BotFather, send /newbot, follow the prompts).
- Basic familiarity with the terminal.
Step 1: Create a dedicated user and project
Never run a bot as root. Create an unprivileged user that owns the code.
adduser --system --group --home /opt/telebot telebot
apt update && apt install -y python3 python3-venv python3-pip
cd /opt/telebotStep 2: Install dependencies in a virtualenv
A virtualenv keeps the bot's packages isolated from the system Python.
python3 -m venv /opt/telebot/venv
/opt/telebot/venv/bin/pip install --upgrade pip
/opt/telebot/venv/bin/pip install python-telegram-bot==21.6Step 3: Write the bot
Save this as /opt/telebot/bot.py. It reads the token from an environment variable (so the secret never sits in your code) and replies to /start and any text message.
import os
import logging
from telegram import Update
from telegram.ext import (
Application, CommandHandler, MessageHandler, ContextTypes, filters,
)
logging.basicConfig(level=logging.INFO)
async def start(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('Bot is alive. Send me anything.')
async def echo(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)
def main():
token = os.environ['BOT_TOKEN']
app = Application.builder().token(token).build()
app.add_handler(CommandHandler('start', start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
app.run_polling()
if __name__ == '__main__':
main()chown -R telebot:telebot /opt/telebotStep 4: Store the token safely
Put the token in an environment file readable only by root, and point systemd at it.
BOT_TOKEN=123456:ABC-YourTokenFromBotFatherchmod 600 /etc/telebot.envStep 5: Create the systemd service
This unit runs the bot as the telebot user, loads the token, and restarts automatically on crash.
[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target
[Service]
User=telebot
Group=telebot
EnvironmentFile=/etc/telebot.env
WorkingDirectory=/opt/telebot
ExecStart=/opt/telebot/venv/bin/python /opt/telebot/bot.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetsystemctl daemon-reload
systemctl enable --now telebot
systemctl status telebotStep 6: Read the logs
All stdout/stderr goes to the journal. Follow it live or grep the last hour.
journalctl -u telebot -f
journalctl -u telebot --since '1 hour ago'Keep it running and updating
- Deploy new code: edit bot.py, then systemctl restart telebot.
- Polling (used here) needs no open inbound ports. If you switch to webhooks, open 443 and put the bot behind a reverse proxy with TLS.
- Prefer pm2 or screen for Node bots? Those work too, but systemd is the only option that reliably survives a reboot without extra setup.
A polling bot is almost free to host: it sips CPU and RAM, so the smallest box is plenty. With hourly billing you can deploy in about 60 seconds, run the bot for cents while you test, and destroy the server the moment the project is over.