DEV Community

John Wick
John Wick

Posted on

Deploy a Telegram Bot on Koyeb Without It Going Idle

A step-by-step tutorial to deploy a Telegram bot on Koyeb with proper health checks and zero idle downtime, using StayPresent.

Deploy a Telegram Bot on Koyeb Without It Going Idle

Koyeb is a solid choice for hosting a Telegram bot — fast deploys, a generous free tier, support for both Git-based and Docker-based builds. But like most PaaS platforms, it expects your service to respond over HTTP, and a Pyrogram or python-telegram-bot script doesn't do that on its own. This tutorial walks through deploying a Telegram bot on Koyeb the right way, so it stays healthy and online instead of idling out.

Table of Contents

  1. Why Telegram Bots Go Idle on Koyeb
  2. Step 1: Install StayPresent
  3. Step 2: Wrap Your Bot's Entry Point
  4. Step 3: Read Koyeb's Assigned Port
  5. Step 4: Choose Your Deploy Path (Git or Docker)
  6. Step 5: Set Koyeb's Health Check Path
  7. Step 6 (Optional): Prevent Scale-to-Zero Idle
  8. Verifying the Deployment
  9. FAQs
  10. Conclusion

Why Telegram Bots Go Idle on Koyeb

A Telegram bot polls or listens for updates from Telegram's own servers — it's an outbound connection, not an inbound one. Koyeb's health checks expect the opposite: something listening on a port it can reach. Without that, Koyeb has no way to distinguish "this bot is working perfectly" from "this bot is broken," and treats the deployment as unhealthy.

Step 1: Install StayPresent

pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode
# requirements.txt
staypresent[prod]
pyrogram
Enter fullscreen mode Exit fullscreen mode

Step 2: Wrap Your Bot's Entry Point

Keep your bot's actual logic in bot.py, untouched. Create main.py:

import staypresent

staypresent.web.json({"status": "running"})

staypresent.run("bot.py")
Enter fullscreen mode Exit fullscreen mode

Step 3: Read Koyeb's Assigned Port

import os
import staypresent

staypresent.web.json({"status": "running"})

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
)
Enter fullscreen mode Exit fullscreen mode

Step 4: Choose Your Deploy Path (Git or Docker)

Git-based (buildpack): Koyeb detects requirements.txt and builds automatically. Set the run command to:

python main.py
Enter fullscreen mode Exit fullscreen mode

Docker-based (useful if your bot needs system packages like ffmpeg):

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
Enter fullscreen mode Exit fullscreen mode

main.py is identical either way — only the deployment mechanism changes.

Step 5: Set Koyeb's Health Check Path

In Koyeb's service settings, point the health check explicitly at /health rather than the default:

staypresent.web.json({"status": "running", "version": "1.0"})
# /health still returns {"status": "ok"} independently of the above
Enter fullscreen mode Exit fullscreen mode

This keeps platform health checks stable even if you later change what / serves.

Step 6 (Optional): Prevent Scale-to-Zero Idle

If your specific Koyeb service type is subject to scale-to-zero behavior you want to avoid, add a self-ping against your own public URL:

staypresent.cron("https://your-app.koyeb.app", interval=240)
Enter fullscreen mode Exit fullscreen mode

Verifying the Deployment

Deploy, then check Koyeb's dashboard — the service should report healthy rather than cycling through restarts. Visit https://your-app.koyeb.app/health directly to confirm it returns {"status": "ok"}. On a recent StayPresent version, /status also gives you a live dashboard showing uptime over time, which is the easiest way to confirm the fix is holding rather than just working once.

FAQs

Does this work with python-telegram-bot instead of Pyrogram?
Yes — the fix is entirely about the entry point, not which Telegram library your bot uses internally.

Do I need Docker for a simple bot?
No — Git-based buildpack deploys handle standard Python dependencies fine; Docker is only needed for extra system-level packages.

Can I reuse this main.py if I later move to Render or Railway?
Yes — as long as PORT is read from the environment, the same file works unchanged across platforms following the same convention.

Conclusion

A Telegram bot going idle on Koyeb almost always comes down to a missing HTTP port, not a problem with the bot's own polling logic. Wrapping your existing bot in staypresent.run(), reading PORT dynamically, and pointing Koyeb's health check at /health solves it completely — Git-based or Docker-based, with no changes to your bot's actual code.

pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)