Skip to content
CreateDiscordBot
Menu

How to host a Discord bot 24/7 in 2026 (free and paid options)

How to host a Discord bot 24/7 in 2026: free tiers and their catches, $1 to $7 bot hosts, PaaS and VPS prices, plus tested systemd, pm2 and Docker setups.

By Adam Peleback. Updated . 18 min read.

On this page
  1. Why a Discord bot goes offline
  2. Hosting options compared (September 2026)
  3. Free options and their catches
  4. Paid options that stay online
  5. Which hosting is best for a Discord bot?
  6. How to host a Discord bot 24/7 on a VPS
  7. Logs
  8. Know when the bot is down
  9. Back up what the bot stores
  10. Updating without surprises
  11. If you'd rather not run it yourself

To host a Discord bot 24/7, run it on a machine that never sleeps and put it under a supervisor that restarts it after a crash and starts it again after a reboot. The machine can be a bot host or platform at $1 to $7 a month, a VPS at $4 to $6 a month, or a free tier if you can live with its catch. The supervisor is systemd, pm2 or Docker, and this guide has a tested setup for each.

Free still exists in 2026, but every free option comes with a condition. Oracle Cloud may reclaim Always Free VMs it considers idle, free bot hosts make you click "renew" every day or every few days, and Replit, Heroku and Glitch no longer keep a bot online for free. If people rely on the bot, pay the few dollars and spend the effort on monitoring instead.

I checked every price on this page in September 2026. I tested the code on September 27, 2026 with discord.js 14.27.0 on Node.js 22.23 and 24.21, pm2 7.0.4, systemd 257 on Debian 13, Docker 29.4 and sqlite3 3.46.

Why a Discord bot goes offline

A normal bot keeps a WebSocket connection open to Discord's gateway, and everything it hears about (messages, members joining, slash commands) arrives over that connection. When the process stops, the connection closes and the bot shows as offline. That is why a bot started from your laptop disappears when the laptop sleeps, and why platforms that put idle apps to sleep don't suit bots.

There is one exception. If your bot only answers slash commands, buttons and modals, Discord can send those to an HTTPS endpoint instead of the gateway. Then nothing has to stay running between requests, and a serverless function can do the job. The section on HTTP interactions covers it.

Hosting options compared (September 2026)

Free options

Option What you get Stays online? The catch
Oracle Cloud Always Free 2 AMD VMs with 1 GB RAM each, plus Arm capacity worth 2 OCPUs and 12 GB RAM Yes Card needed to sign up; idle instances may be reclaimed; "out of host capacity" errors
Google Cloud free tier 1 e2-micro VM in Oregon, Iowa or South Carolina, 30 GB disk Yes Billing account needed; 1 GB outbound a month; the public IPv4 address may be billed
bot-hosting.net Free 1 bot, 256 MB RAM, 25% CPU, 512 MB storage Only if you renew every 4 days Manual renewal
fps.ms Free 128 MB RAM, 25% CPU, 250 MB storage Only if you renew every 24 hours Personal use only
Cloudflare Workers Free 100,000 requests a day, 10 ms CPU per request Nothing to keep online Slash commands, buttons and modals only
Your own PC or a Raspberry Pi Whatever the machine has While it's on Your power, internet and OS updates
Option Cheapest plan that runs a bot all month Worth knowing
Sparked Host $1.00/mo: 512 MB RAM, 50% CPU, 5 GB Unmanaged; FFmpeg doesn't work on its bot plans, so no music bots
Cybrancee $1.99/mo: 512 MB RAM, 15 GB $2.99 for 1 GB; 90-day money-back guarantee
bot-hosting.net Starter $1.99/mo: 1 GB RAM, 2 bots Backups kept 3 days; Starter+ at $2.99 has 2 GB and 4 bots
PebbleHost $3.00/mo: 1 GB RAM Node.js, Python and Java; automatic 7-day backups
Railway Hobby $5/mo, includes $5 of usage Billed per second: $10 per GB of RAM and $20 per vCPU per month
Fly.io about $1.94 per 30 days for shared-cpu-1x with 256 MB in Ashburn Card required; other regions cost more
Render $7/mo background worker, 512 MB The free tier has no background workers
Heroku $5/mo Eco or $7/mo Basic, 0.5 GB RAM An app with only an Eco worker dyno doesn't sleep
Replit Reserved VM $15/mo: 0.5 vCPU, 2 GB RAM Replit's always-on deployment type
DigitalOcean $4/mo: 512 MB RAM, 10 GB disk; $6/mo for 1 GB You run the server
Hetzner Cloud CX23 €5.49/mo plus €0.50 for IPv4: 2 vCPU, 4 GB RAM Germany and Finland only; US locations start at $20.49

