本地数据库客户端只能自己用?用 cpolar 安全访问 NAS 上的 PostgreSQL 管理台

本地数据库客户端只能自己用?用 cpolar 安全访问 NAS 上的 PostgreSQL 管理台

图:用 cpolar 安全访问 NAS 上的 PostgreSQL 管理台

我以前最怕这种验收:数据库跑在家里 NAS 或办公室小主机上,本地客户端连得好好的,同事一问"我能不能看一下表结构和几条测试数据",现场就开始尴尬。

直接把 PostgreSQL 的 5432 端口映射出去肯定不合适。数据库端口不是演示页面,公网裸露风险太高;更别说很多测试库里还混着调试数据,一不小心就把权限放大了。

这篇换个更稳的做法:在 NAS/Docker 上跑 PostgreSQL 测试库和 pgAdmin Web 管理台,只给同事一个临时 HTTPS 入口进管理台,用只读账号验收查询结果。验收结束后关掉 cpolar,入口消失,数据库端口一直不对公网开放。

1 这次要做成什么?

这套方案的重点不是"远程连接数据库",而是"临时验收 Web 管理台"。

最终链路长这样:

text 复制代码
同事浏览器
   ↓ HTTPS 临时地址
cpolar HTTP 隧道
   ↓
NAS 上的 pgAdmin Web 管理台:5050
   ↓ Docker 内网
PostgreSQL 测试库:5432

划重点:外部访问的是 pgAdmin 的 Web 页面,不是 PostgreSQL 的 5432 端口。pgAdmin 再使用 Docker 内网地址连接 PostgreSQL。

这篇里我会用 PostgreSQL 官方镜像和 pgAdmin 官方镜像做演示。pgAdmin 官方文档要求容器启动时设置 PGADMIN_DEFAULT_EMAIL 和 PGADMIN_DEFAULT_PASSWORD,容器默认监听 80,我们把它映射到 NAS 的 5050 端口,方便本地浏览器访问。

安全边界先说清楚:

  • 不公网暴露 PostgreSQL 5432。
  • 不给同事超级管理员账号。
  • 只使用脱敏测试库和只读数据库账号。
  • cpolar 只用于临时验收,验收结束立刻关闭隧道。
  • 生产环境走正式远程接入方案、堡垒机或统一网关,不拿临时隧道当长期入口。

2 环境准备:NAS 上先有 Docker

这篇默认你的 NAS、迷你主机或 Linux 服务器已经能运行 Docker 和 Docker Compose。群晖、威联通、Ubuntu 小主机都可以,命令写法以标准 Docker Compose 为准。

先在 NAS 上建一个单独目录,别把测试库文件散落到系统目录里:

bash 复制代码
mkdir -p ~/pg-review-demo
cd ~/pg-review-demo

这里单独建目录有两个好处:后面清理简单,Compose 文件、初始化 SQL、数据卷都能按项目收口。临时验收结束后,如果确定不用了,整个目录也更容易归档。

再确认 Docker Compose 可用:

bash 复制代码
docker version
docker compose version

如果 docker compose version 没有输出版本号,先把 NAS 的 Docker 套件或 Docker Compose 插件补齐。这里别急着往下跑,Compose 不通,后面的服务编排会直接卡住。

3 部署 PostgreSQL 测试库和 pgAdmin

先写一份 docker-compose.yml。这份配置包含两个服务:

  • postgres:测试用 PostgreSQL 数据库,容器内端口仍是 5432,但不映射到宿主机公网端口。
  • pgadmin:Web 管理台,对宿主机开放 5050,后面 cpolar 只穿透这个端口。
bash 复制代码
cat > docker-compose.yml <<'EOF'
services:
  postgres:
    image: postgres:16
    container_name: pg-review-postgres
    environment:
      POSTGRES_DB: reviewdb
      POSTGRES_USER: app_admin
      POSTGRES_PASSWORD: AdminPass_ChangeMe_2026
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init:/docker-entrypoint-initdb.d:ro
    networks:
      - pg-review-net
    restart: unless-stopped

  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pg-review-pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@example.com
      PGADMIN_DEFAULT_PASSWORD: PgAdmin_ChangeMe_2026
      PGADMIN_DISABLE_POSTFIX: "1"
    ports:
      - "5050:80"
    depends_on:
      - postgres
    networks:
      - pg-review-net
    restart: unless-stopped

volumes:
  pgdata:

networks:
  pg-review-net:
    driver: bridge
EOF

提醒一下,示例密码是为了教程可复制。你自己跑的时候要改成更长的随机密码,尤其是 pgAdmin 登录密码。同事验收只需要 pgAdmin 的登录入口,不需要知道 app_admin 的密码。

这里没有写 5432:5432,是故意的。PostgreSQL 只在 Docker 网络里被 pgAdmin 访问,避免把数据库原始端口暴露到 NAS 宿主机和公网。

4 初始化测试表,并创建只读账号

为了让验收不只是"能打开页面",我们准备一张脱敏订单表,再创建一个只读账号 review_reader。同事后面用这个账号在 pgAdmin 里跑查询,能看到数据,但不能改表。

