A bot is a long-lived process with no HTTP listener. That single difference breaks most of the assumptions that work for a web service, so this page covers what changes.
The container stops when your process exits
For a web app, an exiting process is obviously a crash. For a bot, exiting cleanly is normal operation — a finished job, an idle shutdown, a library that returned. The container follows the process out and goes offline.
Keep the process in the foreground. If you use a supervisor, start the daemon and then attach a foreground process so the container has something to stay alive on:
npx pm2 start bot.js --name bot
npx pm2 save
tail -f /dev/null
PM2 will restart the bot automatically if it crashes, which is the behaviour you want: a bot that dies on one bad interaction should come back without you pressing anything.
No port means no external health check
The panel cannot verify a bot is answering requests, because there are no requests. Confirm health from the console instead. A gateway-connected log line is your signal:
[INFO] logged in as Bot#1234
[INFO] connected to gateway
If those lines appear and no error follows, the bot is online. If they appear once and never again, the gateway connection dropped — which leads to the next point.
Reconnect rather than exit
Every Discord client library ships reconnection handling, and it is enabled by default. The failure mode to avoid is catching the error and calling process.exit(), because that turns a recoverable blip into a visible outage.
Let the library retry. A gateway disconnect usually resolves in seconds; the client resumes the session and replays missed events from the last sequence number. If your bot is restarted instead, Discord replays from your last persisted state and you may double-process anything in between — another reason to avoid exiting on transient errors.
Keep state out of memory
A bot restarted every few days will forget everything held only in a variable. This matters more than it sounds, because users notice:
- Cooldown timers vanish, so rate-limited commands become spammable.
- Cached settings reset to defaults.
- Any in-progress multi-step interaction breaks mid-flow.
Persist to a database. Provision one from the Databases tab and store cooldowns and settings there. Working with databases covers connecting.
The memory cost of doing this properly is small; the memory cost of not doing it is that every restart silently resets your bot's behaviour.
Log with timestamps, and not with tokens
The console is your only diagnostic when something goes wrong at 3 am. Log with timestamps, at a level that tells you whether a handler ran and what it returned.
Be careful about what you log. A bot token is a password: anyone reading the console can take over the bot entirely. Log the last few characters for identification if you must, never the value.
Runtime and plan fit
A typical JavaScript bot runs in 90–150 MB; add roughly 50 MB for Python with common libraries. Starter at 512 MB is comfortable for a single bot. Size up if you cache media, run several bots in one container, or keep a large dataset in memory — and remember sizing at about twice your measured peak.