Prices are as listed in September 2026, and VAT or sales tax may be added depending on where you live. fps.ms also sells paid plans from €0.29 a month, with a €10 minimum top-up.

Free options and their catches

Oracle Cloud Always Free

Every Oracle Cloud account gets two AMD micro VMs (1/8 of an OCPU and 1 GB RAM each) and 1,500 OCPU hours plus 9,000 GB hours of Arm (Ampere A1) capacity a month. Oracle's page says that equals 2 OCPUs and 12 GB of RAM for Always Free accounts, so older guides that promise 4 OCPUs and 24 GB are out of date. Either shape is plenty for a bot.

The catches come from Oracle's own pages:

  • Sign-up needs a credit card or a debit card that works like one. Prepaid and virtual cards are refused, and Oracle may place a temporary authorization hold on the card.
  • Oracle "may reclaim" idle Always Free instances. Idle means that over 7 days the 95th-percentile CPU use is under 20%, network use is under 20%, and on Arm shapes memory use is under 20%. A small bot fits that description, so plan for it.
  • Creating an Arm instance often fails with "out of host capacity". Oracle's advice is to try another availability domain or wait.
  • If you build Arm instances larger than the free allowance during the 30-day trial, all your Arm instances are disabled when the trial ends and deleted 30 days later unless you upgrade.

Oracle suits a hobby bot if you want to learn Linux and keep your backups somewhere else.

Google Cloud's e2-micro

Google's free tier includes one e2-micro VM a month in us-west1, us-central1 or us-east1, 30 GB of standard disk and 1 GB of outbound data from North America. A billing account is required. Watch the IP line on your first invoice: Google's network pricing page lists external IPv4 addresses on standard VMs at $0.005 an hour, about $3.60 a month, and describes the free allowance for them as one hour a month. A bot needs outbound internet access, so it needs that address or a paid NAT gateway.

Free bot hosts

Both free hosts in the table keep a bot online only while you keep renewing it by hand: every 4 days on bot-hosting.net, every 24 hours on fps.ms. Miss an fps.ms renewal and the bot goes offline, with its files kept for 28 days. fps.ms also says free hosting is for personal use and that it shuts down commercial bots.

That works for a bot you are learning with, not for one a community depends on. Other free hosts exist; whichever you try, read its renewal and commercial-use rules before you give it your bot token.

What happened to Replit, Heroku and Glitch

Many older "host your bot free forever" tutorials use one of these three, often with a pinging service to keep the app awake. None of that works today:

  • Heroku stopped offering free dynos from November 28, 2022. The cheapest plan is Eco at $5 a month for 1,000 dyno hours shared across your Eco dynos, and an app that runs only an Eco worker dyno doesn't sleep, so one worker can run a bot for the whole month. In February 2026 Heroku said it is moving to a "sustaining engineering model" focused on stability and security, with no change for customers who pay by card.
  • Replit removed "Always On" on January 1, 2024. The free Starter plan's one published app goes down after 30 days, and the always-on deployment type, a Reserved VM, starts at $15 a month.
  • Glitch shut down project hosting on July 8, 2025.

No server at all: HTTP interactions

If your bot only responds to slash commands, context menu commands, buttons and modals, you can set an Interactions Endpoint URL in the Developer Portal. Discord then sends every interaction to that URL as an HTTPS request. Discord has an official tutorial for running this on Cloudflare Workers, whose free plan allows 100,000 requests a day and 10 ms of CPU time per request. Nothing waits between requests, so there is nothing to keep online.

