Discord 机器人 VPS 托管:7×24 小时保持在线
- 2026年10月18日
- 09:00
- 作者: Adrien Roche
- 教程

为什么 VPS 才能让 Discord 机器人真正常在线
Discord 机器人不是网页。登录之后,它会与 Discord 的 gateway 保持一条长连接 WebSocket,并持续响应心跳;进程一旦停止,机器人立即显示离线,所有命令失效。仅“进程永不休眠”这一条要求,就排除了大多数“免费”托管:
- Heroku 已于 2022 年 11 月取消免费 dyno。
- Replit 不再让免费项目常驻运行,常在线功能已转为付费部署。
- Glitch 已于 2025 年终止应用托管服务。
- 闲置后休眠的免费 Web 方案每次空闲都会切断 gateway 连接;在用户看来,机器人就是挂了。
把 Discord 机器人托管在 VPS 上能从根本上解决问题:一台全天候运行、拥有 root 权限的 Linux 机器,机器人只是由 init 系统管理的一个普通服务。本指南在 Ubuntu 24.04(同样适用于 22.04 和 Debian 12)上,用 discord.py 与 discord.js 完成搭建,并涵盖 token 管理、自动重启、日志、更新和内存规划。
准备 VPS:专用账号与运行环境
先守好大门:在 Ubuntu 上启用并加固 SSH,使用密钥认证、禁止 root 登录并启用 ufw。机器人是主动外连 Discord 的,不需要任何入站端口,因此防火墙除 SSH 外可以全部关闭。
第 1 步:为机器人创建一个非特权账号
sudo useradd -r -m -d /opt/mybot -s /usr/sbin/nologin bot
使用独立账号后,有缺陷的机器人或被投毒的 npm、PyPI 依赖都无法读取你的 SSH 密钥或影响其他服务。所有文件都放在 /opt/mybot,属主为 bot。
第 2 步(Python):在虚拟环境中安装 discord.py
sudo apt update && sudo apt install -y python3 python3-venv python3-pip
sudo -u bot python3 -m venv /opt/mybot/.venv
sudo -u bot /opt/mybot/.venv/bin/pip install -U discord.py python-dotenv
discord.py 2.x 需要 Python 3.8 或更高版本;Ubuntu 24.04 自带 3.12,22.04 自带 3.10,直接用系统解释器即可。只有需要语音频道时才安装 discord.py[voice] 和 ffmpeg。
第 3 步(Node.js):安装当前 LTS 版本与 discord.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
sudo -u bot bash -c 'cd /opt/mybot && npm init -y && npm install discord.js dotenv'
Ubuntu 自带的 nodejs 包版本远落后于上游,而 discord.js v14 需要较新的运行时,因此请用上面的 NodeSource 或 nvm 安装当前 LTS。若使用 nvm,请执行 which node,并在服务单元里填写该绝对路径。
别把 token 写进代码:使用 .env 文件
机器人 token 相当于可完全操控机器人的密码:绝不要粘贴进 bot.py 或 index.js,更不要提交到仓库。把它写进 /opt/mybot/.env,仅机器人账号可读,并用编辑器而不是 echo 编写,因为命令行里输入的 token 会留在 shell 历史记录中:
sudo -u bot nano /opt/mybot/.env # one line: DISCORD_TOKEN=your-token-here
sudo chmod 600 /opt/mybot/.env
echo ".env" | sudo -u bot tee -a /opt/mybot/.gitignore
格式为每行一个 KEY=value,不要加引号,也不要写 export。python-dotenv 和 npm 包 dotenv 都能读取它,systemd 也可以用 EnvironmentFile= 注入同一个文件(见下一节);两者同时使用没有问题,因为这两个库都不会覆盖已存在的变量。一旦 token 泄露,请立即在 Developer Portal 的 Bot → Reset Token 中重置。
discord.py 与 discord.js 的最小示例
两个示例都从环境变量读取 token,启用 Message Content intent,并响应 !ping。在 Developer Portal 中创建应用、添加 bot 用户、复制 token(只显示一次),在 Bot → Privileged Gateway Intents 下启用 Message Content Intent,然后通过 OAuth2 URL generator 用 bot scope 把机器人邀请到测试服务器。
discord.py: /opt/mybot/bot.py
import os
import discord
from dotenv import load_dotenv
load_dotenv()
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print(f"Logged in as {client.user}")
@client.event
async def on_message(message):
if message.author == client.user:
return
if message.content == "!ping":
await message.channel.send("pong")
client.run(os.environ["DISCORD_TOKEN"])
discord.js: /opt/mybot/index.js
require("dotenv").config();
const { Client, GatewayIntentBits, Events } = require("discord.js");
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
client.once(Events.ClientReady, (c) => {
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.MessageCreate, (message) => {
if (message.author.bot) return;
if (message.content === "!ping") message.reply("pong");
});
client.login(process.env.DISCORD_TOKEN);
先在前台运行一次:sudo -u bot /opt/mybot/.venv/bin/python /opt/mybot/bot.py 或 sudo -u bot node /opt/mybot/index.js,等待出现 Logged in as,发送 !ping,然后按 Ctrl-C。此时机器人的生命周期仅限于当前 SSH 会话:关闭终端会向子进程发送 SIGHUP,机器人随即退出。
用 systemd 加 Restart=always 常驻运行
systemd 本就是 Ubuntu 的 init 系统,因此让机器人在退出登录、崩溃和重启后继续在线,最干净的方式就是写一个 service 单元:不需要额外守护进程,日志也直接进入 journal。
第 1 步:编写单元文件
sudo nano /etc/systemd/system/mybot.service
[Unit]
Description=Discord bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bot
Group=bot
WorkingDirectory=/opt/mybot
EnvironmentFile=/opt/mybot/.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/bot.py
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mybot
[Install]
WantedBy=multi-user.target
使用 discord.js 时,请设置 ExecStart=/usr/bin/node /opt/mybot/index.js 并删除 PYTHONUNBUFFERED 那一行。关键指令如下:
Restart=always会在进程以任何方式退出时重启它,无论是崩溃还是正常的sys.exit();RestartSec=5可防止秒退的机器人(token 错误、语法错误)陷入高频重启循环。Wants=/After=network-online.target会等网络就绪后再启动,避免重启后首次登录因 DNS 失败。PYTHONUNBUFFERED=1:没有终端时 Python 会对stdout做块缓冲,print()的内容要么延迟数分钟,要么直到退出才进入 journal。Protect*、PrivateTmp和NoNewPrivileges这几行让文件系统的其余部分对机器人只读或不可见;机器人需要写入的目录请加入ReadWritePaths=。
第 2 步:启用、启动并验证
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot
sudo systemctl kill --signal=KILL mybot # simulate a crash; status is active again after 5 s
enable 会创建开机自启的符号链接,--now 则立即启动单元。kill 那一行才是真正的测试:若几秒后 systemctl status mybot 显示 active (running),说明重启策略生效;再执行 sudo reboot 即可验证开机自启。想和其他服务一起查看,可以用 systemctl 列出正在运行的服务;它会显示为 mybot.service,而 systemctl is-enabled mybot 可确认它会在重启后自动恢复。
替代方案:pm2,以及它与 screen、nohup、Docker 的对比
所有让机器人常驻的方式,都要回答三个问题:SSH 退出后能否存活?崩溃后能否重启?开机后能否自启?
| 方式 | SSH 退出后存活 | 崩溃后重启 | 开机自启 | 结论 |
|---|---|---|---|---|
nohup / & | 是 | 否 | 否 | 仅适合快速测试。 |
screen / tmux | 是 | 否 | 否,除非自行编写脚本 | 用于调试,不适合生产。 |
| pm2 | 是 | 是 | 是,需先执行 pm2 startup + pm2 save | 适合 Node.js 团队;一个命令行工具搞定日志与重启。 |
| systemd 单元 | 是 | 是(Restart=) | 是(enable) | 推荐;无需额外软件,内置安全加固。 |
Docker,restart: unless-stopped | 是 | 是 | 是,依赖 Docker 守护进程 | 当机器人本来就以镜像分发时很合适。 |
pm2 在 Node.js 生态中很流行,也能管理 Python 进程。请以拥有机器人的那个账号运行它:
sudo npm install -g pm2
cd /opt/mybot
pm2 start index.js --name mybot
pm2 start bot.py --name mybot --interpreter /opt/mybot/.venv/bin/python # Python variant
pm2 save
pm2 startup # prints a sudo command to run once
pm2 logs mybot
pm2 install pm2-logrotate # ~/.pm2/logs/ otherwise grows forever
pm2 startup 会生成一个 pm2-<user> 的 systemd 单元,在开机时恢复你保存的进程列表,也就是说 pm2 是叠在 systemd 之上而非取代它,这正是单个机器人直接用 systemd 的理由。当你有多个 Node 进程,或团队已经熟悉 pm2 时,它才真正物有所值。
如果你偏好容器,对应做法是在 Compose 文件里写 restart: unless-stopped;在 Ubuntu VPS 上安装 Docker 的教程涵盖了引擎、Compose 与开机行为。其中关于 ufw 的注意事项不影响机器人,因为它不对外暴露端口。
日志、更新与内存规划
日志
journalctl -u mybot -f # follow live
journalctl -u mybot --since "1 hour ago"
journalctl -u mybot -p err -b # errors since boot
sudo journalctl --vacuum-size=200M # cap journal size
journald 会自动轮转并压缩日志。如果机器人自己写日志文件,请在 Python 中使用 logging.handlers.RotatingFileHandler,或在 Node 中为 pino、winston 配置轮转传输,避免话痨式日志把磁盘写满。
更新
cd /opt/mybot
sudo -u bot git pull
sudo -u bot .venv/bin/pip install -U -r requirements.txt # Node: sudo -u bot npm ci
sudo systemctl restart mybot
重启会让 gateway 连接中断几秒;库会自动重连,用户几乎察觉不到。请在 requirements.txt 或 package-lock.json 中锁定库版本,大版本升级前先读变更日志。用 sudo apt update && sudo apt upgrade 或 unattended-upgrades 保持系统更新。
机器人需要多少内存?
不要按通用数字估算,要实测。systemctl status mybot 会输出一行 Memory:,pm2 list 也能看到同样的数据。纯命令型的 discord.py 机器人空闲时通常只占几十 MB;discord.js 机器人还要加上 Node 运行时的开销。内存占用随状态增长:大型服务器的成员与消息缓存、语音与音乐(每条流一个 ffmpeg 进程)、图像生成或数据库。实际经验是,1 GB 内存足以从容运行系统加一个中小型机器人;语音密集型机器人或同机多个机器人则需要 2 GB 以上;超过 2,500 个服务器时 Discord 要求分片,占用会成倍增加。两个低成本的安全网:在单元里写 MemoryMax=512M,让内存泄漏只导致机器人重启而不是拖垮整机;再加一个小的 swap 文件。
以上一切的前提,是一台全天候在线、拥有 root 权限的 Linux 机器。如果你还差这台机器,rdp.monster 的 Discord 机器人 VPS 在付款确认后约 10 秒即可上线,提供独享 CPU 与内存、完整 root 权限、不限量(公平使用)带宽、无需 KYC、支持加密货币付款,每月 $8.99 起,让上面的 systemctl enable --now mybot 成为机器人变绿之前你敲下的最后一条命令。
常见问题
可以免费 7×24 小时托管 Discord 机器人吗?
systemd 会在崩溃和重启后拉起机器人,也没人会因为它空闲而挂起它。Discord 机器人需要固定 IP 或在 VPS 上开放端口吗?
可以在同一台 VPS 上运行多个 Discord 机器人吗?
/opt/bot-a 和 /opt/bot-b,各自的 .env 与 token,以及各自的单元文件,然后分别执行 systemctl enable --now。使用不同的系统用户,可避免一个机器人的漏洞读到另一个的 token。唯一共享的预算是内存和 CPU:逐个单元查看 systemctl status,总量接近上限时就升级到更大的套餐。Discord 机器人该托管在 Windows 还是 Linux VPS 上?
systemd 单元。在 Windows 上,你得用 Task Scheduler 或 NSSM 才能实现同样的开机自启,操作还更繁琐。Adrien Roche, 基础设施与主机托管编辑
系统工程师,拥有 10 年以上运维 Windows Server 和 Linux 集群的经验。Adrien 负责 rdp.monster 的基础设施文档,并撰写关于 RDP、VPS 托管、服务器管理、网络和隐私工具的指南。




