MongoDB服务器如何部署?安装、权限配置与远程访问教程

MongoDB 是最常用的文档型数据库,很多项目用它存日志、存半结构化数据、存配置,或者干脆拿它当主库。但它的部署和权限配置跟 MySQL 很不一样:默认装完是不需要认证的,绑定地址是 127.0.0.1,一旦为了远程访问随手改成 0.0.0.0 又不设密码,就等于把整个数据库敞开在公网上——这几年被拖库、被勒索的 MongoDB 案例,绝大多数都是这么来的。

这篇文章按"装得上、连得进、管得住、防得住"的顺序,把 MongoDB 在一台 Linux 服务器上的完整部署过程讲清楚:官方仓库安装与发行版包安装的选择、mongod.conf 关键项、开启认证并建用户、远程访问的正确做法与安全红线、以及副本集的简单说明。

一、先搞清楚版本与安装方式

MongoDB 官方版本号采用偶数版本为稳定版(如 6.0、7.0)、奇数版本为开发版的历史约定,现在主流是 6.0 和 7.0 两个系列。选版本时优先选官方仍在维护的稳定版,别用发行版仓库里过旧或被标记 EOL 的版本。

安装有两条路:

一是官方仓库安装,版本新、可控,适合生产环境;二是发行版自带仓库安装,方便但版本通常偏旧。生产环境建议走官方仓库,这样升级和版本选择更自由。

需要注意的是,较新的 MongoDB 对 CPU 有要求:5.0 及以后版本要求 CPU 支持 AVX 指令集。老旧的虚拟机或某些云主机如果 CPU 不支持 AVX,装完会启动失败并报 Illegal instruction。遇到这种情况要么换机型,要么降到 4.4 系列。

检查 CPU 是否支持 AVX:

grep -o 'avx[^ ]*' /proc/cpuinfo | sort -u
# 输出里有 avx 或 avx2 就满足;没有任何输出说明不支持,需要换机型或降版本

二、安装 MongoDB

RHEL / CentOS / Rocky / AlmaLinux

官方仓库通过 yum/dnf 源配置。以 7.0 为例:

# 1. 添加官方仓库(RHEL 8/9、Rocky 8/9)
cat > /etc/yum.repos.d/mongodb-org-7.0.repo <<'EOF'
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-7.0.asc
EOF

# 2. 安装
dnf install -y mongodb-org
# CentOS 7 用 yum:yum install -y mongodb-org

# 3. 启动并设置开机自启
systemctl enable --now mongod
systemctl status mongod

Debian / Ubuntu

# 1. 导入官方 GPG key
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
  gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor

# 2. 添加源(Ubuntu 22.04 示例,其他版本替换 codename)
echo "deb [ arch=amd64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] \
https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" \
> /etc/apt/sources.list.d/mongodb-org-7.0.list

# 3. 安装
apt-get update
apt-get install -y mongodb-org

# 4. 启动
systemctl enable --now mongod

安装完成后,配置文件默认在 /etc/mongod.conf,数据目录默认是 /var/lib/mongo(RHEL 系)或 /var/lib/mongodb(Debian 系),日志在 /var/log/mongodb/mongod.log。这三个路径后面配置时都会用到。

验证是否起来了:

ss -tlnp | grep 27017      # 默认监听 27017
mongod --version           # 查看版本
mongosh                    # 新版命令行客户端,连本机默认实例
# 老版本用 mongo 命令,MongoDB 6.0 起官方客户端叫 mongosh

三、mongod.conf 关键配置

/etc/mongod.conf 是 YAML 格式,缩进用空格,不要用 Tab,否则会启动失败。下面是最常改的几个块:

# 网络配置
net:
  port: 27017
  bindIp: 127.0.0.1      # 默认只监听本机,安全首选

# 存储配置
storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true        # 生产务必开启,保证崩溃后可恢复

# 日志
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# 进程管理
processManagement:
  fork: true             # 用 systemd 管理时一般不需要,交给 systemd
  timeZoneInfo: /usr/share/zoneinfo

# 安全(先别急着开,等建好用户再开,见下一节)
security:
  authorization: disabled

几个必须讲清楚的项:

第一,bindIp 决定谁能连。默认 127.0.0.1 只允许本机,最安全。要提供内网服务可以写内网网卡 IP,比如 bindIp: 127.0.0.1,10.0.0.5,逗号分隔。不要为了方便直接写 0.0.0.0 暴露到公网,这是最典型的被入侵入口。

第二,dbPath 指向数据目录。如果单独挂了一块数据盘,把它改到数据盘上,例如 /data/mongodb。改之前要确保目录存在且属主是 mongod 用户:

mkdir -p /data/mongodb
chown -R mongod:mongod /data/mongodb
# 改完 dbPath 后重启,注意:改目录不会自动搬数据,新目录必须是空的或已放好旧数据
systemctl restart mongod