The limits, from Discord's docs: an app receives interactions either over HTTP or over the gateway, never both. Without a gateway connection there are no gateway events either, so no member joins, messages or reactions. And the first response must arrive within 3 seconds, after which the interaction token stays valid for 15 minutes of follow-ups.

Scheduled jobs can skip the bot process too. The Twitch go-live notifier on Rivals League is a scheduled function that runs every minute and posts to Discord through webhooks, so there is nothing to keep alive between runs. A stream alert bot that polls can run the same way.

Bot hosts at $1 to $3 a month

Sparked Host, Cybrancee, PebbleHost and bot-hosting.net sell plans made for bots, priced in the table above. You upload the code through a web panel (Sparked uses a Pterodactyl panel with SFTP, PebbleHost gives FTP access), set the start command and run it from there. Check two things before you buy: the RAM, and whether FFmpeg works if the bot plays audio. Sparked's bot plans say it doesn't.

Pick one of these for a small bot when you don't want to run a Linux server. The host holds your token, so use one you trust and reset the token if you move away.

Railway, Fly.io and Render

All three can run a bot as a long-running process, like Heroku's worker dynos above, but the details differ.

  • Railway runs a service until you stop it. At its rates, a bot holding 200 MB of RAM around the clock uses about $2 of memory a month, plus CPU, against the $5 of usage included in Hobby. The Free plan's $1 of monthly credit covers about 100 MB for a month before CPU is counted. Railway's optional Serverless mode only sleeps a service after 5 or more minutes without outbound traffic, and a connected bot keeps sending heartbeats to Discord.
  • Fly.io only auto-stops Machines that have services configured, so a bot app with no [http_service] or [[services]] section keeps running. The shared-cpu-1x preset with 256 MB costs about $1.94 per 30 days in Ashburn and about $3.19 with 512 MB, and some regions cost up to about 60% more. Every organization needs a card on file, and the free trial ends after 2 machine hours or 7 days.
  • Render runs bots as background workers from $7 a month for 512 MB. Its free instance type only covers web services, static sites, Postgres and Key Value. A free web service spins down after 15 minutes without inbound traffic, may be restarted at any time, and loses local files, including a SQLite database, whenever that happens.

A VPS

A VPS is a small Linux server you control. DigitalOcean's $4 droplet (512 MB) or $6 droplet (1 GB) is enough for a small bot. Hetzner's CX23 costs more since a June 15, 2026 price change (€5.49, up from €3.99) but gives you 2 vCPUs and 4 GB, only in Germany and Finland. Hetzner's US locations don't offer the CX or Arm plans and start at $20.49 a month, so for a US bot DigitalOcean is the cheaper of the two.

A VPS runs as many bots as fit in its RAM and lets you choose every version. In return, security updates, backups and monitoring are your job.

Which hosting is best for a Discord bot?

  • Learning, or a bot for a few friends: a free bot host, or Oracle Cloud if you want to learn Linux. Accept the renewals or the reclaim risk.
  • A small bot your community uses every day: a $1 to $3 bot host or Railway Hobby, plus an uptime monitor.
  • Several bots, a database, or full control: a $4 to $6 VPS with systemd or Docker.
  • Only slash commands and buttons: HTTP interactions on Cloudflare Workers.
  • A bot that takes payments or runs a league: not a free tier. A few dollars a month is small next to an outage during a match day or a billing run.

How to host a Discord bot 24/7 on a VPS

The rest of this guide sets up a discord.js bot on a Linux server so it keeps running 24/7. Three things matter: code that shuts down cleanly and logs its errors, a supervisor that restarts it and starts it at boot, and a way to find out when it's down. A Python bot needs the same setup; the systemd section shows the one line that changes. If you don't have a bot yet, start with the discord.js guide.

Step 1: Make the bot safe to restart

This is a complete index.js for a bot that only logs in. Add your commands and handlers to it; the parts around them are what keep it running.

index.js
const { Client, Events, GatewayIntentBits, Status } = require('discord.js');

