Skip to content

Riablo/linear-gitlab-sync

Repository files navigation

linear-gitlab-sync

通过本地代理和 Cloudflare Tunnel,把内网自建 GitLab 暴露成 Linear Cloud 可以访问的 GitLab URL。

目标链路:

Linear Cloud -> 公网 HTTPS 域名 -> Cloudflare Tunnel -> Docker proxy -> 内网 GitLab
内网 GitLab -> Linear webhook URL

这个项目不实现自定义 Linear 集成。它只负责让内网 GitLab 看起来像一个公网可访问的 self-hosted GitLab,然后 Linear 继续使用官方 GitLab 集成流程。

功能

  • 运行一个 Bun HTTP GitLab 代理。
  • 将所有请求转发到 UPSTREAM_BASE_URL
  • 将 GitLab 返回中的内网 URL 改写成 PUBLIC_BASE_URL,覆盖 LocationLink、JSON、HTML 和纯文本响应。
  • 通过 Docker Compose 运行 Bun proxy 和 Cloudflare Tunnel。
  • 不保存 GitLab token。Linear 会把 PRIVATE-TOKEN 发给代理,代理只负责转发给 GitLab。

需要准备的值

开始前需要准备:

  • UPSTREAM_BASE_URL:这台机器或 Docker 容器能访问的内网 GitLab 地址,例如 https://gitlab.internal.example.com
  • PUBLIC_BASE_URL:给 Linear 访问的公网 HTTPS 地址,例如 https://gitlab-linear.example.com
  • CLOUDFLARED_TUNNEL_NAME:Cloudflare Tunnel 名称,例如 linear-gitlab-sync
  • CLOUDFLARED_TUNNEL_ID:由 cloudflared tunnel create 生成。
  • CLOUDFLARED_CREDENTIALS_FILEcloudflared tunnel create 生成的 tunnel credential JSON 绝对路径。
  • 给 Linear 使用的 GitLab token:建议使用 api scope。token 所属用户必须能访问要接入的 GitLab 项目。

从零开始配置

安装依赖:

brew install cloudflared
docker --version
docker compose version
bun --version

创建本地配置:

cp .env.example .env

编辑 .env

NODE_ENV=development
HOST=127.0.0.1
PORT=3100
HOST_PORT=3100
LOG_LEVEL=info

UPSTREAM_BASE_URL=https://gitlab.internal.example.com
PUBLIC_BASE_URL=https://gitlab-linear.example.com

CLOUDFLARED_TUNNEL_ID=
CLOUDFLARED_TUNNEL_NAME=linear-gitlab-sync
CLOUDFLARED_CREDENTIALS_FILE=/absolute/path/to/.cloudflared/<tunnel-id>.json
CLOUDFLARED_CONFIG_PATH=cloudflared/config.yml

ALLOWED_IPS=

登录 Cloudflare 并创建 named tunnel:

cloudflared tunnel login
cloudflared tunnel create linear-gitlab-sync

创建命令会输出 tunnel ID,并生成 credential 文件,通常在:

~/.cloudflared/<tunnel-id>.json

把生成的值写回 .env

CLOUDFLARED_TUNNEL_ID=<tunnel-id>
CLOUDFLARED_CREDENTIALS_FILE=/absolute/path/to/.cloudflared/<tunnel-id>.json

创建 DNS route。这里使用 PUBLIC_BASE_URL 的 hostname,不要带 https://

cloudflared tunnel route dns linear-gitlab-sync gitlab-linear.example.com

生成本地 Cloudflare Tunnel 配置:

bun run cloudflared:write-config

启动 Docker Compose:

bun run docker:up

验证服务:

bun run docker:ps
curl http://127.0.0.1:3100/healthz
curl https://gitlab-linear.example.com/healthz

验证 GitLab token 是否能通过代理:

curl -i \
  -H "PRIVATE-TOKEN: <gitlab-token>" \
  https://gitlab-linear.example.com/api/v4/user

预期结果是 HTTP/2 200

连接 Linear

在 Linear 中:

  1. 打开 GitLab integration 设置。
  2. 选择 self-hosted GitLab。
  3. GitLab URL 填公网域名,例如 https://gitlab-linear.example.com
  4. 填入带 api scope 的 GitLab token。
  5. 完成 Linear 的连接流程。

连接成功后,Linear 会给出 webhook URL 和 webhook secret。