第三,journal 是预写日志,保证数据在崩溃后能恢复。生产环境一定要 enabled: true。关掉它也许能提升一点写入性能,但代价是断电后可能丢数据、甚至数据文件损坏——不要为了这点性能冒险。

改完配置后,重启前先验证语法:

mongod --config /etc/mongod.conf --configExpand none --fork=false 2>&1 | head
# 或直接重启并看日志
systemctl restart mongod
journalctl -u mongod -n 50 --no-pager

四、启用认证与创建用户

MongoDB 默认没有认证,"先建管理员、再开认证"是关键顺序,顺序错了会把自己锁在门外。

第一步,连上实例(此时还没开认证),创建管理员账号:

// 在 mongosh 中执行
use admin
db.createUser({
  user: "admin",
  pwd: passwordPrompt(),        // 交互式输入密码,避免明文进 shell 历史
  roles: [ { role: "userAdminAnyDatabase", db: "admin" },
           { role: "readWriteAnyDatabase", db: "admin" } ]
})

角色别乱给。userAdminAnyDatabase 能管理所有库的用户,readWriteAnyDatabase 能读写所有库。真正生产应该最小权限:管理员先只给 userAdminAnyDatabase 和 clusterAdmin 之类管理角色,业务账号按库、按读写范围单独建。

第二步,启用认证。编辑配置:

security:
  authorization: enabled

然后重启:

systemctl restart mongod

重启后再连接就需要带账号了:

# 命令行方式
mongosh -u admin -p --authenticationDatabase admin

# 或连接字符串方式
mongosh "mongodb://admin@127.0.0.1:27017/?authSource=admin"

第三步,为业务库建专用用户和角色。MongoDB 的权限是"库 + 角色"模型,内置角色里常用的有 read、readWrite、dbAdmin、dbOwner:

use myapp
db.createUser({
  user: "appuser",
  pwd: passwordPrompt(),
  roles: [ { role: "readWrite", db: "myapp" } ]
})

// 查看已有用户
db.getUsers()
// 查看某用户权限
db.getUser("appuser")

如果内置角色不够细,可以自定义角色:

use myapp
db.createRole({
  role: "appReadOnly",
  privileges: [{
    resource: { db: "myapp", collection: "" },
    actions: ["find"]
  }],
  roles: []
})

删除用户用 db.dropUser("appuser")。改了密码或权限后,已建立的连接不会自动生效,需要重连。

风险提示:在开启认证的实例上,如果你修改了某个用户、又把它的权限收窄了,务必确认还有一个具备管理权限的账号可用,否则一旦需要恢复会很麻烦。管理员密码务必离线保存一份。

五、远程访问与安全红线

很多人部署 MongoDB 就是为了让应用服务器远程连它。正确做法不是把 bindIp 改成 0.0.0.0 了事,而是分情况处理。

情况一:应用服务器与数据库在同一内网

这是最推荐的方式。把 bindIp 改成内网 IP 或同时监听本机和内网卡:

net:
  bindIp: 127.0.0.1,10.0.0.5

然后在防火墙上只放行应用服务器的内网 IP 到 27017 端口。RHEL 系和 Debian 系的防火墙命令不同:

# RHEL / CentOS / Rocky:用 firewalld
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.20/32" port protocol="tcp" port="27017" accept'
firewall-cmd --reload
firewall-cmd --list-all

# Debian / Ubuntu:用 ufw
ufw allow from 10.0.0.20 to any port 27017 proto tcp
ufw status verbose

如果不用 firewalld/ufw,也可以用 iptables 直接限制来源:

iptables -A INPUT -p tcp -s 10.0.0.20 --dport 27017 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP

情况二:必须跨公网连接

这是高风险场景,强烈建议先评估有没有替代方案。 如果实在避不开,底线是:

  • 认证必须开(authorization: enabled),并且用强密码,业务账号最小权限。
  • 不要直接暴露 27017 到公网,优先走 VPN、专线、或者 SSH 隧道。
  • 如果一定要开放,在云安全组/防火墙层面把来源限制到具体 IP,不要写 0.0.0.0/0。
  • 定期检查用户列表和连接日志,发现陌生来源及时封禁。

SSH 隧道是跨公网相对安全的折中:数据在 SSH 加密通道里传,公网只暴露 22 端口。

# 在应用服务器上建立隧道:把本地 27018 转发到数据库服务器的 127.0.0.1:27017
ssh -N -L 27018:127.0.0.1:27017 user@dbserver-ip
# 应用连接 mongodb://appuser@127.0.0.1:27018/myapp?authSource=myapp