const token = process.env.DISCORD_TOKEN;
if (!token) {
  console.error('DISCORD_TOKEN is not set. Add it to .env or to your host\'s environment settings.');
  process.exit(1);
}

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, (readyClient) => {
  console.log(`Logged in as ${readyClient.user.tag}, in ${readyClient.guilds.cache.size} servers`);
});

// Log problems instead of letting one failed reply take the whole bot down.
client.on(Events.Error, (error) => console.error('Client error:', error));
process.on('unhandledRejection', (error) => console.error('Unhandled promise rejection:', error));

// Optional: tell an uptime monitor "still connected" every 5 minutes.
// The ping is skipped while the gateway connection is down, so the monitor alerts you.
const heartbeatUrl = process.env.HEARTBEAT_URL;
if (heartbeatUrl) {
  setInterval(async () => {
    const connected = client.ws.shards.size > 0 && client.ws.shards.every((shard) => shard.status === Status.Ready);
    if (!connected) return;
    try {
      await fetch(heartbeatUrl, { signal: AbortSignal.timeout(10_000) });
    } catch (error) {
      console.error('Heartbeat failed:', error.message);
    }
  }, 5 * 60 * 1000);
}

// Shut down cleanly: pm2 sends SIGINT, systemd and Docker send SIGTERM.
for (const signal of ['SIGINT', 'SIGTERM']) {
  process.on(signal, async () => {
    console.log(`${signal} received, closing the Discord connection`);
    await client.destroy();
    process.exit(0);
  });
}

client.login(token).catch((error) => {
  console.error('Login failed:', error.message);
  process.exit(1);
});

What each part is for:

  • The token check exits with an error code and a clear message, so the supervisor's log tells you what's wrong instead of showing a stack trace.
  • The error handlers stop one failed interaction reply from crashing the process. Since Node.js 15, an unhandled promise rejection ends the process by default, and every restart costs a new login to Discord (more on why that matters below).
  • The heartbeat checks each gateway shard's status rather than client.isReady(). In discord.js 14.27, isReady() stays true while a dropped connection is reconnecting, so it can't tell you the bot is cut off.
  • The signal handlers close the gateway connection before exiting, so a restart or deploy shows up as a clean stop in the logs.

Step 2: Put the token in .env

.env
DISCORD_TOKEN=paste-your-bot-token-here
HEARTBEAT_URL=https://hc-ping.com/your-check-id

Three rules for this file:

  1. No quotes around values. Node's --env-file, systemd and Docker Compose strip them, but docker run --env-file passes them through literally. In my test it turned "abc123" into a token that starts and ends with a quote mark, which Discord will reject as invalid.
  2. Keep it out of Git. Put .env and node_modules in .gitignore. GitHub reports Discord bot tokens it finds in public repositories to Discord through its secret scanning partner program, and a leaked token has to be reset either way; the bot token guide covers the reset.
  3. Lock it down on the server with chmod 600 .env, so only the bot's user can read it.

On a PaaS or bot host, put the same variables in the platform's environment settings instead of a file. Node's --env-file flag, used by the pm2 setup below, is no longer experimental from Node 24.10 and 22.21. When a variable is set both in the environment and in the file, the environment wins.

Step 3, option A: systemd

systemd already runs every other service on Ubuntu and Debian, so it's the option with the fewest moving parts. Create a user for the bot, put the code in /opt/mybot and install the dependencies:

sudo useradd --system --home-dir /opt/mybot --shell /usr/sbin/nologin mybot
sudo git clone https://github.com/you/mybot.git /opt/mybot
cd /opt/mybot
sudo npm ci --omit=dev
sudo nano .env
sudo chown -R mybot:mybot /opt/mybot
sudo chmod 600 /opt/mybot/.env

Then create the service file:

/etc/systemd/system/mybot.service
[Unit]
Description=My Discord bot
Wants=network-online.target
After=network-online.target
# Never give up; the backoff below keeps a crash loop slow.
StartLimitIntervalSec=0

[Service]
Type=simple
User=mybot
WorkingDirectory=/opt/mybot
EnvironmentFile=/opt/mybot/.env
ExecStart=/usr/bin/node index.js
Restart=always
# First retry after 5 s, then roughly doubling up to 5 minutes (systemd 254+).
RestartSec=5s
RestartSteps=6
RestartMaxDelaySec=5min
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Start it, enable it at boot and watch the log:

sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot
journalctl -u mybot -f

Notes from testing it:

  • ExecStart needs the full path to Node. Run command -v node and use what it prints. /usr/bin/node is where distribution and NodeSource packages put it. If you installed Node with nvm, the path is inside a home directory, and a system-wide Node install is the better choice for a service.
  • The restart backoff gave retries after 5, 10, 20, 40 and 77 seconds in a crash loop, heading for the 5-minute cap. RestartSteps and RestartMaxDelaySec need systemd 254 or newer: Ubuntu 24.04 has 255 and Debian 13 has 257. Debian 12 (252) and Ubuntu 22.04 (249) ignore both lines with an "Unknown key" warning, so on those set RestartSec=2min instead.
  • ProtectSystem=full makes /usr, /boot and /etc read-only for the bot, while /opt/mybot stays writable for a SQLite file.
  • systemctl stop sent SIGTERM, the bot logged "SIGTERM received" and the unit stopped in under 50 ms.

For a discord.py bot in a virtual environment, change one line:

ExecStart=/opt/mybot/.venv/bin/python -u bot.py

The -u stops Python from buffering output, so print() lines reach journalctl straight away. I tested this start line with discord.py 2.7.1 on Python 3.13.

Step 3, option B: pm2

pm2 is a process manager for Node.js with its own log viewer, and a common choice in bot tutorials. Install it, then put this file next to index.js:

ecosystem.config.js
module.exports = {
  apps: [
    {
      name: 'mybot',
      script: 'index.js',
      cwd: __dirname,
      node_args: '--env-file=.env',
      // Only ever one copy: two processes with the same token both answer every event.
      instances: 1,
      exec_mode: 'fork',
      // Wait longer after each crash (up to 15 s), and give up after 10 crashes
      // in a row that happen within a minute of starting.
      exp_backoff_restart_delay: 1000,
      min_uptime: '60s',
      max_restarts: 10,
      // Give the bot time to close its Discord connection on stop/restart.
      kill_timeout: 5000,
      time: true,
    },
  ],
};
npm install -g pm2
pm2 start ecosystem.config.js
pm2 save
pm2 startup

pm2 startup prints one sudo command. Run it, and pm2 brings the bot back after a reboot from the list pm2 save stored. I tested that by restarting pm2's systemd service, and the bot came back online.

What the settings did in testing:

  • exp_backoff_restart_delay grows the wait between restarts up to pm2's maximum of 15 seconds and resets once the bot has stayed up for 30 seconds.
  • min_uptime and max_restarts are what stop a crash loop. With them, a bot that crashed right after starting was restarted 9 times in about 70 seconds and then left alone. pm2 list showed it as "waiting restart" rather than "errored", which is worth knowing when you look. Without the two lines, pm2 kept restarting it every 15 seconds indefinitely, which is about 5,760 logins a day.
  • Stopping sends SIGINT, which index.js handles. kill_timeout gives it 5 seconds before SIGKILL instead of pm2's default 1.6 seconds.
  • Never use cluster mode or more than one instance for a gateway bot. Each copy opens its own connection and answers the same events.

View logs with pm2 logs mybot. pm2 doesn't rotate its log files by itself; pm2 install pm2-logrotate does, rotating at 10 MB and keeping 30 files by default. After you upgrade Node.js, run pm2 unstartup and then pm2 startup again, because the boot script points at the old Node binary.

Step 3, option C: Docker

Docker makes sense if you already use it on the server. You need three files next to index.js, package.json and package-lock.json:

Dockerfile
FROM node:24-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
USER node
CMD ["node", "index.js"]
.dockerignore
node_modules
.env
.git
compose.yaml
services:
  bot:
    build: .
    restart: unless-stopped
    env_file: .env
    logging:
      driver: local
docker compose up -d --build
docker compose logs -f bot

