关于 dokploy-ghcr-deploy
dokploy-ghcr-deploy 是部署技能,用于配置 Docker 化的 GitHub 仓库,将镜像发布到 GHCR,并在 main 分支更新时通过 Dokploy 部署。它按阶段指导设置 GitHub Actions、Dokploy、密钥及手动配置镜像仓库令牌。
主要功能
- 01准备 GitHub Actions 发布工作流
- 02将 Docker 镜像发布到 GHCR
- 03通过 Dokploy MCP 工具配置应用
- 04使用 gh 设置 GitHub 仓库密钥
- 05指导手动配置 GHCR 令牌
适用场景
- 01设置 main 更新后的自动部署
- 02将 GitHub 仓库连接到 Dokploy 应用
- 03配置 GHCR 镜像发布和访问
- 04在首次发布前验证部署触发流程
MCP 相关
此技能要求连接 Dokploy MCP 服务,并使用其工具创建和配置 Dokploy 项目、应用、域名及 API 密钥。随后由 GitHub Actions 调用 Dokploy 部署 API。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jeffreyyvdb/ dokploy-ghcr-deploy --skill dokploy-ghcr-deploy安装后在 Claude Code 中输入/dokploy-ghcr-deploy确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEREADME.mdassets/docker-publish.yml.template详细介绍
Dokploy + GHCR 自动部署
端到端操作指南:将 GitHub 仓库中的 Docker 化应用配置为 Dokploy 应用,使其在每次推送到 main 时自动重新部署。构建在 GitHub Actions 中进行;镜像推送到 GHCR(默认私有);工作流的最后一步通过 REST 调用让 Dokploy 拉取并重新部署。
采用此流程的原因:
- 选择 GHCR,而非 Docker Hub——Docker Hub 的免费套餐最多只能有 1 个私有仓库,而 GHCR 提供无限量的私有包。推送端使用内置的
GITHUB_TOKEN进行身份验证,工作流端无需额外的 PAT。 - 选择 API 触发,而非仓库 Webhook——GHCR 不会触发推送 Webhook,因此工作流会向 Dokploy 的
/api/application.deploy发送 POST 请求,而不是依赖仓库端 Webhook(Docker Hub → Dokploy 的工作方式就是如此)。
请按顺序完成各阶段。每个阶段都有明确的停止条件;如果有步骤未通过,请勿跳到后续阶段。
前置条件——开始前检查
尽可能在后台并行完成以下检查;只向用户说明发现的问题。
- Dockerfile 存在并公开一个端口。 阅读 Dockerfile。搜索
EXPOSE,记录端口号——稍后配置 Dokploy 域名时会用到。如果没有 Dockerfile 或没有EXPOSE,请停止并询问用户;不要根据框架默认值擅自编写 Dockerfile(这属于未经确认的猜测)。 .dockerignore存在。 如果缺失,提出添加一个最简文件(包含node_modules、.git、build、dist、测试文件、.env*)。这不是阻塞项。ghCLI 已通过身份验证。gh auth status应显示一个已激活的账户。如果没有,请停止并让用户先运行gh auth login。- 已连接 Dokploy MCP。 调用
mcp__dokploy-mcp__user-session。如果调用报错,请停止并让用户先连接 Dokploy MCP;没有它,此技能无法完成 Dokploy 相关操作。 - GitHub 远程仓库。 解析
git remote get-url origin以提取owner/repo。将其转为小写——GHCR 不接受镜像路径中的大写字母。如果远程仓库不在 GitHub 上,则此技能不适用;请告知用户。
收集用户输入
将以下问题合并到一次 AskUserQuestion 调用中,让用户一次性回答,而不是分五次询问。括号中为默认值——预先填入并允许用户修改:
- Dokploy 项目名称(默认:仓库名称)
- Dokploy 应用名称(默认:
web) - 要绑定的公开域名(该域名必须已解析到 Dokploy 主机;如果用户有类似
*.example.com的通配符域名,建议使用<project>.example.com) - Dokploy 基础 URL(例如
https://dokploy.example.com)——无法推断此 URL,务必询问 - 除
APP_ENV=production之外的额外环境变量——可选择跳过;之后也可以在 Dokploy UI 中添加。发送到application-saveEnvironment前,验证每一项是否匹配^[A-Z_][A-Z0-9_]*=,并拒绝包含原始换行符的值,避免某个值中意外出现换行符后悄悄注入另一个变量。
阶段 A——准备仓库
- 根据
assets/docker-publish.yml.template编写.github/workflows/docker-publish.yml。该模板使用${{ github.repository }},并在运行时将其转为小写,因此大多数仓库都可以直接使用——通常无需替换任何内容。 - 如果当前不在功能分支上,请创建一个功能分支(不要直接提交到
main——我们希望配置好密钥后,通过 PR 原子性地合入该工作流)。 3.暂存并提交该工作流。暂时不要推送——我们希望先配置好 Dokploy 和 GitHub 密钥,否则首次工作流运行时会针对尚未就绪的应用启动,导致部署历史中留下失败记录。
阶段 B — 通过 MCP 设置 Dokploy
按顺序执行,遇错即停。每次工具调用都会生成后续步骤需要的 ID——请在执行过程中记录。
- 解析组织 — 调用
mcp__dokploy-mcp__organization-active并保存organizationId。 - 使用
name和简短的description调用mcp__dokploy-mcp__project-create。响应包含projectId和自动创建的默认environmentId(名为production)——请同时保存。 - 使用
name(应用名称)和environmentId调用mcp__dokploy-mcp__application-create。保存applicationId。应用的初始sourceType为"github";保存 Docker 提供程序后,它会切换为docker。 - 使用以下参数调用
mcp__dokploy-mcp__application-saveDockerProvider:applicationIddockerImage: "ghcr.io/<lowercase-owner>/<lowercase-repo>:latest"registryUrl: "ghcr.io"username: "<lowercase-owner>"password: "PAT_PLACEHOLDER"— 此占位值可确保 MCP 调用有效,并且会保留原样。真实 PAT 由用户在阶段 E 直接设置到 Dokploy UI 中,因此不会经过本次对话。
- 使用以下参数调用
mcp__dokploy-mcp__application-saveEnvironment:applicationIdcreateEnvFile: trueenv: "APP_ENV=production\n..."(以及用户添加的其他内容)buildArgs: ""、buildSecrets: ""— 显式设置为空字符串,不能使用 undefined。参见注意事项。
- 使用以下参数调用
mcp__dokploy-mcp__domain-create:applicationIdhost: "<domain-the-user-gave>"port: <port-from-Dockerfile>https: true、certificateType: "letsencrypt"path: "/"、stripPath: false、domainType: "application"
- 使用
name: "github-actions-deploy-<repo>"和metadata: {"organizationId": "<from step 1>"}调用mcp__dokploy-mcp__user-createApiKey。保存key——它只会显示一次。提醒用户默认速率限制为每 24 小时 10 次请求;如果经常向 main 推送,可建议用户通过 Dokploy UI 提高限制。
阶段 C — 通过 gh 设置 GitHub 密钥
一次性批量执行三个密钥的 Bash 调用,这样用户只需批准一次:
gh secret set DOKPLOY_URL --repo <owner>/<repo> --body "<dokploy-base-url>" && \
gh secret set DOKPLOY_API_KEY --repo <owner>/<repo> --body "<api-key-from-B7>" && \
gh secret set DOKPLOY_APPLICATION_ID --repo <owner>/<repo> --body "<applicationId-from-B3>"
接着,在推送代码前对 API 进行冒烟测试。read -s 可避免将密钥写入 ~/.bash_history;末尾的 unset 会将其从 shell 中清除,避免它残留在进程环境中:
read -rsp "Paste DOKPLOY_API_KEY (not echoed): " DOKPLOY_API_KEY; echo
DOKPLOY_URL='https://your-dokploy.example.com'
APP_ID='<applicationId from B3>'
DOKPLOY_API_KEY="$DOKPLOY_API_KEY" \
curl -fsS --max-time 30 -o /dev/null -w "%{http_code}\n" \
-X POST "${DOKPLOY_URL%/}/api/application.deploy" \
-H "x-api-key: $DOKPLOY_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -cn --arg id "$APP_ID" '{applicationId:$id}')"
unset DOKPLOY_API_KEY
预期结果为 200。其他任何结果都表示 URL、密钥或应用 ID 有误——请先修复再继续。部署会失败(尚未推送镜像),但触发操作应该成功;这能证明身份验证链路正常。
阶段 D — 推送并创建 PR
推送分支,并使用 gh pr create 创建 PR。PR 正文应说明:
- 必须设置的三个密钥(确认它们已设置)
- Dokploy 应用详情(项目、应用、域名、端口)
- 合并后会触发首次实际部署
阶段 E — GHCR PAT(唯一的手动步骤)
GitHub 没有用于生成 PAT 的 API,所以用户必须在 UI 中完成这一步。不要假装可以自动完成。
PAT 绝不能经过本次对话。 聊天记录中的 read:packages PAT 属于凭据泄露——对话记录通常会保留在服务器端,而且该 PAT 可以拉取用户能访问的所有私有软件包。因此,用户应将其直接粘贴到 Dokploy,而不是粘贴到聊天中。不要要求用户在这里粘贴,也不要使用 mcp__dokploy-mcp__application-saveDockerProvider 调用真实值;应通过 Dokploy UI 原位替换阶段 B 步骤 4 中的 PAT_PLACEHOLDER 占位值。
请逐字告诉用户:
- GitHub → Settings → Developer settings → Personal access tokens (classic) → Generate new token → 仅勾选
read:packages权限范围 → 将有效期设为 90 days(这是 GitHub 为机器凭据推荐的最长有效期;不要选择“No expiration”)→ 生成 → 将令牌复制到剪贴板。- Dokploy → Projects → 你的项目 → 你的应用 → General → Docker provider → 将令牌粘贴到 Password 字段 → Save。
- 在此回复“saved”(不要发送令牌,也不要粘贴令牌)。
只有在用户确认“saved”后,才进入阶段 F。
如需轮换,流程相同:在 GitHub 撤销旧 PAT,生成新的 PAT,然后粘贴到 Dokploy UI。无需经过聊天。
这一步无法自动化的原因:gh CLI 令牌默认不包含 read:packages(其权限范围通常为 repo, read:org, gist, admin:public_key);运行 gh auth refresh -s read:packages 会生成一个用户范围的 OAuth 令牌,且仍附带其他所有权限范围——将它作为服务密码存储会带来过多权限。通过 Dokploy UI 设置一个权限范围仅为 read:packages 的专用 classic PAT,是最妥当的做法。
阶段 F — 首次部署
- 合并 PR(或推送到
main)。工作流将会触发。 - 查看 Actions 选项卡:构建应推送两个标签(
latest和sha-<short>),最后一步应从 Dokploy 收到 2xx 响应。 - 在 Dokploy → app → Deployments 中,确认有一次新部署依次从“Pulling”→“Running”→“Done”。
- 访问域名;预期应用会在 Dockerfile 指定的端口上响应。
如果 Dokploy 部署显示来自 ghcr.io/v2/ 的“denied: denied”,说明 PAT 错误或已过期——返回阶段 E。
注意事项(都是血泪教训)
- MCP zod 联合类型不接受
undefined。application-saveDockerProvider要求必须提供registryUrl, username, password的全部值(传入空字符串或真实值,不要省略)。application-saveEnvironment要求提供buildArgs和buildSecrets——传入""。省略这些值会因不透明的验证错误而白白多耗一轮。 - GHCR 镜像路径必须全部使用小写字母。 工作流模板通过
${IMAGE_NAME,,}处理了这一点。若手动编写,别忘了。 - 不要为 GHCR 推荐 Docker Hub webhook 流程。 GHCR 不支持推送 webhook。Dokploy 文档只在 Docker Hub 的相关说明中提到了 webhook 流程。
- Docker Hub 免费套餐仅支持 1 个私有仓库。 这就是此技能默认使用 GHCR 的原因。只在解释为何不使用 Docker Hub 时提到它。
- 软件包可见性。 GHCR 软件包首次推送时会继承源仓库的可见性——私有仓库 → 私有软件包。无需额外的 API 调用。如果仓库是公开的,软件包也会公开;只需告知用户一次。
- Dokploy API 密钥的默认速率限制为 10 次/24 小时。 对大多数“推送到
main”工作流来说足够了。如果用户每天部署很多次(例如,采用基于主干开发且经常合并),可在 Dokploy UI 中提高限制。 gh auth status显示的权限范围不足以拉取 GHCR 镜像。 典型的gh令牌包含repo, read:org, gist, admin:public_key——不包含read:packages。因此阶段 E 不能依赖 CLI 令牌。- 不要重命名
APP_ENV。 同时支持 Vercel 和 Dokploy 部署的代码库通常会专门根据APP_ENV分支,以避免与VERCEL_ENV混淆。在 Dokploy 中始终将其设为production。
此技能有意不做的事
- 不迁移现有 Dokploy 应用的域名——如果用户要替换一个以 GitHub 为源的 Dokploy 应用,请询问是要在新项目中创建新应用(干净无影响,旧应用也不会停机),还是就地重新配置(需要切换域名)。默认选择新项目。
- 不会将环境变量从一个应用复制到另一个应用。列出环境变量没问题;盲目地在应用之间复制 Stripe/DB 密钥,可能会导致覆盖或重复写入。
- 不设置预览部署、健康检查或副本。这属于范围蔓延;用户提出要求时再添加。