先说一个我见过很多次的场景:有人把 PostgreSQL 装好了,高高兴兴建了表,然后兴冲冲地把经纬度塞进去,接着就开始查空间数据、算范围、量长度,结果 SQL 一执行就报错,说函数不存在。这时候才反应过来,光有 PostgreSQL 是不够的,空间数据这块能力全靠 PostGIS 这个扩展在撑。
所以这篇东西不是只给你贴一段安装命令,而是想把 PostgreSQL + PostGIS 从“装软件”到“真能用”这条路完整捋一遍。我会按 Windows、Linux 源码编译、Docker 三条主流部署路线来讲,并且把网上反复出现的几个痛点——版本不匹配、扩展没启用、socket 锁文件权限不够、外部连不上——全部摊开来说。无论你是第一次接触的新手,还是在已有服务器上补这两个组件的运维,读完应该都能顺利把空间数据库立起来。
1. 安装前先想清楚:版本、依赖、扩展机制是三件不同的事
很多人安装失败的核心原因,是把“PostgreSQL 装好了”和“PostGIS 能用了”划了等号。实际上这两者之间还隔着两层:一是 PostGIS 是由动态库、控制文件、SQL 脚本组成的扩展包,不是 PostgreSQL 自带组件;二是 PostGIS 必须和 PostgreSQL 主版本严格匹配。想明白这一点,后面踩坑会少一半。
1.1 这套组合到底解决了什么问题
PostgreSQL 本身就是一款关系型数据库,但遇到地理坐标、行政区划、路径轨迹这类数据,普通数据库只能把它当字符串或者两个数字字段存。真要计算“两个点相距多远”“这个多边形是否包含某个坐标”时,就得靠外部程序把数据捞回去再算,既慢又别扭。
PostGIS 做的事情,是把空间数据类型、空间索引、空间函数直接做进数据库里。装上之后,你可以用 geometry/geography 类型存点线面,用 GiST 索引加速空间检索,还能在 SQL 里直接调用 ST_Distance、ST_Intersects、ST_Area 这些函数完成空间计算。这也是为什么 GIS 系统、地图服务、车辆轨迹平台普遍采用 PostgreSQL + PostGIS 作为底层存储的原因——它把“管理属性数据”和“分析空间数据”合并到了同一套库里,省掉了维护两套存储的麻烦。
1.2 版本匹配是安装环节最容易翻车的点
PostGIS 不是独立运行的软件,它编译时就要对着某个大版本的 PostgreSQL,安装后也要进入对应版本的扩展目录下。所以你会看到官方提供的下载包命名往往是 postgis-bundle-pg16x64 这种风格,或者 Docker 镜像直接叫 postgis/postgis:16-3.4,这里的 16 指的就是 PostgreSQL 主版本,3.4 是 PostGIS 版本。
我的建议是,除非你有非常明确的理由,否则别把 PostgreSQL 和 PostGIS 版本随便拉高或拉低。PostGIS 的最新版本发布通常会滞后于 PostgreSQL 新版本一段时间,所以新装的 PG 大版本不一定立刻有最匹配的 PostGIS 可用。反过来,PostGIS 版本太老也可能不支持你正在用的 PostgreSQL。选组合时,优先采用官方已经验证过的常用搭配。
| PostgreSQL 版本 | PostGIS 大版本参考 | 常见的获取方式 |
|---|---|---|
| 12/13 | 3.0 ~ 3.2 | 发行版仓库、官方 Bundle |
| 14/15 | 3.2 ~ 3.4 | EDB 安装器、PGDG 仓库 |
| 16 | 3.4 ~ 3.5 | EDB 安装器、PGDG 仓库、Docker 镜像 |
| 17 | 3.5+ | PG DG 仓库、Docker 镜像 |
这张表只是参考,千万别当作死规则。重点是:在下载页选安装包时,看到“支持 PostgreSQL 16”之类的标识,心里要有数——那通常只是说 PostgreSQL 16 的安装包没问题,PostGIS 还需要另外装,而且 PostGIS 安装包的名称里一定还会标注对应 PostgreSQL 版本。
1.3 三条部署路线的适用场景
- Windows 桌面端或内网服务器:使用官方二进制安装包 + 对应平台的 PostGIS Bundle 是最省事的,图形化界面一路点过去即可。适合开发环境、中小项目快速起步。
- Linux 服务器:优先用发行版对应的 PostgreSQL 软件源(比如 PG DG 仓库),然后再装匹配的 postgis 包。如果你的服务器因为各种原因无法走软件源,或者你必须自定义安装路径,才需要走源码编译。
- Docker 环境:直接用官方 postgis/postgis 镜像。这是目前我认为最不容易出问题的路线,因为镜像已经把 PostgreSQL 和 PostGIS 的版本组合锁死了,你要做的就是拉镜像、建数据卷、跑起来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Windows 用户的最短路径:官方安装包加 PostGIS Bundle 的一步步操作
Windows 这个平台看起来简单,但卡点往往藏在几个细节里。经常有人装完 PostgreSQL,却不知道还有 Stack Builder 或者独立 Bundle 这个东西,结果压根没装上 PostGIS。
2.1 下载页面的版本对应关系
Windows 上要装 PostgreSQL,正规来源基本是 EnterpriseDB 提供的安装包,下载页面一般会给出 12.x、13.x、14.x、16.x 这些版本目录。别看到最新版就激动,也别忘了 PostGIS 这回事。
PostGIS 在 Windows 上的获取渠道主要有两条:一是在 PostgreSQL 安装向导收尾时弹出的 Stack Builder 里勾选,二是直接下载对应版本的 PostGIS Bundle。我个人更推荐后者,因为 Stack Builder 在老版本上偶尔会出现下载源连不通、校验失败的情况。安装包命名通常像 postgis-bundle-pg16x64-setup-3.4.x.exe 这样,拆开看:pg16 表示给 PostgreSQL 16 用,x64 表示 64 位系统,3.4.x 是 PostGIS 具体版本。
有一个常见误区:先装了 32 位 PostgreSQL,再下 64 位 PostGIS。两个安装包位数不一致,装到后面 PostgreSQL 压根识别不到扩展。另外装 PostgreSQL 时使用的账户必须能写入安装目录,最好右键以管理员身份运行安装包,否则后面写扩展文件时会报权限错误。
2.2 安装向导里容易被忽略的选项
PostgreSQL 安装向导有几个关键位置要盯紧:
- 安装目录:默认放在
C:\Program Files\PostgreSQL\16\下,最好保持默认路径,因为后续安装 PostGIS 时搜索 PostgreSQL 安装目录会方便很多。 - 超级用户密码:默认超级用户是 postgres,密码务必设一个你不用翻聊天记录就能找到的,因为后面所有数据库操作都要用。
- 端口号:默认 5432。如果机器上另外装了 MySQL,或者占用了 5432,就改成别的端口,然后要一直记得这个端口。
- Locale 设置:默认可以选系统区域,如果希望后面数据库默认编码是 UTF8,可以在 initdb 时自己控制,Windows 安装器这一步通常给的是语言选项,我一般选默认即可。
安装结束后,如果没勾选 Stack Builder,就单独打开下载好的 PostGIS Bundle,安装向导会让你选择要安装到哪个 PostgreSQL 实例。它通常会列出你机器上已装的 PostgreSQL 版本,勾中对应实例后一路 Next。这一过程会在你的 PostgreSQL 安装目录下新增 share/extension/postgis.control 以及一堆 postgis--*.sql 脚本,还会在 lib 目录放入扩展的动态库。
2.3 第一次启动服务并用 psql 验证
安装完成后,Windows 服务管理器里应该能看到名为 postgresql-x64-16 的服务。如果服务没有自动启动,可以手动启动,然后把 pgAdmin 打开,用刚才设置的 postgres 密码登录。但我建议你先别急着用图形界面,直接用命令行验证安装最稳妥。
打开终端切到 PostgreSQL 的 bin 目录:
bash复制cd "C:\Program Files\PostgreSQL\16\bin"
psql -U postgres -p 5432 -h localhost
如果弹出密码输入提示并顺利进入 psql,服务链路基本没问题。此时执行:
sql复制SELECT version();
SHOW server_version;
再执行下面这条,看看 PostgreSQL 默认能识别的扩展里有没有 PostGIS:
sql复制SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name LIKE 'postgis%';
如果结果里出现 postgis 和 postgis_topology,说明扩展文件已经就位。如果这里没有任何记录,别急着去建空间表,八成是 PostGIS Bundle 没装成功或者位数不对应。先去检查安装目录下是否存在 share/extension/postgis.control,没有文件就说明扩展没真正落到正确位置,重装对应位数的 Bundle 才有效。
3. 从源码编译 PostgreSQL 16 开始:CentOS 7 上的完整部署记录
到了 Linux 侧,场景就没那么岁月静好了,尤其是“CentOS 7 + 源码编译 PostgreSQL 16”这个组合在被问到的概率极高。为什么大家会上来就选这条路?有一部分原因是被陈旧仓库版本逼的——CentOS 7 自带的 PostgreSQL 是 9.2,确实老得让人不太想用;也有一部分是公司内部规范要求自定义安装目录。不管出于哪种原因,源码编译这条路的关键点不在make本身,而在编译前依赖准备和编译后的初始化细节。
3.1 编译 PostgreSQL 16 前需要准备什么
源码编译 PostgreSQL 16 并不是什么玄学操作,但依赖库不齐会让你在 configure 阶段反复撞墙。我在 CentOS 7 上编译时,最常补的依赖是这些:
bash复制yum install -y gcc make readline-devel zlib-devel openssl-devel libxml2-devel
逐个解释一下:
- gcc、make 是编译工具链的底线。
- readline 库提供 psql 的命令行编辑能力,没有它也能编译通过,但 psql 用起来会非常难受,上下翻历史、左右移动光标全部失灵。
- zlib 是用作数据库内置备份压缩等相关功能的支持库。
- openssl 用于 SSL 连接支持,如果你的业务需要通过加密方式连数据库,这个库必不可少。
PostgreSQL 16 对编译器的要求不算苛刻,CentOS 7 自带的 gcc 4.8.5 我实际编译下来没有遇到问题。真正要注意的是你系统里是否残留多套编译器或库文件,导致 configure 找到的是错误版本,这种情况比缺依赖更难排查。你可以在 configure 阶段通过 --with-openssl 等参数显式开启某项功能,便于尽早暴露问题。
3.2 configure 参数和编译过程
源码包从官方下载站拿,解压后进入目录。我的推荐参数如下:
bash复制./configure --prefix=/usr/local/pgsql16 \
--with-openssl \
--with-libxml \
--with-readline \
--without-icu \
--without-llvm
--prefix 决定了 PostgreSQL 被安装到哪个目录。这里我特意选择自定义目录,避免和系统原有的 PostgreSQL 组件混在一起。--without-icu 和 --without-llvm 是我在 CentOS 7 这种资源有限的环境里常加的选项,因为这两个东西需要额外依赖,如果你的业务场景不需要本地化排序的高级功能和 JIT 编译,完全可以先不集成。注意,这不是禁用什么核心功能,只是裁剪编译范围。
configure 完成后,执行:
bash复制make -j$(nproc)
make install
make 阶段会编译很久,日志刷屏时别慌,多看最后 20 行有没有 error。如果中途报错,多数是缺某个头文件,把对应的 -devel 包装上,再重新执行 configure,重新 make 即可。由于 PostgreSQL 的源码目录写入了生成的 Makefile,最好先执行 make clean 清理掉上一次的编译产物再重新编译,避免残留问题。
3.3 initdb 初始化数据库目录与首次启动
编译安装完成后,还要做三件事:创建系统用户、初始化数据目录、启动服务。很多人在这里会直接用 root 执行 initdb,这会在后面埋下巨大的权限坑。
按照 PostgreSQL 的安全模型,数据库进程不允许以 root 用户运行。所以我们需要一个低权限用户:
bash复制useradd postgres
mkdir -p /data/pgdata /usr/local/pgsql16/logs
chown -R postgres:postgres /data/pgdata /usr/local/pgsql16/logs
然后切到 postgres 用户执行初始化:
bash复制su - postgres
/usr/local/pgsql16/bin/initdb -D /data/pgdata -E UTF8 --locale=en_US.UTF-8 -U postgres
-D 指定数据目录,-E UTF8 把默认编码设成 UTF8,--locale 控制排序和字符分类规则。这里我特意把数据目录放在源码包之外,因为数据目录和安装包分离会让后续升级、备份都轻松一些。
首次启动时,建议先用 pg_ctl 前台方式验证,而不是直接加入 systemd:
bash复制/usr/local/pgsql16/bin/pg_ctl -D /data/pgdata -l /usr/local/pgsql16/logs/pg.log start
日志文件先写清楚路径,后面服务起不来时,第一件事就是去翻这个文件。启动成功后再用 pg_isready 确认:
bash复制/usr/local/pgsql16/bin/pg_isready -p 5432
此时你只是让 PostgreSQL 跑起来了,还没有任何空间能力。这只是上半场。
3.4 编译完 PostgreSQL 16 之后,PostGIS 怎么落进去
这里就是整个编译路线最让人纠结的部分。如果 PostgreSQL 是通过系统仓库或 PG DG 仓库安装的,PostGIS 用 yum 一条命令就能装好。但如果你和我一样走的是自定义前缀的源码编译安装,直接用系统 postgis 包基本不可能被正确识别,因为那些包把文件安装到系统默认的 /usr/pgsql-16 路径,而你的 PostgreSQL 却装在 /usr/local/pgsql16。
解决路径其实只有两条:要么在最初就放弃自定义路径,改用仓库包;要么连 PostGIS 也源码编译。PostGIS 源码编译需要先解决一大堆依赖:GEOS、PROJ、GDAL、json-c、libxml2 等,这些库在 CentOS 7 默认仓库里版本往往偏低,可能要升级或额外编译,这个过程很容易让人崩溃。
我认为更务实的建议是分情况处理:
- 如果你的服务器允许从软件源安装,请先卸载掉自己刚编译的 PostgreSQL,改用 PG DG 仓库里的 PostgreSQL 16。然后把 postgis 装上,安装命令大概是这样:
bash复制yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install -y postgresql16-server postgresql16-postgis-3
- 如果项目硬性要求自定义编译目录,那你需要继续下载 GEOS、PROJ、GDAL、PostGIS 的源码逐一编译,并用
--with-pgconfig指向 PostgreSQL 自身的pg_config,让 PostGIS 知道要把扩展装到哪里。这个流程不是不能走,而是你应当为自己保留足够的时间预算。
考虑到多数读者是想在存量 CentOS 7 上快速得到一个能跑的空间库,我的个人倾向非常明确:能用软件源就用软件源,能用 Docker 就用 Docker,源码编译 PostgreSQL 本身可以作为一种控盘手段,但不要为了 PostGIS 也去硬啃一遍源码依赖链。如果你现在还没有开始编译,只是单纯想要一个 PostgreSQL + PostGIS 环境,先直接跳到下一节,Docker 路线会替你省下几个小时。
4. Docker 一条命令拉起空间库,但有几个数据卷的坑必须避开
Docker 路线被越来越多人接受是有原因的。官方维护的 postgis/postgis 镜像把 PostgreSQL 和 PostGIS 打包在一张镜像里,版本组合已经验证过,拉下来启动后直接就是带空间能力的数据库。这比什么安装向导和源码编译都省心。
4.1 镜像标签怎么选
如果此前没接触过这个镜像,第一反应可能是 docker pull postgis/postgis:latest。latest 虽然方便,但我一般不建议在正经环境里用它,因为你无法从镜像名直接判断里面 PostgreSQL 和 PostGIS 到底是多少版本。
更好的做法是直接拉你确定要用的标签。比如:
bash复制docker pull postgis/postgis:16-3.4
这个标签已经说明:PostgreSQL 16,PostGIS 3.4。如果你用的是 PostgreSQL 15,就找 15-3.3 或 15-3.4 这类标签,前面部分对齐主版本,后面的 PostGIS 版本选官方维护周期内较新的稳定版。标签是镜像维护方定的,去 Docker Hub 搜一下就清楚了。
4.2 初始化脚本和挂载卷
启动容器时,我几乎总会做两件事:挂载一个数据卷,以及把初始化 SQL 放进容器的 /docker-entrypoint-initdb.d/ 目录。下面是一个最小例子:
bash复制docker run -d \
--name geodb \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=YourStrongPassword \
-e POSTGRES_DB=geodb \
-p 5432:5432 \
-v /srv/pgdata:/var/lib/postgresql/data \
-v /srv/scripts:/docker-entrypoint-initdb.d \
postgis/postgis:16-3.4
如果你把建库脚本放在 /srv/scripts 下,例如 init.sql,那么容器首次启动时会按字母序自动执行这些脚本。这个机制对于一次性创建扩展非常顺手:
sql复制CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;
需要特别说明的是,/docker-entrypoint-initdb.d 下的脚本只在数据目录为空、容器首次初始化时执行。如果数据卷已经有旧数据,脚本不会重复执行,你只能手动进容器执行 CREATE EXTENSION。另外 PostgreSQL 16 之后,官方镜像对数据目录的权限检测更严格,挂载本地目录后如果出现权限问题,多半是目录属主不是 uid 999,可以先执行 chown -R 999:999 /srv/pgdata 或用具名卷解决。
4.3 日常维护时怎么进容器操作
容器跑起来后,日常维护有两种思路:一种是直接进容器,使用容器内自带的 psql;另一种是在宿主机上用 psql 客户端连接容器暴露的端口。
第一种更常见:
bash复制docker exec -it geodb psql -U postgres -d geodb
进入后执行:
sql复制SELECT postgis_version();
只要返回 PostGIS 版本号,说明镜像内置的 PostGIS 已经生效,空间库的基础已经打好。如果你发现还没有扩展,先执行创建扩展的语句,再继续往下走。
这种部署方式还有个隐藏好处:以后要把整个环境迁移走,只要把数据卷内容和镜像标签记录好,换个机器重新跑一条 docker run 命令,就能复现一套几乎一致的环境。线上团队协作时,这种方式远比“谁机器上手工装了一套”容易交代。
5. 创建空间数据库的“最后一公里”:扩展初始化与常用验证
数据库软件装完了,PostGIS 扩展也装进了 PostgreSQL 的扩展目录,但你会发现直接建一个普通数据库,里面还是没有空间函数。原因在于 PostGIS 的启用是库级别的动作:你想让哪个数据库拥有空间能力,就必须在那个数据库里显式执行扩展初始化。这一步新手经常漏掉。
5.1 先建业务库,再初始化 PostGIS
如果你还没建业务库,可以先建一个:
sql复制CREATE DATABASE geodb;
然后用 \c geodb 切换到这个库,并执行初始化:
sql复制CREATE EXTENSION IF NOT EXISTS postgis;
这一条执行完,PostGIS 的核心扩展已经在这个库中生效。如果想使用拓扑相关功能,还可以继续执行:
sql复制CREATE EXTENSION IF NOT EXISTS postgis_topology;
如果业务场景需要模糊匹配文本,可以把 PostGIS 自带的模糊匹配相关扩展一并装上。但最核心的就是 postgis 这个扩展,另外两个都算按需添加。注意,执行 CREATE EXTENSION 需要当前用户对该数据库拥有足够权限,通常使用超级用户 postgres 执行最省事。
这里有个常见的疑问:为什么我建了一个库,pgAdmin 里也看到 postgis 扩展列表了,但表里还是不能使用 geometry 类型?这通常是因为你在错误的数据库里执行了初始化。PostGIS 扩展的作用域是当前数据库,不跨库共享。所以要么你在业务库中手动执行 CREATE EXTENSION postgis,要么就基于官方模板库创建新库。
5.2 验证扩展是否真正可用
最简单的验证分两层。
第一层,查版本:
sql复制SELECT postgis_version();
正常输出类似 3.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1 的一串信息,里面有版本号,还有编译时启用的依赖库标志。如果只返回 3.4 或者没有任何结果,说明扩展没有加载完整。
第二层,实际建一张带空间字段的表并写入一个点:
sql复制CREATE TABLE demo_points (
id serial PRIMARY KEY,
name text,
geom geometry(Point, 4326)
);
INSERT INTO demo_points (name, geom)
VALUES ('站点A', ST_SetSRID(ST_MakePoint(116.4074, 39.9042), 4326));
SELECT name, ST_AsText(geom) FROM demo_points;
这条语句会用到 geometry(Point,4326) 类型和两个空间函数,只要能顺利返回结果,说明数据库端空间能力已经可以交付业务使用了。把空间字段的 SRID 显式写在表里是很重要的习惯,不然坐标系混乱会直接让后续距离计算变成笑话。
5.3 关于模板库和权限的两个提醒
PostGIS 安装包在部分 Linux 发行版里会自带一个名为 template_postgis 的模板库,但这是历史包袱。现代 PostgreSQL 中更推荐的方式是创建普通模板库或者干脆每个业务库手动初始化,因为扩展是可管理的实体,重复初始化成本很低,而且模板库容易被跳过,反而造成困惑。
另一个提醒是权限控制。不是每个应用账号都有权限执行 CREATE EXTENSION,生产环境应该只允许超级用户或具有相应权限的开发账号初始化扩展。业务运行账号只需要对数据表进行增删改查,不需要碰扩展管理,否则一旦误执行扩展更新或禁用操作,影响范围会非常大。
6. 启动失败和外部连接失败的现场排查:/var/run/postgresql 下的锁文件问题
网上有一个报错反复出现在各种安装教程后面:could not create lock file "/var/run/postgresql/.s.PGSQL.5432.lock": Permission denied。中文环境通常会显示为“无法创建锁文件 /var/run/postgresql/.s.pgsql.5432.lock: 权限不够”。这条报错看着唬人,但根因往往非常简单。我用一次现场复现带你把整个排查链路走一遍。
6.1 这个报错出现的直接原因
先看这个路径:/var/run/postgresql。在多数 Linux 发行版中,/var/run 是指向 /run 的软链接,这个目录是 tmpfs,即内存文件系统,专门用来存放运行时文件。PostgreSQL 在这里创建锁文件,目的是标记“5432 端口正在被某个实例使用”,避免两个实例同时监听同一个端口。
问题在于,创建这个锁文件需要对该目录有写权限。如果你用源码方式手动安装 PostgreSQL,并且用 postgres 用户执行了:
bash复制mkdir -p /var/run/postgresql
chown postgres:postgres /var/run/postgresql
那通常不会报权限错。但很多情况下,这个目录要么不存在,要么它的属主不是 postgres,要么你在 postgresql.conf 里配置了 unix_socket_directories = '/var/run/postgresql',但目录权限没跟上。
6.2 一步步定位,而不是靠猜
遇到这类报错,我的排查顺序已经固定下来,按步骤走基本不会漏:
第一步,看是不是有旧实例占用。
bash复制ps -ef | grep postgres
如果进程列表里已经有一个 postgres 实例在跑,并且监听端口也是 5432,那你再启动第二个实例时,它自然会尝试去写同一个锁文件,并在发现端口冲突之前就报权限错。处理方式是先停掉旧实例,或者给新实例换一个数据目录和端口。
第二步,确认 unix_socket_directories 指向哪里。
最直接的办法是在启动命令里临时配置并观察日志:
bash复制/usr/local/pgsql16/bin/pg_ctl -D /data/pgdata -l /tmp/pg.log start
然后看日志:
bash复制tail -n 50 /tmp/pg.log
如果日志里就是上面那条 Permission denied,去 postgresql.conf 里搜索 unix_socket_directories 这个参数,确认它是否被设置。如果你走的是发行版自带的安装方式,默认值可能是 /var/run/postgresql;如果你走的是源码编译,默认值通常是 /tmp。两个默认值的差异很容易制造混乱:用源码安装的人,发现 psql 能连上,但发行版工具连不上的时候,往往就是 socket 路径不一致导致的。
第三步,检查 socket 目录的真实权限。
假设报错指向 /var/run/postgresql,执行:
bash复制ls -ld /var/run/postgresql
stat -c '%U %G %a' /var/run/postgresql
正常情况下,目录属主应该属于 postgres 用户,权限通常为 2775(组内可写、可继承组)。如果输出显示属主是 root,权限是 755,那问题就一目了然了:postgres 用户没有写权限。修复方式也很简单:
bash复制chown postgres:postgres /var/run/postgresql
chmod 2775 /var/run/postgresql
之所以用 2775 而不是 777,是因为目录的 setgid 位能保证该目录下新创建的文件继承 postgres 组,避免后续再出现组权限不匹配的连锁问题。
第四步,仍然不行就把 socket 目录切到 /tmp。
如果目录权限调整后仍然有问题,那基本可以确定是你手动指定的目录还有什么隐藏限制。此时不妨临时改一下 unix_socket_directories,把它指到 /tmp:
bash复制unix_socket_directories = '/tmp'
然后重启服务。这是一个非常有效的兜底方案,因为 /tmp 对任何用户都可写,几乎不存在权限问题。代价是你以后用 psql -h localhost 连接时会走 TCP,或者要用 psql -h /tmp 显式让 psql 去找 /tmp 下的 socket 文件。
6.3 服务能启动但外部连不上,又是另一套排查思路
安装阶段还有一个高频问题是:本机通过 psql 能连接,换成局域网或其他服务器就连不上。这时候不要怀疑 PostGIS,注意力应该聚焦在 PostgreSQL 的监听设置和认证规则上。
先看监听地址,postgresql.conf 里如果还是默认的 listen_addresses = 'localhost',那外部根本没法通过 TCP/IP 访问。改成:
conf复制listen_addresses = '*'
改完重启服务,再看 pg_hba.conf。这个文件控制谁能通过什么方式访问哪个数据库,最常用的规则是:
conf复制host all all 0.0.0.0/0 scram-sha-256
表示允许任意来源 IP 通过加密密码访问所有数据库。生产环境最好把这个范围收紧到具体网段,只开放必要来源。很多连接失败的场景都是因为只改了 listen_addresses 而忽略了 pg_hba.conf,或者反过来。
之后再检查系统防火墙和云平台的安全组规则。CentOS 7 上常用 firewall-cmd:
bash复制firewall-cmd --permanent --add-port=5432/tcp
firewall-cmd --reload
如果部署在云服务器上,管理控制台里安全组的入方向规则也要放通 5432 端口。这里的规则很容易重复,但少一条就会让你在外面干瞪眼。
7. 装完只是开始:备份、主从复制与跨库同步的基本方向
PostgreSQL + PostGIS 安装完成、空间库创建成功,这只是把地基打完了。实际落地时还躲不开备份恢复、容灾、多环境数据同步这些事。没必要在安装阶段就把所有运维方案铺开,但至少要知道下一步该往哪个方向走。
7.1 数据备份:pg_dump 与物理备份的区别
对于空间数据,常规逻辑备份可以用 pg_dump:
bash复制/usr/local/pgsql16/bin/pg_dump -U postgres -d geodb -F c -f geodb.dump
-F c 是自定义压缩格式,配合 pg_restore 恢复时比较灵活:
bash复制/usr/local/pgsql16/bin/pg_restore -U postgres -d geodb --clean --if-exists geodb.dump
逻辑备份适合定期导出某个库,但如果数据量非常大,或者你需要完整恢复整个实例,包括角色、表空间、所有数据库,那更合适的是用 pg_basebackup 做物理备份,也是对后面搭建主从复制直接有用的基础工具。
7.2 从主从复制到高可用部署
PostgreSQL 原生支持基于 WAL 的流复制,主库把预写日志实时传给备库,备库持续回放。配主从的核心其实就两个动作:主库打开相关配置并创建一个有复制权限的账号,备库用 pg_basebackup 拉基础备份并启动 standby 模式。高可用集群方案 Repmgr、Patroni 本质也是在这套流
