缘起
这个网站已经上线五年了,一直使用Hugo框架。Hugo框架非常好用,但经过几年的使用,我还是感受到了一些不便之处。
具体来说,由于我这个网站用docker容器部署,博客的内容则用GitHub仓库管理,因此每次更新博客内容都需要在本地电脑上修改markdown文件,然后提交到GitHub仓库,最后再在服务器上拉取更新,重新构建容器并启动。
这一系列操作虽然不算麻烦,但写博客时必须得在有这个博客Git仓库的电脑上进行。有时突然有了些灵感,想写点儿东西,但手机上或者电脑上没有这个博客的Git仓库,就只能先写在其他地方,之后再复制到博客的markdown文件中。这确实有点儿麻烦,但更让人不舒服的点是,有时想继续写之前没写完的博客,但如果没有这个博客的Git仓库,就看不到之前写的内容,没法接着写。
所以我就在想,有没有什么办法,能给博客加个编辑系统,能够将博客的草稿保存在服务器上,这样无论在哪个电脑上,甚至在手机上,都可以打开草稿继续写,写完了之后再发布到博客上。
根据ChatGPT的提示,这样的系统叫做内容管理系统(CMS),并且建议我可以使用DeCap CMS这个开源的CMS系统来搭建博客的编辑系统。
DeCap CMS简介
DeCap CMS是一个基于Git的内容管理系统,支持多种静态网站生成器(如Hugo、Jekyll、Gatsby等)。它提供了一个用户友好的界面,允许用户通过浏览器编辑和管理博客内容,并将更改直接提交到Git仓库中。
DeCap CMS的安装也非常简单,只需要在静态网站的根目录下放一个admin文件夹,里面放入一个HTML文件和一个配置文件。比较麻烦的部分是要配置一个沟通DeCap CMS和GitHub仓库的后端服务。
DeCap CMS的工作原理
DeCap CMS的工作流程
DeCap CMS的工作流程大致可分为4个步骤:
- 网站管理员登录界面:在静态网站的根目录下放一个
admin文件夹,就可以通过访问https://blog.example.com/admin/来进入DeCap CMS的登录界面。 - 用户认证:DeCap CMS支持多种认证方式,包括GitHub OAuth、GitLab OAuth、Bitbucket OAuth等。用户可以选择适合自己的认证方式来登录。
- 内容编辑:登录成功后,用户可以通过DeCap CMS的界面来编辑博客内容。DeCap CMS提供了一个所见即所得的编辑器,用户可以直接在浏览器中编辑博客内容,并且可以预览编辑的效果。
- 内容发布:当用户完成编辑后,可以点击发布按钮。利用我们给DeCapCMS提供的可以访问Git仓库的令牌,DeCap CMS会将更改提交到Git仓库中,并触发静态网站生成器(如Hugo)的构建过程,最终将更新后的博客内容发布到网站上。
DeCap CMS的构件
由此可见,我们需要准备好4个东西:
- DeCap CMS的前端文件:需要在博客的根目录下创建一个
admin文件夹,并在其中放入DeCap CMS的前端文件──一个HTML文件和一个配置文件。 - 登录认证:需要选择一种认证方式,并配置相应的认证信息。
- Git仓库访问令牌:需要生成一个可以访问博客Git仓库的令牌,并将其配置到DeCap CMS中。
- 将DeCap CMS的请求转发到后端的服务:需要配置一个后端服务来处理DeCap CMS的请求,并将其转发到Git仓库中。
以我的需求为例,我使用Hugo作为博客框架,博客的内容保存在GitHub仓库中,因此我需要配置DeCap CMS来支持Hugo。DeCap CMS支持GitHub OAuth认证,因此我可以选择使用GitHub OAuth来进行用户认证。最后,我需要配置一个后端服务来处理DeCap CMS的请求,并将其转发到GitHub仓库中。
DeCap CMS的安装与配置
安装DeCap CMS的前端文件
对于Hugo框架,DeCap CMS要求把前端文件放在Hugo项目根目录的static文件夹下(对于其他框架,可能需要放在public、src、site等文件夹下,具体需要根据DeCap CMS的文档来确定)。因此我们在博客的Hugo项目根目录下创建一个static/admin文件夹,并在其中放入DeCap CMS的前端文件:
-
index.html:DeCap CMS的主界面文件,包含了DeCap CMS的前端逻辑和界面设计。1 2 3 4 5 6 7 8 9 10 11<!doctype html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Jin Li Misc Admin</title> </head> <body> <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script> </body> </html> -
config.yml:DeCap CMS的配置文件,用于配置DeCap CMS的认证方式、Git仓库访问令牌等信息。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27backend: name: github repo: jin-li/blog branch: main base_url: https://decap.example.com auth_endpoint: /auth media_folder: "hugosite/static/images" public_folder: "/images" site_url: https://blog.example.com display_url: https://blog.example.com publish_mode: editorial_workflow collections: - name: "blog" label: "Blog Posts" folder: "blog/content/posts" create: true slug: "{{year}}-{{month}}-{{day}}-{{slug}}" fields: - { label: "Title", name: "title", widget: "string" } - { label: "Date", name: "date", widget: "datetime" } - { label: "Draft", name: "draft", widget: "boolean", default: true } - { label: "Tags", name: "tags", widget: "list", required: false } - { label: "Body", name: "body", widget: "markdown" }其中
backend里配置了后端的服务用GitHub,本网站的GitHub仓库是jin-li/blog,分支是main,后端服务的地址是https://decap.example.com,认证接口是/auth。media_folder和public_folder分别配置了媒体文件的存储路径和访问路径。site_url和display_url配置了网站的URL。publish_mode配置了发布模式,这里使用了编辑工作流模式。最后,collections配置了内容集合,这里配置了一个名为“blog”的集合,用于管理博客文章。这样,当我们访问
http://yourwebsite.com/admin/时,DeCap CMS会加载管理界面,并显示GitHub OAuth的登录选项。
配置GitHub OAuth认证
要使用GitHub OAuth认证,我们需要在GitHub上创建一个OAuth应用,并获取相应的客户端ID和客户端密钥。具体步骤如下:
- 登录GitHub,点击右上角的头像,选择“Settings”。
- 在左侧菜单中选择“Developer settings”。
- 在左侧菜单中选择“OAuth Apps”,然后点击“New OAuth App”。
- 在“Register a new OAuth application”页面中,填写应用的名称、主页和回调URL。其中主页URL应该是你的博客地址,例如这里是
https://blog.example.com,回调URL应该是DeCap CMS后端服务的认证接口地址,例如这里是https://decap.example.com/callback。 - 点击“Register application”按钮,完成应用的注册。注册完成后,你会看到应用的客户端ID(Client ID)和客户端密钥(Client Secret)。记录下这两个值,后续配置DeCap CMS时需要用到。
配置DeCap CMS的代理
在我们访问https://blog.example.com/admin/,并点击GitHub OAuth登录按钮后,DeCap CMS会向https://decap.example.com/auth发送一个认证请求。这个请求需要被转发到GitHub的OAuth认证接口,以完成认证流程。因此,我们需要配置一个代理来处理这个请求。
网上有网友开发的Docker容器来处理DeCap CMS的请求转发,例如:
我试着部署了这两个容器,像其他容器一样用Traefik和Cloudflare Tunnel来反向代理,但都没能成功。
最后我发现还有网友使用Cloudflare Workers来实现这个代理功能,例如这个GitHub仓库decap-proxy所示。Cloudflare Workers是Cloudflare提供的一种无服务器计算平台,可以让我们在Cloudflare的边缘网络上运行JavaScript代码,从而实现请求的处理和转发。
具体步骤可参考GitHub仓库里的说明,大致步骤如下:
-
克隆
decap-proxy仓库到本地:1git clone https://github.com/sterlingwes/decap-proxy.git -
进入
decap-proxy目录,可见一个wrangler.toml.sample文件,这是Cloudflare Workers的配置文件。我们需要将其复制一份,并命名为wrangler.toml:1cp wrangler.toml.sample wrangler.toml -
编辑
wrangler.toml文件,配置Cloudflare Workers的相关信息,例如:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34#:schema node_modules/wrangler/config-schema.json # "compatibility_date" and "main" are values you are unlikely to need to change compatibility_date = "2025-11-17" # schema version main = "src/index.ts" # entry point for the worker # The "name" parameter defines the name of the worker in your Cloudflare # Dashboard. It also specifies the first element of the default URL that # will reach your worker. name = "decap-proxy" # optional: uncomment and alter the following lines if using a custom domain. # route = { pattern = "decap.example.com", zone_name = "example.com", custom_domain = true } # optional: uncomment the following line if you don't want wrangler to set up # the worker to be available at the default workers.dev url of # <worker-name>.<account-name>.workers.dev # where <worker-name> is the "name" parameter configured above. # workers_dev = false # optional: this worker template uses Web Crypto API natively and doesn't require # nodejs_compat you can add this flag if you need Node.js polyfills, # but please be aware that those polyfills may have vulnerabilities # compatibility_flags = ["nodejs_compat"] # Variable bindings. These are arbitrary, plaintext strings (similar to environment variables) # Docs: # - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables # Note: Use secrets to store sensitive data. # - https://developers.cloudflare.com/workers/configuration/secrets/ [vars] GITHUB_REPO_PRIVATE = "1" # Should be set to "1", if your website repo is private里面的注释已经解释得很清楚了,我们主要需要修改
route,配置成我们的DeCap CMS后端服务的地址,例如这里是decap.example.com。如果不想让Cloudflare自动帮我们设置默认的workers.dev域名,可以将workers_dev设置为false。最后,我们需要在[vars]部分配置一个变量GITHUB_REPO_PRIVATE,如果我们的博客GitHub仓库是私有的,就将其设置为1,否则可以不设置。 -
配置好
wrangler.toml文件后,我们就可以使用Cloudflare Workers CLI工具wrangler来部署我们的Worker了。GitHub仓库里说可以将Cloudflare的账号和令牌设置为环境变量就可以直接在命令行登录,但我试了并没有登录成功。于是我用unset命令将环境变量清除掉了,之后再运行npx wrangler login命令登录。如果你之前没有安装过
wrangler,首次运行npx wrangler login命令时,系统会提示你安装wrangler,你可以按照提示进行安装。安装完成后,再次运行npx wrangler login命令,会在命令行中显示一个URL,提示你打开这个URL来完成登录。注意:你需要在与运行
npx wrangler login命令相同的电脑中打开这个URL,因为在用你的Cloudflare账号完成验证后,wrangler跳转的URL是一个本地地址,例如http://localhost:8787/callback?code=xxx&state=yyy,这个URL会被wrangler监听到,并从中获取认证信息来完成登录。如果你在其他电脑上打开这个URL,虽然也能完成验证,但wrangler无法监听到这个URL,因此登录会失败。登录成功后会看到如下所示的浏览器界面:

