Craft.do 自定义域名

💡
欢迎加入 Craft Docs 中文社区(非官方): @craft_do
目前 Craft 的分享页面还不支持自定义域名, 所以写了一个 Cloudflare Worker 脚本, 用于反向代理 Craft 页面, 从而实现自定义域名的效果.
notion image

演示

源代码

视频教程

隔壁文章发了个视频版的教程 (点击跳转), 这里就不传了, 给 Notion 节省点空间.

已实现

  • 在 Craft 编辑器里即可配置网站
  • 页面内容实时更新
  • 完整适配 Craft 页面
    • 支持页面白名单
    • 支持密码访问 (公开但需要密码访问)
  • 支持 Craft 评论功能
    • 支持评论提醒 (提醒发送到 Telegram)
  • 支持在 Craft 编辑器中自定义网站界面
  • 优化图片缓存
  • 支持 sitemap
  • SEO 优化

未实现

支持 RSS
支持搜索
支持外联页面

使用方法

1. 准备工作

需要准备以下账号和域名:
  • Cloudflare 账号
  • 托管在 Cloudflare 的域名
  • Craft Docs 账号
  • Telegram 账号(可选, 用于接收评论提醒)
这些服务都是免费的, 其中 Cloudflare Worker 每日都有十万次免费额度(个人网站完全够用), Craft Docs 免费账号也可以使用这个脚本.

2. 设置 DNS 解析

打开 Cloudflare 的仪表盘, 设置域名中添加一项 CNAME 记录. 如果你有一个域名是 mydomain.com, 你希望直接用 mydomain.com 做 Craft 站点, "名称"一栏就填 @ , 如果想用 note.mydomain.com 作为 Craft 站点, "名称"一栏就填 note .
"目标"填 craft.do, 实际上这里填其他任意有效域名都可以, 安全起见就写 Craft 域名吧.
notion imagenotion image

3. 初始化站点

首先在 Craft 软件中创建一个文件夹, 例如 My Public Notes 或者其他你喜欢的名字. 在文件夹中新建一个页面, 这个页面将会用作你的网站首页, 你可以随意布置这个页面.
点击分享这个页面, 把”显示标题”关闭, 这样你的首页会更好看.
notion image
复制这个页面的分享链接, 我们马上就需要它了.

现在我们还需要再创建一个页面, 它将作为整个网站的配置中心. 现在我们打开这个”配置”页面, 在这个页面的第一行(必须确保是第一行)插入一个代码块, 如下图所示:
notion imagenotion image
Craft 会弹出一个代码输入框, 高亮选择 JSON.
notion image
在框内填入下面内容:
{ "index": "https://www.craft.do/s/XXXXXXXXX" }
其中 index 是不可改变的, 后面的链接是你刚刚复制的”首页”创建的分享链接.
最后一步, 把这个”配置”页面也打开分享, 复制分享链接. 现在你的 Craft 已经完成初始化.

你可以参考我的网站, 我的首页是 https://note.zuolan.me/ , 我的配置页面是 https://www.craft.do/s/3MtGzyRv7l26kF .
以后, 当你有新的页面想发布, 只需要到”配置”页面的代码块中添加即可. 例如我想添加一个”关于我”的页面, 我只需要在”配置”页面添加新页面的路径和 Craft 的分享链接.
{ "index": "https://www.craft.do/s/XXXXXXXXX", "about": "https://www.craft.do/s/WWWWWWWWW" }

4. 配置 Worker 脚本

打开 Cloudflare 控制台, 点击 Worker 面板, 新建一个 Worker.
notion image
新建页面需要修改三个地方:
  1. 修改 Worker 的名字, 在下图 1 的地方, 修改成你喜欢名字.
  1. 删除代码编辑器里的所有内容, 粘贴 Github 上的代码, 并根据注释修改代码顶部的内容, 改为你的信息.
  1. 点击”保存并部署”.
notion imagenotion image
返回 Worker 面板, 为刚才创建的脚本设置一个路由, 选择刚刚创建的 worker, 填上你的域名, 注意路由后面的 * 符号是必不可少的.
notion imagenotion image
现在脚本已经就绪.
你现在可以通过你配置的域名来访问首页了.

5. 自定义你的页面 (可选)

