远程服务器运行 PostgreSQL、Redis 和 Weaviate 时,可以用一个 SSH 连接转发多个端口。服务器上的 Docker 端口只绑定本机,管理电脑上的客户端统一连接自己的 127.0.0.1。
配置好以后,只需执行一次 ssh -N home-services,不必在每个客户端里分别配置 SSH,也不需要把数据库发布到公网。
连接经过哪几个端口
以 PostgreSQL 为例:
管理电脑的数据库客户端
↓ 127.0.0.1:15432
管理电脑的 SSH 本地转发监听
↓ 加密 SSH 连接
服务器的 SSH 服务
↓ 127.0.0.1:15432
服务器上的 Docker 端口映射
↓ 容器端口 5432
PostgreSQL两边都出现 127.0.0.1,但属于不同电脑。容器中的 5432、服务器上的 15432、管理电脑上的 15432,也分别属于三个位置;后两者用相同数字只是便于记忆。
本篇从普通 SSH 登录已经可用开始。Mac 配合 Tailscale 的完整配置见 用 Tailscale 和 SSH 远程管理家中 Mac。Tailscale 负责服务器可达,端口转发由 OpenSSH 完成;其他可用的 SSH 网络也适用。
在服务器发布本机管理端口
在已有 compose.yaml 的对应服务中合并以下 ports,保留原来的镜像、认证、环境变量和数据挂载:
services:
postgres:
ports:
- '127.0.0.1:15432:5432'
redis:
ports:
- '127.0.0.1:16379:6379'
weaviate:
ports:
- '127.0.0.1:18080:8080'
- '127.0.0.1:50051:50051'15432:5432 没有指定宿主机地址,默认可能发布到所有宿主机接口;前面加上 127.0.0.1,把访问入口限制在宿主机回环地址。
Weaviate 的 8080 是 HTTP 端口,50051 用于需要 gRPC 的客户端。HTTP 通了,不代表使用 gRPC 的客户端也已具备全部连接条件。
应用配置前,在服务器检查相关宿主机端口是否已被其他程序占用。Mac 可以执行:
lsof -nP -iTCP:15432 -sTCP:LISTEN
lsof -nP -iTCP:16379 -sTCP:LISTEN
lsof -nP -iTCP:18080 -sTCP:LISTEN
lsof -nP -iTCP:50051 -sTCP:LISTEN如果已经有这套容器运行,出现它的监听是正常的,先确认进程归属。然后在服务器项目目录执行:
docker compose -f compose.yaml config --quiet
docker compose -f compose.yaml up -d --no-deps postgres redis weaviate
docker compose -f compose.yaml ps postgres redis weaviate修改端口映射可能重建相关容器并短暂中断连接。保留数据挂载,不为应用端口配置删除数据。预期 PORTS 显示 127.0.0.1:15432->5432/tcp 等映射。
继续在服务器检查:
nc -vz 127.0.0.1 15432
nc -vz 127.0.0.1 16379
nc -vz 127.0.0.1 18080
nc -vz 127.0.0.1 50051先确保服务器本机端口可达,再处理管理电脑的转发。
在管理电脑配置一次 SSH 转发
编辑管理电脑的 ~/.ssh/config,加入一个专用别名,替换服务器地址、账户和密钥路径:
Host home-services
HostName <服务器IP或可解析名称>
User <服务器登录账户>
IdentityFile ~/.ssh/id_ed25519_home
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
ExitOnForwardFailure yes
LocalForward 127.0.0.1:15432 127.0.0.1:15432
LocalForward 127.0.0.1:16379 127.0.0.1:16379
LocalForward 127.0.0.1:18080 127.0.0.1:18080
LocalForward 127.0.0.1:50051 127.0.0.1:50051每条 LocalForward 的左侧是管理电脑要监听的地址,右侧是服务器能访问的目标。使用独立别名,可以避免日常登录服务器时顺带占用所有管理端口。
在管理电脑执行:
ssh -N home-services-N 表示不执行远端命令。终端没有输出、一直保持运行是正常状态。保持它打开,另开终端或客户端使用这些端口;按 Ctrl+C 关闭转发。
ExitOnForwardFailure yes 能发现建立转发监听失败,但不会提前验证所有远端目标,也不能保证连接后数据库持续可用。OpenSSH LocalForward 与 ExitOnForwardFailure
客户端连接管理电脑本机
| 服务 | 客户端填写的地址 | 认证信息 |
|---|---|---|
| PostgreSQL | 127.0.0.1:15432 | 数据库用户、密码和实际库名 |
| Redis | 127.0.0.1:16379 | 当前 Redis ACL 用户及密码,或单密码配置 |
| Weaviate HTTP | http://127.0.0.1:18080 | 按服务实际配置提供 API Key |
| Weaviate gRPC | 127.0.0.1:50051 | 按客户端配置认证和协议 |
已经建立系统 SSH 转发时,Navicat 等客户端不再开启内置 SSH 隧道。这里填写的主机是管理电脑本机,用户名和密码是数据库凭据,不是服务器的 SSH 登录凭据。
连接 PostgreSQL 后,可以查询:
SELECT current_database(), current_user;检查是否连到了预期的库和角色。Redis 可以执行 PING,预期返回 PONG。端口的 nc 检查只验证 TCP 连通,这些操作才进一步验证服务协议和认证。
示例内部服务若使用明文 HTTP/gRPC,客户端也按相同协议配置,由 SSH 保护跨电脑传输。若原服务启用了 TLS,则继续保留它的 TLS 配置,不能因为有隧道就自动改成明文。
端口冲突和连接失败怎样查
如果管理电脑本身已经占用 15432,只改 LocalForward 左侧即可:
LocalForward 127.0.0.1:25432 127.0.0.1:15432客户端也改为 25432,服务器映射和数据库容器不需要修改。如果是服务器的 15432 冲突,才需要改 Docker 宿主机端口和 LocalForward 右侧。
| 现象 | 检查位置 |
|---|---|
Address already in use | 管理电脑本地监听端口是否被占用 |
| SSH 登录失败 | 网络、服务器账户、密钥及访问规则 |
channel ... connect failed | 服务器是否能连接转发目标,Docker 映射是否已应用 |
| 数据库认证失败 | 数据库用户、密码、库名及服务端访问策略 |
| HTTP 正常,Weaviate 客户端仍失败 | 是否还需要 gRPC,客户端端口和协议是否匹配 |
这套配置只转发选定的端口,不会把远程 Docker 网络整体搬到管理电脑。仅需查看日志或临时执行数据库命令时,直接 SSH 登录后使用 docker compose exec,也可以不发布这些管理端口。