在 Linux VM 上部署 PostgreSQL
在 Ubuntu/Debian 类 Linux VM 上安装 PostgreSQL、创建最小权限应用角色、按需开放远程连接、限制网络暴露面,并通过本机与远程连接验证部署结果。
[!info] related notes
- 数据库对象: PostgreSQL
- 网络与主机: UFW, SSH 命令速查
- 本地练习: 用 Docker 启动本地 MySQL 和 PostgreSQL 练习环境
- 后续: 创建第一个数据库与表:MySQL / PostgreSQL 对照练习
- 查询分析: 用 EXPLAIN 分析 MySQL 和 PostgreSQL 查询计划
在 Linux VM 上部署 PostgreSQL
目标与成功状态
完成后至少满足:
systemctl status postgresql
→ service active
sudo -u postgres psql
→ 本机管理连接成功
psql "postgresql://app_user@<db-host>/<app_db>"
→ 应用角色从允许的网络路径连接成功
ss -lntp
→ PostgreSQL 只监听预期接口
firewall
→ 只允许预期来源访问 5432
这篇 howto 关注单机 VM 部署闭环,不负责 PostgreSQL 原理、查询优化、HA/PITR 或云托管选型。
1. 先决定网络边界
部署前先回答:
- 只有 VM 本机应用访问?
- 同一私有 LAN / VPC 中的应用访问?
- 需要跨公网访问?
默认最安全的是:
数据库不直接暴露公网
→ 本机 / 私网访问
→ 跨公网优先 VPN / SSH tunnel / private network
不要先把 5432/tcp 对 0.0.x.x/0 开放,再考虑安全。
2. 安装 PostgreSQL
Ubuntu / Debian 通常可以直接使用发行版包:
sudo apt update
sudo apt install postgresql
如果项目明确需要某个 PostgreSQL 主版本,再使用 PostgreSQL 官方 PGDG APT repository,并安装指定版本。
版本选择应来自项目兼容性与生命周期要求,不要把某个历史版本永久写死在通用部署笔记里。
安装后验证:
systemctl status postgresql
psql --version
3. 先验证本机数据库
进入管理 shell:
sudo -u postgres psql
查看基础信息:
SELECT version();
SHOW listen_addresses;
先证明本机实例健康,再处理远程连接;否则网络层和数据库层问题会混在一起。
4. 创建应用角色与数据库
不要让业务应用直接使用 PostgreSQL superuser。
示例:
CREATE ROLE app_user
LOGIN
PASSWORD 'replace-with-a-secret';
CREATE DATABASE app_db
OWNER app_user;
然后退出:
\q
凭据应进入 secret manager / 环境变量,而不是提交到仓库。
5. 决定是否需要远程 TCP 连接
仅本机访问
保持只监听 loopback 即可,通常不需要开放防火墙端口。
私网远程访问
远程 TCP 连接需要同时满足两层:
postgresql.conf
listen_addresses
+
pg_hba.conf
允许的 user / database / source network / auth method
只改其中一层都不够。
查看实际配置文件:
SHOW config_file;
SHOW hba_file;
不要假设路径一定是某个固定版本目录。
6. 配置监听地址
例如只监听 VM 的私网地址与 localhost:
listen_addresses = 'localhost,10.0.x.x'
如果使用 '*',必须依赖 pg_hba.conf 与主机/云防火墙进一步收窄来源;不要把 listen_addresses='*' 理解成完整访问控制。
修改后 reload/restart,并再次验证:
sudo systemctl restart postgresql
sudo ss -lntp | grep 5432
7. 配置 pg_hba.conf
例如只允许应用用户从私网子网连接指定数据库:
host app_db app_user 10.0.x.x/24 scram-sha-256
这里四个核心问题是:
连接类型是什么?
访问哪个 database?
哪个 role?
来自哪个 network?
用什么认证方法?
不要用:
host all all 0.0.x.x/0 ...
作为默认配置。
修改后可以 reload:
sudo systemctl reload postgresql
8. 配置主机 / 云防火墙
如果 VM 上使用 UFW,只允许实际应用来源:
sudo ufw allow OpenSSH
sudo ufw allow from 10.0.x.x/24 to any port 5432 proto tcp
sudo ufw enable
sudo ufw status
如果 VM 还位于云平台中,还要同时检查 Security Group / NSG / VPC firewall。
访问链通常是:
Client
→ cloud firewall
→ VM firewall
→ PostgreSQL listen socket
→ pg_hba.conf
→ role authentication
→ database privileges
任何一层拒绝都会表现成“连不上数据库”,所以排障要逐层验证。
9. 从客户端验证
先验证网络:
nc -vz <db-host> 5432
再验证 PostgreSQL 协议与认证:
psql "host=<db-host> port=5432 dbname=app_db user=app_user"
不要只用 ping 判断 PostgreSQL 是否可达;ICMP 成功不能证明 TCP 5432、认证或数据库权限正确。
10. 应用连接
应用连接字符串示例:
postgresql://app_user:<secret>@<db-host>:5432/app_db
生产环境还应明确:
- TLS 要求;
- connection pool;
- statement / connection timeout;
- secret rotation;
- migration ownership;
- backup / restore;
- monitoring。
这些是下一层运维设计,不应全部塞进“安装数据库”步骤里。
验证矩阵
| 层 | 验证 |
|---|---|
| service | systemctl status postgresql |
| local DB | sudo -u postgres psql |
| listener | ss -lntp |
| cloud / host firewall | 从真实 client 测 TCP 5432 |
| HBA / auth | psql 使用真实 app role |
| privileges | 执行最小 CREATE/SELECT 或应用 migration |
| application | 应用启动并完成 health check |
常见失败路径
Connection refused
优先检查:
- PostgreSQL service 是否运行;
listen_addresses;- 实际监听 IP/port;
- firewall。
no pg_hba.conf entry
说明 TCP 已到达 PostgreSQL,但 HBA 没有匹配规则。
检查:
- database;
- role;
- client CIDR;
- SSL / non-SSL record 类型。
password authentication failed
网络和 HBA 已经基本通过,继续检查:
- role 是否正确;
- secret 是否正确;
- role 是否允许 LOGIN;
- 客户端是否连到了预期实例。
本机能连,远程不能连
把问题分层:
listen_addresses
→ host/cloud firewall
→ pg_hba.conf
→ authentication
不要反复重装 PostgreSQL。
不再推荐的旧习惯
- 为“安全”单纯更换 5432 端口:只能减少部分扫描噪声,不是访问控制。
- 为方便测试直接开放
0.0.x.x/0:5432。 - 应用长期使用 postgres superuser。
- 把固定配置文件路径写死到某个 PostgreSQL 主版本。
- 在通用部署笔记中硬编码某一台 VMware 的 IP、账号和资源规格。
无提示执行检查
不看正文,在一台空 Linux VM 上说明并执行:
- 安装 PostgreSQL;
- 证明本机实例健康;
- 创建非 superuser 应用角色和数据库;
- 仅允许一个指定私网 CIDR 访问;
- 用
ss、firewall 和psql分层验证; - 制造一次 HBA 拒绝,并根据错误定位到正确层;
- 解释
listen_addresses、firewall、pg_hba.conf、role privilege 四层为什么不能互相替代。