通过 Cloudflare Worker 我们还可以定制一些内容, 例如我的网站右上角的 Logo 菜单. 如果你想自定义一些内容, 可以在脚本代码最后面找到两个类: BodyRewriter 和 HeadRewriter.
在两个类中编写你的 HTML/CSS/JS 代码即可实现自定义页面.
下面是我的自定义菜单的代码 (点击展开)
class BodyRewriter { element(element) { element.append(` <div class="navigation"> <input type="checkbox" class="navigation__checkbox" id="nav-toggle" /> <label for="nav-toggle" class="navigation__button"> <a aria-label="toggle navigation menu"> <img alt="logo" class="navigation__logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDBwdCIgaGVpZ2h0PSIxMDBwdCIgdmlld0JveD0iMCAwIDEwMCAxMDAiPjxnIGZpbGw9ImJsdWUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLDEwMCkgc2NhbGUoMC4wODAwMDAsLTAuMDgwMDAwKSI+PHBhdGggZD0iTTc2MiAxMjAzIGMtNiAtMTUgLTEzIC00NiAtMTcgLTY4IC00IC0yMiAtMTMgLTQ5IC0yMCAtNjEgLTE1IC0yMyAtMTIyIC02OSAtMjU3IC0xMDkgLTQ5IC0xNCAtODggLTI4IC04OCAtMjkgMCAtMiAzMyAtMjAgNzMgLTQwIDQ5IC0yNCA4NyAtMzYgMTE1IC0zNiAyOCAwIDQyIC00IDQyIC0xMyAwIC0zNCAtMjk1IC01MTcgLTM5MCAtNjM5IC00MCAtNTIgLTQgLTI4IDg2IDU2IDQ5IDQ2IDEwNSAxMDkgMTI0IDE0MSAxOSAzMSA2NCA5OCAxMDAgMTQ4IDc3IDEwOCAxMjUgMTg2IDE3MyAyODMgMjAgMzkgNDYgNzggNTkgODYgMTMgOCA2OSAzNCAxMjYgNTggMTA3IDQ1IDExOCA1NyAxMTAgMTExIC0zIDIxIC0xMCAyNSAtNzggMzQgbC03NSAxMCAtNSA0NSBjLTUgNDIgLTcgNDUgLTM2IDQ4IC0yNiAzIC0zMyAtMSAtNDIgLTI1eiIvPjxwYXRoIGQ9Ik03NTQgNjE2IGMtNDAgLTE5IC04OCAtMzkgLTEwOCAtNDYgLTQzIC0xNCAtNDUgLTMwIC03IC03MiAyNSAtMjggMzMgLTMxIDgwIC0zMCAzOSAxIDU0IC0zIDU4IC0xNSA3IC0xOCAtMzAgLTE0MCAtNTggLTE5MiAtMzYgLTY3IDYgLTkzIDEzNSAtODQgbDg2IDYgMCAtMjYgYzAgLTE0IC00IC0zNyAtMTAgLTUxIC01IC0xNCAtOCAtMjYgLTYgLTI2IDcgMCAxMTAgNjggMTI5IDg1IDExIDEwIDE3IDMwIDE3IDYwIDAgNjIgLTIyIDcwIC0xNTAgNTcgLTUyIC01IC05OCAtNiAtMTAzIC0yIC00IDMgMyAzMSAxNiA2MSAxMyAzMCAzMiA3OCA0MiAxMDggMTAgMzAgMjggNzAgNDEgODkgMjYgMzggMzAgNjMgMTQgOTMgLTE3IDMxIC05MSAyNSAtMTc2IC0xNXoiLz48L2c+PC9zdmc+" /> </a> </label> <div class="navigation__background"></div> <h1 class="navigation__title">左蓝的笔记</h1> <div class="navigation__icon"> <a target="_blank" href="<https://t.me/zuolan>"> <img alt="Telegram" src="data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+VGVsZWdyYW08L3RpdGxlPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0xMS45NDQgMEExMiAxMiAwIDAgMCAwIDEyYTEyIDEyIDAgMCAwIDEyIDEyIDEyIDEyIDAgMCAwIDEyLTEyQTEyIDEyIDAgMCAwIDEyIDBhMTIgMTIgMCAwIDAtLjA1NiAwem00Ljk2MiA3LjIyNGMuMS0uMDAyLjMyMS4wMjMuNDY1LjE0YS41MDYuNTA2IDAgMCAxIC4xNzEuMzI1Yy4wMTYuMDkzLjAzNi4zMDYuMDIuNDcyLS4xOCAxLjg5OC0uOTYyIDYuNTAyLTEuMzYgOC42MjctLjE2OC45LS40OTkgMS4yMDEtLjgyIDEuMjMtLjY5Ni4wNjUtMS4yMjUtLjQ2LTEuOS0uOTAyLTEuMDU2LS42OTMtMS42NTMtMS4xMjQtMi42NzgtMS44LTEuMTg1LS43OC0uNDE3LTEuMjEuMjU4LTEuOTEuMTc3LS4xODQgMy4yNDctMi45NzcgMy4zMDctMy4yMy4wMDctLjAzMi4wMTQtLjE1LS4wNTYtLjIxMnMtLjE3NC0uMDQxLS4yNDktLjAyNGMtLjEwNi4wMjQtMS43OTMgMS4xNC01LjA2MSAzLjM0NS0uNDguMzMtLjkxMy40OS0xLjMwMi40OC0uNDI4LS4wMDgtMS4yNTItLjI0MS0xLjg2NS0uNDQtLjc1Mi0uMjQ1LTEuMzQ5LS4zNzQtMS4yOTctLjc4OS4wMjctLjIxNi4zMjUtLjQzNy44OTMtLjY2MyAzLjQ5OC0xLjUyNCA1LjgzLTIuNTI5IDYuOTk4LTMuMDE0IDMuMzMyLTEuMzg2IDQuMDI1LTEuNjI3IDQuNDc2LTEuNjM1eiIvPjwvc3ZnPg==" /> </a> <a target="_blank" href="<https://twitter.com/izuolan>"> <img alt="Twitter" src="data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+VHdpdHRlcjwvdGl0bGU+PHBhdGggZmlsbD0iZ3JheSIgZD0iTTIzLjk1MyA0LjU3YTEwIDEwIDAgMDEtMi44MjUuNzc1IDQuOTU4IDQuOTU4IDAgMDAyLjE2My0yLjcyM2MtLjk1MS41NTUtMi4wMDUuOTU5LTMuMTI3IDEuMTg0YTQuOTIgNC45MiAwIDAwLTguMzg0IDQuNDgyQzcuNjkgOC4wOTUgNC4wNjcgNi4xMyAxLjY0IDMuMTYyYTQuODIyIDQuODIyIDAgMDAtLjY2NiAyLjQ3NWMwIDEuNzEuODcgMy4yMTMgMi4xODggNC4wOTZhNC45MDQgNC45MDQgMCAwMS0yLjIyOC0uNjE2di4wNmE0LjkyMyA0LjkyMyAwIDAwMy45NDYgNC44MjcgNC45OTYgNC45OTYgMCAwMS0yLjIxMi4wODUgNC45MzYgNC45MzYgMCAwMDQuNjA0IDMuNDE3IDkuODY3IDkuODY3IDAgMDEtNi4xMDIgMi4xMDVjLS4zOSAwLS43NzktLjAyMy0xLjE3LS4wNjdhMTMuOTk1IDEzLjk5NSAwIDAwNy41NTcgMi4yMDljOS4wNTMgMCAxMy45OTgtNy40OTYgMTMuOTk4LTEzLjk4NSAwLS4yMSAwLS40Mi0uMDE1LS42M0E5LjkzNSA5LjkzNSAwIDAwMjQgNC41OXoiLz48L3N2Zz4=" /> </a> <a target="_blank" href="<https://github.com/izuolan>"> <img alt="Giithub" src="data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+R2l0SHViPC90aXRsZT48cGF0aCBmaWxsPSJncmF5IiBkPSJNMTIgLjI5N2MtNi42MyAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDMgMy40MzggOS44IDguMjA1IDExLjM4NS42LjExMy44Mi0uMjU4LjgyLS41NzcgMC0uMjg1LS4wMS0xLjA0LS4wMTUtMi4wNC0zLjMzOC43MjQtNC4wNDItMS42MS00LjA0Mi0xLjYxQzQuNDIyIDE4LjA3IDMuNjMzIDE3LjcgMy42MzMgMTcuN2MtMS4wODctLjc0NC4wODQtLjcyOS4wODQtLjcyOSAxLjIwNS4wODQgMS44MzggMS4yMzYgMS44MzggMS4yMzYgMS4wNyAxLjgzNSAyLjgwOSAxLjMwNSAzLjQ5NS45OTguMTA4LS43NzYuNDE3LTEuMzA1Ljc2LTEuNjA1LTIuNjY1LS4zLTUuNDY2LTEuMzMyLTUuNDY2LTUuOTMgMC0xLjMxLjQ2NS0yLjM4IDEuMjM1LTMuMjItLjEzNS0uMzAzLS41NC0xLjUyMy4xMDUtMy4xNzYgMCAwIDEuMDA1LS4zMjIgMy4zIDEuMjMuOTYtLjI2NyAxLjk4LS4zOTkgMy0uNDA1IDEuMDIuMDA2IDIuMDQuMTM4IDMgLjQwNSAyLjI4LTEuNTUyIDMuMjg1LTEuMjMgMy4yODUtMS4yMy42NDUgMS42NTMuMjQgMi44NzMuMTIgMy4xNzYuNzY1Ljg0IDEuMjMgMS45MSAxLjIzIDMuMjIgMCA0LjYxLTIuODA1IDUuNjI1LTUuNDc1IDUuOTIuNDIuMzYuODEgMS4wOTYuODEgMi4yMiAwIDEuNjA2LS4wMTUgMi44OTYtLjAxNSAzLjI4NiAwIC4zMTUuMjEuNjkuODI1LjU3QzIwLjU2NSAyMi4wOTIgMjQgMTcuNTkyIDI0IDEyLjI5N2MwLTYuNjI3LTUuMzczLTEyLTEyLTEyIi8+PC9zdmc+" /> </a> </div> <nav class="navigation__nav" role="navigation"> <ul class="navigation__list"> <li class="navigation__item"> <a href="<https://note.zuolan.me/>" target="_blank" class="navigation__link">首页</a> </li> <li class="navigation__item"> <a href="<https://note.zuolan.me/about>" target="_blank" class="navigation__link">关于</a> </li> <li class="navigation__item"> <a href="#" class="navigation__link">联系</a> </li> </ul> <p class="footer">© CC BY-NC-SA 4.0</p> </nav> </div> `, { html: true }) } } class HeadRewriter { element(element) { element.append(` <style> /* Hide the Craft "Login in" button in comment board. */ .sc-CtfFt { visibility: hidden; } .hGGlzy { visibility: hidden; } .header .right-side { padding-right: 3rem; } .navigation { position: fixed; top: 0; right: 0; z-index: 400; } .navigation__checkbox { display: none; } .navigation__button { position: absolute; top: 0.5rem; right: 0.8rem; height: 2.4rem; width: 2.4rem; text-align: center; border-radius: 50%; z-index: 300; cursor: pointer; } .navigation__logo { width: 1.5rem; height: 1.5rem; padding-top: 0.4rem; padding-right: 0.1rem; } .navigation__title { position: fixed; top: 0.5rem; right: 3rem; visibility: hidden; margin: 0.5rem 1rem; color: gray; font-size: 1rem; z-index: 300; transition: all 200ms ease-out; } .navigation__background { position: fixed; top: 0.5rem; right: 0.7rem; height: 2.4rem; width: 2.4rem; border-radius: 50%; background: #FFFFFF; /* background-size: cover; background-position: center; */ z-index: 100; transition: all 400ms cubic-bezier(0.86, 0, 0.07, 1); } .navigation__nav { position: fixed; top: 0; right: 0; opacity: 0; width: 100%; visibility: hidden; z-index: 200; transition: all 400ms ease-in; } .navigation__icon { position: fixed; top: 17rem; right: 0; visibility: hidden; margin: 0.8rem 2rem; z-index: 300; transition: all 200ms ease-out; } .navigation__icon a { top: 0; right: 0; display: inline-block; width: 1rem; margin: 0.5rem; z-index: 300; } .navigation__list { position: absolute; top: 4rem; right: 1rem; list-style: none; } .navigation__item { margin: 1rem; } .navigation__link:link, .navigation__link:visited { display: inline-block; padding: 0.5rem 1rem; color: #494b4e; font-size: 1.4rem; text-decoration: none; transition: all 0.2s; } .navigation__icon a:hover { opacity: 0.7; } .navigation__link:hover { color: #494b4e; transform: scale(1.2); } .navigation__checkbox:checked ~ .navigation__background { background: #edeeee; transform: scale(20); /* transform: scale(80); */ } .navigation__checkbox:checked ~ .navigation__title { visibility: visible; opacity: 1; } .navigation__checkbox:checked ~ .navigation__icon { visibility: visible; opacity: 1; } .navigation__checkbox:checked ~ .navigation__nav { width: 100%; visibility: visible; opacity: 1; } .footer { position: absolute; top: 20rem; right: 2rem; color: #b7c0c3; font-size: 0.8rem; } </style> `, { html: true }) } }
If you have any questions, please contact me.