Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 4 additions & 5 deletions website/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,8 @@ defaultContentLanguageInSubdir = true
createIssueManually= true # If it is 'false', it is auto to make a Github issue when the administrators login.
distractionFreeMode= true # Enable hot key (cmd|ctrl + enter) submit comment.
# 登录代理:GitHub 的 /login/oauth/access_token 接口不返回 CORS 头,浏览器无法直接调用,必须经服务端中转。
# 原来的 Heroku 免费应用已停服,故改为指向本站同源路径,由服务器反向代理到 GitHub。
# 因为与站点同源(都是 books.halfrost.com),浏览器不触发 CORS,最稳。
# 需要在服务器 web 配置里加一个反代到 https://github.com/login/oauth/access_token 的 location。
# 完整且修好 502(SNI) 的 nginx 配置见 website/deploy/nginx-gitalk-oauth.conf。
proxy= "https://books.halfrost.com/gitalk-oauth"
# 阿里云(大陆)服务器到 github.com 出网不稳定,nginx 直连会随机 502/504/404,配置再对也修不好。
# 故改用 Cloudflare Worker(边缘到 github 稳定)做 token 交换,绕开阿里云出网。
# Worker 源码见 website/deploy/gitalk-oauth-worker.js;nginx 直连方案(备用)见 website/deploy/nginx-gitalk-oauth.conf。
proxy= "https://gitalk-oauth.ydz627.workers.dev"

59 changes: 59 additions & 0 deletions website/deploy/gitalk-oauth-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Gitalk OAuth 代理 —— Cloudflare Worker 版
// 用途:替代 nginx 直连 GitHub 的方案。当「服务器到 github.com 出网不稳定」(随机 502/504/404)时,
// 把 token 交换放到 Cloudflare 边缘(到 github 稳定),彻底绕开你服务器的网络问题。
//
// 部署(二选一):
// A. 仪表盘最简单:
// 1. Cloudflare 控制台 → Workers & Pages → Create → Create Worker
// 2. 把本文件内容整段贴进去 → Deploy
// 3. 记下分配的地址,形如 https://gitalk-oauth.<你的子域>.workers.dev
// B. 命令行:npm i -g wrangler && wrangler deploy
//
// 部署后改一行 config.toml:
// [params.gitalk]
// proxy = "https://gitalk-oauth.<你的子域>.workers.dev"
// 然后重新构建发布(npm run build)。
//
// 注意:Worker 与站点不同源,必须返回 CORS 头(下面已处理);这点和原来的同源 nginx 代理不同。

const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';

function corsHeaders() {
return {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
};
}

export default {
async fetch(request) {
// 预检请求
if (request.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders() });
}
if (request.method !== 'POST') {
return new Response(JSON.stringify({ error: 'method_not_allowed' }), {
status: 405,
headers: { 'Content-Type': 'application/json', ...corsHeaders() },
});
}

const body = await request.text();
const ghResp = await fetch(GITHUB_TOKEN_URL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': request.headers.get('Content-Type') || 'application/json',
'User-Agent': 'gitalk-oauth-worker',
},
body,
});

