如何在 VPS 上安装和配置 MongoDB(完整指南)
MongoDB 是一个面向文档的 NoSQL 数据库,将记录存储为 BSON(Binary JSON)文档,通过原生分片实现无模式数据建模和水平可扩展性。与关系型数据库不同,MongoDB 不需要预定义的表模式,使其成为具有不断演变的数据结构、高写入吞吐量或分层数据关系的应用程序的首选。
本指南介绍了在 Linux VPS 上进行生产级 MongoDB 部署的步骤——涵盖从官方存储库安装、身份验证加固、网络访问控制、TLS 配置、性能调优和备份自动化。每个步骤都假设您在真实服务器环境中运行,其中安全性和可靠性是不可协商的。
前置条件
继续之前,请确认以下内容:
- 运行 Ubuntu 20.04 LTS 或 Ubuntu 22.04 LTS 的 VPS(两者命令相同)
- 通过 SSH 进行 Root 或
sudo-privileged 用户访问 - 最少 2 GB RAM(生产工作负载建议 4 GB)
- 快速存储卷上至少 20 GB 的可用磁盘空间
- UFW 或 iptables 可用于防火墙管理
- 基本熟悉 Linux 命令行
> 架构说明:MongoDB 的 WiredTiger 存储引擎使用默认内部缓存,大小为 (RAM – 1 GB) 的 50%。在 2 GB VPS 上,这大约产生 512 MB 的缓存。对于读取密集型工作负载,至少配置 4 GB RAM 以避免缓存压力导致的持续磁盘 I/O。
MongoDB 与其他 NoSQL 数据库:快速对比
| 功能 | MongoDB | Redis | Cassandra | CouchDB |
|---|---|---|---|---|
| 数据模型 | 文档 (BSON) | 键值 | 宽列 | 文档 (JSON) |
| 查询语言 | MQL (丰富查询) | 命令 | CQL | Mango / MapReduce |
| 水平扩展 | 原生分片 | 集群模式 | 原生 | 多主 |
| ACID 事务 | 是 (v4.0+, 多文档) | 部分 (Lua 脚本) | 轻量级 | 是 |
| 最佳用例 | 通用应用、API | 缓存、会话 | 时间序列、物联网 | 离线优先同步 |
| 磁盘持久化 | 主存储 | 可选 (RDB/AOF) | 主存储 | 主存储 |
| 全文搜索 | Atlas Search / 文本索引 | 有限 | 否 | 有限 |
第1步:更新系统
始终从完全修补的系统开始。过时的软件包会引入已知的CVE,这些漏洞可能在您安装应用程序堆栈之前就被利用。
sudo apt update && sudo apt upgrade -y应用内核或libc更新后,重新启动以激活新内核:
sudo reboot服务器重新上线后通过SSH重新连接(通常需要30–60秒)。
第 2 步:从官方存储库安装 MongoDB
Ubuntu 的默认 apt 存储库提供的是过时的、社区重新打包的 MongoDB 版本,缺乏最新的安全补丁和引擎改进。始终从 MongoDB 的官方存储库安装。
添加 MongoDB GPG 密钥和存储库
apt-key 命令在 Ubuntu 22.04 上已弃用。使用推荐的密钥环方法,该方法适用于 20.04 和 22.04:
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc |
sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg添加官方存储库条目:
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ]
https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" |
sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list> 版本说明:如果您需要特定版本以实现应用程序兼容性,请将 7.0 替换为您的目标版本(例如 6.0)。MongoDB 7.0 是截至 2024 年的当前长期支持版本。
安装 MongoDB 软件包
sudo apt update
sudo apt install -y mongodb-org这将安装以下组件:
mongod — 主数据库守护程序
mongos — 分片路由器(用于分片集群部署)
mongosh — 现代 MongoDB Shell(替代旧版 mongo 二进制文件)
mongodb-database-tools — 包括 mongodump、mongorestore、mongoexport 和 mongoimport固定已安装的版本
防止可能破坏应用程序兼容性的意外升级:
echo "mongodb-org hold" | sudo dpkg --set-selections
echo "mongodb-org-database hold" | sudo dpkg --set-selections
echo "mongodb-org-server hold" | sudo dpkg --set-selections
echo "mongosh hold" | sudo dpkg --set-selections
echo "mongodb-org-mongos hold" | sudo dpkg --set-selections
echo "mongodb-org-tools hold" | sudo dpkg --set-selections第 3 步:配置系统级先决条件
MongoDB 在守护程序启动前调整某些内核和文件系统参数时性能最佳。
为打开的文件设置 ulimit
MongoDB 需要较高的文件描述符限制。创建 systemd 覆盖:
sudo mkdir -p /etc/systemd/system/mongod.service.d
sudo tee /etc/systemd/system/mongod.service.d/limits.conf > /dev/null <<EOF
[Service]
LimitFNOFILE=64000
LimitNPROC=64000
EOF禁用透明大页面 (THP)
THP 会导致 MongoDB 中出现显著的延迟峰值。持久禁用它:
sudo tee /etc/systemd/system/disable-thp.service > /dev/null <<EOF
[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=mongod.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null'
ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null'
[Install]
WantedBy=basic.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now disable-thp验证设置是否生效:
cat /sys/kernel/mm/transparent_hugepage/enabled输出应显示 [never] 作为活动值。
第 4 步:启动并启用 MongoDB
sudo systemctl daemon-reload
sudo systemctl start mongod
sudo systemctl enable mongod确认守护进程正在运行:
sudo systemctl status mongod在输出中查找 Active: active (running)。如果服务启动失败,立即检查日志:
sudo tail -50 /var/log/mongodb/mongod.log常见的启动失败包括:
- 端口 27017 已在使用 — 另一个进程绑定到该端口;使用
sudo ss -tlnp | grep 27017识别它 - 数据目录权限 —
mongod用户必须拥有/var/lib/mongodb;使用sudo chown -R mongodb:mongodb /var/lib/mongodb修复 - THP 仍然启用 — WiredTiger 引擎会记录警告,可能会降低性能
第5步:保护MongoDB — 身份验证和授权
这是最关键的部分。暴露在互联网上的未受保护的MongoDB实例已导致数千起数据泄露事件。默认安装没有身份验证,这意味着任何能够访问端口27017的人都可以完全读写访问每个数据库。
创建管理员用户
连接到本地MongoDB shell(启用身份验证前不需要身份验证):
mongosh在shell内,切换到admin数据库并创建超级用户:
use admin
db.createUser({
user: "adminuser",
pwd: passwordPrompt(),
roles: [
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" },
{ role: "dbAdminAnyDatabase", db: "admin" },
{ role: "clusterAdmin", db: "admin" }
]
})使用passwordPrompt()而不是纯文本字符串可以防止密码出现在shell历史记录中。在提示时输入密码,然后退出:
exit在mongod.conf中启用身份验证
打开MongoDB配置文件:
sudo nano /etc/mongod.conf找到security部分(它将被注释掉)并启用授权:
security:
authorization: enabled保存并退出(Ctrl+X,然后Y,然后Enter),然后重启守护进程:
sudo systemctl restart mongod验证身份验证已强制执行
尝试未经身份验证的连接 — 现在应该失败:
mongosh --eval "db.adminCommand({ listDatabases: 1 })"您应该收到Unauthorized错误。现在正确进行身份验证:
mongosh -u adminuser -p --authenticationDatabase admin创建应用程序范围的用户
切勿将管理员超级用户用于应用程序连接。为每个应用程序数据库创建最小权限用户:
use myappdb
db.createUser({
user: "appuser",
pwd: passwordPrompt(),
roles: [
{ role: "readWrite", db: "myappdb" }
]
})第 6 步:配置网络绑定和防火墙规则
限制或扩展 bindIp
默认情况下,mongod.conf 仅绑定到 127.0.0.1。如果您的应用程序在同一 VPS 上运行,这是正确的设置。如果您需要远程访问(例如,从单独主机上的应用程序服务器),请编辑 /etc/mongod.conf:
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.5将 10.0.0.5 替换为应用程序服务器的特定私有 IP。切勿在没有防火墙规则限制对已知 IP 访问的公共接口上设置 bindIp: 0.0.0.0。绑定到所有接口且没有防火墙是导致 MongoDB 数据泄露事件的主要原因。
更改后重新启动:
sudo systemctl restart mongod配置 UFW 防火墙规则
如果需要远程访问,仅允许特定的受信任 IP:
sudo ufw allow from 10.0.0.5 to any port 27017 proto tcp
sudo ufw enable
sudo ufw status verbose阻止所有其他对端口 27017 的外部访问:
sudo ufw deny 27017UFW 按顺序处理规则 — 上面的特定 allow from 规则优先于广泛的 deny 规则,对受信任的 IP 生效。
第 7 步:为加密连接启用 TLS/SSL
对于任何 MongoDB 流量跨越网络的部署——即使是私有 LAN——TLS 加密是强制性的。没有它,凭证和数据以明文形式传输。
生成自签名证书用于测试(在生产环境中使用 CA 签名的证书——考虑将其与您域名的 SSL 证书配对):
sudo mkdir -p /etc/mongodb/ssl
sudo openssl req -newkey rsa:4096 -nodes -keyout /etc/mongodb/ssl/mongodb.key
-x509 -days 365 -out /etc/mongodb/ssl/mongodb.crt
-subj "/CN=your-vps-hostname"
sudo cat /etc/mongodb/ssl/mongodb.crt /etc/mongodb/ssl/mongodb.key |
sudo tee /etc/mongodb/ssl/mongodb.pem > /dev/null
sudo chown -R mongodb:mongodb /etc/mongodb/ssl
sudo chmod 600 /etc/mongodb/ssl/mongodb.pem将 TLS 配置添加到 /etc/mongod.conf:
net:
port: 27017
bindIp: 127.0.0.1
tls:
mode: requireTLS
certificateKeyFile: /etc/mongodb/ssl/mongodb.pem重启 MongoDB 并使用 TLS 连接:
sudo systemctl restart mongod
mongosh --tls --tlsCertificateKeyFile /etc/mongodb/ssl/mongodb.pem
--tlsAllowInvalidCertificates -u adminuser -p --authenticationDatabase admin--tlsAllowInvalidCertificates 标志仅在开发环境中对自签名证书可接受。使用 CA 签名的证书时将其删除。
第8步:在 mongod.conf 中进行性能调优
对于在具有专用资源的 VPS 上的生产部署,调优 WiredTiger 缓存和日志记录设置。打开 /etc/mongod.conf 并添加或修改以下内容:
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 1.5
operationProfiling:
slowOpThresholdMs: 100
mode: slowOp
replication:
oplogSizeMB: 1024关键调优参数说明:
cacheSizeGB— 将其设置为可用 RAM 的大约 50% 减去 1 GB。在 4 GB VPS 上,使用1.5。在 8 GB VPS 上,使用3.5。slowOpThresholdMs— 超过此阈值(以毫秒为单位)的查询将被记录到分析器。降低此值有助于及早识别未索引的查询。oplogSizeMB— 如果您计划稍后添加副本集成员,则相关。预先调整 oplog 大小可避免高写入工作负载上的复制延迟。
应用更改:
sudo systemctl restart mongod第9步:使用 mongodump 进行备份和恢复
手动备份
mongodump
--uri="mongodb://adminuser:yourpassword@127.0.0.1:27017/?authSource=admin"
--out /var/backups/mongodb/$(date +%Y-%m-%d)手动恢复
mongorestore
--uri="mongodb://adminuser:yourpassword@127.0.0.1:27017/?authSource=admin"
/var/backups/mongodb/2024-06-15使用 Cron 自动化备份
创建一个专用备份脚本:
sudo tee /usr/local/bin/mongodb-backup.sh > /dev/null <<'EOF'
#!/bin/bash
BACKUP_DIR="/var/backups/mongodb"
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
MONGO_URI="mongodb://adminuser:yourpassword@127.0.0.1:27017/?authSource=admin"
RETENTION_DAYS=7
mkdir -p "${BACKUP_DIR}/${TIMESTAMP}"
mongodump --uri="${MONGO_URI}" --out="${BACKUP_DIR}/${TIMESTAMP}"
find "${BACKUP_DIR}" -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} ;
EOF
sudo chmod +x /usr/local/bin/mongodb-backup.sh将其安排为每天凌晨 2:00 运行:
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/mongodb-backup.sh >> /var/log/mongodb-backup.log 2>&1") | crontab -> 生产环境考虑:将备份存储在服务器外。将备份保存在与数据库相同的 VPS 上无法防止磁盘故障或服务器泄露。使用 rsync、rclone 或 S3 兼容的对象存储将备份复制到远程位置。
第 10 步:监控 MongoDB 健康状况
内置监控命令
在 mongosh 内运行服务器统计:
db.serverStatus()
db.stats()
db.currentOp()使用 mongostat 和 mongotop
从 shell 监控实时操作计数:
mongostat --uri="mongodb://adminuser:yourpassword@127.0.0.1:27017/?authSource=admin"监控每个集合的读/写时间:
mongotop --uri="mongodb://adminuser:yourpassword@127.0.0.1:27017/?authSource=admin"关键指标监控
| 指标 | 警告阈值 | 表示内容 |
|---|---|---|
wiredTiger.cache.bytes currently in cache | > 90% 的 cacheSizeGB | 缓存压力;增加 RAM 或减少数据集 |
connections.current | > 80% 的 connections.available | 连接池耗尽;调整应用程序池 |
opcounters.getmore | 持续高值 | 游标效率低;检查查询模式 |
repl.lag(副本集) | > 10 秒 | 复制延迟;检查网络和磁盘 I/O |
locks.Global.acquireWaitCount | 任何持续值 | 锁争用;检查长时间运行的操作 |
为 MongoDB 选择合适的托管
您的 MongoDB 实例的性能和可靠性直接与底层基础设施相关。考虑这些部署层级:
- 开发和暂存:具有 2–4 GB RAM 的标准 VPS 足以满足非生产工作负载、架构测试和集成环境的需求。
- 生产单节点:具有 4–8 GB RAM、NVMe 存储和专用 CPU 核心的 VPS 可处理大多数 Web 应用程序的中等生产流量。
- 高吞吐量生产:专用服务器消除了虚拟化环境中固有的嘈杂邻居效应。WiredTiger 的 I/O 模式从裸机 NVMe 阵列中受益匪浅。
- ML/分析工作负载:如果您在运行 MongoDB 以及数据管道、聚合密集型分析或向量搜索,GPU 托管可以加速下游处理任务。
对于需要图形管理界面的部署,带 cPanel 的 VPS 为不太熟悉纯 CLI 管理的团队提供了熟悉的环境,尽管直接 mongod.conf 编辑对于高级配置仍然是必要的。
部署决策矩阵
上线前使用此检查清单:
- [ ] MongoDB 从官方存储库安装,版本已固定
- [ ]
mongod服务已启用并确认active (running) - [ ] 透明大页已禁用并验证
- [ ]
ulimit文件描述符设置为 64000 或更高 - [ ] 在
mongod.conf中启用身份验证(authorization: enabled) - [ ] 已创建管理员用户,使用
passwordPrompt()— shell 历史记录中没有明文密码 - [ ] 已创建应用程序特定用户,具有最小权限角色
- [ ]
bindIp仅限于 localhost 或特定受信任 IP - [ ] UFW 规则已就位 — 端口 27017 从公网阻止
- [ ] 已启用 TLS 并配置有效证书
- [ ] WiredTiger 缓存大小设置为 (RAM – 1 GB) 的 50%
- [ ] 已启用慢查询分析(
slowOpThresholdMs: 100) - [ ] 自动每日备份,带离线服务器复制
- [ ] 备份恢复已测试 — 从未恢复过的备份不是备份
常见问题
MongoDB 默认监听的端口是什么,应该更改吗?
MongoDB 默认监听 TCP 端口 27017。将其更改为非标准端口会增加一点隐蔽性,但不能替代身份验证和防火墙规则。如果更改,请在 /etc/mongod.conf 中更新 net.port,并相应调整所有 UFW 规则和连接字符串。
为什么 MongoDB 即使在数据集较小的情况下也会占用大量 RAM?
WiredTiger 根据公式 max(50% of (RAM - 1 GB), 256 MB) 预分配其内部缓存。这是有意的——将工作数据保存在内存中可以消除磁盘读取。如果在小型 VPS 上 RAM 消耗是个问题,请在 /etc/mongod.conf 中明确将 cacheSizeGB 设置为较低的值。
我可以在共享主机上运行 MongoDB 吗?
不可以。MongoDB 需要持久的后台守护进程 (mongod)、对其数据目录的直接文件系统访问,以及绑定到网络端口的能力。这些在共享虚拟主机上都不可用。VPS 是最低可行的环境。
mongodump 和文件系统快照备份之间有什么区别?
mongodump 执行逻辑备份——它通过 MongoDB 查询接口读取文档并将其导出为 BSON 文件。它具有可移植性并可跨版本工作,但速度较慢,在没有 --oplog 的情况下无法保证高写入实例上的时间点一致性。文件系统快照 (LVM、ZFS 或云块存储快照) 在一致的时间点捕获原始数据文件,对于大型数据集速度明显更快,但需要存储引擎处于一致状态。
如何检查已安装的 MongoDB 版本?
从终端运行以下命令:
mongod --version或从 mongosh 内部:
db.version()