A Telegram bot that only runs while your laptop is open isn't really running — it's demoing. To have it actually online, answering at 3am, surviving your reboots and its own crashes, it needs to live on a server. Here's the whole path, start to finish, with the commands.
Good news first: a bot is a tiny workload. It mostly sits idle waiting for messages, so the cheapest box runs it fine — no dedicated IP, no domain, nothing fancy.
1. Get a token from BotFather
In Telegram, message @BotFather, send /newbot, pick a name and username. It hands you a token that looks like 12345:AAH.... Treat it like a password — anyone with it controls your bot.
2. A minimal bot
SSH into the server, set up Python and the library:
sudo apt update && sudo apt install -y python3-venv
mkdir ~/mybot && cd ~/mybot
python3 -m venv venv && source venv/bin/activate
pip install python-telegram-bot
A bot that replies — ~/mybot/bot.py:
import os
from telegram.ext import ApplicationBuilder, CommandHandler
async def start(update, ctx):
await update.message.reply_text("Alive and on a server. 🟢")
app = ApplicationBuilder().token(os.environ["BOT_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.run_polling()
Note it reads the token from an environment variable — not hardcoded. That matters in the next step.
3. The part that actually keeps it running: systemd
If you just run python bot.py, it dies the moment you close SSH. A systemd service is what makes it survive logout, crashes, and reboots. Create /etc/systemd/system/mybot.service:
[Unit]
Description=Telegram bot
After=network-online.target
[Service]
WorkingDirectory=/home/youruser/mybot
Environment=BOT_TOKEN=12345:AAH...your-token
ExecStart=/home/youruser/mybot/venv/bin/python bot.py
Restart=always
RestartSec=5
User=youruser
[Install]
WantedBy=multi-user.target
Then:
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo systemctl status mybot # should say active (running)
journalctl -u mybot -f # live logs
Restart=always is the line doing the real work — crash, and it's back in 5 seconds. enable means it comes up after a reboot. That's the whole difference between "I ran a bot once" and "my bot is up."
4. Why no domain or open ports
The bot uses long polling — it reaches out to Telegram for updates, so nothing needs to reach in. No public URL, no inbound firewall rule, no dedicated IP. This is exactly why a NAT VPS (shared IP, SSH on a port) is a fine and cheap home for a bot. Webhooks exist for very high volume, but you almost certainly don't need them to start.
Honest caveats
- Token hygiene: here it's inline in the unit file for clarity — fine on a locked-down box, but for anything shared, load it from a root-only
EnvironmentFileinstead, and never commit it to git. Leaked? Revoke in BotFather, issue a new one. - Heavy bots: if your bot does the work itself (image generation, a local model), it's no longer tiny — size up accordingly.
That's it. Lock the box down first with the security checklist, drop the service in, and your bot stays online whether or not you do. On a crypto-paid VPS you can have it running a minute after you decide to.