PostgreSQL 没有公网 IP 时,如果客户端已经能 SSH 到一台服务器,优先复用 SSH 本地端口转发;如果没有可达的 SSH 入口,再考虑用 cpolar 把 PostgreSQL 的 TCP 端口映射出去。两条链路的起点相同:先用 psql 验证 127.0.0.1:5432 的监听和认证正常,再处理隧道。SSH 转发可以让数据库看到来自 localhost 的连接,cpolar 则需要把公网 TCP 流量转给隧道客户端实际能够访问的数据库地址。
不要一遇到远程连接失败,就把 listen_addresses 改成 '*',再向 pg_hba.conf 追加 0.0.0.0/0。在这两种隧道方案中,数据库通常可以继续只监听本机,公网侧只保留 SSH 或 cpolar 的 TCP 入口。使用 cpolar 时,也应先用随机 TCP 地址跑通连接,再切换到固定 TCP 地址,而不是把尚未验证的地址直接写进应用配置。
本地 5432 先闭环
本文假定 PostgreSQL 已经安装并运行。排查的第一条命令不是配置隧道,而是从数据库所在机器登录本机 PostgreSQL:
psql -h 127.0.0.1 -p 5432 -U your_db_user -d your_db_name
如果这里就失败,问题还在数据库进程、监听地址、账号密码或本地 pg_hba.conf,与公网入口无关。连接成功后,可以在 psql 中查询当前实例真正使用的配置文件:
SHOW config_file;
SHOW hba_file;
不同 PostgreSQL 版本和发行版的安装路径并不相同,查询结果比直接照抄其他教程里的路径更可靠。尤其是 CentOS 的 PGDG 安装、发行版自带软件包和容器部署,配置文件位置可能完全不同;尚未安装数据库的读者应从 PostgreSQL 官方下载页选择与自己的操作系统和版本对应的软件包,不在这里混用不同版本的命令。
同网段机器还可以尝试连接数据库的内网地址,用来判断 PostgreSQL 本身是否允许远程登录,但这一步不能证明公网链路已经打通。内网可达与公网可达是两层问题,后文仍要分别验证隧道、入口和认证。
两条链路的前提不同
SSH 隧道与 cpolar 都能绕开“没有公网 IP”这个限制,但选择依据不是哪个工具看起来更方便,而是现场是否已经有可复用的入口。
| 对比项 | SSH 隧道 | cpolar TCP |
|---|---|---|
| 入口前提 | 客户端能够 SSH 到一台服务器 | 客户端能够连接 cpolar,并能访问 PostgreSQL 地址 |
| 公网暴露 | 不需要额外开放数据库的 5432 | 使用 cpolar 分配的公网 TCP 地址访问数据库 |
| 地址稳定性 | 本地转发端口可以固定,但依赖 SSH 入口地址 | 随机 TCP 地址可能变化,适合先测试;长期使用可切换固定地址 |
| 主要故障点 | SSH 连通性、转发目标、本地监听、客户端 | 隧道状态、映射地址、TCP 域名与端口、数据库认证 |
| 适用条件 | 已有服务器、堡垒机或 VPN 环境 | 没有可用 SSH 入口的开发、联调或临时演示环境 |
SSH 隧道复用现有的运维入口,通常不需要再增加一个第三方公网入口。cpolar 更适合完全没有 SSH 通路、但允许运行隧道客户端的环境。无论采用哪一种,隧道都只负责搬运 TCP,PostgreSQL 的密码认证、HBA 规则和 TLS 仍然需要单独配置。
SSH 隧道复用现有入口
SSH 本地转发的结构是:客户端在本机监听一个端口,例如 5433,再通过 SSH 连接把该端口收到的数据转发到 SSH 服务端侧的 5432 端口。
ssh -L 5433:127.0.0.1:5432 user@your_ssh_server
随后在客户端连接本地转发端口,而不是直接连接数据库的公网地址:
psql -h 127.0.0.1 -p 5433 -U your_db_user -d your_db_name
这里的 127.0.0.1:5432 由 SSH 服务端解析和连接。如果 PostgreSQL 与 SSH 服务端在同一台机器上,数据库只监听 loopback 即可,连接在 HBA 规则看来通常也来自 localhost。
如果 SSH 服务器只是独立网关,PostgreSQL 位于另一台内网机器,转发目标应改成数据库的内网地址:
ssh -L 5433:your_db_private_ip:5432 user@your_ssh_gateway
这时 PostgreSQL 看到的来源是 SSH 网关的实际地址,pg_hba.conf 应精确放行该地址,而不是放行整个内网或所有来源。
PostgreSQL 与 SSH 服务端同机时,转发目标还应明确使用 127.0.0.1。某些环境下 localhost 会优先解析为 IPv6 地址 ::1,如果对应 HBA 规则与认证方式不一致,就可能出现 Ident authentication failed;强制 IPv4 loopback 往往能避开这个问题。
需要长期保持隧道时,可以考虑用 autossh 维持连接。运行 psql、DBeaver 或应用代码的机器需要安装 PostgreSQL 客户端;只在数据库服务器上安装客户端,并不能解决远端机器的 psql: command not found。
cpolar 映射本地 TCP
没有可用 SSH 入口时,可以让 cpolar 客户端在能够访问 PostgreSQL 的机器上运行,再创建 TCP 隧道。不同版本的菜单名称和字段位置可能变化,应以当前 cpolar 界面为准,但映射关系不变:
隧道类型:TCP
本地地址:127.0.0.1:5432
公网地址:<cpolar 分配的 TCP 域名>:<TCP 端口>
cpolar 与 PostgreSQL 同机时,本地地址填写 127.0.0.1:5432,PostgreSQL 不需要为了远程连接而监听所有网卡。cpolar 位于另一台机器时,本地地址应填写那台机器能够访问的数据库内网地址,同时根据实际隧道来源精确配置 HBA 规则。
先使用 cpolar 分配的随机 TCP 地址验证完整链路:
psql -h your_tcp_domain -p your_tcp_port -U your_db_user -d your_db_name
连接成功后,再创建或启用固定 TCP 地址,并把固定域名和端口交给客户端。DBeaver 等工具使用相同的 TCP 域名、分配端口、用户名和数据库名即可;端口应使用控制台给出的 TCP 端口,不要想当然地填成 PostgreSQL 默认的 5432。
固定地址交给客户端
固定 TCP 地址解决的是连接参数反复变化的问题,并不等于把 PostgreSQL 的 5432 端口直接开放给整个互联网。随机地址验证、账号权限和 TLS 配置完成后,再把固定参数交付给 psql、DBeaver、DataGrip 或应用程序。
交付时应记录 TCP 域名、端口、数据库名和用户名,但不要把隧道令牌、数据库密码或管理入口写进公开配置。固定地址突然失效时,排查顺序应是:先确认隧道是否在线,再确认映射目标是否正确,最后检查 PostgreSQL 的认证规则和连接数限制,而不是先改客户端地址。
报错沿连接链路定位
远程连接失败时,应按“本地数据库、SSH 或 cpolar 隧道、公网入口、客户端”逐层检查。不要一看到连接失败就直接放开 listen_addresses 或追加 0.0.0.0/0,否则可能把原本由隧道保护的服务直接暴露出去。
no pg_hba.conf entry for host
这个报错表示连接请求没有匹配到可用的 pg_hba.conf 规则。HBA 按顺序匹配,第一条适用的规则生效,因此不能只在文件末尾追加一条规则,还要检查前面是否已有更宽泛或不同认证方式的规则。
下面的片段只是结构示意,实际值应按真实来源地址和现有规则顺序调整:
# 仅作结构示意,实际使用前检查规则顺序和真实来源地址
host your_db_name your_db_user 127.0.0.1/32 scram-sha-256
SSH 与 PostgreSQL 同机时,转发连接通常表现为 localhost;SSH 网关与数据库分离时,应放行网关的实际来源地址。不要为了消除报错直接写成 host all all 0.0.0.0/0 scram-sha-256。
Ident authentication failed
这个问题常见于 localhost 被解析为 IPv6,而 ::1 对应的 HBA 规则或认证方式与预期不一致。不要用 trust 掩盖问题,优先让客户端明确连接 IPv4 loopback:
psql --host 127.0.0.1 --port 5433 -U your_db_user -d your_db_name
如果 SSH 服务端与数据库分离,该命令中的 127.0.0.1 仍指向 SSH 客户端本机;隧道目标地址不变,只是不用 localhost 触发可能不同的解析路径。
隧道建立后连接一直挂起
先检查 SSH 转发的目标。转发目标是在 SSH 服务端解析的,如果数据库只监听 loopback,却把目标写成数据库服务器的公网地址,SSH 隧道即使已经建立,流量也到不了正确的 PostgreSQL 监听端口。
随后确认本地 5433 仍在监听、SSH 进程没有退出,以及数据库目标端口确实是 5432。若采用独立 SSH 网关,还要确认网关能够访问数据库内网地址。
psql: command not found
这个报错与数据库是否启动无关,它说明当前执行命令的机器没有安装 PostgreSQL 客户端,或者客户端二进制文件不在 PATH 中。客户端应安装在实际运行 psql 的那一端,而不是只安装在数据库服务器上。
Connection refused
按层检查目标地址。数据库侧确认 PostgreSQL 是否监听预期地址;SSH 侧确认本地转发端口和远端目标是否正确;cpolar 侧确认隧道在线,并且本地映射确实指向 PostgreSQL 的真实端口。隧道状态正常但映射地址写错,同样会表现为连接被拒绝。
公网入口只开放必要范围
在本文讨论的隧道拓扑中,不需要把 PostgreSQL 改成监听所有网卡,也不需要向整个互联网放开 5432。cpolar 与 PostgreSQL 同机时,数据库可以保持 loopback 监听;SSH 与 PostgreSQL 同机时也可以沿用 localhost。
远程账号应使用 SCRAM-SHA-256,不要直接拿 postgres 超级用户作为日常连接账号,也不要用 trust 代替正常的密码认证。公网链路需要启用 PostgreSQL TLS,并为固定入口视实际情况配置连接数限制、IP 白名单和凭据轮换。
HBA 规则必须跟随真实拓扑变化:SSH 与数据库分离时,只放行 SSH 网关;cpolar 与数据库分离时,只放行实际隧道来源。固定 TCP 地址解决的是地址稳定性,不是身份认证问题,公网入口仍须通过数据库自身的强认证。
按检查结果选择下一步
先运行本地 psql。本地连接通过后,再检查客户端能否 SSH 到数据库服务器或独立网关:能够连接,就先验证 ssh -L 隧道和本地 5433;不能连接,再创建 cpolar TCP 隧道,用随机地址验证成功后切换固定地址,并更新 DBeaver 或应用中的连接参数。
如果本地 psql 都无法通过,先根据 SHOW config_file 和 SHOW hba_file 的结果检查实际配置,不必急着讨论公网映射。把这两步分开验证,远比同时修改监听地址、HBA 和客户端参数更容易定位问题。










暂无评论内容