背景
在 自建博客数据统计服务 umami v2 中我曾提到要迁移博客的评论系统,日历转到八月,看了眼 Railway 不思悔改心意已决,便注销账号(顺带放弃我珍贵的 $3.7 余额)。然鹅天有不测风云,小半个月过去 Vercel 提供外包的数据库在 dashboard 仍旧没有读写记录,umami 后台也一直显示 0 访客。
博客虽然冷冷清清凄凄惨惨戚戚,但也不至于完全没有流量,我百思不得其解,加之之前访客的 referrer 大都来自 cn.bing.com
,还以为禁用了 GPTBot 影响如此严重。机缘巧合下才发现原来是 vercel.json
配置错误,如有兴趣详见 #Vercel 部署 Umami,此处不再赘述。
正巧前几日在 GitHub Trending 看到 sql-mother,经过一晚上的学习算是对 SQLite 的基础功能都掌握了七七八八,随后也速读了『SQL 必知必会』和『MySQL 必知必会』,『SQL 进阶教程』也搬上了日程,也就摩拳擦掌想手动实践一番。奈何 cusdis 年久失修(其实是在准备 V2 大版本更新),虽然偶有更新,但依赖版本已经大幅落后,而且存在巨量安全漏洞,实际部署之前少不了一番 PR。闲话到此为止,下面开始回顾搭建 PostgreSQL 数据库踩的各种坑。
Vercel 搭建 Cusdis
由于 PostgreSQL 的坑实在是多,先介绍一下相对简单的这部分。理论上参考 官方文档,fork 仓库后填写对应参数即可,但事与愿违,Vercel 免费方案只能托管一个 PostgreSQL 数据库,已经用作博客数据统计,评论系统就只能自己动手丰衣足食了。
这里先假设 PostgreSQL 的坑已经填完,Vercel 能够顺利连接数据库,那么应该会出现这么一个错误:
精简后的日志
Failed to compile. ./style.css.webpack[javascript/auto]!=!./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[1].oneOf[13].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[1].oneOf[13].use[2]!./style.css Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/node' is not defined by "exports" in /vercel/path0/node_modules/postcss/package.jsonError [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath ‘./lib/node’ is not defined by “exports” in /vercel/path0/node_modules/postcss/package.json
– inner error – Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath ‘./lib/node’ is not defined by “exports” in /vercel/path0/node_modules/postcss/package.json
根据 这个 issue,升级 postcss 依赖或设置 Node 版本为 16.x 即可解决。
记得成功后到 Vercel 环境变量页面添加 NEXTAUTH_URL
为自定义域名再重新部署。
可以顺便设置 NEXT_TELEMETRY_DISABLED=1
关闭 NextJS 遥测数据的收集。
之后参考 Hugo 论坛教程 完成 Hugo 的 Cusdis 配置即可,如果遇到跨域问题可以参考 Sometimes form shows on page, sometimes not - CORS issue。
附上脱敏后的 Hugo 配置参考,我干了几天也没有什么别的,大概两件事:
- 根据文章的
isCJKLanguage
值选择性显示翻译挂件 - 打完安全补丁后部署访问
cusdis.es.js
返回 404,根据 Vercel 输出的静态文件目录,经过和https://cusdis.com/js/cusdis.es.js
对比确认改为cusdis.umd.js
可以正常工作
<!-- layouts/_default/single.html -->
<div id="cusdis_thread"
data-host="https://log.vinfall.com"
data-app-id="xxxxxx"
data-page-id="{{ .File.UniqueID }}"
data-page-url="{{ .Permalink }}"
data-page-title="{{ .Title }}"
>
</div>
{{ if .Params.isCJKLanguage }}
<script defer src="https://log.vinfall.com/js/widget/lang/zh-cn.js"></script>
{{ end }}
<script async defer src="https://log.vinfall.com/js/cusdis.umd.js"></script>
很惭愧,就做了一点微小的工作。
PostgreSQL 数据库搭建的最佳实践
安装
倒也算不上坑,只是一开始一顿操作,做完 best practice,结果发现 PostgreSQL 15 修改了公共模式的默认行为,导致前功尽弃。1 我使用的是 Debian testing/unstable,可以选择从 Debian 官方源安装,也可以选择 PostgreSQL 提供的 Apt 源。由于前面提到的 15 大版本问题,我两种都尝试过,让我意外的是,PostgreSQL 官方源 竟然还支持 Debian testing/13 和 unstable。建议 stable 用户选择 Debian 官方源,而 testing/unstable 用户选择 PostgreSQL 源。
访问 IP 设置
由于架构上后端数据库只要求 Vercel 能够访问,最好禁止除了数据库本机 IP、局域网和 Vercel IP 之外的所有访问。随手一搜在 networksdb.io 还真搜到了 Vercel 的 IP 范围(76.76.21.0 - 76.76.21.255
),注意 PostgreSQL 配置中的 IP 均为 CIDR 掩码,只填 IP 地址是没有用的……
这部分都是现学现卖的,就不班门弄斧了,参考下面两个页面自行设置:
SSL
配置 PostgreSQL 的 SSL 访问需要三个证书相关文件:
server.key
: 密钥server.crt
: 服务器证书root.crt
: 根证书
同上一节,具体流程自行参考以下页面和 PostgreSQL 官方文档(写得挺好的):
- How to Configure SSL on PostgreSQL
- PostgreSQL: Documentation: 15: 19.9. Secure TCP/IP Connections with SSL
- PostgreSQL: Documentation: 15: 73.1. Database File Layout (
PGDATA
介绍及常见位置)
连接测试
# restart
sudo systemctl enable postgresql
sudo systemctl restart postgresql
sudo systemctl status postgresql
# test
su -- postgres
psql -U <user-name> -d <db-name>
psql -U <user-name> -h <配置的数据库域名> -d <db-name>
psql "postgresql://$DB_USER:$DB_PWD@$DB_SERVER/$DB_NAME"
参考配置
脱敏后的配置节选,仅供参考:
/etc/postgresql/15/main/pg_hba.conf
# If you want to allow non-local connections, you need to add more
# "host" records. In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
host db-name user-name 76.76.21.0/24 md5
hostssl db-name user-name 76.76.21.0/24 md5
#host db-name user-name 76.76.21.0/24 trust
#hostssl db-name user-name 76.76.21.0/24 trust
host db-name user-name 127.0.0.1/32 md5
hostssl db-name user-name 127.0.0.1/32 md5
# 注意末尾的 /0,漏了就会报错
host db-name user-name <本机 IP>/0 md5
hostssl db-name user-name <本机 IP>/0 md5
# Database administrative login by Unix domain socket
# 由于 postgres 用户的鉴权基于 Unix,这里不能改为 md5,否则 log 会一堆报错
local all postgres peer
# "local" is for Unix domain socket connections only
# 这里从 peer 改成 md5,否则无法使用 psql 用户的密码访问
local all all md5
/etc/postgresql/15/main/postgresql.conf
#listen_addresses = 'localhost' # what IP address(es) to listen on;
listen_addresses = 'localhost,<本机 IP>,<数据库配置的域名>'
#listen_addresses = '*'
ssl = on
ssl_ca_file = '/path/to/root.crt'
ssl_cert_file = '/path/to/server.crt'
#ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
#ssl_crl_file = ''
#ssl_crl_dir = ''
ssl_key_file = '/path/to/server.key'
#ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
ssl_prefer_server_ciphers = on
各种坑
Postgres createuser command not found after installing with homebrew on my Mac
createuser
命令不在 $PATH
,加上就好了。参考命令和输出如下,于是乎把 /usr/lib/postgresql/14/bin
加到 $PATH
。
$ sudo find / -name createuser
/usr/lib/postgresql/14/bin/createuser
/usr/bin/createuser
/usr/share/bash-completion/completions/createuser
PostgreSQL: Why psql can’t connect to server?
症状:安装过 Debian 官方源的 postgresql
卸载并且未清除配置,随后安装 PostgreSQL 提供的 Apt 源,用 postgresql
用户创建用户提示 Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
,反正就是服务没启动连不上。
解决方案:查看日志发现 postgresql-14 的端口被改成了 5433,在对应配置文件中改回 5432,重启服务,一切正常。
$ vim /var/log/postgresql/postgresql-14-main.log
LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5433"
$ VISUAL=vim sudoedit /etc/postgresql/14/main/postgresql.conf
port = 5432
Can’t Connect to Postgresql on Port 5432
考虑了端口、防火墙、加密方式、权限等等原因,重启服务无数次,最后发现还是 pg_hba.conf
的问题,格式为 TYPE DATABASE USER CIDR-ADDRESS METHOD
,其中 IP 地址用标准的带有 CIDR 掩码长度的点分十进制声明,掩码长度表示客户端 IP 地址必须匹配的高位二进制位数。在给出的 IP 地址里,这个长度的右边的二进制位应该为零。在 IP 地址、/
、CIDR 掩码长度之间不能有空白。要声明单个主机,给 IPv4 地址声明 CIDR 掩码 32,给 IPv6 地址声明 128。不要在地址中省略结尾的 0。
就是被这个 CIDR 坑了,折腾了一小时……
结语
虽然洋洋洒洒两千字,但实际上踩坑部分也只鼓捣了一个半小时,第一天基于 PostgreSQL 15 的最佳实践尝试也只花了一晚上,和更新 Cusdis 那点过时依赖等待 Vercel 和 dependabot 一遍又一遍检测依赖更新并部署到 preview 浪费的五个小时相比,根本不值一提。
这次又要表演一次那个:不要靠近 JavaScript,会变得不幸?不要靠近 JavaScript,会变得不幸。不要靠近 JavaScript,会变得不幸!
其实并没有,但这点我要到第二天踩了许多坑顺利搭建完 PostgreSQL 14 才发现 ↩︎