Why it's set up this way:

  • .dockerignore keeps .env out of the image. The token only reaches the container at runtime through env_file, so you can push the image without leaking it. I checked that .env wasn't inside the built image.
  • USER node runs the bot as the unprivileged user that the official Node image already includes. The code in /app belongs to root, so the bot can't write there; a bot that keeps a SQLite file needs a volume the node user can write to.
  • logging: driver: local because Docker's default json-file driver doesn't rotate logs, and Docker's docs warn it can fill the disk. The local driver rotates by default.
  • Node runs as process 1 in the container, and signals only stop it if the code handles them. index.js does, so docker compose stop finished at once instead of waiting out Docker's grace period and then killing the bot.

Crash loops and Discord's 1,000 logins a day

Discord allows each bot 1,000 IDENTIFY calls, meaning new gateway sessions, per 24 hours. Resuming a dropped session doesn't count. If you hit the limit, Discord ends all of the bot's sessions, resets its token and emails the owner. Every restart of a crashed process opens a new session, so a supervisor that restarts too eagerly can get your token reset.

Supervisor What it did in a crash loop (tested) Restarts per day at most
systemd, unit above Waits of 5, 10, 20, 40 and 77 seconds, capped at 5 minutes About 290
pm2, file above Waits growing to 15 seconds, then stopped after 10 quick crashes About 10, then it waits for you
Docker, unless-stopped 100 ms doubling to 1 minute, but the delay resets after 10 seconds of uptime About 2,900 if the bot crashes 30 seconds after each start

The Docker row is the one to watch. A bot that logs in, runs for 11 seconds and crashes was restarted about 7 times every 90 seconds in my test, because each run counted as a successful start. on-failure:5 stops that, but the count only resets when the container is recreated, so the sixth crash of that container's life, even months later, leaves it down. In my test, a container on on-failure:2 that ran 11 seconds before each crash stayed down after its third crash. With Docker, the error handlers in index.js and the uptime alert below do most of the protecting.

Logs

  • systemd: journalctl -u mybot -f follows the log, and journalctl -u mybot --since "1 hour ago" shows the recent past. The journal caps its own disk use by default, at 10% of the file system up to 4 GB.
  • pm2: pm2 logs mybot, plus pm2-logrotate as described above.
  • Docker: docker compose logs -f bot, rotated by the local driver.

The lines in index.js are enough to tell a crash from a deploy: a clean stop logs "SIGTERM received" or "SIGINT received" first, and a crash doesn't.

Know when the bot is down

Restarts handle crashes. They don't help when the whole server is down, when Discord has reset the token, or when the process is running but can't reconnect. For those you need a check from outside:

  • Healthchecks.io has a free Hobbyist plan with 20 checks. Create a check with a 5-minute period and some grace time, put its ping URL in HEARTBEAT_URL, and you get an alert when the pings stop.
  • Uptime Kuma is open source and self-hosted, with Push monitors that work the same way and notifications to Discord and many other services. Run it somewhere other than the bot's server, or it goes down with the bot.

Back up what the bot stores

If the bot keeps data in SQLite, copying the file with cp while the bot writes to it can give you a broken copy, according to SQLite's own documentation. The sqlite3 command-line tool (sudo apt install sqlite3) has a .backup command that makes a consistent copy of a live database:

/usr/local/bin/mybot-backup.sh
#!/bin/sh
set -e
mkdir -p /var/backups/mybot
# wait up to 10 s for a write in progress instead of failing with "database is locked"
sqlite3 -cmd ".timeout 10000" /opt/mybot/data/bot.db ".backup '/var/backups/mybot/bot-$(date +%F).db'"
# keep two weeks of daily copies
find /var/backups/mybot -name 'bot-*.db' -mtime +14 -delete

Create it with sudo, make it executable with sudo chmod +x /usr/local/bin/mybot-backup.sh, then run it every night at 04:15 by adding 15 4 * * * /usr/local/bin/mybot-backup.sh with sudo crontab -e. The script lives outside /opt/mybot because root runs it, and the bot's user can change anything in /opt/mybot. Keeping the date format inside the script avoids cron's rule that % must be escaped in a crontab line.

