⟵ Все статьи
Читать на:

How to Run a Telegram Bot on a VPS: Deployment, Auto-Start, and Webhooks

How to Run a Telegram Bot on a VPS: Deployment, Auto-Start, and Webhooks

Writing a bot is half the battle. The second half begins when you need to move it off your laptop to a place where it will respond around the clock: without crashing after a lost connection, with logs, automatic restarts, and a clear way to roll out updates.

This guide is about exactly that second half. It works for a bot in any language, but all examples are given for Python, as it is the most common case.

Why a Bot Needs a Dedicated Server

Telegram does not store your code: it only delivers messages to a program that must be running. As long as it runs on your home computer, the bot dies with every reboot, sleep mode, or Wi-Fi switch.

Free platforms for running code solve this problem only halfway: they put the process to sleep during idle time, limit uptime, and do not allow you to store files and a database properly. A VPS is free from these limitations: it is your machine that simply never turns off.

Step 1. Get a Server

In the NodexGo panel, click Create Server. Then follow the steps: location — your real ping to each one is shown next to it; plan and system image; server name; payment period of 1, 3, 6, or 12 months.

On resources: a bot running on polling is fine with the entry-level plan with 1 vCPU and 2 GB of RAM. Extra capacity is only needed if the bot processes images, maintains a large database, or sends messages to tens of thousands of users. Choose Ubuntu 24.04 as the image — the commands below are written for it.

A minute after payment, the server is ready: the IP address and root password will appear in the panel and be sent to your email.

A round-the-clock server for your bot — starting from 1 vCPU and 2 GB, ready in one minute.

Create a Server

Step 2. Basic Server Configuration

Connect and update the system:

ssh root@server-IP-address
apt update && apt upgrade -y

Create a separate user: running the bot as root is a bad habit — any error in the code gets full access to the entire machine.

adduser bot
usermod -aG sudo bot

Close everything unnecessary with a firewall. Allow SSH before enabling ufw, otherwise you will cut off your own access:

ufw allow OpenSSH
ufw enable

Install Python and git:

apt install -y python3 python3-venv python3-pip git

Step 3. Transfer the Bot Code to the Server

The most convenient way is via git: updating later will take just one command. Log in as the bot user and clone the repository:

su - bot
git clone https://github.com/your-account/your-bot.git ~/bot
cd ~/bot

If there is no repository, you can simply copy the files from your computer — run this command in your local terminal, not on the server:

scp -r ./mybot bot@server-IP-address:~/bot

Install dependencies into a virtual environment:

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Step 4. Secrets Go in a Separate File

The bot token, database password, and keys must not be in the code: their place is in a .env file that does not end up in the repository.

nano ~/bot/.env
BOT_TOKEN=your-token-from-BotFather
ADMIN_ID=your-numeric-id
DATABASE_URL=sqlite:///bot.db
chmod 600 ~/bot/.env

Make sure .env is listed in .gitignore — otherwise your token will end up in a public repository on the next commit.

Step 5. Auto-Start via systemd

systemd is the standard way to keep a program alive: it starts the bot when the server boots and restarts it after any crash. Exit to root and create a service:

exit
nano /etc/systemd/system/bot.service
[Unit]
Description=Telegram bot
After=network.target

[Service]
Type=simple
User=bot
WorkingDirectory=/home/bot/bot
EnvironmentFile=/home/bot/bot/.env
ExecStart=/home/bot/bot/venv/bin/python /home/bot/bot/main.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Enable and start:

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

You can verify that the bot would actually survive a server reboot the honest way:

reboot

Reconnect after half a minute and confirm that the service came up on its own.

Step 6. Logs and Code Updates

All bot output goes to the system journal. Live view and the last one hundred lines:

journalctl -u bot -f
journalctl -u bot -n 100 --no-pager

Deploying a new version comes down to three commands:

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

The journal grows over time — limit it so it does not eat up your disk:

journalctl --vacuum-size=200M

Polling or Webhook

Polling — the bot asks Telegram once a second whether there are any new messages. This is the simplest approach: it works right away and requires no domain or certificate. For most bots, this is sufficient forever.

A webhook is the opposite: Telegram itself sends updates to your address. It is more efficient and responds faster, but requires a domain, an HTTPS certificate, and an open port 443. It makes sense when there is truly a high volume of messages.

If you chose a webhook, put a reverse proxy with automatic certificate handling in front of the bot — Caddy does this most easily:

apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy

Point the domain A record to the server IP and describe the proxying in two lines in /etc/caddy/Caddyfile:

bot.example.com {
    reverse_proxy 127.0.0.1:8080
}
ufw allow 80/tcp
ufw allow 443/tcp
systemctl reload caddy

Caddy will issue and renew the certificate automatically. The webhook address in the bot code is https://bot.example.com/your-secret-path.

Backups

If the bot stores data, it needs to be backed up separately: the server is not a backup. The simplest option for SQLite is a daily scheduled copy. Open the scheduler:

crontab -e

And add a line — a copy every day at 4 AM with the date in the filename:

0 4 * * * cp /home/bot/bot/bot.db /home/bot/backup-$(date +\%F).db

For PostgreSQL, use pg_dump instead of copying the file. At least once a month, verify that the backup actually opens — a backup that has never been restored does not count as a backup.

Common Issues

Error Conflict: terminated by other getUpdates request — the bot is running twice with the same token. Usually the second copy is still running on your home computer: stop it.

The service keeps restarting — check journalctl; almost always it is an incorrect path in ExecStart or a .env file that was not loaded.

The bot works but gradually slows down — check memory with the free -h command; it is often a leak or a bloated journal. If resources are genuinely low, the server card has an Upgrade Plan button: the plan switches to a higher tier, the disk and IP are preserved, and nothing needs to be migrated.

No access to the server at all — in the panel, every server has a VNC web console that works independently of SSH and the network, along with buttons to Change Root Password and Reinstall OS.

In Brief

Rent a VPS, create a separate user, transfer the code via git, move secrets to .env, attach the bot to systemd with Restart=always, and monitor it via journalctl. After that, an update is just a git pull and a service restart, and the bot responds even when your computer is off.

Choose the configuration for your bot — upgrading to a higher plan takes just one click.

View Plans

Мы используем файлы cookie: необходимые — для входа в аккаунт и языка интерфейса, аналитические — чтобы понимать, какими страницами пользуются. Сторонних рекламных систем у нас нет. Подробнее