严重风险提示:把 MongoDB 的 bindIp 设为 0.0.0.0 且未启用认证,等同于把数据库完全公开。公网上有大量自动化扫描程序,会在数小时内发现并清空你的数据、留下勒索信息。绝不要在公网 IP 上运行无认证、全监听的 MongoDB。 如果已经这样运行过,立即开启认证、限制来源、检查数据完整性,并检查是否有异常用户或可疑连接。

再补充两个安全项:一是禁用或限制 HTTP 接口(老版本有,新版本默认关闭);二是开启审计或至少保留日志,便于事后追查。云厂商的托管 MongoDB 通常提供了免运维的认证和网络隔离,如果团队运维能力有限,托管是值得考虑的选项。

六、副本集简述

单节点 MongoDB 没有冗余,机器一挂数据就不可用,也谈不上高可用。生产环境通常部署副本集(replica set):至少三个节点,一个主节点(primary)负责写,其余从节点(secondary)复制数据。

最小可用配置是三个节点(或者两个数据节点加一个仲裁节点 arbiter)。启动时每个节点带 --replSet 参数:

# 每个节点的 mongod.conf 增加
replication:
  replSetName: rs0

然后连到其中一个节点初始化:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "10.0.0.5:27017" },
    { _id: 1, host: "10.0.0.6:27017" },
    { _id: 2, host: "10.0.0.7:27017" }
  ]
})
// 查看状态
rs.status()

副本集带来两个额外好处:一是自动故障切换(主节点挂了,从节点选举出新主),二是读写分离(从节点可以承担读流量)。连接字符串也要相应调整:

mongosh "mongodb://appuser@10.0.0.5:27017,10.0.0.6:27017,10.0.0.7:27017/myapp?replicaSet=rs0&authSource=myapp"

副本集里每个节点都要单独建用户吗?不用——用户在副本集内是同步的,在主节点建一次即可。但要注意副本集内部的认证密钥(keyfile 或 x.509),用于节点之间互相验证身份,否则内部通信不安全。

七、日常运维与备份

几条日常命令:

# 看服务状态和日志
systemctl status mongod
tail -f /var/log/mongodb/mongod.log

# 查看数据库和占用
mongosh -u admin -p --authenticationDatabase admin --eval \
  'db.adminCommand({listDatabases:1})'

# 逻辑备份(小数据量)
mongodump --uri="mongodb://appuser@127.0.0.1:27017/myapp?authSource=myapp" \
  --out=/backup/mongo-$(date +%F)

# 恢复
mongorestore --uri="mongodb://appuser@127.0.0.1:27017/myapp?authSource=myapp" \
  --dir=/backup/mongo-2026-10-12/myapp

# 副本集生产环境更推荐物理备份(文件系统快照或 mongodump 结合 oplog)

mongodump 适合中小数据量,数据量大时它会造成明显负载,且不是一致性快照(除非结合 --oplog)。生产环境更推荐基于存储快照的物理备份,或者使用云厂商的自动备份。无论哪种方式,必须定期做恢复演练,没验证过的备份等于没有备份。

常见问题

Q:装完启动失败,日志报 Illegal instruction,怎么办?
基本可以确定是 CPU 不支持 AVX。grep avx /proc/cpuinfo 确认后,换一台支持 AVX 的机器,或改用 4.4 系列版本。

Q:开了认证之后连不上了,怎么办?
先确认连接时带了 authSource(管理账号通常是 admin)。如果管理员密码也忘了,需要以 --noauth(旧版)或临时改回 authorization: disabled 启动来重置,操作前务必备份数据目录。

Q:bindIp 改了 0.0.0.0 但还是连不上?
检查三层:MongoDB 是否监听成功(ss -tlnp | grep 27017)、服务器防火墙是否放行(firewalld/ufw/iptables)、云厂商安全组是否放行。很多"连不上"其实是安全组没开。

Q:改 dbPath 后启动报权限错误?
新目录属主必须是 mongod:mongod,且 SELinux 开启时还需要正确的安全上下文。可以用 chcon -R -t mongod_var_lib_t /data/mongodb 或 semanage fcontext 处理,RHEL 系尤其常见。

Q:单节点够用吗?
开发和测试够用。生产要可用性和数据安全,副本集是基本要求,单节点只能靠频繁备份兜底,恢复期间业务是中断的。

总结

  • 生产环境用官方仓库安装,注意 5.0+ 需要 CPU 支持 AVX,否则启动会失败。
  • mongod.conf 里 bindIp 默认只监听本机最安全,务必开 journal,改 dbPath 要处理目录属主和 SELinux。
  • 正确顺序是"先建管理员用户,再开 authorization: enabled",业务账号按库按最小权限创建。
  • 远程访问优先走内网 + 防火墙白名单,跨公网优先用 SSH 隧道/VPN,绝不要在公网跑无认证、0.0.0.0 监听的实例。
  • 生产必须有副本集和经过演练的备份,单节点只适合开发测试。