Deploy a koyeb python bot with proper health checks, port binding, and crash recovery using StayPresent — Git and Docker deploy paths covered.
Run Python Bots Without Sleep On Koyeb With StayPresent
Koyeb supports deploying straight from a Git repository or from a Dockerfile, and like most serverless-leaning PaaS platforms, it evaluates your service's health through HTTP checks against a port it expects your app to bind. A koyeb python bot — a Discord bot, Telegram bot, or background worker — needs that same small HTTP layer every other platform in this series requires, and StayPresent provides it with the same one-line setup regardless of which Koyeb deploy path you use.
Table of Contents
- Two Ways to Deploy on Koyeb
- The Port Binding Requirement
- Setting Up StayPresent
- Configuring Koyeb's Health Check Path
- Self-Ping Considerations
- Crash Recovery
- Full Working Example (Git-Based)
- Full Working Example (Docker-Based)
- Best Practices
- Common Mistakes
- FAQs
- Conclusion
Two Ways to Deploy on Koyeb
Koyeb supports two primary deployment paths for a Python service: a Git-based buildpack deploy, where Koyeb detects and builds your app automatically from requirements.txt, and a Dockerfile-based deploy, where you provide the full container definition yourself. Both ultimately run the same command you specify and expect the same thing from it: a bound HTTP port.
The Port Binding Requirement
Koyeb injects a PORT environment variable, exactly like Render, Railway, and Heroku:
import os
import staypresent
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
)
Without something bound to that port, Koyeb's health checks will report the service as unhealthy — independent of whether your bot itself is running perfectly fine internally.
Setting Up StayPresent
For a Git-based deploy, add the production extra to requirements.txt:
staypresent[prod]
And set your main.py:
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
)
Koyeb's run command:
python main.py
Configuring Koyeb's Health Check Path
By default, a platform's health check often targets /. StayPresent's built-in /health endpoint — which always returns {"status": "ok"} regardless of what's configured at your root route — is generally the better target, since it stays stable even if you later change what / serves:
staypresent.web.json({"status": "running", "version": "1.0"})
# /health remains {"status": "ok"} independently
In Koyeb's service settings, set the health check path explicitly to /health rather than relying on the default.
Self-Ping Considerations
Koyeb's specific behavior around scaling-to-zero or idle handling depends on the service type and plan you've configured — check Koyeb's current documentation for your particular setup rather than assuming. If your deployment is subject to any form of inactivity-based scaling you want to avoid, staypresent.cron() can generate outbound traffic against your own public URL:
staypresent.cron("https://my-app.koyeb.app", interval=240)
Crash Recovery
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
restart_on_crash=True,
max_restarts=5,
restart_delay=2.0,
)
If restarts are ultimately exhausted, StayPresent exits the process with the bot's original exit code, letting Koyeb's own deployment-level restart behavior serve as a final backstop.
Full Working Example (Git-Based)
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
restart_on_crash=True,
max_restarts=5,
)
# requirements.txt
staypresent[prod]
python-telegram-bot
Full Working Example (Docker-Based)
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
main.py is identical to the Git-based example above — the deploy mechanism changes, the StayPresent configuration doesn't.
Best Practices
- Set the health check path to
/healthexplicitly in Koyeb's dashboard rather than leaving it on a default that may target/. - Use the Docker deploy path if your bot has system-level dependencies (e.g.
ffmpeg) that a buildpack deploy won't install automatically. - Keep
main.pyplatform-agnostic (readingPORTfrom the environment, targeting the correct public URL forcron()) so the same file works unchanged if you later move to Render or Railway.
Common Mistakes
- Leaving the health check path on a default that doesn't match what your root route actually serves, causing false-negative health failures.
-
Assuming a Git-based deploy and a Docker-based deploy require different StayPresent configuration. They don't — only the deployment mechanism around
main.pychanges. -
Forgetting
ffmpeg,ImageMagick, or other system packages a bot might depend on, which a plain Git buildpack deploy won't install — this calls for the Docker path instead.
FAQs
Does Koyeb require a Dockerfile?
No — Git-based buildpack deploys work for standard Python projects without one; Docker is only needed for more customized environments.
Can I use the exact same main.py across Koyeb, Render, and Railway?
Yes, as long as PORT is read from the environment and any self-ping URL is configured per-platform.
Does /health need to be manually created?
No — it's provisioned automatically by StayPresent unless you explicitly register your own response there.
Conclusion
A koyeb python bot, whether deployed via Git or Docker, needs the same thing every PaaS bot deployment needs: a bound HTTP port and a reliable health check target. StayPresent provides both with an identical, minimal setup regardless of which Koyeb deploy path you choose.
pip install staypresent[prod]
Top comments (0)