简介:这是一份面向运维人员与初学者的 PostgreSQL 离线安装教程,适用于无网络或内网隔离环境下的数据库部署场景。内容以 PostgreSQL 9.5 版本为例,完整覆盖依赖包准备、RPM 强制安装、CMake 插件编译、源码安装、创建 postgres 用户与数据目录、初始化数据库、启动服务及创建数据库等核心步骤,并详细说明了通过 pg_hba.conf 与 postgresql.conf 配置远程访问权限的方法。资源为 1 个 docx 文档,压缩包大小 43KB,当前已有 795 人学习下载。文档以命令清单和配置说明为主,结构紧凑、可直接对照执行,省去了自行查找依赖和排查配置细节的时间,适合需要在内网环境中快速完成 PostgreSQL 部署的读者作为操作参考。
1. 离线安装 postgresql:真正的难点不在 PG 本身,而在依赖和包源
接到一个内网服务器的数据库需求,第一反应往往是“把 PG 装上就行”,结果卡在 yum 源连不通、apt 源超时、依赖缺一个装一个的泥潭里。这套方案的定位是 postgresql 离线安装,目标是让一台完全不能访问外网的机器,从零装出能连、能建库、能安全重启的 PostgreSQL。它适合做内网交付的运维、在隔离环境里搭库的研发,以及要批量复制数据库环境的人。先把反直觉的结论摆出来:PG 自己的安装包反而是最好准备的,真正烧时间的是 readline、zlib、icu 这些编译和运行依赖;把依赖清单理清,比装 PG 本身更值钱。
2. 装前准备:先把版本和依赖定死,再动手
2.1 PostgreSQL 16 还是 15:离线场景怎么选版本
每次群里看到“postgresql 下载哪个版本”这种问题,离线场景的答案从来不是“最新”,而是“你的包源里稳定存在哪个”。我一般会选 PostgreSQL 16。它不是最新,但在 RPM 与源码两条路径上都被验证得足够多:官方 yum 仓库对 RHEL 7/8/9 都提供 postgresql16-server,CentOS 7.9 这种还在大量服役的内网机器可以直接用;source tarball 在 gcc 4.8 的环境下也能编过。PG 15 也行,它的 rpm 包在老旧发行版里更常见,如果你所在的内网已经有团队在用 15,跟着存量版本走,别在新项目里另起 16,省得以后备份恢复还要跨大版本折腾。
选版本还要看目标机的系统。如果一个内网里混着 CentOS 7 和 Rocky 9,我建议统一选同一个大版本,比如都是 16,介质里只放 16 的包。跨版本混装后期会带来两个麻烦:一是 pg_upgrade 只能就近往上升,二是 16 和 15 的 data 目录格式不兼容,谁都不想在内网里做一次数据迁移。另外要确认目标机磁盘,PG 16 完整安装加 contrib 约占用 300MB 左右,源码编译则要预留 1GB 以上的临时空间——内网机器经常磁盘很小,这个提前量必须算进去。
对架构也要看一眼:x86_64 的 rpm 直接在官方源里拿;如果是 ARM 或国产 CPU,rpm 常常拿不到,直接走源码编译(第 4 章)。源码编译对 GCC 版本不挑到很离谱,CentOS 7 自带的 gcc 4.8.5 编 PG 16 没问题,但 configure 时会卡在缺头文件,所以编译依赖要按 4.1 的清单一次拉全,不要到了目标机才一个个试。
2.2 依赖清单:readline、zlib、icu 一个都不能少
离线安装的翻车点八成在依赖。RPM 方式下依赖会被包管理器自动解析,前提是依赖包本身在本地仓库里;源码方式下 configure 会逐个检查头文件和库,缺哪个就停在哪一个。下面这张表是我每次装之前都要对照的清单:
| 依赖包(RHEL 系 / Debian 系) | 作用 | 缺了会怎样 |
|---|---|---|
| postgresql16-libs / postgresql-16 | 运行库,包含 libpq.so.5 | rpm 装 server 时直接报缺 libpq.so.5 |
| readline-devel / libreadline-dev | psql 的行编辑与命令历史 | 源码 configure 卡在 checking for readline |
| zlib-devel / zlib1g-dev | pg_dump 压缩备份、WAL 压缩 | 备份体积变大,甚至备份功能异常 |
| libicu-devel / libicu-dev | ICU 排序规则与国际化 | PG 16 默认偏好 ICU 排序,缺了只能退回 libc |
| openssl-devel / libssl-dev | SSL 连接与加密 | configure 检查 openssl 失败,只能 --without-openssl |
| systemd-devel / libsystemd-dev | 生成 systemd 通知支持 | rpm 装在 systemd 系统上一般会需要 |
| llvm / clang(可选) | JIT 即时编译 | 缺了不是致命错误,configure 加 --without-llvm 即可 |
这里解释一下为什么这几样是刚需。readline 管着 psql 的上下键历史,没有它 psql 用起来非常痛苦;zlib 关系到备份压缩,离线环境里备份几乎是唯一的后悔药,不能省;icu 在 PG 16 里是排序规则的首选实现,你不装它,数据库也能初始化,但排序和大小写行为可能和线上用 yum 装出来的实例不一致,以后做数据对比会对不上。
还有一类依赖容易被忽略:rpm 方式会自动拉入 systemd-libs 这类基础库,源码方式则要自己准备。如果你走源码编译,编译期的 -devel 包列表以 4.1 为准;如果你走 rpm,放心交给包管理器,前提是 repotrack 时把整个依赖树拉全。
2.3 安装介质从哪来:rpm 包和源码包两条路
离线安装本质上就是把在线安装时“联网拉包”的动作提前做完。常见做法有两套,按目标机情况二选一。第一套是先找一台和 target 同样系统大版本、同样 CPU 架构的能联网机器,配好 PG 官方 yum 源,再用 yum 的 repotrack 把指定包和它们的依赖全部拉下来,打成 tar 包传进内网,做成本地 yum 源。命令如下:
mkdir -p /opt/pg-rpms && cd /opt/pg-rpms yum install -y yum-utils createrepo repotrack -a x86_64 postgresql16-server postgresql16-contrib createrepo /opt/pg-rpms tar czf /opt/pg16-rpms.tar.gz /opt/pg-rpmsrepotrack 和 yumdownloader 的区别要说明一下:yumdownloader 只会拉你指定的那一个包,不拉依赖;repotrack 会把依赖递归拉全。离线场景最怕的不是主包缺,而是装到一半发现个没见过的依赖,所以一定要用 repotrack 或类似工具。-a x86_64 是显式指定架构,防止在 x86_64 的机器上下出 noarch 或 i686 的混包。之后把 pg16-rpms.tar.gz 传到内网目标机解压即可。
第二套是直接拿源码 tarball 进内网编译,适合没有现成 rpm 的架构或国产化系统。源码方式的准备工作在第 4 章展开,原则是一样的:不只是主源码包,编译期的 -devel 依赖也要提前用 repotrack 拉全。两条路在动手前都要先确认目标机有没有 yum/apt 之外的包管理工具能用,如果连 rpm 都没有,那基本只能是源码编译一条路了。
3. 用 RPM 离线安装 PostgreSQL 16:下载、传包、初始化一条线走通
3.1 在内网目标机上搭建本地 yum 源
把上一步打的 tar 包解压到目标机后,先做一件事:把目录变成 yum 能认的本地仓库。解压后 /opt/pg-rpms 下会有一堆 rpm 包和 repodata 目录,如果 repodata 没生成,就在目标机上重新执行一次 createrepo。然后写一个只指向本地目录的 repo 文件:
cd /opt/pg-rpms createrepo . cat > /etc/yum.repos.d/pg-local.repo <<'EOF' [pg-local] name=PostgreSQL Local RPMs baseurl=file:///opt/pg-rpms enabled=1 gpgcheck=0 EOF yum clean all && yum makecache这里有两处值得解释。gpgcheck=0 是因为离线内网通常没有 PG 官方 GPG key,先把签名校验关掉;如果你们内网有密钥分发机制,建议保留 gpgcheck=1 并把 RPM-GPG-KEY 放到 /etc/pki/rpm-gpg,否则以后审计会找你麻烦。第二处是 baseurl 用 file:// 指向本机路径,yum 对本地目录的权限要求不高,但目录和 rpm 文件不能被 root 之外的人改写成奇怪的权限,否则 makecache 会静默失败,现象就是 yum 列表里看不到任何包——这个在第 5 章会展开。
检查源是否生效,用 yum repolist 看 pg-local 是否在列表里,正常会显示 repo id 和包数量。如果显示 0 packages,先检查 repodata 目录是否存在、repomd.xml 是不是空文件,这两个是最常见的静默失败点。
3.2 用 yum 的互斥参数装主套件
本地源建好后,安装命令要刻意避开外网源。我一般会写死两个互斥参数,防止 yum 因为某个未禁用的官方源去连外网:
yum install -y postgresql16-server postgresql16-contrib \ --disablerepo=* --enablerepo=pg-local--disablerepo=* 把所有仓库禁用,--enablerepo=pg-local 只放行本地仓库。顺序是先禁后放,这样即使机器上还有 dl.fedoraproject.org 之类的残留源也不会去连。contrib 包建议一起装,pg_stat_statements、uuid-ossp、postgres_fdw 这些常用扩展都在里面,离线环境里再想补一个包要重新走一遍拉包流程,代价很大。装完验证一下:
rpm -qa | grep postgresql正常情况下会看到 postgresql16-server、postgresql16-libs、postgresql16-contrib 等包。如果 rpm 输出为空,先看 yum 是否真的走了 pg-local 源,可以用 yum history 或查看 /var/log/yum.log 确认,而不是直接放弃重装。另外用 rpm -qi postgresql16-server 看一眼 Version 字段,确认拉到的确实是 16 而不是 15,版本锁错在内网很常见。
3.3 initdb 初始化数据目录与 systemd 启动
包装完不代表能用,还要初始化数据目录。PG 官方 rpm 会提供一个初始化脚本,以 postgres 用户执行 initdb:
/usr/pgsql-16/bin/postgresql-16-setup initdb systemctl enable --now postgresql-16 systemctl status postgresql-16postgresql-16-setup 这个脚本本质上是“用 postgres 用户跑 initdb -D /var/lib/pgsql/16/data”,并且会自动处理数据目录的属主权限。如果你装完直接 systemctl start,大概率会看到服务起来了但日志里全是权限报错,因为 rpm 包不会帮你初始化数据目录。这一步不要用 root 去手动执行 initdb,否则后面所有配置文件属主都会乱掉。
接着改密码和允许局域网访问。PG 16 默认的 pg_hba.conf 里,本地 socket 是 trust,host 只有 127.0.0.1/32 和 ::1/128,远程机器根本连不上。先连接本地实例改密码:
sudo -u postgres psql -c "ALTER USER postgres PASSWORD '你的强密码';"然后改两处文件。第一处 /var/lib/pgsql/16/data/postgresql.conf 里把 listen_addresses 从 localhost 改成实际监听地址,内网常用 '*' 监听所有网卡;第二处 /var/lib/pgsql/16/data/pg_hba.conf 增加一条 host 规则,例如:
host all all 192.168.1.0/24 scram-sha-256listen_addresses 的修改必须重启才生效,pg_hba.conf 执行 reload 即可。如果 sudo -u postgres psql 时报 could not connect to socket,先看 /tmp/.s.PGSQL.5432 是否存在,socket 文件被清理或权限不对都会导致本地连不上。最后确认防火墙没有挡 5432 端口;CentOS 7 常见做法是 systemctl stop firewalld 或 firewall-cmd --add-port=5432/tcp --permanent。到这里一个 RPM 方式的离线安装就算通了,后面第 5 章会补几个最容易在这条链路里翻车的地方。
4. 源码编译离线安装:没有现成 rpm 时的完整路径
4.1 上游源码与编译依赖要一起打包
当目标机是 ARM 架构、国产化系统,或者你拿不到任何现成 rpm 时,源码编译几乎是唯一出路。离线源码编译的第一步还是在有网的机器上准备三样东西:PG 源码 tarball、编译工具链、-devel 头文件。源码包从 PostgreSQL 官网下载,文件名类似 postgresql-16.x.tar.gz,你直接搜对应版本就能找到。下载后做一件事:比对 sha256sum,防止 U 盘拷贝或 FTP 传输把包弄坏,离线环境里介质损坏非常常见,校验这一步能省掉后面大量玄学问题。
编译工具链和依赖用 repotrack 一次拉全,我的习惯是全部拉到同一个目录再一起打包:
mkdir -p /opt/pg-build-deps && cd /opt/pg-build-deps repotrack -a x86_64 gcc make bison flex readline-devel zlib-devel libicu-devel openssl-devel tar czf /opt/pg-build-deps.tar.gz /opt/pg-build-deps这里为什么要 bison 和 flex?PG 的语法解析器源码在编译时需要用 bison 生成 parser 文件,flex 生成词法分析器,缺了它们 make 会直接报错,而且报错信息很隐晦,经常是“bison: command not found”这种看起来没头没尾的一句话。gcc 和 make 是编译基础,readline/zlib/icu/openssl 的 -devel 包决定 configure 的检查结果。如果你确定内网机器已经装了 gcc,可以省掉,但多带没坏处——离线环境里补一个包的成本,你跑过一次现场就懂。
4.2 configure 与 make 编译参数怎么设
源码包传到目标机后解压,进入目录开始配置。configure 的核心作用是把“缺依赖”的问题集中在第一步暴露出来,而不是等到 make 到一半才崩:
tar xzf postgresql-16*.tar.gz cd postgresql-16* ./configure --prefix=/usr/local/pgsql \ --with-icu --with-openssl --without-llvm--prefix 指定安装目录,我习惯用 /usr/local/pgsql,这样和官方 rpm 装的 /usr/pgsql-16 在视觉上就能区分开,避免后期运维搞混。--with-icu 启用 ICU 排序,--with-openssl 编译 SSL 支持,两者都依赖对应的 -devel 包,如果你在 4.1 里没拉全,configure 会在这里退出。--without-llvm 是刻意关掉 JIT,原因很现实:内网机器通常不需要 JIT 提升那一点性能,而且 LLVM 工具链又大又难凑齐,关了反而让编译链路更短。如果你后面要用 pg_stat_statements 这类扩展,记得 configure 阶段不要加 --without-contrib,默认会带上 contrib 子目录。
configure 挂掉的时候,别只盯着终端最后一行。它会生成一个 config.log,里面记录了每个检查项的具体失败原因。用 grep 'error' config.log 往往能直接看到“readline.h: No such file”这类关键信息,这比在黑匣子里反复猜测快得多。这也是源码安装和 rpm 安装最大的体验差异:没有依赖解析器兜底,每一步都显式暴露。
configure 完成后执行编译。make 的并行数按 CPU 核数走,内网机器的核数可能不高,但 -j$(nproc) 仍然比单线程快很多:
make -j$(nproc) make installmake install 只装主程序,contrib 里的扩展还要单独进目录编一次:
cd contrib make -j$(nproc) make install编译期间如果报错,先看 make 停在哪一步。比较常见的是缺头文件、缺 bison/flex、磁盘空间不足三种,前两种回到 4.1 补包,第三种则要给目标机清理临时空间。
4.3 用 postgres 用户 initdb、配置环境变量与启动
源码安装不会自动创建 postgres 用户,也不会生成 systemd 服务,这些都是手工活。我一般按下面顺序做:
useradd -m postgres mkdir -p /data/pgsql chown -R postgres:postgres /data/pgsql sudo -u postgres /usr/local/pgsql/bin/initdb \ -D /data/pgsql --encoding=UTF8 --locale=en_US.UTF-8initdb 一定用 postgres 用户跑,这是源码安装和 rpm 安装都要遵守的规矩,否则数据文件属主变成 root,后面启动服务会因为权限问题直接失败。--encoding=UTF8 是生产环境标配,中文场景尤其要显式指定,避免默认编码和客户端的 UTF-8 不一致导致乱码。--locale 用 en_US.UTF-8,如果目标机没有这个 locale,可以先用 localedef -i en_US -f UTF-8 en_US.UTF-8 生成,或者干脆用 --locale=C,代价是排序行为更接近二进制比较,中文排序会不那么符合直觉。
启动时先手动拉起一次,确认没有配置错误:
sudo -u postgres /usr/local/pgsql/bin/pg_ctl -D /data/pgsql \ -l /data/pgsql/logfile start手动能起来之后,立刻把 systemd unit 文件补上,否则机器一重启,PG 又变成没装过的状态。unit 文件写到 /etc/systemd/system/postgresql.service:
cat > /etc/systemd/system/postgresql.service <<'EOF' [Unit] Description=PostgreSQL database server After=network.target [Service] User=postgres ExecStart=/usr/local/pgsql/bin/postgres -D /data/pgsql ExecReload=/usr/local/pgsql/bin/pg_ctl -D /data/pgsql reload [Install] WantedBy=multi-user.target EOF systemctl daemon-reload && systemctl enable --now postgresql注意 ExecStart 用的是 postgres 这个可执行文件而不是 pg_ctl,因为前者是前台主进程,适合交给 systemd 托管。最后把 psql 等客户端工具加进 PATH,避免每次都要写全路径:
echo 'export PATH=/usr/local/pgsql/bin:$PATH' > /etc/profile.d/pgsql.sh source /etc/profile.d/pgsql.sh到这里源码方式的离线安装就闭环了。相比 rpm 方式,源码安装多出来的工作主要集中在依赖准备和系统服务托管两件事上,其余行为和 rpm 实例没有本质区别。
5. 离线安装避坑:5 个高频故障的现象、原因与解决
5.1 yum 装 server 时报缺 libpq.so.5,装到一半就停
现象:yum install postgresql16-server 时提示需要 libpq.so.5()(64bit),但本地仓库里似乎有这个包,却仍然装不上。
原因:本地仓库里缺 postgresql16-libs,或者显式装的是 PostgreSQL 15 的 libs。libpq.so.5 是 PostgreSQL 16 的客户端库,它由 postgresql16-libs 提供;如果 repotrack 只拉了 server 和 contrib,没有把 libs 一起拉进来,依赖解析就不可能通过。
解决:回到有网机器上重新 repotrack postgresql16-libs,并放在同一个本地仓库目录里。也可以用 rpm -ivh postgresql16-libs-*.rpm 先单独装上再装 server,但这样绕过了 yum 的依赖记录,之后重装会很乱,不推荐。最稳妥的做法是本地仓库里 server、libs、contrib 三类包齐全,一次 yum install 全部解决。
5.2 root 手动跑 initdb,报 Permission denied
现象:手动执行 initdb -D /var/lib/pgsql/16/data 时提示 could not create directory ... Permission denied,但目录明明存在。
原因:官方 rpm 的初始化脚本 postgresql-16-setup 内部是以 postgres 用户身份跑 initdb 的;如果排查时图快用 root 去跑,数据目录的属主就被写成 root,initdb 会尝试在属于 postgres 的父目录下建文件,权限对不上就报错了。
解决:所有 initdb 操作统一用 sudo -u postgres 执行。如果已经用 root 初始化过,删掉数据目录里的内容重新用 postgres 用户初始化,不要手动 chown 修补,因为修补出来的文件权限可能有遗漏。顺便检查一下数据目录的父目录属主,比如 /var/lib/pgsql 目录本身要是 postgres 的。
5.3 源码 configure 卡在 checking for readline... no
现象:执行 ./configure 后输出 checking for readline... no,然后整个配置流程退出,没有给出更具体的错误。
原因:readline-devel 没装。configure 的这个检查是黑匣子,它同时检查头文件和库文件,只要 dev 包缺失就直接 no,不会告诉你缺的是 readline.h 还是 libreadline.so。
解决:装 readline-devel 后重新 configure。注意 configure 脚本是有缓存的,重新执行前最好 make distclean 清一次现场,或者直接解压新目录再编。如果你实在找不到 readline-devel,可以用 --without-readline 绕过,但这样 psql 会失去命令历史和行编辑功能,内网排查问题时非常难受,我一般只在极端情况下才这么干。
5.4 systemd 启动后服务反复重启,日志里提示找不到配置文件
现象:systemctl start postgresql-16 后服务一直处于 activating,journalctl -u postgresql-16 显示 could not find configuration file ... postgresql.conf。
原因:数据目录没有 initdb,或者 initdb 的 -D 路径和 systemd unit 文件里的 ExecStart 路径不一致。rpm 安装后如果跳过了 postgresql-16-setup initdb,/var/lib/pgsql/16/data 根本不存在,服务自然起不来。
解决:rpm 方式先跑 postgresql-16-setup initdb;源码方式先确认 initdb -D 用的路径和 unit 文件 ExecStart 里的 -D 完全一致。改完路径要 systemctl daemon-reload 再 start,否则 systemd 还在用旧的 unit 缓存。这个坑我早期踩得最多,一次 path 打错,排查半小时起步。
5.5 局域网客户端连不上,连接超时或被拒绝
现象:网络通的,从另一台机器 psql -h 192.168.1.x -U postgres 连接超时,或者报 no pg_hba.conf entry for host。
原因:listen_addresses 还是默认的 localhost,pg_hba.conf 没有对应网段的 host 规则,或者 5432 端口被防火墙挡了。这三件事经常是叠加的,只看一个配置很容易漏。
解决:按 3.3 的顺序来:postgresql.conf 里 listen_addresses 改为 '*';pg_hba.conf 增加 host all all 网段 scram-sha-256;重启服务使监听地址生效;再放行 5432 端口。验证时优先用 pg_isready -h 目标机IP -p 5432 看端口层通不通,通了再谈 psql 能不能连,这样能把问题切成两段排查。
6. 装完怎么验收:写一个健康检查脚本,把离线安装的成果固化下来
安装流程走完不能以“psql 能连”作为唯一验收标准,尤其是离线环境,补一次依赖代价太高。我习惯在交付前跑一遍自制的健康检查脚本,把端口、版本、进程、磁盘、备份能力五项一次验完:
#!/bin/bash # pg_healthcheck.sh —— 离线安装后的最小验收脚本 PGHOST="${PGHOST:-127.0.0.1}" PGPORT="${PGPORT:-5432}" PGUSER="${PGUSER:-postgres}" export PGPASSWORD="${PGPASSWORD:-postgres}" echo "== 1. pg_isready ==" /usr/pgsql-16/bin/pg_isready -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" || exit 1 echo "== 2. 版本与基础查询 ==" /usr/pgsql-16/bin/psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres \ -c "select version();" echo "== 3. 进程与数据目录空间 ==" ps -ef | grep '[p]ostgres' | head -5 df -h /var/lib/pgsql/16/data | tail -1 echo "== 4. 备份可用性 ==" /usr/pgsql-16/bin/pg_dump -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" \ -d postgres -Fc -f /tmp/pg_health_$$.dump \ && ls -lh /tmp/pg_health_$$.dump \ && rm -f /tmp/pg_health_$$.dump脚本里所有连接参数都支持环境变量覆盖,密码不写死在代码里。前三步分别验证端口层可达、数据库层可查询、进程与磁盘空间正常;第四步 pg_dump 用 -Fc 输出 custom 格式备份,这一步是对 zlib 依赖和备份能力最直接的验证,比单纯 select 1 靠谱得多。如果你用的是源码安装,把脚本里的 /usr/pgsql-16/bin 换成 /usr/local/pgsql/bin 即可。
提示:PGPASSWORD 环境变量在 psql 里是明文的,内网测试环境用没问题,生产环境建议改用 ~/.pgpass 文件或换用其它认证方式。
这套脚本我每次离线交付都跑一遍。早年有一次图省事,psql 能连就当装完了,后来第一次做 pg_dump 时才发现 zlib 没编进去,备份文件打出来是坏的,在内网里补依赖又折腾了一整天。从那以后,备份可用性一定进验收清单,宁可验证多花五分钟,不要事后跑一趟现场。离线环境每一步都走得比在线慢,但每一步都可以提前验证;把这条安装和验收流程固化下来,后面再装第二台、第三台机器就是复制粘贴的活了。希望帮到你。
本文还有配套的精品资源,点击获取