const respBody = await ghResp.text();
return new Response(respBody, {
status: ghResp.status,
headers: { 'Content-Type': 'application/json', ...corsHeaders() },
});
},
};
59 changes: 32 additions & 27 deletions website/deploy/nginx-gitalk-oauth.conf
Original file line number Diff line number Diff line change
@@ -1,58 +1,63 @@
# Gitalk OAuth 反向代理 —— 修复点击「使用 GitHub 登录」报
# Error: Request failed with status code 502
# Error: Request failed with status code 502 / 504
#
# 背景:
# GitHub 的 token 接口 https://github.com/login/oauth/access_token 不返回 CORS 头,
# 浏览器无法直接调用,必须由站点同源转发(config.toml 里 Gitalk.proxy =
# https://books.halfrost.com/gitalk-oauth 就是指这里)。
#
# 关于 502 的定位(重要):
# 经实测,GitHub 端一切正常——不带 SNI 也能握手,直接 POST 返回 200(incorrect_client_credentials
# 的 JSON)。所以 502 是【本服务器侧】的故障,最常见两类:
# (1) 原来的 /gitalk-oauth 没有直连 GitHub,而是转发给一个本地中转程序
# (gatekeeper / cors-anywhere 之类的 node 应用),该进程挂了 → nginx 502。
# (2) 服务器到 github.com 出网被阻断/重置(国内主机常见)→ upstream 连接失败 → 502。
# 下面的配置改成【nginx 直连 GitHub】,可消除 (1)。若换上后仍 502,基本就是 (2),
# 请看文件末尾的「仍然 502 怎么办」。
# 关于 502/504 的定位(重要):
# GitHub 端一切正常(直接 POST 返回 200 的 incorrect_client_credentials JSON)。
# halfrost 的原配置里 proxy_pass 路径 / Host / SNI 都是对的,但仍间歇 502/504,
# 根因在【上游连接健壮性】,按概率:
# (1) DNS 过期(最可能):proxy_pass 用字面量 github.com 时,nginx 只在【启动时】解析一次 IP
# 并一直沿用。GitHub 走 Fastly,IP 会轮换;启动时那个 IP 失效后 → 间歇 502/504。
# => 用 resolver + 变量改成【请求时实时解析】。
# (2) IPv6 陷阱:实时解析若返回 AAAA 而机器无 IPv6 出网 → 连接失败 502。=> resolver 加 ipv6=off。
# (3) HTTP 版本:默认 proxy_http_version 1.0,升 1.1 + Connection "" 更稳。
# 下面这版把以上三点都处理了。若换上后仍 502/504,看文件末尾「仍然 502 怎么办」拿 error.log 定位。
#
# 用法:把下面的 location 放进 books.halfrost.com server {} ,然后
# 用法:books.halfrost.com server{} 里现有的 location = /gitalk-oauth 整段替换为下面这段,然后
# nginx -t && nginx -s reload
# 验证:
# curl -s -o /dev/null -w '%{http_code}\n' -X POST https://books.halfrost.com/gitalk-oauth \
# -H 'Accept: application/json' \
# -d 'client_id=x&client_secret=x&code=x'
# 修好后应返回 200(GitHub 回 incorrect_client_credentials 的 JSON,但 HTTP 状态是 200),不再是 502。
# 修好后应返回 200(GitHub 回 incorrect_client_credentials 的 JSON,但 HTTP 状态是 200),不再是 502/504

location = /gitalk-oauth {
proxy_http_version 1.1;
proxy_pass https://github.com/login/oauth/access_token;
# 请求时实时解析 github.com,避免 nginx 启动时缓存的 IP 轮换失效导致间歇 502/504;
# ipv6=off 防止返回 AAAA 而机器无 IPv6 出网导致连接失败。
resolver 1.1.1.1 8.8.8.8 valid=60s ipv6=off;
set $gh_oauth https://github.com/login/oauth/access_token;
proxy_pass $gh_oauth;

proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host github.com; # GitHub 按 Host 路由
proxy_ssl_server_name on; # 发送 SNI(最佳实践;某些网络下必需)
proxy_ssl_server_name on; # 发送 SNI
proxy_ssl_name github.com;
proxy_ssl_protocols TLSv1.2 TLSv1.3;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Accept application/json;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# 连接到 GitHub 慢/不稳时,给足超时,避免过早 502
proxy_connect_timeout 15s;
proxy_read_timeout 15s;

# 若改用变量形式的 proxy_pass(set $up https://github.com;)才需要显式 DNS:
# resolver 1.1.1.1 8.8.8.8 valid=300s;
proxy_connect_timeout 10s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}

# ───────────────────────── 仍然 502 怎么办 ─────────────────────────
# 先看真正的报错(关键):
# ───────────────────────── 仍然 502/504 怎么办 ─────────────────────────
# 看真正的报错(关键,一句话就能定性):
# tail -n 50 /var/log/nginx/error.log
# · "upstream timed out" → 服务器到 github 出网慢/被拦(见下方 Cloudflare 兜底)
# · "no live upstreams" / "could not be resolved" → DNS 问题(确认 resolver 生效)
# · "SSL_do_handshake() failed" → TLS/SNI 问题(确认 proxy_ssl_server_name on)
# 再在【服务器上】直接测到 GitHub 的连通性:
# curl -v -m 15 -X POST https://github.com/login/oauth/access_token \
# -H 'Accept: application/json' -d 'client_id=x&client_secret=x&code=x'
# · 若服务器上这条 curl 也连不上/超时/reset → 是服务器出网到 github 的问题(上面的(2))
# nginx 配置再怎么改都没用。此时改用下面的 Cloudflare Worker 兜底(部署在 GitHub 可达的边缘)。
# · 若服务器上这条 curl 也连不上/超时/reset → 是服务器出网到 github 的问题,
# nginx 配置再怎么改都没用,改用下面的 Cloudflare Worker 兜底(部署在 GitHub 可达的边缘)。
#
# ── 兜底方案:Cloudflare Worker(绕开本服务器出网,免费)──
# 1. 在 Cloudflare 新建一个 Worker,代码:
Expand Down
Loading
Loading