diff --git a/.gitignore b/.gitignore index 5a7f121..309047e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ dist/ .env.* !.env.example pnpm-debug.log* +.obsidian/ +.pnpm-store/ \ No newline at end of file diff --git a/NOTICE.md b/NOTICE.md index 62d4da4..16178ad 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -2,7 +2,7 @@ Mirages 是一个基于 Astro 的静态博客主题,用于发布文章和独立页面。旧版 PHP 文件位于本项目之外,保持不变。 -本文档说明 Astro 主题的常用配置、Twikoo 评论和文章 Frontmatter。 +本文档说明 Astro 主题的常用配置、Twikoo 评论、WebMention 和文章 Frontmatter。 ## 运行项目 @@ -117,6 +117,22 @@ pnpm build 如果页面显示“评论暂时不可用”,依次检查云函数地址是否能从浏览器直接访问、CORS 配置、Twikoo 环境变量和 `envId` 是否包含多余路径或空格。 +## WebMention 配置 + +WebMention 与 Twikoo 并行工作:Twikoo 接收本站评论,WebMention 接收其他网站对文章的回复、提及、点赞和转发。配置入口位于 `src/site.config.ts`: + +```ts +webmentions: { + enabled: true, + endpoint: 'https://webmention.example.com', + form: true +}, +``` + +启用后,全站 `
` 会声明 `${endpoint}/receive`,文章页从 `${endpoint}/get` 读取当前 canonical URL 的已批准 WebMention。`form` 控制是否在文章底部显示手动发送表单。 + +仓库在 `deploy/webmention/` 提供了基于 webmentiond、SQLite 和 Docker Compose 的自托管配置。服务器部署、SMTP 登录、反向代理及验证步骤见该目录的 `README.md`。 + ## 文章 Frontmatter 文章位于 `src/content/posts`,独立页面位于 `src/content/pages`。两者使用相同的字段结构: diff --git a/deploy/webmention/.env.example b/deploy/webmention/.env.example new file mode 100644 index 0000000..f7a735b --- /dev/null +++ b/deploy/webmention/.env.example @@ -0,0 +1,15 @@ +WEBMENTION_PORT=8080 +WEBMENTION_PUBLIC_URL=https://webmention.example.com +WEBMENTION_ALLOWED_TARGET_DOMAINS=www.example.com,example.com +WEBMENTION_ALLOWED_ORIGIN=https://www.example.com +WEBMENTION_ADMIN_EMAILS=you@example.com + +SERVER_AUTH_JWT_SECRET=replace-with-a-long-random-secret + +MAIL_HOST=smtp.example.com +MAIL_PORT=587 +MAIL_USER=you@example.com +MAIL_PASSWORD=replace-with-your-smtp-password +MAIL_FROM=you@example.com +MAIL_USE_STARTTLS=true +MAIL_NO_TLS=false diff --git a/deploy/webmention/Caddyfile.example b/deploy/webmention/Caddyfile.example new file mode 100644 index 0000000..2038fa9 --- /dev/null +++ b/deploy/webmention/Caddyfile.example @@ -0,0 +1,4 @@ +webmention.example.com { + encode zstd gzip + reverse_proxy 127.0.0.1:8080 +} diff --git a/deploy/webmention/README.md b/deploy/webmention/README.md new file mode 100644 index 0000000..5364e9b --- /dev/null +++ b/deploy/webmention/README.md @@ -0,0 +1,79 @@ +# WebMention 接收端 + +本站使用 [webmentiond](https://github.com/zerok/webmentiond) 作为自托管接收端。它负责异步验证来源页面、将结果存入 SQLite,并提供审核后台与公开查询 API。Twikoo 继续作为站内评论系统,两者互不替代。 + +## 1. 准备域名 + +将 `webmention.example.com` 解析到运行 Docker 的服务器。如果要换成其他域名,同时修改: + +- `src/site.config.ts` 中的 `webmentions.endpoint` +- `.env` 中的 `WEBMENTION_PUBLIC_URL` +- Caddy 或 Nginx 的域名 + +接收端必须使用公网可访问的 HTTPS 地址。 + +## 2. 配置并启动 + +在服务器上进入本目录,复制示例环境变量并填写真实值: + +```sh +cp .env.example .env +docker compose pull +docker compose up -d +``` + +Compose 会先用一次性 `webmention-init` 容器将数据卷所有者设为 webmentiond 使用的 UID 1500,然后再启动接收端。若曾使用旧版 Compose,并在日志中看到 `unable to open database file`,可在部署目录执行: + +```sh +docker compose stop webmentiond +docker compose run --rm --no-deps --user 0 --entrypoint /bin/sh webmentiond -c 'chown -R 1500:1500 /data' +docker compose up -d webmentiond +``` + +必须修改以下值: + +- `WEBMENTION_ADMIN_EMAILS`:允许登录审核后台的邮箱,可用逗号分隔多个地址。 +- `SERVER_AUTH_JWT_SECRET`:长随机字符串,可用 `openssl rand -hex 32` 生成。 +- `MAIL_*`:SMTP 地址、账号、密码和发件人。后台使用邮件链接登录,因此 SMTP 不能省略。 + +SQLite 数据保存在 Docker 卷 `webmention-data`。更新容器不会删除它,仍建议定期备份该卷。 + +## 3. 配置反向代理 + +任选 `Caddyfile.example` 或 `nginx.conf.example` 作为反向代理参考。容器只监听服务器本机的 `127.0.0.1:8080`,TLS 由反向代理处理。 + +部署完成后访问: + +```text +https://webmention.example.com/ui/ +``` + +输入 `WEBMENTION_ADMIN_EMAILS` 中的邮箱,通过邮件链接登录。收到的 WebMention 验证成功后仍需在这里批准,批准后才会出现在博客文章底部。 + +## 4. 接口与站点集成 + +博客构建结果会在 `` 中自动声明: + +```html + +``` + +文章页通过以下接口读取当前 canonical URL 已批准的项目: + +```text +GET https://webmention.example.com/get?target=https://www.example.com/posts/example/ +``` + +文章底部也提供发送表单,POST `source` 和 `target` 到 `/receive`。`WEBMENTION_ALLOWED_ORIGIN` 必须与博客的浏览器 Origin 完全一致,否则读取与发送都会被 CORS 拦截。 + +## 5. 验证 + +完成接收端和博客部署后: + +1. 查看任一文章源码,确认存在 `rel="webmention"`。 +2. 打开 `https://webmention.example.com/ui/`,确认可以收到登录邮件。 +3. 使用 [webmention.rocks](https://webmention.rocks/) 检查接收端标准兼容性。 +4. 从一个确实包含本站文章链接的公开页面发送 WebMention。 +5. 在管理后台批准后,刷新对应文章,确认它出现在“站外回应”。 + +`webmentiond` 按完整 target URL 精确查询。发送方若将带 `#fragment` 的链接作为 target,它会被视为与文章 canonical URL 不同的目标;建议发送时使用不带锚点的文章永久链接。 diff --git a/deploy/webmention/compose.yaml b/deploy/webmention/compose.yaml new file mode 100644 index 0000000..92a8566 --- /dev/null +++ b/deploy/webmention/compose.yaml @@ -0,0 +1,46 @@ +services: + webmention-init: + image: zerok/webmentiond:latest + user: "0:0" + entrypoint: + - /bin/sh + - -c + command: + - chown -R 1500:1500 /data + volumes: + - webmention-data:/data + restart: "no" + + webmentiond: + image: zerok/webmentiond:latest + restart: unless-stopped + depends_on: + webmention-init: + condition: service_completed_successfully + ports: + - "127.0.0.1:${WEBMENTION_PORT:-8080}:8080" + environment: + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + MAIL_USER: ${MAIL_USER} + MAIL_PASSWORD: ${MAIL_PASSWORD} + MAIL_FROM: ${MAIL_FROM} + MAIL_USE_STARTTLS: ${MAIL_USE_STARTTLS:-true} + MAIL_NO_TLS: ${MAIL_NO_TLS:-false} + SERVER_AUTH_JWT_SECRET: ${SERVER_AUTH_JWT_SECRET} + volumes: + - webmention-data:/data + command: + - --addr + - 0.0.0.0:8080 + - --public-url + - ${WEBMENTION_PUBLIC_URL} + - --allowed-target-domains + - ${WEBMENTION_ALLOWED_TARGET_DOMAINS} + - --allowed-origin + - ${WEBMENTION_ALLOWED_ORIGIN} + - --auth-admin-emails + - ${WEBMENTION_ADMIN_EMAILS} + +volumes: + webmention-data: diff --git a/deploy/webmention/nginx.conf.example b/deploy/webmention/nginx.conf.example new file mode 100644 index 0000000..2db0636 --- /dev/null +++ b/deploy/webmention/nginx.conf.example @@ -0,0 +1,13 @@ +server { + listen 443 ssl http2; + server_name webmention.example.com; + + # Keep the existing certificate directives from your server configuration. + + location / { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/src/components/EngagementTabs.astro b/src/components/EngagementTabs.astro new file mode 100644 index 0000000..4feec8f --- /dev/null +++ b/src/components/EngagementTabs.astro @@ -0,0 +1,249 @@ +--- +import TwikooComments from '@/components/TwikooComments.astro'; +import Webmentions from '@/components/Webmentions.astro'; +import { siteConfig } from '@/site.config'; + +interface Props { + commentsEnabled: boolean; + webmentionEnabled: boolean; + path: string; + target: string; +} + +const { commentsEnabled, webmentionEnabled, path, target } = Astro.props; +const showWebmention = webmentionEnabled && siteConfig.webmentions.enabled && Boolean(siteConfig.webmentions.endpoint.trim()); +const commentsConfigured = siteConfig.comments.provider === 'twikoo'; +const showComments = commentsEnabled && commentsConfigured; +const showTabs = showWebmention && showComments; +--- + +{(showWebmention || showComments) &&Twikoo 尚未配置
评论
+评论