服务器装好 MongoDB 之后,很多人第一件事就是改 bindIp,结果要么连不上,要么把数据库直接怼到公网上裸奔。这篇文章把配置文件里最关键的两项——认证开关和监听地址——一次说清楚,再给一套不暴露公网端口的连接方案。
打开服务器上的配置文件:
cat /etc/mongod.conf
下面几行是重点:
net:
port: <端口>
bindIp: 127.0.0.1
security:
authorization: enabled
一个管监听,一个管认证。下面分开说。
authorization: enabled 的意思是开启认证——连上数据库之后必须提供用户名密码,没有账号什么也做不了。这是生产环境必须保持的状态。
那如果把它注释掉呢?
# security:
# authorization: enabled
关闭认证后,任何人都能凭 IP 和端口直接连接数据库——只要敲一条 mongosh 就能进库,不用账号密码。所以这个开关务必保持开启,不能图省事关掉。唯一的例外是忘记密码时:可以短暂关闭认证进入数据库重置密码,重置完记得立刻恢复认证。
关键一步:改完配置文件必须重启 mongod 服务,新配置才会生效。
sudo systemctl restart mongod
# 部分系统的服务名是 mongodb,按实际情况来
# sudo systemctl restart mongodb
重启之后,你要么用已有账号登录,要么在没有账号的情况下临时关认证、先建账号。建账号的流程如下:
mongosh
use admin
# 第一次建 root 用户
db.createUser({user: "root", pwd: "<强密码>", roles: ["root"]})
# 也可以切换到其它数据库,修改普通用户密码
use <库名>
db.changeUserPassword("normal-user", "<新密码>")
注意:如果 root 用户已经存在,再执行 db.createUser 会直接报错。这时候改用 db.changeUserPassword 或 db.updateUser 来改密码,例如:
use admin
db.changeUserPassword("root", "<新密码>")
还有个前提:恢复认证之前,提前在云服务器的安全组里关掉 <端口>(MongoDB 默认 27017)的公网访问,避免关掉认证的那段时间里有人趁虚而入。关掉之后,只有本机能访问数据库。
可以使用
openssl rand -hex 24命令生成密码,格式如: d210be950e168479d34b7fcc140681ec33fb6eca4372822e
net:
port: <端口>
bindIp: 127.0.0.1
127.0.0.1:只监听本机回环地址,只有本机能连数据库。0.0.0.0:监听本机所有网卡,包括公网网卡。如果想让公网访问数据库,最常见的做法是改成 0.0.0.0:
net:
port: <端口>
bindIp: 0.0.0.0
这里要补一句:0.0.0.0 只是让 MongoDB 在公网网卡上开始监听,能不能从外网真的连上,还取决于云安全组和系统防火墙有没有放行 <端口>。两者都放行了,外部才连得进来。
这样配确实方便,但有个隐患:你能访问,别人只要拿到你的用户名密码,一样能访问。
那怎么做,才能让别人即便知道你的数据库用户名和密码,也没办法访问数据库?
如果你家宽带是固定 IP,比如 1.2.3.4,可以直接绑定这个 IP:
net:
port: <端口>
bindIp: 1.2.3.4
但实际情况是家里路由器一重启,IP 就变了。更稳妥的方式是用 SSH 隧道。
原理很简单:本地后端不直接连服务器的 <端口>,而是连本机的一个转发端口,这个端口通过 SSH 加密通道把流量送到服务器上的 127.0.0.1:<端口>。
以前:本地后端 ──公网──▶ 服务器:<端口> (Mongo)
现在:本地后端 ──▶ 本机:<本地端口> ══SSH加密通道(22端口)══▶ 服务器 ──▶ 127.0.0.1:<端口> (Mongo)
命令:
ssh -N -L <本地端口>:127.0.0.1:<端口> root@<服务器IP>
参数说明:
-L 本地端口:目标地址:目标端口:在本机开一个端口,发到这个端口的数据都通过 SSH 转给服务器上的 127.0.0.1:<端口>。-N:只建隧道,不打开远程 shell。所以窗口看起来像卡住了,这是正常的。写进 ~/.ssh/config,以后一条命令:
Host myapp-db
HostName <服务器IP>
User root
LocalForward <本地端口> 127.0.0.1:<端口>
以后只要执行:
ssh -N myapp-db
本机后端的数据库连接串也要改成走本地端口:
MONGODB_URL=mongodb://<mongo用户>:<密码>@127.0.0.1:<本地端口>/<库名>
验证隧道是否通了:
lsof -nP -iTCP:<本地端口> -sTCP:LISTEN # 能看到 ssh 进程在监听
然后用项目代码连一下库,执行:
mongosh "mongodb://127.0.0.1:<本地端口>" --eval "db.runCommand({ping: 1})"
返回 ok: 1.0,就说明隧道通了。
方式一:借用已经开着的隧道(最简单)。 URI 填:
mongodb://<mongo用户>:<新密码>@127.0.0.1:<本地端口>/<库名>
方式二:让 Compass 自己建隧道。
mongodb://127.0.0.1:<本地端口>/<库名>。admin(或在 URI 里写 authSource=admin);建在业务库则填对应的 <库名>。~/.ssh/id_rsa。在 macOS 的文件选择框里按 Cmd+Shift+. 可以显示隐藏目录。↶ 返回首页 ↶