How to Run a Telegram Bot 24/7 on a VPS (systemd)
Your bot shouldn't go silent when your laptop sleeps. Learn how to run a Python Telegram bot 24/7 on an Ubuntu 24.04 VPS with systemd, store the token safely and follow the logs.
You built a Telegram bot, tested it on your own computer and it works. The problem: as soon as the laptop goes to sleep, the Wi-Fi drops or Windows decides to reboot for updates, the bot goes quiet — and your users are left waiting. This guide shows how to run a Telegram bot 24/7 on a VPS the proper way: a dedicated user, a Python virtual environment, a token that never lives in your code, and a systemd service that brings the bot back automatically if it ever crashes. Commands are for Ubuntu 24.04 and work the same on Debian 12.
Why a VPS instead of your home computer?
- Always on: a VPS runs on a server in a data center that never sleeps. Power cuts at home, router reboots or closing your laptop don't affect the bot.
- Stable connection and IP: home connections change IPs and drop occasionally; a server connection is far more predictable.
- Your machine stays free: no need to leave a laptop running day and night.
- Low cost: a simple Telegram bot needs very few resources, so a small Linux VPS is usually enough.
We covered the general approach to running Python apps on a server in running a Python app on a VPS. Here we focus specifically on Telegram bots and systemd.
Step 1: Create the bot with BotFather and get the token
Open @BotFather in Telegram, send /newbot, choose a display name and a username ending in _bot. BotFather replies with a token that looks like this:
123456789:AAF...a-long-random-string
Treat the token like a password. Don't hard-code it, don't push it to GitHub, don't post it in screenshots. If it leaks, use /revoke in BotFather to issue a new one.
Step 2: Prepare the server
Connect over SSH or through the web terminal in the customer panel, then update the system:
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-venv python3-pip git
Create a dedicated user for the bot
Running a bot as root is an unnecessary risk: a bug in your code or in a dependency could hand an attacker the whole server. Instead, create a system user that cannot log in:
sudo adduser --system --group --home /opt/telegram-bot botuser
This creates a botuser account with no password and no login shell, plus the /opt/telegram-bot directory.
Step 3: Virtual environment and library
Give the bot its own virtual environment so you never touch system Python. Ubuntu 24.04 blocks system-wide pip install anyway, so a venv is the right way:
sudo -u botuser python3 -m venv /opt/telegram-bot/venv
sudo -u botuser /opt/telegram-bot/venv/bin/pip install --upgrade pip
sudo -u botuser /opt/telegram-bot/venv/bin/pip install "python-telegram-bot>=21"
Since version 20, python-telegram-bot is fully async. The example below targets version 21 and newer.
Step 4: Write a minimal bot
Create the file:
sudo nano /opt/telegram-bot/bot.py
Paste this code:
import logging
import os
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
logging.basicConfig(
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
level=logging.INFO,
)
TOKEN = os.environ["BOT_TOKEN"]
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.effective_message.reply_text("Hi! This bot runs 24/7 on a VPS.")
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.effective_message.reply_text(update.effective_message.text)
def main() -> None:
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
app.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
Hand the file over to the bot user:
sudo chown botuser:botuser /opt/telegram-bot/bot.py
Notice that the token isn't in the code — it's read from the BOT_TOKEN environment variable.
Step 5: Store the token in a protected file
sudo nano /etc/telegram-bot.env
Add a single line (no quotes):
BOT_TOKEN=123456789:AAF...your-token
Make it readable by root only:
sudo chown root:root /etc/telegram-bot.env
sudo chmod 600 /etc/telegram-bot.env
systemd reads this file as root when the service starts and passes the variable to the bot, so not even botuser can read the file directly.
Step 6: Create the systemd service
This is the heart of the setup. systemd starts the bot at boot, restarts it on failure and collects its output in the journal.
sudo nano /etc/systemd/system/telegram-bot.service
[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=botuser
Group=botuser
WorkingDirectory=/opt/telegram-bot
EnvironmentFile=/etc/telegram-bot.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/telegram-bot/venv/bin/python /opt/telegram-bot/bot.py
Restart=always
RestartSec=5
# Basic hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/telegram-bot
[Install]
WantedBy=multi-user.target
What the key lines do:
Restart=always+RestartSec=5: whatever stops the bot, systemd starts it again after 5 seconds.PYTHONUNBUFFERED=1: Python output reaches the logs immediately instead of being buffered.ProtectSystem=strict+ReadWritePaths: the bot can't write to system files, only to its own directory. Keep any SQLite database or data files under/opt/telegram-bot.NoNewPrivileges=true: the process can never gain extra privileges later.
Step 7: Start the service and watch the logs
sudo systemctl daemon-reload
sudo systemctl enable --now telegram-bot
sudo systemctl status telegram-bot
If you see active (running), send /start to your bot in Telegram. To follow the live log:
sudo journalctl -u telegram-bot -f
Use sudo journalctl -u telegram-bot -n 100 --no-pager for the last 100 lines. More day-to-day commands are collected in our server management commands guide.
Want proof that the bot recovers on its own? Kill it and check again a few seconds later:
sudo systemctl kill telegram-bot
sleep 6
sudo systemctl status telegram-bot
Updating your code
If your bot lives in a Git repository, clone it into /opt/telegram-bot as botuser. Updating then takes two commands:
sudo -u botuser git -C /opt/telegram-bot pull
sudo systemctl restart telegram-bot
Added a new dependency? Install your requirements first:
sudo -u botuser /opt/telegram-bot/venv/bin/pip install -r /opt/telegram-bot/requirements.txt
And whenever you edit the service file itself, run sudo systemctl daemon-reload.
Polling or webhook?
The bot above uses long polling: it keeps asking Telegram's servers "any new updates?". The big advantage is that you don't have to open any inbound port, and you need neither a domain nor an SSL certificate. For most bots it is the simplest option and perfectly adequate.
With a webhook, Telegram pushes every update to an HTTPS URL on your server. It suits high-traffic bots, but you'll need a domain, a valid certificate and a web server in front. Our Nginx and Let's Encrypt SSL guide walks you through that part.
Same recipe for Node.js and Discord bots
systemd doesn't care about the language. For a Node.js bot, only ExecStart changes:
ExecStart=/usr/bin/node /opt/telegram-bot/index.js
Discord bots, userbots and small scheduled scripts can run the same way. Use a separate service file (for example discord-bot.service) and a separate env file for each bot.
How many resources does a bot need?
A simple command-and-reply bot typically uses a few dozen megabytes of RAM and almost no CPU, so an entry-level VPS is enough for most bots. If your bot processes images, downloads large files, calls an AI API heavily or keeps a database, plan for more RAM. You can watch RAM and CPU usage per server in the customer panel.
Frequently Asked Questions
What happens if my bot crashes?
Thanks to Restart=always, systemd restarts it within seconds. After a server reboot it starts automatically because the service is enabled. Check journalctl -u telegram-bot to see what went wrong.
Can I run several bots on one server?
Yes. Give each bot its own directory, env file and service file (bot1.service, bot2.service and so on). Just keep an eye on total RAM usage.
Isn't screen or tmux good enough?
For quick tests, yes. But the bot won't come back after a reboot, and nobody restarts it if it crashes. For anything permanent, systemd is far more reliable.
A server for your bot
TürkiyeVPS VPS plans are hosted in Istanbul and start at $0.89/month, with Ubuntu 24.04 or Debian 12, full root access and unlimited traffic. Your server is set up automatically once payment is confirmed (we currently accept USDT on TRC20), and you can connect right away through the web terminal in the customer panel. If you get stuck, reach us via live chat on the site or open a support ticket.
You might also like
If apps keep dying on your 512 MB or 1 GB VPS, swap is the first aid. Learn how to add swap on Ubuntu 24.04, p...
Planning a Metin2 server but unsure whether a VPS is enough or you need a VDS? We compare shared vs dedicated...
Point your domain to your VPS, install Nginx, publish your site and secure it with a free Let's Encrypt certif...