A tutorial for deploying a python bot on Fly.io with proper health checks and no unwanted machine suspension, using StayPresent.
How to Run a Python Bot on Fly.io Without It Sleeping
Fly.io deploys apps as lightweight VMs ("Machines") close to your users, and its free allowance is a popular choice for small bots. It also has a specific behavior worth understanding before you deploy: Fly can automatically stop machines when they're idle, and restart them on the next incoming request — great for a web app, potentially disruptive for a bot that needs to stay connected continuously. This tutorial covers deploying a Python bot on Fly.io correctly, avoiding both the standard HTTP-port issue and Fly's specific auto-stop behavior.
Table of Contents
- How Fly.io's Health Checks Work
- Fly's Auto-Stop/Auto-Start Behavior
- Step 1: Install StayPresent
- Step 2: Wrap Your Bot's Entry Point
- Step 3: Configure
fly.toml - Step 4: Disable Auto-Stop for a Bot Machine
- Step 5: Deploy
- Verifying It's Actually Staying Up
- FAQs
- Conclusion
How Fly.io's Health Checks Work
Like most modern platforms, Fly can be configured to check your service over HTTP and restart it if it stops responding. A Discord or Telegram bot doesn't open an HTTP port on its own, so without something bridging that gap, a configured health check has nothing to actually verify.
Fly's Auto-Stop/Auto-Start Behavior
This is the part that's specific to Fly and worth calling out: Fly Machines can be configured to automatically stop when idle and start again on the next request — a cost-saving feature that makes sense for a typical web app, but works against a bot that's supposed to maintain a continuous connection to Discord or Telegram in the background, with no incoming HTTP requests driving that connection at all.
Step 1: Install StayPresent
pip install staypresent[prod]
# requirements.txt
staypresent[prod]
Step 2: Wrap Your Bot's Entry Point
Your bot logic in bot.py stays unchanged:
# main.py
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
)
Step 3: Configure fly.toml
app = "my-bot"
[env]
PORT = "8080"
[[services]]
internal_port = 8080
protocol = "tcp"
[[services.ports]]
port = 80
handlers = ["http"]
[[services.tcp_checks]]
interval = "15s"
timeout = "2s"
This gives Fly the HTTP surface it's looking for to consider your machine healthy.
Step 4: Disable Auto-Stop for a Bot Machine
This is the step specific to Fly that's easy to miss. In fly.toml, make sure auto-stop isn't configured against your bot service — a bot needs to stay running continuously, not spin down between requests the way a typical stateless web app would:
[[services]]
internal_port = 8080
protocol = "tcp"
auto_stop_machines = false
auto_start_machines = false
min_machines_running = 1
min_machines_running = 1 specifically ensures Fly always keeps at least one instance of your bot running, rather than scaling it down to zero during a quiet period.
Step 5: Deploy
fly deploy
Verifying It's Actually Staying Up
Check fly status to confirm your machine is showing as started consistently, not cycling between stopped and started. You can also hit /health directly via your app's Fly URL to confirm StayPresent's HTTP server is responding. On a recent StayPresent version, /status gives you an ongoing uptime view, which is the clearest way to confirm the bot is staying connected over time rather than restarting repeatedly.
FAQs
Do I need staypresent.cron() on Fly.io too?
Generally no, if auto_stop_machines = false and min_machines_running = 1 are set correctly — those settings are what actually control Fly's idle behavior, unlike platforms where self-pinging is the main lever.
Does this work the same for a Telegram bot as a Discord bot?
Yes — the fix addresses the HTTP port and auto-stop behavior generically, regardless of which bot library or platform API your bot talks to.
Will min_machines_running = 1 cost more than the free tier allows?
Fly's specific pricing and free allowances change over time — check Fly's current pricing page for your usage before assuming either way.
Conclusion
Running a Python bot reliably on Fly.io means solving two separate things: giving Fly's health check an HTTP port to verify (via staypresent.run()), and explicitly disabling Fly's auto-stop behavior so your bot isn't treated like a scale-to-zero web app. Both together keep your bot connected and online continuously, the way a bot actually needs to run.
pip install staypresent[prod]
Top comments (0)