PostgreSQL 无公网 IP,SSH 隧道和 cpolar 怎么选?

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 和客户端参数更容易定位问题。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容