I tested it while another process was writing to the database. Without the .timeout line, 2 of 5 backups failed with "database is locked"; with it, all 10 runs worked and every copy passed SQLite's integrity check. Then copy the backups off the server, because a backup on the same VPS disappears with it.

Updating without surprises

Updating the code:

# systemd
cd /opt/mybot && sudo -u mybot git pull && sudo -u mybot npm ci --omit=dev && sudo systemctl restart mybot

# pm2
git pull && npm ci --omit=dev && pm2 restart mybot

# Docker
git pull && docker compose up -d --build

Running git and npm as the mybot user keeps file ownership right. Never run the old and the new version at the same time with the same token, not even for a quick test, because both will answer every command.

Updating Node.js. Node.js 20 reached end of life on April 30, 2026. Node.js 22 is supported until April 30, 2027 and Node.js 24 until April 30, 2028. After an upgrade, check that the ExecStart path still points at the right binary, or rerun pm2 unstartup and pm2 startup.

Updating the library, and keeping up with Discord. Bots often stop working without anyone touching them, because Discord changed something. Three recent examples from Discord's change log:

  • Since February 23, 2026, pinning messages needs the new Pin Messages permission; Manage Messages alone no longer does it.
  • Since March 1, 2026, voice connections must support Discord's end-to-end encryption (DAVE). For discord.js that means @discordjs/voice 0.19 or newer, which requires Node.js 22.12 or newer. For discord.py it means 2.7.0 or newer.
  • From November 16, 2026, the endpoint that lists a server's channels will leave out channels the bot can't view.

Read the release notes before you update, and try the update first with a separate test application in a private server, so it never shares the live bot's token. If the bot has already stopped responding, Discord bot not working? walks through the usual causes.

If you'd rather not run it yourself

Everything above is an evening's work to set up and a little time every month to keep up. If you'd rather hand that off, my Care plan is $49 a month for managed hosting, uptime monitoring, library and security updates when Discord changes things, and daily database backups. It also works for bots I didn't build. If your bot is already broken or stuck on an old host, a Bot Rescue gets it running again for a fixed $149, and you pay nothing if I can't fix it. You can ask about Care here.

Questions

Can I run a Discord bot 24/7 for free?

Yes, with a catch: Oracle Cloud's Always Free VMs can run one, but Oracle may reclaim instances it considers idle, and free bot hosts such as bot-hosting.net and fps.ms keep it online only while you renew it every 4 days or every 24 hours. If the bot only answers slash commands and buttons, Cloudflare Workers' free plan can serve it with no process running at all.

Why does my bot go offline when I close the terminal?

The bot is a process on your computer. Closing the terminal, logging out or letting the laptop sleep ends that process, which closes its connection to Discord. Run it on a machine that stays on, under systemd, pm2 or Docker, so it survives logouts, crashes and reboots.

Is BotGhost 24/7?

BotGhost lists 24/7 hosting on its free plan, but free bots created since November 2024 go offline if none of their commands is used for 48 hours, and free bots can join at most 5 servers. Premium removes those limits. If you are thinking about moving off a builder, see BotGhost alternatives.

Can I host a Discord bot on GitHub?

Not as a 24/7 bot. GitHub Pages only serves static files, a GitHub Actions job on GitHub's runners stops after 6 hours, and GitHub's terms rule out using those runners for anything unrelated to producing, testing, deploying or publishing the repository's software. Keep the code on GitHub and deploy it to a host.

Does hosting a Python bot work the same way?

Yes. PebbleHost, Cybrancee, bot-hosting.net and any VPS run Python bots, and in the systemd setup only the start line changes, for example ExecStart=/opt/mybot/.venv/bin/python -u bot.py, where -u sends print output to the logs straight away. For the code itself, see the discord.py guide.

Sources

