Ghost 是一个专注于会员和时事通讯的开源 CMS。
Discourse是一款专注于社区建设的开源论坛软件。
您将 Ghost 和 Discourse 结合起来,您将获得围绕您的会员站点构建社区的“完美”组合。
只是,它并不完美。 会员需要在两个平台上创建不同的账户。 这很不方便,尤其是当两个平台都允许单点登录 (SSO) 时。
为了解决这个问题,Vikas 创建了一个 Discourse on Ghost (DoG) 插件。 使用它,您可以将 Ghost 网站的成员与 Discourse 论坛无缝集成。
在本教程中,我将向您展示如何使用 DoG 在 Discourse 上设置 Ghost SSO。
官方文档遗漏了我在测试中发现的一些关键点,因此我创建了这个教程来帮助其他人了解我的经验。
在 Ghost 上设置 Discourse
在您继续之前,我建议您阅读官方网页上的信息。
现在您已经有了一些想法,让我们看看本教程需要什么。
先决条件
- 使用 Node 而非 Docker 的自托管 Ghost 实例。 最好,服务器应该是基于 Debian/Ubuntu 的。
- 子域或另一个域上的自托管 Discourse 社区论坛,但不应是子文件夹(如 site.com/forum/)
?我正在使用“Session”方法,它反映了 Ghost 用于验证成员的身份验证。 在这种方法中,DoG 与 Ghost 位于同一域和服务器上。
第 1 步:在 Ghost (DoG) 上安装 Discourse
以 root 身份登录到托管您的 Ghost 网站的服务器。
您需要创建一个包含 DoG 代码的目录。 该目录可以在任何地方。 我把它放在 /root/
,根用户的主目录。
创建目录:
mkdir discourse-on-ghost
并切换到这个新创建的目录:
cd discourse-on-ghost
现在使用节点安装 DoG 的依赖项:
npm install @potluri/discourse-on-ghost
通过从刚刚安装的代码中复制它来创建命名的环境变量文件。 该文件将在下一节中修改。
cp node_modules/@potluri/discourse-on-ghost/.env.example .env
现在创建入口点脚本:
echo "import('@potluri/discourse-on-ghost/build/targets/node.js');" > index.js
第 2 步:在 Ghost 中为 DoG 创建集成
登录到 Ghost 安装的前端。 转到设置 – >集成:
在这里,创建一个新的集成。 将其命名为任何相关的名称,例如 DoG 或 Discourse-Ghost-SSO。
如果您转到新创建的集成,它会显示一些参数。 他们之中, 管理员 API 密钥 是您在后面的部分中需要的。

第 3 步:在 Discourse 中创建 API
现在以以下身份登录您的 Discourse 论坛 admin. 前往 行政 区域 -> API标签 并创建一个 新的 API 密钥.

给 API 一个相关的名称,用户级别设置为 All Users
和范围 Global
:

记下生成的密钥,因为它不会再次显示。 我们将在下一节中使用此密钥。

