PostgreSQL远程管理:通过SSH隧道连接

需要在自己电脑上查看服务器里的 PostgreSQL,可以通过 SSH 转发连接。本例适用于Ubuntu 24.04、PostgreSQL 16,且 SSH 与数据库位于同一台服务器:数据库保留本机监听,无需把 5432 放到公网。

先准备可用的 SSH 登录资料、数据库名和数据库角色密码。下文的 serveradmin是 Linux 账号,appuser是数据库角色,appdb是数据库名;都要换成自己的实际值。尚未安装数据库时,先看PostgreSQL 安装教程。

先在服务器本机验证数据库连接

通过SSH 登录服务器,检查 5432 的监听,再进入管理员会话。已自定义端口或管理员认证方式时,使用现有的有效连接资料,不要为登录临时改成免密认证:

sudo ss -lntp 'sport = :5432'
sudo -u postgres psql -X -p 5432 -d postgres

在 postgres=#提示符中执行:

SHOW server_version;
SHOW port;
SHOW listen_addresses;
SHOW hba_file;

本例需要能通过 127.0.0.1:5432连接数据库;listen_addresses=localhost即可,不需要改为 *。如果当前只启用了 Unix 套接字,先由管理员安排本机 TCP 监听;修改监听地址需要重启数据库,不要在业务运行中贸然重启。

输入 \q退出 psql,在服务器的 Linux 命令行测试业务角色。密码在提示时输入,不放进命令或截图。已有严格 TLS 校验时,改用下文的 verify-full 写法,并把端口改为 5432;不要降低校验级别。

psql -X -h 127.0.0.1 -p 5432 -U appuser -d appdb -W

能登录后输入 \q退出。本机这一步失败,先处理数据库认证;在电脑上反复建隧道不会解决它。数据库密码与 Linux 登录密码分别设置,不能混用。

回到自己的电脑建立隧道

在电脑的 PowerShell、终端或其他已安装 OpenSSH 客户端的命令行执行下面一整行。203.0.113.10是示例地址,必须替换。首次连接先核对 SSH 主机指纹,非默认 SSH 端口将 -p 22改为实际值:

ssh -N -T -p 22 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -L 127.0.0.1:15432:127.0.0.1:5432 serveradmin@203.0.113.10

认证成功后,窗口没有返回命令提示符通常是正常现象,保留它。前一个 127.0.0.1:15432是你电脑上的入口,后一个 127.0.0.1:5432是服务器本机的数据库。不要在服务器终端里执行这一条,也不要把本地绑定地址改成 0.0.0.0。

ExitOnForwardFailure能让本地端口绑定失败时及时退出,但不能证明远端数据库已经可用,仍需下一步实际登录。

数据库工具连接本地15432端口

新开一个本地窗口,使用已安装的 PostgreSQL 客户端。没有另行规定 TLS 校验参数时,可用:

psql -X -h 127.0.0.1 -p 15432 -U appuser -d appdb -W

如果数据库要求 verify-full,直接拿 127.0.0.1 校验证书可能出现名称不匹配。psql 使用 libpq,可把连接地址与证书名称分别指定:

psql -X -W "host=db.example.com hostaddr=127.0.0.1 port=15432 dbname=appdb user=appuser sslmode=verify-full sslrootcert=/absolute/path/root-ca.crt"

hostaddr指向本地隧道,host保留证书中的数据库名称。将示例域名换成证书匹配的真实名称,CA 路径换成管理员提供的可信证书文件路径;已有的客户端证书等要求也要保留。

图形化工具可参考下表。严格校验证书时,工具须支持分别指定连接地址和证书名称;不支持就换用支持的客户端,不能关闭名称或证书校验。已经通过外部 SSH 窗口建立隧道,就不要再建第二条。

字段 本例填写
连接地址、端口 127.0.0.1、15432;严格 TLS 另填证书名称
数据库、用户名 实际数据库名、数据库角色;不是 Linux 账号
密码 该数据库角色的密码
SSL 沿用现有 TLS 与证书校验要求;SSH 隧道不替代它们

连接后执行一条只读查询,确认不是误连到电脑上另一套数据库:

SELECT current_database(), current_user,
       inet_client_addr(), inet_server_addr(), inet_server_port();

本例应返回实际数据库和角色,服务端地址为 127.0.0.1、端口为 5432。返回的服务端端口不是 15432,这正是转发后的结果。

密码明明正确,为什么仍被拒绝?

服务器上的 sudo -u postgres psql通常走 Unix 套接字,可能使用 peer核对系统身份;隧道到达数据库时是本机 TCP 连接,按是否使用 TLS 匹配 host、hostssl等规则。前一种能进,并不代表业务角色密码正确。

由数据库管理员在 psql 中查看规则及语法错误:

SELECT rule_number, file_name, line_number, type,
       database, user_name, address, auth_method, error
FROM pg_hba_file_rules
ORDER BY rule_number NULLS LAST, file_name, line_number;

规则从上往下匹配,命中后认证失败不会继续尝试后面的规则。若现有策略确实缺少这组访问权限,先备份 SHOW hba_file返回的文件,再由管理员在合适位置加入精确规则。下面的 host示例仅适用于现有策略允许不使用 TLS 的本机 TCP 连接:

host    appdb    appuser    127.0.0.1/32    scram-sha-256

已有强制 TLS 策略时沿用 hostssl,保留原有证书等限制,不能用上述 host规则覆盖或绕过它。不要机械加到末尾或全部替换。角色必须允许 LOGIN、拥有该库的 CONNECT 权限,并已设置可用于 SCRAM 的密码。已在使用的业务密码不要为排错随意重置。

文件中 error列均为空后,管理员执行:

SELECT pg_reload_conf();

该函数返回 true 只表示重载信号已发出;规则视图显示的也只是磁盘文件内容。还要查看当前数据库日志,并新建一次连接验证,不能用旧会话仍然在线判断修改成功。

报错 检查位置
Address already in use 电脑上的 15432 被占用。换一个空闲端口,SSH 命令和数据库工具同步修改。
Connection refused 查看 SSH 窗口的转发错误,并核对远端 PostgreSQL 是否在正确的本机端口监听。
administratively prohibited SSH 服务的转发权限或 PermitOpen 限制,不是数据库密码问题;由管理员核对授权范围。
Peer authentication failed 核对是否遗漏 -h 127.0.0.1,误走了本机 Unix 套接字。
password authentication failed 核对数据库角色、密码和第一条匹配的 HBA 规则;不要改成 trust 规避。

使用完先关闭数据库工具,再回到 SSH 隧道窗口按 Ctrl+C 结束转发。电脑休眠或网络切换后,应重新建立隧道,再新建数据库连接。