先创建初始化目录和 SQL 文件:

bash 复制代码
mkdir -p init
cat > init/01-review-demo.sql <<'EOF'
CREATE SCHEMA IF NOT EXISTS review_app;

CREATE TABLE IF NOT EXISTS review_app.orders (
  id BIGSERIAL PRIMARY KEY,
  order_no TEXT NOT NULL UNIQUE,
  customer_name TEXT NOT NULL,
  amount NUMERIC(10, 2) NOT NULL,
  status TEXT NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

INSERT INTO review_app.orders (order_no, customer_name, amount, status, created_at) VALUES
  ('T20260720001', '测试用户A', 128.50, 'PAID', '2026-07-20 10:20:00+08'),
  ('T20260720002', '测试用户B', 68.00, 'PENDING', '2026-07-20 10:35:00+08'),
  ('T20260720003', '测试用户C', 299.90, 'PAID', '2026-07-20 11:05:00+08')
ON CONFLICT (order_no) DO NOTHING;

CREATE ROLE review_reader LOGIN PASSWORD 'ReaderPass_ChangeMe_2026'
  NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;

GRANT CONNECT ON DATABASE reviewdb TO review_reader;
GRANT USAGE ON SCHEMA review_app TO review_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA review_app TO review_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA review_app GRANT SELECT ON TABLES TO review_reader;
EOF

PostgreSQL 官方文档里,CREATE ROLE 可以明确指定 LOGIN、NOSUPERUSER、NOCREATEDB、NOCREATEROLE 这些权限属性。这里把危险权限全部关掉,只保留登录和查询需要的权限。

注意:/docker-entrypoint-initdb.d 里的 SQL 只会在数据库数据目录首次初始化时执行。如果你已经启动过一次 PostgreSQL,再改初始化 SQL 不会自动重跑。测试阶段想重置环境,可以执行:

bash 复制代码
docker compose down -v
docker compose up -d

down -v 会删除 Compose 创建的数据卷,测试数据也会一起清掉。别在真实库上这么干,这一步只适合当前这种临时演示库。

5 启动服务,本地先确认管理台能打开

现在启动两个容器:

bash 复制代码
docker compose up -d

看一下状态:

bash 复制代码
docker compose ps

正常情况下能看到 pg-review-postgres 和 pg-review-pgadmin 都处于运行状态。如果 pgAdmin 还在启动中,等十几秒再刷新页面,它第一次初始化会比普通静态页面慢一点。

在局域网电脑上打开:

text 复制代码
http://NAS_IP:5050

把 NAS_IP 换成你的 NAS 地址,比如 192.168.1.20。登录账号使用刚才配置里的:

text 复制代码
admin@example.com
PgAdmin_ChangeMe_2026

图:局域网先通过 pgAdmin :5050 验收数据库

这一步应该看到 pgAdmin 的登录页和主界面。图里适合截两块:浏览器地址栏里的 :5050,以及 pgAdmin 登录后的首页。这样读者能一眼看懂:现在只是局域网访问,还没对外开放。

如果打不开,先查三件事:

bash 复制代码
docker compose ps
docker logs pg-review-pgadmin --tail=80
curl -I http://127.0.0.1:5050

curl 能返回 HTTP 响应,说明 pgAdmin 在 NAS 本机端口已经起来;局域网电脑打不开,多半是 NAS 防火墙、Docker 端口映射或访问地址填错。

6 在 pgAdmin 里添加 PostgreSQL 服务器

登录 pgAdmin 后,需要手动把 Docker 内网里的 PostgreSQL 加进去。

在左侧或首页找到添加服务器入口,填写这些信息:

text 复制代码
General / Name: review-postgres
Connection / Host name/address: postgres
Connection / Port: 5432
Connection / Maintenance database: reviewdb
Connection / Username: review_reader
Connection / Password: ReaderPass_ChangeMe_2026

这里最容易填错的是 Host。不要填 127.0.0.1,也不要填 NAS 的局域网 IP。pgAdmin 和 PostgreSQL 在同一个 Docker Compose 网络里,服务名 postgres 就是可解析的内网主机名。

为什么这一步用 review_reader,而不是 app_admin?因为验收只需要看表结构和跑查询,不需要建库、删表、改权限。把只读账号提前接好,同事拿到 Web 页面后也只能做只读验证。

连接成功后,展开:

text 复制代码
Servers → review-postgres → Databases → reviewdb → Schemas → review_app → Tables → orders

在 Query Tool 里执行:

sql 复制代码
SELECT id, order_no, customer_name, amount, status, created_at
FROM review_app.orders
ORDER BY id;

能看到 3 条测试订单,说明数据库、权限和 Web 管理台链路都通了。

再试一条写入语句验证只读限制:

sql 复制代码
UPDATE review_app.orders
SET status = 'CANCELLED'
WHERE order_no = 'T20260720002';

这条语句会被权限拒绝。这个报错是好事,说明只读账号没有被放大权限。验收前建议自己先跑一遍,别等同事打开页面才发现权限给多了或给少了。

7 用 cpolar 开临时 HTTPS 入口给同事验收

本地确认没问题后,再让外网同事访问。这里用 cpolar 开 HTTP 隧道,目标端口是 pgAdmin 的 5050。

Linux 环境可以使用官方一键安装脚本:

bash 复制代码
curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash

安装完成后,先确认本机管理端口能打开:

bash 复制代码
cpolar version
curl -s http://127.0.0.1:9200 >/dev/null && echo "cpolar web ui ok"

cpolar 支持通过 Web UI 登录完成账号绑定,也支持命令行手动写入 authtoken。纯命令行环境可以执行:

bash 复制代码
cpolar authtoken YOUR_CPOLAR_AUTH_TOKEN

把 YOUR_CPOLAR_AUTH_TOKEN 换成你自己后台里的 token。这里不要把 token 发给同事,也不要写进公开仓库。

临时验收直接运行:

bash 复制代码
cpolar http 5050

命令输出里会出现公网访问地址,选择 https:// 开头的地址发给同事。免费随机地址适合这种短时演示,cpolar 已核对规则里免费套餐的随机公网地址会在 24 小时内变化,所以不要把它写进长期文档。

图:cpolar HTTPS 临时入口交付同事验收

这张图适合截 cpolar 输出的 HTTPS 地址,以及同事浏览器打开 pgAdmin 登录页的状态。注意截图时遮住邮箱、token、真实公网地址里的敏感片段,只保留能说明"HTTPS 临时入口已生成"的部分。

发给同事时,只给这几项:

text 复制代码
pgAdmin 临时地址:https://xxxx.cpolar.xxx
pgAdmin 登录账号:admin@example.com
pgAdmin 登录密码:PgAdmin_ChangeMe_2026
数据库连接名:review-postgres
可验收查询:SELECT * FROM review_app.orders ORDER BY id;

更稳一点的做法,是验收前把 pgAdmin 密码改成一次性的强密码,验收后再改掉或直接关闭容器。别把自己长期使用的 pgAdmin 管理员密码拿出来共享。

8 验收结束后怎么收口

同事确认能登录、能看表、能跑只读查询后,立刻关闭 cpolar 隧道。

如果你是在前台运行 cpolar http 5050,在终端按:

bash 复制代码
Ctrl+C

再确认外网地址打不开,pgAdmin 页面就不会继续暴露在公网入口上。

如果这套 PostgreSQL 和 pgAdmin 只是本次验收使用,也可以停掉容器:

bash 复制代码
docker compose down

如果连测试数据也不保留,执行:

bash 复制代码
docker compose down -v

再次提醒,down -v 会删除 PostgreSQL 数据卷。只要里面有任何需要留存的数据,就不要加 -v。

这里还有几个收口动作我建议固定做:

  • 删除或更换 pgAdmin 临时登录密码。
  • 确认没有在路由器、防火墙、NAS 控制台里额外开放 5432。
  • 如果测试库来自生产数据,验收前只保留脱敏字段,手机号、邮箱、地址、真实姓名不要原样放进去。

9 总结

这次我们做成的不是"把 PostgreSQL 放到公网",而是把 NAS 上的 pgAdmin Web 管理台临时拿出来给同事验收。数据库仍然待在 Docker 内网里,外部只通过 HTTPS 临时入口访问管理台,再用只读账号查看测试表。

关键步骤可以记成三件事:

  • PostgreSQL 不映射 5432,pgAdmin 映射到 NAS 的 5050。
  • 数据库里提前创建 review_reader,只给 CONNECT、USAGE 和 SELECT。
  • cpolar 只穿透 pgAdmin 的 Web 端口,验收结束马上关闭。

安全边界也别省:同事验收用脱敏测试库,不给超级管理员,不共享长期密码;生产环境使用正式远程接入方案、堡垒机或统一网关。临时演示就用临时入口,做完收口,这样既能让协作顺畅,也不会把数据库安全押在侥幸上。

相关推荐
l1t14 小时前
DeepSeek总结的pg_clickhouse 与 chdb 更新:编码、嵌套与类型
数据库·clickhouse·postgresql
ayaya_mana1 天前
MCTier 组网联机工具:安装、配置与私有化部署
网络·windows·内网穿透·联机
余槐i2 天前
EXPLAIN 显示走了索引查询仍慢:回表与选择性在 500 万行表上拉开 10 倍耗时
数据库·postgresql·性能优化·vacuum·explain
梦在远山后3 天前
PostgreSQL 锁与死锁:结合 DevMind 讲清楚
python·postgresql·agent
浪潮IT馆3 天前
Windows 10 安装 PostgreSQL 9.6.24 完整教程
数据库·windows·postgresql
岳麓丹枫0013 天前
PG 孤儿物理复制槽残留导致 pg_wal 膨胀 19G 故障分析
postgresql
haerapi3 天前
把 PostgreSQL 复制巡检做成可审计闭环:确定性采集、阈值判定与受控模型归纳
数据库·postgresql
如果'\'真能转义说3 天前
Docker Desktop | 本地化挂载 Postgresql
docker·postgresql·容器