-
完成验证后,
wrangler会提示你登录成功。之后,我们把之前获得的GitHub OAuth应用的客户端ID和客户端密钥设置为Cloudflare Worker的环境变量:1 2npx wrangler secret put GITHUB_CLIENT_ID npx wrangler secret put GITHUB_CLIENT_SECRET运行上述命令后,系统会提示你输入相应的值。输入完成后,
wrangler会将这些值作为秘密环境变量存储在Cloudflare中。 -
最后,我们就可以部署我们的Worker了:
1npx wrangler publish -
部署完成后,我们可以打开浏览器访问
https://decap.example.com,如果看到页面显示Hello 👋,说明我们的Cloudflare Worker已经成功部署并运行。
测试访问DeCap CMS
完成上述安装配置后,我们的DeCap CMS应该已经可以正常工作了。我们可以通过访问https://blog.example.com/admin/来测试访问DeCap CMS的登录界面:

如果能够看到GitHub OAuth的登录选项,并且能够成功登录,会看到DeCap CMS的内容编辑界面:

在编辑界面中,我们可以创建新的博客文章,编辑现有的博客文章,并且可以预览编辑的效果。当我们完成编辑后,点击发布按钮,DeCap CMS会将更改提交到GitHub仓库中,并触发Hugo的构建过程,最终将更新后的博客内容发布到网站上。