在 GitLab 中:

  1. 打开 Project 或 Group 的 webhook 设置。多个项目建议使用 Group webhook。
  2. 粘贴 Linear 给出的 webhook URL。
  3. 粘贴 Linear 给出的 webhook secret。
  4. 启用这些 triggers:Push eventsCommentsMerge request eventsPipeline events
  5. 保持 SSL verification 开启。
  6. 保存 webhook。

GitLab 配置 webhook 通常需要 Maintainer 或更高权限。

端到端测试

创建一个 Linear issue,然后创建一个 GitLab branch 或 merge request,标题里包含 Linear issue ID:

ABC-123 test GitLab integration

创建 merge request 后,Linear issue 页面应该出现 GitLab 活动。merge request 合并后,Linear 可能会按集成设置把 issue 移到完成状态。

Docker 命令

启动或更新:

bun run docker:up

查看状态:

bun run docker:ps

查看日志:

bun run docker:logs

重启:

bun run docker:restart

停止:

bun run docker:down

Cloudflare 凭证维护

Tunnel credential JSON 是敏感文件,不要提交到 Git。仓库已经忽略:

cloudflared/config.yml
cloudflared/*.json
cloudflared/*.pem
.env

如果只是停止后重新启动 tunnel:

bun run docker:down
bun run docker:up

不需要修改凭证。

如果本地 credential JSON 被删除,但 tunnel 仍然存在:

cloudflared tunnel login
cloudflared tunnel token --cred-file /absolute/path/to/.cloudflared/<tunnel-id>.json <tunnel-name-or-id>

然后更新 .env

CLOUDFLARED_CREDENTIALS_FILE=/absolute/path/to/.cloudflared/<tunnel-id>.json

重新生成配置并重启:

bun run cloudflared:write-config
bun run docker:up

如果要重新创建 tunnel:

cloudflared tunnel delete <old-tunnel-name-or-id>
cloudflared tunnel create linear-gitlab-sync
cloudflared tunnel route dns linear-gitlab-sync gitlab-linear.example.com

然后把新的 tunnel ID 和 credential 路径写入 .env,重新生成配置并启动:

bun run cloudflared:write-config
bun run docker:up

如果更换 Cloudflare 账号:

cloudflared tunnel login
cloudflared tunnel create linear-gitlab-sync
cloudflared tunnel route dns linear-gitlab-sync gitlab-linear.example.com

公网域名所在的 DNS zone 必须在新的 Cloudflare 账号里。如果域名还在旧账号,要么迁移 zone,要么换用新账号里的域名。

故障排查

检查 Docker 是否在运行:

docker compose ps

检查 Cloudflare 是否能访问 proxy:

curl https://gitlab-linear.example.com/healthz

检查 GitLab 是否收到 token:

curl -i \
  -H "PRIVATE-TOKEN: <gitlab-token>" \
  https://gitlab-linear.example.com/api/v4/personal_access_tokens/self

检查 token 是否能列出项目:

curl -i \
  -H "PRIVATE-TOKEN: <gitlab-token>" \
  "https://gitlab-linear.example.com/api/v4/projects?membership=true&per_page=1&pagination=offset"

这两条都应该返回 200

如果 Linear 能连接 GitLab,但 webhook 没有更新 issue,去 GitLab webhook 的 delivery 记录里查。这个方向是:

内网 GitLab -> Linear 给出的 webhook URL

这条链路不经过本代理。

安全说明

  • 不要把 GitLab token 写进本项目的 .env。GitLab token 应该配置在 Linear 中。
  • 不要在 GitLab 公网域名前面加 Cloudflare Access 登录页,否则 Linear 无法直接调用 GitLab API。
  • 建议给 Linear 单独创建 GitLab bot 或 service account。
  • Cloudflare tunnel credential JSON 不要提交到 Git。
  • ALLOWED_IPS 可以限制访问来源,但建议先确认 Linear GitLab integration 请求实际使用的来源 IP 后再开启。

公开发布前检查

当前可提交文件不应包含真实 GitLab 域名、真实 Cloudflare 域名、本地绝对路径、tunnel ID、credential JSON 或 token。

发布到公开 GitHub 前建议检查:

git grep -n -E "your-company|internal-domain|real-domain|tunnel-id|token|secret" HEAD
git status --short

如果仓库历史里曾经提交过真实域名、tunnel ID 或本地路径,不要直接 push 整个历史。可以选择:

  • git archive HEAD 导出当前干净快照再创建新仓库。
  • 或重写 Git 历史,把敏感内容从所有历史提交中移除。

About

Expose private self-hosted GitLab to Linear through Cloudflare Tunnel

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors