ghost 功能介绍
Ghost 是一款基于 Node.js 构建的开源内容管理系统,主打简洁高效的博客和出版平台。它支持 Markdown 编辑,内置会员及订阅功能,丰富站点主题供选择,适合开发者和内容创作者搭建个性化网站。截至 2024 年,Ghost 已拥有数百万用户和活跃社区,持续保持稳定迭代。官方 GitHub 项目地址为:github.com/TryGhost/Gh…
安装方式
官网给出四种安装方式:
- Ghost CLI - 适合在服务器上直接部署,不需要对ghost做任何改动。由于很难横向扩展,不适合线上环境部署。
- Docker 安装 - 通过ghost官方镜像安装,适合大部分环境部署。
- 本地安装 - 在本地安装ghost,可以通过docker镜像build的方式得到适合线上部署的镜像。
- 源码安装 - 从Git安装ghost,适合Ghost贡献者或者需要大范围修改内部代码。
因为线上使用,我选择的是 Docker 安装的方式,以下也是这个方式踩过的坑。
ghost部署架构图
底层基础设施依托AWS云服务,涵盖部署环境、邮件服务及系统监控。Ghost 通过适配器模式集成上述能力,实现云服务的标准化接入。同时,Ghost 提供包括支付处理、性能监测及运营分析在内的功能模块,支撑站点稳定运行与数据观测。
踩坑问题
镜像问题
-
Q: [镜像剪枝] ghost docker安装方式默认使用docker compose运行,并集成了cabby等服务。多个镜像在同一台机器上,一方面不是所有服务都必须运行,另一方面不同服务之间可能会竞争资源,影响性能。
A: 只启动ghost镜像,其他服务不运行。需要流量监控时,可以将相关服务单独部署,并通过服务间数据上报实现监控。
-
Q: [分级部署] 官方方案中,使用docker compose会加载对应环境的env文件,自动进行分级部署。但ghost单镜像的分级部署方式没有详细说明。
A: 根据ghost源码,ghost运行时会自动加载
/var/lib/ghost目录下相应环境的config.[env].json配置文件。 -
Q: [镜像架构不匹配] ghost启动后失败,日志打印 exec /usr/local/bin/docker-entrypoint.sh: exec format error
A: 出现
exec format error的原因是镜像的系统架构与服务器不匹配。比如:在 Mac(通常为 arm64 架构)上拉取镜像并推送到镜像库,但在 Linux 服务器(通常为 x86_64 架构)上运行时,二进制文件架构不兼容,导致无法启动。 -
Q:【分级配置不生效】基于官方镜像制作新的镜像的dockerfile中,将
config.[env].json复制到配置的文件夹下后,通过NODE_ENV设置工作模式,镜像中会加载对应环境配置。但是在部署线上环境时,发现仍然使用测试环境的配置。对应dockerfile部分如下:
A: 检查镜像发现,复制目标位置存在一份配置文件:config.production.json 与config.development.json,并且前者为后者的软链。复制操作会对同一文件先用config.production.json覆盖,再用config.development.json覆盖,导致最后只有dev环境的配置。修改镜像解除二者的软链关系,再打出对应镜像即可。
配置问题
-
Q: 部署实例后,访问没有返回
A: 这个问题可能的原因有很多。以下是我实际遇到的一种情况:
网站需要运行在
https://medo.dev/blog路径下,因此在config.json中将url配置为https://medo.dev/blog,这样所有请求都会带有/blog前缀。但是,反向代理(如 Nginx)在将流量转发到实例时,必须携带
/blog路径,否则 Node.js 服务只会处理根路径/下的请求,导致访问没有返回或资源加载失败。 -
Q: 接口服务响应时浏览器报错 mix content
A: 出现“mixed content”错误,通常是因为前端页面以 HTTPS 协议访问,而接口服务(API)却用 HTTP 协议响应,违反了浏览器的安全策略。
在 Ghost 这类应用中,
config.json配置里的url字段不仅影响页面资源请求地址前缀,同时还影响 Ghost 服务监听和响应时的协议处理:- 如果
url配置为 HTTPS,且使用 ALB(如 AWS 的 Application Load Balancer)做 HTTPS 协议卸载,ALB 转发到 Ghost 实例时用 HTTP 协议,这时 Node 服务会收到 HTTP 请求,但检测到url配置是 HTTPS,于是会重定向到 HTTPS,造成页面不断 301 跳转。 - 如果
url配置为 HTTP,则不会重定向,但页面用 HTTPS 加载,接口/资源为 HTTP,便触发 mixed content 报错。
官方推荐的解决办法: 在 ALB 层增加 header 配置,把
X-Forwarded-Proto: https透传到 Ghost 服务器。Ghost 会根据该 header 判断实际访问协议,从而正确处理请求和响应,避免重定向与 mixed content 问题。解决办法: 通过自定义镜像,修改 Ghost 源码或 Express 服务,去掉 301 协议校验
- 如果
-
Q:部署完成,在管理后台通过邀请链接邀请其他人使用,用户点击链接登录、邮箱验证之后,又跳转回登陆页面。
A: 当前部署架构是在负载均衡后的某一个path指向部署服务器。用户登录后,服务端设置用户登陆信息的cookie后,对应的 set-cookie header 没有带到浏览器中。对应的解决方式是两种:
-
Nginx 配置
proxy_cookie_path强制设置SameSite=None; Secure,允许服务器返回的header透传给浏览器 1. 修改源码镜像中中携带的cookie强制为sameSite,以及secure、domain信息如下,并且在 config.[env].json 中增加配置 root.session.cookie.path 为服务器 serve path,root.session.cookie.domain 为服务域名
适配器问题
-
Q: S3 适配器安装后项目不能启动
A: 从日志(docker log)看到类似如下报错:
ERROR Unable to find storage adapter s3 in ,/var/lib/ghost/content/adapters/,/var/lib/ghost/versions/6.10.3/core/server/adapters/.
这说明 Ghost 在配置文件里尝试加载 S3 存储适配器,但在上述路径下没有找到正确的适配器文件。
排查时发现:
- 通过 docker exec 进入容器,适配器文件其实已经放到对应路径。
- 但 Ghost 并不识别该适配器,依然报错。
原因分析:
Ghost 要求适配器为打包好的index.js文件,且该文件应作为模块入口放在适配器路径下。例如:
/var/lib/ghost/content/adapters/storage/s3/index.js
如果只是将源码文件复制进去,Ghost 可能无法正确加载。需要将源码打包成一个标准的 Node.js 模块入口文件。
解决方法:
- 使用esbuild工具将 S3 适配器打包为单个
index.js文件: - 将生成的
index.js放到 Ghost 指定的存储适配器目录下。例如:/var/lib/ghost/content/adapters/storage/s3/index.js
-
Q: redis连接超时,日志表现首请求处理时间长,页面持续loading
A: 这是由于 Ghost 官方文档中 Redis 的配置不完整或缺失,导致 Ghost 在首次请求时尝试连接 Redis 超时,表现为首请求处理时间很长,页面一直 loading。
{
"adapters": {
"cache": {
"Redis": {
"host": "master.redis-host.com",
"port": 6379,
"password": "password",
"storeConfig": {
"tls": {} // 使用 tls 加密协议
}
},
"imageSizes": {
"adapter": "Redis",
"host": "master.redis-host.com",
"port": 6379,
"password": "password",
"ttl": 60,
"tls": {
"rejectUnauthorized": false
},
"keyPrefix": "image-sizes:"
}
}
}
}
AWS 配置问题
- Q: S3 上传报错 The bucket does not allow ACLs
A: 这是因为 S3 的存储桶(Bucket)开启了“Object Ownership(对象所有权)”的新策略,并设置为了“Bucket owner enforced(强制桶所有者拥有权限)”。此配置会自动禁用所有 ACL(访问控制列表),也就是不能在上传对象时设置ACL参数,否则就会报错The bucket does not allow ACLs。
解决办法:
-
修改 Bucket 的 Object Ownership 设置:
- 进入 S3 控制台,找到Bucket。
- 在“权限” > “对象所有权”里,把属性由“Bucket owner enforced”改为“ACLs enabled”,允许使用 ACL。
原因说明:
- AWS S3 2023年后新建 Bucket 默认开启“Bucket owner enforced”,自动禁止所有 ACL,推荐用 Bucket Policy 管理权限。
- 只要上传时有 ACL 字段(甚至是
ACL: null)都会报错。
-
Q: S3上传报错 is not authorized to perform: s3:PutObjectAcl
A: 这是因为 S3 上传对象时,如果指定了 ACL(如
ACL: 'public-read'),需要同时拥有s3:PutObjectAcl权限。而你的 IAM 用户的策略只授予了s3:PutObject,没有包含s3:PutObjectAcl,导致报错。解决办法:为 IAM 用户增加
s3:PutObjectAcl权限在 S3 的 policy(策略)中,添加如下权限:s3:PutObjectAcl这样就允许该用户在上传对象时设置 ACL。 -
Q: 项目启动时报错: Migration lock was never released or currently a migration is running
A: 这是因为项目在初始化数据库迁移时被中断(如进程异常终止或网络原因),导致迁移锁(migration lock)没有被释放。这个锁通常是由数据库中的某条记录控制,防止多进程同时迁移。
在 AWS 云数据库环境下,如果是首次初始化且数据库还没有数据,可以直接删除整个数据库,然后重新执行初始化流程即可,锁定问题会自动解决。
总结
Ghost本身能力非常完整,如果独立域名自建部署的方式,由于网络路径短,遇到的问题和排查难度都会降低不少;但是在既有域名的subpath下指向ghost服务,会遇到一些怪异的问题。这种情况下,可以通过AI IDE读源码的方式,十分快速的解决遇到的问题。