DEV Community

John Wick
John Wick

Posted on

Deploying Multiple Python Bots to a Single Railway Container

A tutorial for running two or more python bots on Railway inside one container and one service, with independent crash recovery for each.

Deploying Multiple Python Bots to a Single Railway Container

If you're running more than one Python bot — say, a Telegram ingestion bot and a Discord notification bot that share a database — deploying each as its own Railway service means double the hosting cost and double the configuration for something that's logically one unit. This tutorial covers deploying both bots inside a single Railway container, with each one still getting fully independent crash recovery.

Table of Contents

  1. Why Two Services Is Usually Overkill
  2. The Naive Fix and Why It Falls Short
  3. Step 1: Install StayPresent
  4. Step 2: Structure Your Project
  5. Step 3: Configure Multiple Bots in One Entry Point
  6. Step 4: Read Railway's Assigned Port
  7. Step 5: Deploy as a Single Railway Service
  8. Verifying Both Bots Are Running
  9. FAQs
  10. Conclusion

Why Two Services Is Usually Overkill

Railway (like most PaaS platforms) charges per service, and each service needs its own configuration, environment variables, and deployment pipeline. If two bots are closely related — sharing a database, a queue, or just conceptually belonging to the same project — running them as two separate Railway services duplicates all of that for no real benefit.

The Naive Fix and Why It Falls Short

A common first instinct is a shell script:

python telegram_bot.py & python discord_bot.py & wait
Enter fullscreen mode Exit fullscreen mode

This runs both, but there's no real process supervision here — if telegram_bot.py crashes, nothing restarts it, and you still haven't solved Railway's HTTP port requirement, since neither script opens one.

Step 1: Install StayPresent

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

Step 2: Structure Your Project

project/
├── main.py
├── telegram_bot.py
├── discord_bot.py
├── requirements.txt
Enter fullscreen mode Exit fullscreen mode

Both bot scripts stay exactly as they are — nothing about their internal logic needs to change.

Step 3: Configure Multiple Bots in One Entry Point

main.py:

import os
import staypresent

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

staypresent.run(
    bots=[
        {"file": "telegram_bot.py"},
        {"file": "discord_bot.py"},
    ],
)
Enter fullscreen mode Exit fullscreen mode

Each bot listed here is launched as its own subprocess, monitored independently — if telegram_bot.py crashes and restarts, discord_bot.py is completely unaffected and keeps running.

If each bot needs different environment variables:

staypresent.run(
    bots=[
        {"file": "telegram_bot.py", "env": {"ROLE": "ingestion"}},
        {"file": "discord_bot.py", "env": {"ROLE": "notifications"}},
    ],
)
Enter fullscreen mode Exit fullscreen mode

Step 4: Read Railway's Assigned Port

import os
import staypresent

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

staypresent.run(
    bots=[
        {"file": "telegram_bot.py"},
        {"file": "discord_bot.py"},
    ],
    port=int(os.getenv("PORT", 8080)),
)
Enter fullscreen mode Exit fullscreen mode

Step 5: Deploy as a Single Railway Service

Set your Railway start command to:

python main.py
Enter fullscreen mode Exit fullscreen mode

Deploy once. Both bots now run inside the same container, under one Railway service, with one hosting bill.

Verifying Both Bots Are Running

If you're on a recent StayPresent version, visit /status on your deployed URL — each bot appears as its own row, with its own uptime and restart count, so you can confirm both are actually healthy at a glance rather than guessing from Railway's own single-service view.

You can also give each bot its own lightweight endpoint for a quick manual check:

staypresent.web.json({"status": "online"}, path="/telegram")
staypresent.web.json({"status": "online"}, path="/discord")
Enter fullscreen mode Exit fullscreen mode

FAQs

Does one bot crashing affect the other?
No — each bot in the bots list gets its own restart counter and its own monitoring thread, completely independent of the others.

Can I run more than two bots this way?
Yes — bots accepts as many entries as you need, each independently supervised.

Does this work the same way on Render or Koyeb?
Yes — the same main.py and multi-bot configuration work unchanged across any platform that follows the standard $PORT convention.

Conclusion

Running multiple related Python bots on Railway doesn't require multiple services. staypresent.run(bots=[...]) supervises each one independently — separate crash recovery, separate restart counters — while sharing a single container, a single port, and a single deployment.

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

Top comments (0)