?如果您不小心错过了记下 API 密钥,您可以将其删除并创建一个新的。
第 4 步:配置 DoG
回到托管 Ghost 的服务器。
在您在步骤 1 中创建的 discourse-on-ghost 目录中,您必须编辑 .env
您之前创建的文件。
该文件有一些默认条目,但您还必须更改一些参数。 您可以参考此页面以了解有关这些环境变量的详细信息。
这是您获得的默认 .env 文件:
DOG_HOSTNAME="127.0.0.1" # Optional
DOG_PORT="3286" # Optional
DOG_GHOST_URL="https://127.0.0.1:2368/"
DOG_GHOST_ADMIN_URL="" # Optional - defaults to DOG_GHOST_URL
DOG_DISCOURSE_SHARED_SECRET=""
DOG_GHOST_ADMIN_TOKEN=""
DOG_DISCOURSE_URL="https://127.0.0.1:4200/"
DOG_DISCOURSE_API_KEY=""
DOG_DISCOURSE_API_USER="" # Optional
DOG_LOG_DISCOURSE_REQUESTS="false"
DOG_LOG_GHOST_REQUESTS="false"
DOG_GHOST_MEMBER_WEBHOOKS_ENABLED="false"
DOG_GHOST_MEMBER_UPDATED_WEBHOOK_ID="BAFF1EDBEADEDCAFEBABB1ED"
DOG_GHOST_MEMBER_DELETED_WEBHOOK_ID="BAFF1EDBEADEDCAFEBABB1ED"
DOG_GHOST_MEMBER_DELETE_DISCOURSE_ACTION="suspend"
DOG_DISCOURSE_SSO_TYPE="session"
DOG_JWT_GHOST_SSO_PAGE="" # Optional (absolute path)
DOG_SSO_NO_AUTH_REDIRECT="" # Optional (url)
这里有 你必须改变的参数 对他们的价值观提出建议。
- DOG_GHOST_URL:使用您的 Ghost 网站的 URL 和尾部斜杠,例如 https://myurl.com/
- DOG_DISCOURSE_SHARED_SECRET:这是一个长 64 个字符的字母数字字符串,总共 小写字母. 您可以在线使用随机字符串生成器来获得一个。
- DOG_GHOST_ADMIN_TOKEN:使用您在第 2 步中创建的 Ghost 集成生成的管理 API 密钥。
- DOG_DISCOURSE_URL:您的 Discourse 社区论坛的 URL。
- DOG_DISCOURSE_API_KEY:您在第 3 步中生成的 API 密钥。
- DOG_GHOST_MEMBER_UPDATED_WEBHOOK_ID:有一个24个字符的字符串,改成相同长度,字母数字,但 小写字符串.
- DOG_GHOST_MEMBER_DELETED_WEBHOOK_ID:同上。 有一个 24 个字符的字符串,但将其更改为相同的长度,字母数字但 小写字符串.
- DOG_SSO_NO_AUTH_REDIRECT:用于登录或注册的 Ghost 网站的登录页面。 您还可以使用门户链接 https://site.com/#/portal/account。
这是我的演示站点的 .env 文件的样子:
DOG_HOSTNAME="127.0.0.1" # Optional
DOG_PORT="3286" # Optional
DOG_GHOST_URL="https://learnubuntu.com/"
DOG_GHOST_ADMIN_URL="" # Optional - defaults to DOG_GHOST_URL
DOG_DISCOURSE_SHARED_SECRET="5368a5f6992140c165953482682a6440cdfe02f1c9f6ab6ee9ef097857bc7d5a"
DOG_GHOST_ADMIN_TOKEN="6457822b4cf40f06511b2bd4:ee3fb9a1f83131ea29dac4b7d2d979a42e295daf848bdb4feaerrtdb9b81a0aa"
DOG_DISCOURSE_URL="https://community.learnubuntu.com/"
DOG_DISCOURSE_API_KEY="9757fdf91a4ed3f36f33a511e8b4b44ba538f4e5fe78baafb672e7d0ad97a194"
DOG_DISCOURSE_API_USER="" # Optional
DOG_LOG_DISCOURSE_REQUESTS="false"
DOG_LOG_GHOST_REQUESTS="false"
DOG_GHOST_MEMBER_WEBHOOKS_ENABLED="false"
DOG_GHOST_MEMBER_UPDATED_WEBHOOK_ID="baff1edddadedcafebabb1ed"
DOG_GHOST_MEMBER_DELETED_WEBHOOK_ID="baff1edddadedcafebabb1ee"
DOG_GHOST_MEMBER_DELETE_DISCOURSE_ACTION="suspend"
DOG_DISCOURSE_SSO_TYPE="session"
DOG_JWT_GHOST_SSO_PAGE="/sso/" # Optional (absolute path)
DOG_SSO_NO_AUTH_REDIRECT="https://learnubuntu.com/#/portal/account" # Optional (url)
现在一切都已设置 .env
文件,运行脚本。
node node_modules/@potluri/discourse-on-ghost/build/targets/node-first-run.js
每次更改 Ghost 会员级别时,都应该运行此脚本。
如果在此阶段没有发现任何错误,则可以进入下一阶段更改 Nginx 服务器。
第 5 步:设置 NGNIX
创建目录结构 api/external_discourse_on_ghost
在里面 Ghost安装目录.
我正在使用 Digital Ocean 提供的一键安装。 我的 Ghost 安装在 /var/www/ghost
他们建议使用 ghost-mgr
负责任何与 Ghost 相关的任务。 所以,我切换到这个帐户和目录。 如果您不使用 DigitalOcean 的一键式 Ghost 安装,这对您来说可能会有所不同。
cd /var/www/ghost
mkdir -p api/external_discourse_on_ghost
现在我在 Ghost 上有一个 /var/www/ghost/api/external_discourse_on_ghost 目录。
接下来,修改安装 Ghost 时自动创建的 NGINX 配置。 您可以在中找到该文件 /etc/nginx/sites-enabled/your.site-ssl.conf
.
在最后一行之前添加以下内容:
location /var/www/ghost/api/external_discourse_on_ghost {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass https://127.0.0.1:3286;
}
这是我的测试站点 learnubuntu.com 的样子:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name learnubuntu.com;
root /var/www/ghost/system/nginx-root; # Used for acme.sh SSL verification (https://acme.sh)
ssl_certificate /etc/letsencrypt/learnubuntu.com/fullchain.cer;
ssl_certificate_key /etc/letsencrypt/learnubuntu.com/learnubuntu.com.key;
include /etc/nginx/snippets/ssl-params.conf;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass https://127.0.0.1:2368;
}
location /ghost/api/external_discourse_on_ghost {
proxy_pass https://127.0.0.1:3286;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
}
location ~ /.well-known {
allow all;
}
client_max_body_size 50m;
}
Save 文件和 以 root 用户身份运行以下命令:
nginx -s reload
没有显示为输出。 这很正常。
第六步:配置DoG服务
Ubuntu 使用 systemd,因此您可以为 Discourse on Ghost 创建一个新的 systemd 服务。
对我来说,systemd 单元文件看起来像这样,但你必须做一些修改:
[Unit]
Description=Discourse on Ghost
Documentation=https://github.vikaspotluri.me/discourse-on-ghost
[Service]
Type=simple
# Don't forget to update this!
WorkingDirectory=/root/discourse-on-ghost
# The user might be different for `jwt` mode
User=root
Environment="NODE_ENV=production"
# You can get your node path by running `which node`
ExecStart=/usr/bin/node index.js
Restart=always
[Install]
WantedBy=multi-user.target
在上面,改变 WorkingDirectory
保存位置的值 discourse-on-ghost
,您在步骤 1 中创建的目录。
Save 以上为 /lib/systemd/system/discourse_on_ghost.service
使用 根用户.
然后以 root 用户身份一条一条运行以下命令:
systemctl daemon-reload
systemctl enable discourse_on_ghost.service
systemctl start discourse_on_ghost.service
完成后,通过检查 systemd 服务的状态来验证一切是否正常:
systemctl status discourse_on_ghost.service
它应该显示 加载 和 活动(运行):
● discourse_on_ghost.service - Discourse on Ghost
Loaded: loaded (/lib/systemd/system/discourse_on_ghost.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2023-05-07 12:08:43 UTC; 2 days ago
Docs: https://github.vikaspotluri.me/discourse-on-ghost
Main PID: 759 (node)
Tasks: 11 (limit: 2338)
Memory: 35.9M
CGroup: /system.slice/discourse_on_ghost.service
└─759 /usr/bin/node index.js
第 7 步:配置 Discourse
你拥有大部分你需要的东西。 现在,以以下身份登录 Discourse 站点 admin. 转到“设置”中的登录侧边栏选项卡。 你也可以 搜索话语连接.

你必须提供 discourse connect url
价值。 它应该是您在第 5 步中创建的 API 目录的位置。对我来说,它是 https://learnubuntu.com/ghost/api/external_discourse_on_ghost/sso
如上图所示。 请注意,您必须为其提供 Ghost 网站的完整 URL。
您必须填写的下一个字段是 discourse connect secret
. 记住 .env
您在第 4 步中创建的文件? 使用的价值 DOG_DISCOURSE_SHARED_SECRET
来自 .env
文件。
现在,检查 enable discourse connect
选项。
好吧! 如果有人点击 Discourse 中的登录按钮,他们将被重定向到您的 Ghost 网站的登录或登陆页面(无论您在 .env 文件中设置)。
工作快完成了。 唯一剩下的就是处理成员删除和更新操作以将其与 Discourse 同步。
步骤 8:配置 Ghost Webhooks
登录到您的 Ghost 网站并转到您在第 2 步中创建的集成。单击 添加网络钩子 选项:

您必须在此处创建两个 webhook。 一个用于成员更新,另一个用于成员删除。
您应该使用的目标 URL 的形式为 https://site.com/ghost/api/external_discourse_on_ghost/DOG_GHOST_MEMBER_UPDATED_WEBHOOK_ID
在上面,将 site.com 替换为您网站的 URL,将 DOG_GHOST_MEMBER_UPDATED_WEBHOOK_ID 替换为您在 .env
您在步骤 4 中创建的文件。

同样,在为成员删除创建 webhook 时,您在目标 URL 结构中使用 DOG_GHOST_MEMBER_DELETED_WEBHOOK_ID。
你们都准备好了。 一切就绪。 你可以开始测试它。 恭喜您在 Discourse 上使用 Ghost SSO。
去之前要知道的事情…
在您出发之前,您应该了解以下几点。
当有人尝试登录 Discourse 时,他们将被重定向到 Ghost 登录。
它将为非 Discourse 会员的现有 Ghost 会员创建一个新的 Discourse 帐户。
对于不是 Ghost 会员的现有 Discourse 会员,他们应该使用用于 Discourse 的相同电子邮件地址创建一个 Ghost 帐户。 这样,他们将能够访问他们现有的 Discourse 帐户。
请记住,这适用于 Discourse admin 帐户也是如此。 您应该使用与 Discourse 帐户相同的电子邮件地址创建或更新 Ghost 帐户。
在里面 .env
文件中,DOG_GHOST_MEMBER_DELETE_DISCOURSE_ACTION 设置为暂停。 这意味着如果用户从 Ghost 中删除,他们的帐户将在 Discourse 中被暂停。 您可以将其更改为这些值之一。
我知道这是一篇很长的文章。 但是当我尝试按照官方文档进行操作时,我发现一些关键部分缺失或不按应有的顺序排列。 因此,我创建了本教程。
您可能会遇到我没有遇到的问题。 如果是这样,请在评论中告诉我,我会尽力帮助您。