Prices and features were checked on September 27, 2026.

  1. Discord Developer Docs, Gateway (persistent connections, 1,000 IDENTIFY calls per 24 hours)
  2. Discord Developer Docs, Receiving and responding to interactions (HTTP vs gateway, 3-second deadline)
  3. Discord Developer Docs, Hosting a Reddit API Discord app on Cloudflare Workers
  4. Discord Developer Docs, Change log (DAVE voice requirement, permission splits, channel obfuscation)
  5. Oracle Cloud Infrastructure, Always Free resources (checked September 2026)
  6. Oracle Cloud Free Tier FAQ (card verification, authorization holds, trial end)
  7. Google Cloud, Free Tier features (e2-micro)
  8. Google Cloud, VPC network pricing (external IP addresses)
  9. bot-hosting.net, plans (checked September 2026)
  10. bot-hosting.net, pricing (Free, Starter and Starter+ tiers, checked September 2026)
  11. fps.ms, free Discord bot hosting (checked September 2026)
  12. Cloudflare Workers, pricing and free plan limits
  13. Sparked Host, Discord bot hosting plans (checked September 2026)
  14. Cybrancee, Discord bot hosting (checked September 2026)
  15. PebbleHost, Discord bot hosting (checked September 2026)
  16. Railway, pricing (checked September 2026)
  17. Railway Docs, Serverless (formerly App Sleeping)
  18. Fly.io, resource pricing (per-second Machine rates, card requirement)
  19. Fly.io, free trial
  20. Fly.io, autostop and autostart (only for apps with services)
  21. Render, pricing (checked September 2026)
  22. Render Docs, deploy for free (limits of free instances)
  23. Heroku, pricing
  24. Heroku Dev Center, Eco dyno hours (worker dynos don't sleep)
  25. Heroku, Heroku's next chapter (free plans end November 28, 2022)
  26. Heroku, An update on Heroku (February 6, 2026)
  27. Replit, Changes to hosting on Replit (Always On removed January 1, 2024)
  28. Replit Docs, publishing costs (Reserved VM prices)
  29. Replit Docs, Starter plan (one free published app that goes down after 30 days)
  30. Glitch, Important changes are coming to Glitch (hosting ends July 8, 2025)
  31. DigitalOcean, Droplet pricing (checked September 2026)
  32. Hetzner Docs, Price adjustment June 15, 2026
  33. Hetzner Docs, Primary IPs (IPv4 price)
  34. Hetzner, Cost-optimized cloud servers (CX23 specs)
  35. BotGhost Documentation, 2024 changelog (free bot restrictions, November 21, 2024)
  36. BotGhost Documentation, premium features (free plan limits)
  37. GitHub Docs, What is GitHub Pages? (static site hosting)
  38. GitHub Docs, Actions limits (6-hour job limit)
  39. GitHub, Terms for additional products and features (Actions)
  40. GitHub Docs, Supported secret scanning patterns (Discord bot token)
  41. systemd.service manual (Restart=, RestartSteps=, RestartMaxDelaySec=)
  42. systemd.exec manual (ProtectSystem=, EnvironmentFile=)
  43. journald.conf manual (default journal size limits)
  44. Ubuntu packages, systemd in 24.04 (255) and 22.04 (249)
  45. Debian packages, systemd in Debian 13 (257) and Debian 12 (252)
  46. PM2, Restart strategies (exponential backoff)
  47. PM2, Startup script
  48. PM2, Ecosystem file attributes
  49. PM2, Graceful stop (SIGINT, then SIGKILL after 1.6 s)
  50. PM2, Log management (pm2-logrotate)
  51. pm2-logrotate README (10 MB and 30 files by default)
  52. Docker Docs, docker container run (restart policy delays)
  53. Docker Docs, Configure logging drivers (no rotation by default)
  54. Node.js 24, command-line options (--env-file no longer experimental from v24.10.0; unhandled rejections throw since v15)
  55. Node.js 22, command-line options (--env-file no longer experimental from v22.21.0)
  56. Node.js Release schedule
  57. discord.js, @discordjs/voice changelog (DAVE support)
  58. Healthchecks.io, pricing
  59. Uptime Kuma (push monitors)
  60. SQLite, How to corrupt an SQLite database file (backups during transactions)
  61. SQLite, Command line shell (.backup and .timeout)

Tell me what your server needs

Send a short brief. You get a reply within one business day with questions or a price range, and a fixed quote before any work starts.