{"id":4450,"date":"2026-08-20T03:40:54","date_gmt":"2026-08-20T03:40:54","guid":{"rendered":"https:\/\/tucumandevelopers.com\/index.php\/2026\/08\/20\/deploying-multiple-python-bots-to-a-single-railway-container\/"},"modified":"2026-08-20T03:40:54","modified_gmt":"2026-08-20T03:40:54","slug":"deploying-multiple-python-bots-to-a-single-railway-container","status":"publish","type":"post","link":"https:\/\/tucumandevelopers.com\/index.php\/2026\/08\/20\/deploying-multiple-python-bots-to-a-single-railway-container\/","title":{"rendered":"Deploying Multiple Python Bots to a Single Railway Container"},"content":{"rendered":"<div>\n<div>\n<div data-article-id=\"4439654\" id=\"article-body\">\n<blockquote>\n<p>A tutorial for running two or more python bots on Railway inside one container and one service, with independent crash recovery for each.<\/p>\n<\/blockquote>\n<h2> <a name=\"deploying-multiple-python-bots-to-a-single-railway-container\" href=\"#deploying-multiple-python-bots-to-a-single-railway-container\"> <\/a> Deploying Multiple Python Bots to a Single Railway Container <\/h2>\n<p>If you&#8217;re running more than one Python bot \u2014 say, a Telegram ingestion bot and a Discord notification bot that share a database \u2014 deploying each as its own Railway service means double the hosting cost and double the configuration for something that&#8217;s logically one unit. This tutorial covers deploying both bots inside a single Railway container, with each one still getting fully independent crash recovery.<\/p>\n<h2> <a name=\"table-of-contents\" href=\"#table-of-contents\"> <\/a> Table of Contents <\/h2>\n<ol>\n<li>Why Two Services Is Usually Overkill<\/li>\n<li>The Naive Fix and Why It Falls Short<\/li>\n<li>Step 1: Install StayPresent<\/li>\n<li>Step 2: Structure Your Project<\/li>\n<li>Step 3: Configure Multiple Bots in One Entry Point<\/li>\n<li>Step 4: Read Railway&#8217;s Assigned Port<\/li>\n<li>Step 5: Deploy as a Single Railway Service<\/li>\n<li>Verifying Both Bots Are Running<\/li>\n<li>FAQs<\/li>\n<li>Conclusion<\/li>\n<\/ol>\n<h2> <a name=\"why-two-services-is-usually-overkill\" href=\"#why-two-services-is-usually-overkill\"> <\/a> Why Two Services Is Usually Overkill <\/h2>\n<p>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 \u2014 sharing a database, a queue, or just conceptually belonging to the same project \u2014 running them as two separate Railway services duplicates all of that for no real benefit.<\/p>\n<h2> <a name=\"the-naive-fix-and-why-it-falls-short\" href=\"#the-naive-fix-and-why-it-falls-short\"> <\/a> The Naive Fix and Why It Falls Short <\/h2>\n<p>A common first instinct is a shell script: <\/p>\n<div>\n<pre><code>python telegram_bot.py &amp; python discord_bot.py &amp; <span>wait<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>This runs both, but there&#8217;s no real process supervision here \u2014 if <code>telegram_bot.py<\/code> crashes, nothing restarts it, and you still haven&#8217;t solved Railway&#8217;s HTTP port requirement, since neither script opens one.<\/p>\n<h2> <a name=\"step-1-install-staypresent\" href=\"#step-1-install-staypresent\"> <\/a> Step 1: Install StayPresent <\/h2>\n<div>\n<pre><code>pip <span>install <\/span>staypresent[prod] <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<div>\n<pre><code># requirements.txt staypresent[prod] <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"step-2-structure-your-project\" href=\"#step-2-structure-your-project\"> <\/a> Step 2: Structure Your Project <\/h2>\n<div>\n<pre><code>project\/ \u251c\u2500\u2500 main.py \u251c\u2500\u2500 telegram_bot.py \u251c\u2500\u2500 discord_bot.py \u251c\u2500\u2500 requirements.txt <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Both bot scripts stay exactly as they are \u2014 nothing about their internal logic needs to change.<\/p>\n<h2> <a name=\"step-3-configure-multiple-bots-in-one-entry-point\" href=\"#step-3-configure-multiple-bots-in-one-entry-point\"> <\/a> Step 3: Configure Multiple Bots in One Entry Point <\/h2>\n<p><code>main.py<\/code>: <\/p>\n<div>\n<pre><code><span>import<\/span> <span>os<\/span> <span>import<\/span> <span>staypresent<\/span> <span>staypresent<\/span><span>.<\/span><span>web<\/span><span>.<\/span><span>json<\/span><span>({<\/span><span>\"<\/span><span>status<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>running<\/span><span>\"<\/span><span>,<\/span> <span>\"<\/span><span>bots<\/span><span>\"<\/span><span>:<\/span> <span>2<\/span><span>})<\/span> <span>staypresent<\/span><span>.<\/span><span>run<\/span><span>(<\/span> <span>bots<\/span><span>=<\/span><span>[<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>telegram_bot.py<\/span><span>\"<\/span><span>},<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>discord_bot.py<\/span><span>\"<\/span><span>},<\/span> <span>],<\/span> <span>)<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Each bot listed here is launched as its own subprocess, monitored independently \u2014 if <code>telegram_bot.py<\/code> crashes and restarts, <code>discord_bot.py<\/code> is completely unaffected and keeps running.<\/p>\n<p>If each bot needs different environment variables: <\/p>\n<div>\n<pre><code><span>staypresent<\/span><span>.<\/span><span>run<\/span><span>(<\/span> <span>bots<\/span><span>=<\/span><span>[<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>telegram_bot.py<\/span><span>\"<\/span><span>,<\/span> <span>\"<\/span><span>env<\/span><span>\"<\/span><span>:<\/span> <span>{<\/span><span>\"<\/span><span>ROLE<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>ingestion<\/span><span>\"<\/span><span>}},<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>discord_bot.py<\/span><span>\"<\/span><span>,<\/span> <span>\"<\/span><span>env<\/span><span>\"<\/span><span>:<\/span> <span>{<\/span><span>\"<\/span><span>ROLE<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>notifications<\/span><span>\"<\/span><span>}},<\/span> <span>],<\/span> <span>)<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"step-4-read-railways-assigned-port\" href=\"#step-4-read-railways-assigned-port\"> <\/a> Step 4: Read Railway&#8217;s Assigned Port <\/h2>\n<div>\n<pre><code><span>import<\/span> <span>os<\/span> <span>import<\/span> <span>staypresent<\/span> <span>staypresent<\/span><span>.<\/span><span>web<\/span><span>.<\/span><span>json<\/span><span>({<\/span><span>\"<\/span><span>status<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>running<\/span><span>\"<\/span><span>,<\/span> <span>\"<\/span><span>bots<\/span><span>\"<\/span><span>:<\/span> <span>2<\/span><span>})<\/span> <span>staypresent<\/span><span>.<\/span><span>run<\/span><span>(<\/span> <span>bots<\/span><span>=<\/span><span>[<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>telegram_bot.py<\/span><span>\"<\/span><span>},<\/span> <span>{<\/span><span>\"<\/span><span>file<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>discord_bot.py<\/span><span>\"<\/span><span>},<\/span> <span>],<\/span> <span>port<\/span><span>=<\/span><span>int<\/span><span>(<\/span><span>os<\/span><span>.<\/span><span>getenv<\/span><span>(<\/span><span>\"<\/span><span>PORT<\/span><span>\"<\/span><span>,<\/span> <span>8080<\/span><span>)),<\/span> <span>)<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"step-5-deploy-as-a-single-railway-service\" href=\"#step-5-deploy-as-a-single-railway-service\"> <\/a> Step 5: Deploy as a Single Railway Service <\/h2>\n<p>Set your Railway start command to: <\/p>\n<div>\n<pre><code>python main.py <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Deploy once. Both bots now run inside the same container, under one Railway service, with one hosting bill.<\/p>\n<h2> <a name=\"verifying-both-bots-are-running\" href=\"#verifying-both-bots-are-running\"> <\/a> Verifying Both Bots Are Running <\/h2>\n<p>If you&#8217;re on a recent StayPresent version, visit <code>\/status<\/code> on your deployed URL \u2014 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&#8217;s own single-service view.<\/p>\n<p>You can also give each bot its own lightweight endpoint for a quick manual check: <\/p>\n<div>\n<pre><code><span>staypresent<\/span><span>.<\/span><span>web<\/span><span>.<\/span><span>json<\/span><span>({<\/span><span>\"<\/span><span>status<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>online<\/span><span>\"<\/span><span>},<\/span> <span>path<\/span><span>=<\/span><span>\"<\/span><span>\/telegram<\/span><span>\"<\/span><span>)<\/span> <span>staypresent<\/span><span>.<\/span><span>web<\/span><span>.<\/span><span>json<\/span><span>({<\/span><span>\"<\/span><span>status<\/span><span>\"<\/span><span>:<\/span> <span>\"<\/span><span>online<\/span><span>\"<\/span><span>},<\/span> <span>path<\/span><span>=<\/span><span>\"<\/span><span>\/discord<\/span><span>\"<\/span><span>)<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"faqs\" href=\"#faqs\"> <\/a> FAQs <\/h2>\n<p><strong>Does one bot crashing affect the other?<\/strong><br \/> No \u2014 each bot in the <code>bots<\/code> list gets its own restart counter and its own monitoring thread, completely independent of the others.<\/p>\n<p><strong>Can I run more than two bots this way?<\/strong><br \/> Yes \u2014 <code>bots<\/code> accepts as many entries as you need, each independently supervised.<\/p>\n<p><strong>Does this work the same way on Render or Koyeb?<\/strong><br \/> Yes \u2014 the same <code>main.py<\/code> and multi-bot configuration work unchanged across any platform that follows the standard <code>$PORT<\/code> convention.<\/p>\n<h2> <a name=\"conclusion\" href=\"#conclusion\"> <\/a> Conclusion <\/h2>\n<p>Running multiple related Python bots on Railway doesn&#8217;t require multiple services. <code>staypresent.run(bots=[...])<\/code> supervises each one independently \u2014 separate crash recovery, separate restart counters \u2014 while sharing a single container, a single port, and a single deployment. <\/p>\n<div>\n<pre><code>pip <span>install <\/span>staypresent[prod] <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Fuente: <a href=\"https:\/\/dev.to\/codenamew\/deploying-multiple-python-bots-to-a-single-railway-container-4hf1\">Art\u00edculo original<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;re running more than one Python bot \u2014 say, a Telegram ingestion bot and a Discord notification bot that share a database [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4449,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"webixso_pending_account_ids":""},"categories":[41],"tags":[],"class_list":["post-4450","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devto"],"jetpack_publicize_connections":[],"_links":{"self":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/4450","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/comments?post=4450"}],"version-history":[{"count":0,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/4450\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media\/4449"}],"wp:attachment":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media?parent=4450"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/categories?post=4450"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/tags?post=4450"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}