<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[violet]]></title><description><![CDATA[Only the paranoid survive.]]></description><link>https://blog.violet.vin</link><image><url>https://blog.violet.vin/innei.svg</url><title>violet</title><link>https://blog.violet.vin</link></image><generator>Yohaku (https://github.com/Innei/Yohaku)</generator><lastBuildDate>Mon, 04 May 2026 05:32:28 GMT</lastBuildDate><atom:link href="https://blog.violet.vin/feed" rel="self" type="application/rss+xml"/><pubDate>Mon, 04 May 2026 05:32:28 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[Hello World]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/notes/1">https://blog.violet.vin/notes/1</a></blockquote><span>从astro迁移到了yohaku</span><p style="text-align:right"><a href="https://blog.violet.vin/notes/1#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/notes/1</link><guid isPermaLink="true">https://blog.violet.vin/notes/1</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sun, 26 Apr 2026 08:57:34 GMT</pubDate></item><item><title><![CDATA[2025]]></title><description><![CDATA[<link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/0sbx7qi6k8lg5k0ysp.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/8b73tjwxfi9pc57sr5.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/dzaykxlidwib011m5q.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/1li5x1f70htju6w04u.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/furzu3c84l5pp24ran.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/sfndin757l4xugf01i.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/m9r1ka69qw3p6vx91z.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/5zhpjm7ar7t1qt0ng5.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/scd0mha00ouy356g4j.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/ijgfod2tu6cvzdauje.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/1esn0mwhbm7akhadmu.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/7xrsu587adwf4fdkp9.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/krtrmvcuu3ue0yj0wp.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/m3aitxbzpnu89xxupb.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/22y82j0fx9gsdz670f.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/w5gofvuvhotq37e4es.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/gixkajldgvg75gsao0.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/umsdozotblxc7nczmk.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/4t4xmymbyip4qp80y4.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/fj5zjedizwpuj87hn5.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/lrwo8v9c0lmcrwf283.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/ofm5onhm0qd61z8hue.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/ihamn277za7ppp5axy.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/yf887ocwluloy9jvm0.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/bvc17fk1sa4c1q14a8.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/cx4l0d8r7jp5tv4pgn.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/v85yrky5ijmnibtffj.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/20cl20ifbsjn8baj9n.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/2025">https://blog.violet.vin/posts/default/2025</a></blockquote><div><blockquote><p>已经不想总结这一年了，看看这一年我都折腾了哪些玩意吧</p><h2 id="">设备</h2></blockquote>
<h3 id="">阿里云轻量服务器</h3><p>成都-200MB / 45元/月 / 2H2G
<img height="1441" src="https://blog.violet.vin/api/v2/objects/image/0sbx7qi6k8lg5k0ysp.png" width="3249"/>
长期持有，按月续费部署网络相关应用和高SLA需求应用</p><h3 id="">小主机</h3><p><img src="https://blog.violet.vin/api/v2/objects/image/8b73tjwxfi9pc57sr5.png"/>
大多数服务都部署在这台服务器上，不属于任何云厂商，放在我的电脑桌旁边
<img src="https://blog.violet.vin/api/v2/objects/image/dzaykxlidwib011m5q.png"/></p><h2 id="">网络</h2><h3 id="tailscale--derp">Tailscale / Derp</h3><p>使用 <a href="https://github.com/tailscale/tailscale">Tailscale</a> 组网实现公网服务器访问家里的服务器，并通过在公网服务器设置反向代理，实现一部分公网访问（除非公网访问是必须的，否则优先只允许使用内网访问）。</p><p>我的derp节点部署在阿里云服务器上，使用tailscale官方的控制面。有迁移的想法但是由于网络属于基础设置，迁移涉及到非常多IP变动，所以一直懒得动，至少目前运行良好（指的是暂时没有连不上 <code>login.tailscale.com</code> 的情况）</p><h2 id="">工具</h2><h3 id="vaultwardenhttpsgithubcomdani-garciavaultwarden"><a href="https://github.com/dani-garcia/vaultwarden">vaultwarden</a></h3><p>最重要的程序，保存了我所有的密码、SSL密钥、两步验证器，需要保证最高级别的SLA。vaultwarden挂了我将无法登录几乎所有的网站。自从部署vaultwarden开始，我几乎为所有网站都使用了网站支持的最高位数的随机字符密码，并且尽可能使用两步验证、passkey、无密码账户。</p><p>vaultwarden运行在我的阿里云服务器上，vaultwarden保存了小主机PVE的登录密码，所以vaultwarden不可能运行在家中服务器上。</p><p>为了保证数据不丢失，我使用 <a href="https://github.com/offen/docker-volume-backup">docker-volume-backup</a> 对vaultwarden的数据每日备份，并上传到腾讯云对象存储中。</p><h3 id="rss">RSS</h3><p><img src="https://blog.violet.vin/api/v2/objects/image/1li5x1f70htju6w04u.png"/></p><ul><li><a href="https://github.com/miniflux/v2">miniflux</a>：RSS阅读器</li><li><a href="https://github.com/DIYgod/RSSHub">RSSHub</a>：从不支持RSS的网站抓取RSS订阅</li><li><a href="https://github.com/electh/nextflux">nextflux</a>：miniflux的UI界面</li></ul><p>RSS是我获取信息最主要的方式，我的订阅包含了个人博客、HackerNews、大厂技术团队博客、几个主要的论坛、一些国内外新闻媒体、其他有趣的内容（每日图片等等）。</p><p>我将RSSHub部署在家里的服务器上，从家中服务器访问互联网会自动根据IP进行TProxy，IP质量和网络连接都有保证。</p><h3 id="certdhttpsgithubcomcertdcertd"><a href="https://github.com/certd/certd">Certd</a></h3><p>一个SSL证书更新工具，用于给Derp服务和Nginx服务器自动替换SSL证书，自动从 <code>Let&#x27;s Encrypt</code> 获取证书并部署，配合简单的shell命令重启，目前运行良好。
<img src="https://blog.violet.vin/api/v2/objects/image/furzu3c84l5pp24ran.png"/></p><h3 id="giteahttpsgithubcomgo-giteagitea"><a href="https://github.com/go-gitea/gitea">Gitea</a></h3><p>用于存储我的各种程序、Docker配置文件、笔记、Fork开源项目、以及一些不想发布到GitHub的代码
<img src="https://blog.violet.vin/api/v2/objects/image/sfndin757l4xugf01i.png"/></p><h2 id="">监控</h2><h3 id="grafanahttpsgithubcomgrafanagrafana"><a href="https://github.com/grafana/grafana">Grafana</a></h3><p><img src="https://blog.violet.vin/api/v2/objects/image/m9r1ka69qw3p6vx91z.png"/></p><p>我部署了 <a href="https://github.com/grafana/grafana">Grafana</a>、<a href="https://github.com/prometheus/prometheus">Prometheus</a>、<a href="https://github.com/grafana/loki">Loki</a> 用于服务器监控、日志收集、网络监控等等功能。</p><p>监控我的所有服务器
<img src="https://blog.violet.vin/api/v2/objects/image/5zhpjm7ar7t1qt0ng5.png"/></p><p>监控NAS机械硬盘温度
我曾经写过一篇文章介绍我是<a href="/posts/prometheus-jian-kong-bing-cun-chu-linux-xi-tong-zhong-ji-xie-ying-pan-wen-du/">如何监控机械硬盘温度的</a>
<img src="https://blog.violet.vin/api/v2/objects/image/scd0mha00ouy356g4j.png"/></p>
<h1 id="">总结</h1><ul><li>路由器/交换机：466 + 209 + 549 + 259 = 1500</li><li>显示器：3000</li><li>声卡：800</li><li>NAS：主板CPU内存3000（去年买的不算），机箱 + 电源 = 1600</li><li>硬盘：SSD + HDD = 4500</li><li>服务器：5000</li><li>游戏：800</li></ul><p>合计约：17200</p><h2 id="">路由器/交换机</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/ijgfod2tu6cvzdauje.png"/>
精致小巧，拿到之后特别小。普通路由器只是开放了比较多的配置选项，但是我只用到了DHCP Option，其他的也没用到，千兆网络性能完全足够。
第一次用Mikrotik路由器，系统配置复杂还算能接受，用了两个月实在是搞不定旁路由所以还是咸鱼出了。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/1esn0mwhbm7akhadmu.png"/>
用来和Mikrotik配合做旁路由，信了网上的鬼话，以后再也不信了。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/7xrsu587adwf4fdkp9.png"/>
购入的第三款路由器，算是想明白了我想要的是什么，就是简单主路由。多网口的主路由太贵了，而且多一个网口也没啥用（一条宽带）。于是购买了这款双2.5G的路由器，性能只用来跑路由非常足够了，TUN下跑满500兆宽带 CPU占用30%，非常够用。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/krtrmvcuu3ue0yj0wp.png"/>
平平无奇的2.5G交换机，主要是便宜。缺点是交换机灯闪的不够快，看着不够高端，用着没发现问题，交换机存在感很低。两个光口买来从来没用上。</p><h2 id="">游戏</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/m3aitxbzpnu89xxupb.png"/>
再也不买首发游戏了，为了第一天能玩到，多花了至少250块钱，实际上发售一个月之后价格就正常了，那时候买合适多了。再也不买首发游戏了。</p><h2 id="">存储</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/22y82j0fx9gsdz670f.png"/>
给电脑装了双系统，这块硬盘只用来安装Arch系统，性能一般，价格合适。优势是京东物流第二天就到了。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/w5gofvuvhotq37e4es.png"/>
路由器的硬盘，主要是便宜+京东物流，128GB给路由器完全是浪费，半年下来最多用了5G。后面不给路由器装Docker 了，在8GB内存的路由器中，硬盘使用率几乎只有开关机了。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/gixkajldgvg75gsao0.png"/>
两块监控盘拿来组Raid1存放重要数据，重要的数据都不大，大的数据都不重要。
买NAS之前做好了功课，知道数据分类存储才能最大化利用存储空间，所以没有随大流上来就组Raid5。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/umsdozotblxc7nczmk.png"/>
7200转的空气盘绝对是最垃圾的，温度又高又吵，为了给这空气盘降温风扇转速都拉高了，5000转的空气盘还能买，7200转的空气盘我再也不买了。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/4t4xmymbyip4qp80y4.png"/>
当时觉得16TB挺贵的，现在年底硬盘涨价了还得谢谢自己买的早，现在看这价格也合适。
7200转就该买氦气盘，虽说声音也大但是至少温度低呀，温度低风扇转速可以调低点。
和上面的8T一起存电影用，加入了一个存储池没组Raid，数据随时可丢，丢了完全不心疼数据，只会心疼我的硬盘。</p><h2 id="nas">NAS</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/fj5zjedizwpuj87hn5.png"/>
现在来看有更好的选择。空间太极限了，不是很好装，价格略贵，散热噪音一般。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/lrwo8v9c0lmcrwf283.png"/>
买的第一个NAS电源，用了三个月风扇噪音太大了，疑似故障，联系厂家维修结果换了新的回来，新的都没拆封直接咸鱼出了，维修期间买了新电源。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/ofm5onhm0qd61z8hue.png"/>
价格贵，但是是模组电源，虽然每条线都用上了，是不是模组好像没啥用。
不过用的这几个月里一直都很安静，功率未知，只要安静就好。</p><h2 id="">声卡</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/ihamn277za7ppp5axy.png"/>
为了搭配去年买的漫步者N300音响和PS5和新显示器，主要是为了聚合电脑音频和PS5音频。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/yf887ocwluloy9jvm0.png"/>
一个声卡，音质没听出来差别，主要是为了方便切换电脑音频（USB输入）和PS5音频（音频分离器-光纤输入）。</p><h2 id="">显示器</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/bvc17fk1sa4c1q14a8.png"/>
质感好，很好用（我基本不调节），物有所值</p><p><img src="https://blog.violet.vin/api/v2/objects/image/cx4l0d8r7jp5tv4pgn.png"/>
为了用上HDR1000买了这款显示器，中途有一次维修，厂家最后换货了。故障是屏幕50%的区域疑似故障，一直闪烁，不能正常使用。
HDR效果还行，至少比原来的HDR400好太多了，Windows系统可以常开HDR显示，不会出现发白的情况。质感很好，有种苹果的感觉。</p><h2 id="">服务器</h2><p><img src="https://blog.violet.vin/api/v2/objects/image/v85yrky5ijmnibtffj.png"/>
<img src="https://blog.violet.vin/api/v2/objects/image/20cl20ifbsjn8baj9n.png"/></p><p>图片是在NodeSeek上交易服务器的金额，具体买服务器花了多少钱不好统计了，估计5000+？
有了路由器开始买各种服务器，家里是电信宽带。
起初我也是抱着省钱的想法买服务器的，后面发现为了省钱买了一堆垃圾，各种不稳定不能用。后来想明白了，要么不买 要买就买最好的，后面只买DMIT/BWH，其他厂家统统不买。</p></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/2025#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/2025</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/2025</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sun, 01 Mar 2026 14:25:25 GMT</pubDate></item><item><title><![CDATA[从 PostgreSQL APT Archive 安装旧版本 PostgreSQL 15]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/linux/install-old-postgresql-15-from-apt-archive">https://blog.violet.vin/posts/linux/install-old-postgresql-15-from-apt-archive</a></blockquote><div><blockquote><p><a href="https://apt-archive.postgresql.org">https://apt-archive.postgresql.org</a></p></blockquote>
<h2 id="pgp-key">设置PGP KEY</h2><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo mkdir -p /usr/share/keyrings

curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/postgresql-archive.gpg
</code></pre>
<h2 id="pgsql">添加PGSQL源（旧版本）</h2><pre class="language-sh lang-sh"><code class="language-sh lang-sh">UBUNTU_CODENAME=&quot;$(lsb_release -cs)&quot;

sudo tee /etc/apt/sources.list.d/pgdg-archive.sources &gt; /dev/null &lt;&lt;EOF
Types: deb
URIs: https://apt-archive.postgresql.org/pub/repos/apt
Suites: ${UBUNTU_CODENAME}-pgdg-archive
Components: main
Signed-By: /usr/share/keyrings/postgresql-archive.gpg
EOF

sudo apt update
</code></pre>
<h2 id="">查找版本号</h2><pre class="language-sh lang-sh"><code class="language-sh lang-sh">apt-cache madison postgresql-15 | grep 15.6
apt-cache madison postgresql-client-15 | grep 15.6 
</code></pre>
<p>输出示例</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">root@playground /e/a/sources.list.d# apt-cache madison postgresql-15 | grep 15.6
postgresql-15 | 15.6-1.pgdg130+1 | https://apt-archive.postgresql.org/pub/repos/apt trixie-pgdg-archive/main amd64 Packages

root@playground /e/a/sources.list.d# apt-cache madison postgresql-client-15 | grep 15.6
postgresql-client-15 | 15.6-1.pgdg130+1 | https://apt-archive.postgresql.org/pub/repos/apt trixie-pgdg-archive/main amd64 Packages
</code></pre>
<h2 id="">安装</h2><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo apt install -y \
  postgresql-15=15.6-1.pgdg22.04+1 \
  postgresql-client-15=15.6-1.pgdg22.04+1
</code></pre>
<p>替换=后面的 <code>15.6-1.pgdg22.04+1</code> 为上一步输出的版本号</p><h2 id="">查询安装的版本</h2><pre class="language-sh lang-sh"><code class="language-sh lang-sh">dpkg -l | egrep &#x27;postgresql-(15|client-15|contrib-15)|postgresql-(client-)?common&#x27; | awk &#x27;{print $2, $3}&#x27;
</code></pre>
<pre class="language-sh lang-sh"><code class="language-sh lang-sh">psql --version
</code></pre></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/linux/install-old-postgresql-15-from-apt-archive#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/linux/install-old-postgresql-15-from-apt-archive</link><guid isPermaLink="true">https://blog.violet.vin/posts/linux/install-old-postgresql-15-from-apt-archive</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sun, 25 Jan 2026 03:48:46 GMT</pubDate></item><item><title><![CDATA[我的 Windows 使用技巧]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/windows-tips">https://blog.violet.vin/posts/default/windows-tips</a></blockquote><div><h2 id="">按键映射</h2><blockquote><p><a href="https://learn.microsoft.com/en-us/windows/powertoys/">https://learn.microsoft.com/en-us/windows/powertoys/</a></p></blockquote>
<p>使用PowerToys修改按键映射
![[Pasted image 20260120101045.png]]</p><p>修改后</p><ul><li>Caps Lock = Win + Space：用于切换输入法</li><li>Alt + C = Ctrl + Insert：复制</li><li>Alt + E = Win + E：打开文件资源管理器</li><li>Alt + Q = Alt + F4：关闭程序</li><li>Alt + V = Alt + Shift：粘贴</li><li>Alt + X = Ctrl + X：剪贴</li><li>Ctrl + V = Shift + Insert：粘贴</li><li>Ctrl + Shift + Space = Caps Lock：大写锁定切换</li></ul><h2 id="app">App启动</h2><p><a href="https://www.raycast.com/">https://www.raycast.com/</a></p><p>![[Pasted image 20260120101409.png]]</p><h2 id="">虚拟桌面</h2><p>常驻4个虚拟桌面</p><ul><li>微信聊天</li><li>开发</li><li>文档</li><li>摸鱼</li></ul><p>增加快捷键切换，使用Alt + 1、2、3、4，通过AHK实现（AI写的）
需要下载<a href="https://github.com/Ciantic/VirtualDesktopAccessor/releases">VirtualDesktopAccessor.dll</a>文件到ahk相同目录</p><pre class="language-text lang-text"><code class="language-text lang-text">#Requires AutoHotkey v2.0
#SingleInstance Force

dll := A_ScriptDir &quot;\VirtualDesktopAccessor.dll&quot;
if !FileExist(dll) {
    MsgBox &quot;缺少 VirtualDesktopAccessor.dll`n请把 DLL 放到脚本同目录：`n&quot; dll
    ExitApp
}

; -------- 热键 --------
!1::Go(1)
!2::Go(2)
!3::Go(3)
!4::Go(4)
!5::Go(5)

!+1::MoveAndGo(1)
!+2::MoveAndGo(2)
!+3::MoveAndGo(3)
!+4::MoveAndGo(4)
!+5::MoveAndGo(5)
; ----------------------

Go(n) {
    global dll
    try {
        ; 参数：int desktopNumber（0-based）
        ; 返回：int
        DllCall(dll &quot;\GoToDesktopNumber&quot;, &quot;Int&quot;, n-1, &quot;Int&quot;)
    } catch as e {
        MsgBox &quot;GoToDesktopNumber 调用失败：`n&quot; e.Message &quot;`n`n常见原因：DLL 位数不匹配（x86/x64）或 DLL 不是这个版本&quot;
    }
}

MoveAndGo(n) {
    global dll
    hwnd := WinGetID(&quot;A&quot;)
    if !hwnd
        return

    try {
        ; 参数：HWND + int desktopNumber（0-based）
        ; 返回：int
        DllCall(dll &quot;\MoveWindowToDesktopNumber&quot;, &quot;Ptr&quot;, hwnd, &quot;Int&quot;, n-1, &quot;Int&quot;)
        DllCall(dll &quot;\GoToDesktopNumber&quot;, &quot;Int&quot;, n-1, &quot;Int&quot;)
    } catch as e {
        MsgBox &quot;MoveWindowToDesktopNumber/GoToDesktopNumber 调用失败：`n&quot; e.Message &quot;`n`n若你在移动“管理员权限窗口”，脚本也需要管理员运行&quot;
    }
}
</code></pre>
<h2 id="">输入法</h2><p><a href="https://github.com/mbbill/no_english_mode">https://github.com/mbbill/no_english_mode</a>
使用这个软件做到每次切换到中文输入法的时候都是中文，修改之后体验类似Mac，只是用Caps Lock切换输入法，使用Ctrl + Shift + Caps Lock 切换大写锁定</p></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/windows-tips#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/windows-tips</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/windows-tips</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sat, 10 Jan 2026 07:05:25 GMT</pubDate></item><item><title><![CDATA[25+小时的Vibe coding]]></title><description><![CDATA[<link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/3qkn3t0yn5h6a1qrtr.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/3ewexdes13hhkvjf4r.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/1zzga92ksh0v6u0zog.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/dd5z6ugs59w8stkfcc.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/25-hours-vibe-coding">https://blog.violet.vin/posts/default/25-hours-vibe-coding</a></blockquote><div><blockquote><p>最近尝试使用Claude Code进行了约20个小时的vibe code。最终获得了两个半成品的项目，一个是DNS服务器，一个是浏览器起始页。总共花费了约600000的Tokens，约500刀的额度。</p></blockquote>
<p><img height="736" src="https://blog.violet.vin/api/v2/objects/image/3qkn3t0yn5h6a1qrtr.png" width="1454"/>
我用AI实现了一个自动分类的DNS服务器，有关这个项目的详细功能可以查看<a href="/posts/yi-ge-zi-dong-fen-lei-de-dns-fu-wu-qi/">这篇文章</a>。
使用Go语言编写，GoLand实时观测实现进度，ArchLinux作为开发环境，总共花费时间大约在12小时，这12个小时中，大部分时间都在等待AI回复，实际用在测试和需求设计上的时间大约在2-3小时，我没有让AI进行测试，所有的测试都是我自己完成。实际完成度约90%（如果不算后续新想法额外增加的功能）。</p><p>另一个项目是浏览器起始页，实现了一个简单的网页，主要用来管理书签，增加了工作区功能，实现重点在界面样式，需要向AI准确说出想要的界面交互逻辑，并不容易，这部分大约花费了6-8小时，其余时间用在调试Forgejo工作流中，也就是项目部署阶段。实际完成度约80%。
<img src="https://blog.violet.vin/api/v2/objects/image/3ewexdes13hhkvjf4r.png"/>
这两个项目使用的都是我不熟悉的语言，后端比较熟悉使用Java语言和Spring框架，前端熟悉Vue，使用自己不熟悉的语言原因是，这些语言我看腻了也比较熟悉了，我怕忍不住自己上手写代码了。</p><h2 id="dns">DNS服务器项目</h2><h3 id="">开发流程</h3><p>在DNS服务器的项目中，按照以下步骤开发</p><ol start="1"><li>有一个想法，最初的DNS服务器设想，直接写服务最终运行需要使用的配置文件 <code>config.yml</code></li><li>根据配置文件写 <code>README.md</code> 解释配置文件中每个配置项的作用，后续README将作为项目的设计文档使用</li><li>找AI优化README文档，结合自己的新想法和未考虑到的内容，更新设计文档、配置文件</li><li>告诉ClaudeCode，根据设计文档实现整个项目</li><li>手动Build并启动项目，让AI解决Build时期的错误，程序运行起来了</li><li>开始进行测试、修改、测试、修改，直到完成</li></ol><h3 id="">问题</h3><p><strong>问题一</strong>：没有告诉AI验证代码是否可用的逻辑，AI写了一部分代码之后直接就停止了，然而此时的代码中还存在着编译错误，于是我告诉AI每次完成之后都需要执行 <code>build</code> 但不要执行测试，后面才知道，由于这句话没有写入到 <code>CLAUDE.md</code> 导致AI老是忘记这计划，自己开始测试，然后测试中一直启动着程序导致端口被占用排查了好一会。</p><p><strong>问题二</strong>：AI在偷懒，代码中留了好几个简化实现，测试期间发现少逻辑又得去找AI补充这部分逻辑，此时我已经发现两个简化实现了，我告诉AI不能简化实现，必须立即实现设计的功能，然而AI并没有全部实现，导致后面还在补充本来早应该实现的功能。</p><p><img src="https://blog.violet.vin/api/v2/objects/image/1zzga92ksh0v6u0zog.png"/>
<img src="https://blog.violet.vin/api/v2/objects/image/dd5z6ugs59w8stkfcc.png"/>
<strong>问题三</strong>：开发规范问题，在前期开发设计时明确指出了，需要统一日志的输出，然而实际情况是，一部分日志是fmt输出的，一部分是logger输出的，在后期我不得不用好几次的对话让AI将所有的fmt输出改为统一的logger输出</p><h2 id="">书签管理项目</h2><p>有了上一次的经验，不敢让AI一次性实现整个项目了。AI生成的UI太相似了，以至于现在打眼一看就知道一个前端UI界面是不是AI写的，为了保持样式统一，这次明确说明了使用UI库。</p><h3 id="">开发流程</h3><ol start="1"><li>有一个想法，写了大于500字的核心功能描述，并确认需要使用的开发语言和框架Nextjs+Postgres</li><li>找AI先根据核心功能生成详细设计文档，并不断确认和优化文档，最终生成了约1000行的README作为设计文档，里面几乎将所有需要的功能都写到了。之后我在文档最后面补充了数据库连接信息，以及最重要的原则</li></ol><pre class=""><code class="">### 代码规范  

- 只写必要的注释，注释需要精简，使用中文  
- 每次完成一步之后，都需要保证运行、编译成功、并提交代码
- 需要保证设计文档README.md和代码保持一致，需要同步更新
</code></pre>
<ol start="3"><li>创建文件夹，写入README.md文件，使用 <code>/init</code> 让Claude初始化项目</li><li>让Claude补充详细设计文档，在文档最后添加详细的实现步骤，共分为几个阶段实现，每个阶段需要实现什么内容，并补充重要原则</li></ol><pre class=""><code class="">## 17. AI 编码 Checklist  
  
&gt; ⚠️ **重要规则：每完成一项任务后，必须：**  
&gt; 1. 运行 `npm run build` 确保编译通过  
&gt; 2. 立即 `git commit` 提交代码  
&gt; 3. 提交信息格式：`feat: 完成 xxx` 或 `fix: 修复 xxx`  
&gt;  
&gt; 这确保代码库始终可运行，后续 AI 接手时有清晰起点。
</code></pre>
<ol start="5"><li>告诉根据README设计文档，实现阶段一的步骤123，并最终完成所有功能</li></ol><h3 id="">问题</h3><p><strong>问题一</strong>：AI不使用UI库提供的组件，反而一直在使用alert这种来给页面弹提示消息，我是用shadcn UI，UI库里包含了消息提示的组件。</p><p><strong>问题二</strong>：简化理解我的需求，每次需要修改的时候，我都会使用序号分点详细描述我想要实现的效果，大约300-500字左右，然而AI接受到之后，我一行100字左右的功能需求描述没压缩到了10个字左右，导致此次对话实现的功能和需求不符，导致了反复修改。</p><h2 id="">总结</h2><p>我感觉可能会有用的一些建议</p><ul><li>事实证明一次性生成整个项目是不现实的，一定需要给AI指定外部计划，让AI按照计划分布完成，每次只完成一部分功能</li><li>重要原则一定要预先定义，并且写入prompt，每次对话都需要牢记</li><li>让AI每一步执行完成都需要验证代码，提交代码</li><li>不要试图一次性提出多个改进，每次只提出一部分</li><li>前端使用UI库，避免最后样式不可控</li></ul></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/25-hours-vibe-coding#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/25-hours-vibe-coding</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/25-hours-vibe-coding</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Fri, 02 Jan 2026 18:52:59 GMT</pubDate></item><item><title><![CDATA[SSH 配置文件 ~/.ssh/config 的基本使用]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/linux/ssh-config-basic-usage">https://blog.violet.vin/posts/linux/ssh-config-basic-usage</a></blockquote><div><p>该文件路径为 <code>~/.ssh/config</code> 用于保存ssh配置。
将其他服务器的登录信息配置在这里，以后可以使用 <code>ssh host-name</code> 快捷登录
本文主要记录 <code>~/.ssh/config</code> 的基本使用</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">vi ~/.ssh/config
</code></pre>
<h2 id="">配置服务器</h2><p>一个简单的配置如下，按照此配置后，使用 <code>ssh home-server</code> 即可连接到该服务器。</p><pre class="language-txt lang-txt"><code class="language-txt lang-txt">Host home-server
       HostName 10.115.15.25
       User root
       Port 22
       IdentityFile ~/.ssh/id_ed25519
</code></pre>
<p>为了实现无密码登录，此处需要使用密钥</p><p>注意：此处的密钥文件需要将权限设置为600 <code>-rw-------</code> 仅所有者可读写
如果key还未生成，可以使用命令 <code>ssh-keygen</code> 生成公私钥对
公钥文件以 <code>.pub</code> 结尾，需要将此文件上传到目标服务器</p><h2 id="">上传公钥</h2><p>公钥上传并写入到 <code>~/.ssh/authorized_keys</code> 文件，每行一个
此文件不存在可以自行创建，但注意需要修改权限为600</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">chmod 600 ~/.ssh/authorized_keys
</code></pre>
<p>如果仍然无法连接，需要修改服务器ssh配置</p><p>此处的最佳实践是创建 <code>/etc/ssh/sshd_config.d/99-custom.conf</code> 将新的配置添加到该文件中</p><pre class="language-conf lang-conf"><code class="language-conf lang-conf"># 修改ssh端口
Port 53387 
# 关闭密码登录并启用强制密钥认证
PasswordAuthentication no  
AuthenticationMethods publickey
# 禁用root远程登录（只能通过VNC等本地登录），你应该尝试使用普通用户登录，之后切换到root
AuthorizedKeysFile  .ssh/authorized_keys
PermitRootLogin prohibit-password
</code></pre>
<p>关于 <code>PermitRootLogin</code>，其实还有另一种选择</p><ul><li>yes：运行root远程登录</li><li>no：禁止root远程登录</li><li>forced-commands-only：允许root远程通过密钥登录，只能执行特定命令</li><li>prohibit-password：允许root远程登录，但是只能使用密钥登录</li></ul><p><code>/etc/ssh/sshd_config.d</code> 和 <code>/etc/ssh/ssh_config.d</code></p><ul><li><code>/etc/ssh/sshd_config.d</code> 保存的是服务端配置</li><li><code>/etc/ssh/ssh_config.d</code> 保存客户端配置</li></ul><p>最后不要忘记重启sshd</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">systemctl restart sshd
systemctl restart ssh
</code></pre></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/linux/ssh-config-basic-usage#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/linux/ssh-config-basic-usage</link><guid isPermaLink="true">https://blog.violet.vin/posts/linux/ssh-config-basic-usage</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sat, 06 Dec 2025 16:29:56 GMT</pubDate></item><item><title><![CDATA[我的 Arch Linux 配置]]></title><description><![CDATA[<link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/koy6imhuem4pi8xp4f.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/vny1zr1h8r1brqabdy.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/kzhntwae8bjjno3kyq.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/y46kmugv5w95fnevsz.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/my-arch-linux-setup">https://blog.violet.vin/posts/default/my-arch-linux-setup</a></blockquote><div><h2 id="">电脑配置</h2><p><img height="877" src="https://blog.violet.vin/api/v2/objects/image/koy6imhuem4pi8xp4f.png" width="1777"/></p><h2 id="">提升系统流畅度</h2><p>Nvidia显卡会自动进入低功耗模式，导致浏览器上下滚动时有较大延迟，并且系统动画也不流畅，锁定显卡频率即可</p><p><img src="https://blog.violet.vin/api/v2/objects/image/vny1zr1h8r1brqabdy.png"/></p><p><img src="https://blog.violet.vin/api/v2/objects/image/kzhntwae8bjjno3kyq.png"/></p><p>我的显卡是RTX4060TI，为了使显卡保持在Performance Level 2,至少需要设置Graphics Clock为405以上，设置Memory Transform Rate到10002以上</p>
<p>这里的600,3015是最小值和最大值</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo nvidia-smi -lgc 600,3105
sudo nvidia-smi -lmc 2000,10002
</code></pre>
<p>或者使用以下命令，设置强制最大性能模式</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo nvidia-settings -a &quot;[gpu:0]/GPUPowerMizerMode=1&quot;
</code></pre>
<p>以上设置在重启后会失效，配置自启动</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo vim /etc/systemd/system/nvidia-gpu-oc.service
</code></pre>
<pre class="language-ini lang-ini"><code class="language-ini lang-ini">[Unit]
Description=Set NVIDIA Clock Limits
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/bin/nvidia-smi -lgc 1200,3105
ExecStart=/usr/bin/nvidia-smi -lmc 2000,10002
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
</code></pre>
<pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo systemctl daemon-reload
sudo systemctl restart nvidia-gpu-oc.service
sudo systemctl status nvidia-gpu-oc.service
</code></pre>
<p>或者设置最大功耗（二选一即可）</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo vim ~/.config/autostart-scripts/nvidia-powermizer.sh
</code></pre>
<pre class="language-sh lang-sh"><code class="language-sh lang-sh">#!/bin/bash
nvidia-settings -a &quot;[gpu:0]/GPUPowerMizerMode=1&quot;
</code></pre>
<pre class="language-sh lang-sh"><code class="language-sh lang-sh">chmod +x ~/.config/autostart-scripts/nvidia-powermizer.sh
</code></pre>
<h2 id="">按键映射/输入法切换</h2><p>习惯了Mac输入法切换模式，Capslock切换输入法
同时会将Ctrl+V改为Shift+Insert
这里暂时使用 <a href="https://github.com/sezanzeb/input-remapper">Input Remappere</a> 来解决，等我后面找到更好的 再来更新吧</p><h2 id="">输入法问题</h2><blockquote><p><a href="https://www.bilibili.com/opus/931225106804375591">https://www.bilibili.com/opus/931225106804375591</a></p></blockquote>
<p>设置下面的环境变量</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sudo vim /etc/environment
</code></pre>
<p>写入下面这四行</p><pre class=""><code class="">XMODIFIERS=@im=fcitx  
GTK_IM_MODULE=fcitx  
SDL_IM_MODULE=fcitx  
QT_IM_MODULE=fcitx
</code></pre>
<p>设置中选择虚拟键盘
选择启动器的这个选项</p><p><img src="https://blog.violet.vin/api/v2/objects/image/y46kmugv5w95fnevsz.png"/></p><h2 id="">键盘映射</h2><p>使用keyd，实现以下目标</p><ul><li>CapsLock键取消原逻辑，重新映射为left ctrl + left shift + space。用于切换输入法</li><li>映射left shift + CapsLock 为切换全局大小写</li><li>映射left alt + c为left ctrl + insert</li><li>映射left alt + v为left shift + insert</li><li>映射left alt + x为left ctrl + x</li></ul><p>安装keyd</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">yay -S keyd
</code></pre>
<p>配置</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">vi /etc/keyd/default.conf
</code></pre>
<pre class="language-txt lang-txt"><code class="language-txt lang-txt">[ids]  
* 
  
[main]  
capslock = C-S-space  

leftshift = layer(shift)  

leftalt = layer(alt)  
  
[shift:S]  
capslock = capslock  
  
[alt:M]  
c = C-insert  
v = S-insert  
x = C-x
</code></pre>
<h2 id="jetbrains">JetBrains点击错位</h2><p>Help → Edit Custom VM Options
添加</p><pre class=""><code class="">-Dawt.toolkit.name=WLToolkit
</code></pre>
<p><a href="https://github.com/hyprwm/Hyprland/issues/4888">https://github.com/hyprwm/Hyprland/issues/4888</a>
https://www.polar-labs.com/idea-intellij-based-ides-under-wayland/</p><h2 id=""><del>更新中......</del></h2><p>已经不用arch了，已放弃</p></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/my-arch-linux-setup#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/my-arch-linux-setup</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/my-arch-linux-setup</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Wed, 05 Nov 2025 15:05:55 GMT</pubDate></item><item><title><![CDATA[极简 OpenWRT 安装与扩容]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/nas/minimal-openwrt-installation-and-storage-expansion">https://blog.violet.vin/posts/nas/minimal-openwrt-installation-and-storage-expansion</a></blockquote><div><blockquote><p>留给自己折腾用，不适用于新手第一次安装！</p></blockquote>
<h2 id="">前期准备</h2><ul><li>OpenWRT镜像
<ul><li>下载地址：https://downloads.openwrt.org/releases/24.10.3/targets/x86/64/
选这个镜像包没毛病</li></ul></li></ul><p>![[Pasted image 20251019125437.png]]</p><ul><li>U盘
<ul><li>写盘工具：https://rufus.ie/zh/</li><li>选择U盘+镜像，点击开始，完成后拔出U盘</li></ul></li><li>OpenWRT主机
<ul><li>我的是N100主机，4H8H，120GB SSD，双2.5G网口</li></ul></li><li>键盘</li><li>显示屏</li><li>稍微聪明的脑子</li></ul><h2 id="">安装步骤</h2><ul><li>主机插入U盘，连接键盘显示器开机</li><li>按delete键进入BIOS，进入boot设置第一启动项为U盘</li><li>进入U盘中的OpenWRT系统</li><li>输入命令，查询主机中磁盘名称</li></ul><pre class="language-sh lang-sh"><code class="language-sh lang-sh">cat /proc/partitions
</code></pre>
<p>![[Pasted image 20251019130328.png]]</p><ul><li>根据容量大小，分辨出U盘和硬盘</li><li>复制U盘内容到硬盘</li></ul><pre class="language-sh lang-sh"><code class="language-sh lang-sh">dd if=/dev/sda of=/dev/nvme0n1 bs=4M &amp;&amp; sync
</code></pre>
<p>注意上面的 <code>/dev/sda</code> 替换为U盘名称，<code>/dev/nvme0n1</code> 替换为硬盘名称</p><ul><li>等待，预计10-20分钟，等待完成之后的输出</li><li>输入 <code>reboot</code> 重启</li><li>进入BIOS，设置硬盘启动</li><li>启动后拔出U盘，至此安装已完成</li></ul><h2 id="">安装完配置</h2><h3 id="">跳过启动时确认</h3><p>![[Pasted image 20251019131015.png]]</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">vi /boot/grub/grub.cfg
</code></pre>
<p>这里的 <code>set timeout=&quot;0&quot;</code> 改成0，<code>reboot</code> 生效</p><h3 id="">网口配置</h3><pre class="language-sh lang-sh"><code class="language-sh lang-sh">vi /etc/config/network
</code></pre>
<p>lan这里的ipaddr改成你需要的网段之后重启</p><p>![[Pasted image 20251019131304.png]]</p><h3 id="dpkg">dpkg换源</h3><p><a href="https://mirrors.tuna.tsinghua.edu.cn/help/openwrt/">https://mirrors.tuna.tsinghua.edu.cn/help/openwrt/</a></p><p>一键替换</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">sed -i &#x27;s_https\?://downloads.openwrt.org_https://mirrors.tuna.tsinghua.edu.cn/openwrt_&#x27; /etc/opkg/distfeeds.conf
</code></pre>
<h2 id="">扩容</h2><p>使用脚本直接扩容，来源于OpenWRT官网，扩容完成后会自动重启</p><p><a href="https://openwrt.org/docs/guide-user/advanced/expand_root">https://openwrt.org/docs/guide-user/advanced/expand_root</a></p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">opkg update
opkg install parted losetup resize2fs blkid

wget -U &quot;&quot; -O expand-root.sh &quot;https://openwrt.org/_export/code/docs/guide-user/advanced/expand_root?codeblock=0&quot;

. ./expand-root.sh
sh /etc/uci-defaults/70-rootpt-resize
</code></pre></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/nas/minimal-openwrt-installation-and-storage-expansion#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/nas/minimal-openwrt-installation-and-storage-expansion</link><guid isPermaLink="true">https://blog.violet.vin/posts/nas/minimal-openwrt-installation-and-storage-expansion</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sun, 19 Oct 2025 04:52:36 GMT</pubDate></item><item><title><![CDATA[电子邮件PGP加密]]></title><description><![CDATA[<link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/u63g5a3vcsklhlxmqi.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/5sar4369tmggkuud4c.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/zpjan9zxwuz2bf9wc4.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/wdj7dq08l64e8q44i5.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/tz1lqslj49uf3xea2c.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/j007z5wasfxmvtyh1b.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/email-pgp-encryption">https://blog.violet.vin/posts/default/email-pgp-encryption</a></blockquote><div><h2 id="pgp">PGP</h2><p>Pretty Good Privacy (PGP)。直译为 &quot;相当好的隐私&quot;，是一种常用于邮件的加密协议，特点是非对称加密，加密一方使用公钥进行加密，本地邮件客户端收到邮件之后，使用私钥进行解密。PGP加密防止了最终收件邮箱保存用户明文邮件的问题，邮件服务提供商很可能会收集你的邮件用于AI模型的训练等等，产生可能的隐私问题。</p><h3 id="">加密步骤</h3><ul><li>发送方随机生成一个会话密钥，并使用该密钥对邮件进行加密</li><li>使用公钥加密会话密钥，将会话密钥共享给接收方，发送邮件</li><li>接收方使用私钥解密获取会话密钥，使用会话密钥解密邮件</li></ul><h3 id="pgp">PGP使用</h3><p>可以直接付费使用支持 PGP 加密的邮件服务提供商的服务，例如：</p><ul><li><a href="https://mailbox.org/">mailbox.org</a></li><li><a href="https://proton.me/mail">Proton Mail</a></li></ul><p>在了解到PGP之前，我主要使用阿里企业邮箱，我会将我拥有的所有邮箱的所有邮件都转发到阿里企业邮箱中，并在本地使用outlook邮箱客户端查看邮件。在意识到阿里云能看到所有的邮件之后，我觉得对数据进行加密，以防止潜在的隐私问题。
最终我的方案如下：
<img height="858" src="https://blog.violet.vin/api/v2/objects/image/u63g5a3vcsklhlxmqi.png" width="2290"/></p><ul><li>所有的邮件都会经过simplelogin使用PGP加密之后，转发到阿里企业邮箱</li><li>不再使用 Outlook、Gmail 等主邮箱直接注册网站，只使用别名邮箱注册（如果网站不支持别名邮箱，我会重新注册 Outlook 账号）</li><li>客户端使用 <a href="https://www.thunderbird.net/">Thunderbird</a> 解密邮件</li></ul><h2 id="pgp">PGP配置</h2><h3 id="simplelogin">Simplelogin</h3><p>SimpleLogin 提供邮箱别名服务，充值会员后，用户可以创建无限个别名邮箱。新注册网站时，我始终使用别名邮箱注册。安装这个 <a href="https://chromewebstore.google.com/detail/simplelogin-by-proton-sec/dphilobhebphkdjbpfohgikllaljmgbn">Chrome 插件</a>后，可以直接在右键菜单中生成包含当前网页域名的邮箱地址。</p><p>同时还提供别名邮件回信功能，实现发信和收信时始终隐藏真实邮件地址。</p><h3 id="thunderbird">Thunderbird</h3><p>Thunderbird 是由 Mozilla 开发维护的开源免费邮件客户端，支持邮件收发的 PGP 加解密功能，同时支持共享自己的公钥和获取对方公钥。</p><h3 id="pgp">生成PGP公私钥</h3><p>在 Thunderbird 的账户设置中，找到&quot;端到端加密&quot;选项，点击&quot;添加密钥&quot;即可生成 PGP 密钥对</p><p><img src="https://blog.violet.vin/api/v2/objects/image/5sar4369tmggkuud4c.png"/></p><h3 id="">配置公钥</h3><p>生成密钥对后，复制公钥内容，填写到 SimpleLogin -&gt; Mailboxes -&gt; Pretty Good Privacy (PGP) 配置中即可</p><p><img src="https://blog.violet.vin/api/v2/objects/image/zpjan9zxwuz2bf9wc4.png"/>
<img src="https://blog.violet.vin/api/v2/objects/image/wdj7dq08l64e8q44i5.png"/></p><h3 id="">共享公钥</h3><p>公钥发布后，当有人需要发送邮件到这个邮箱时，可以查询到公钥。如果能够查找到我方共享的公钥，即可发送一封经过 PGP 加密的邮件，只有我方的私钥才能解密
<img src="https://blog.violet.vin/api/v2/objects/image/tz1lqslj49uf3xea2c.png"/>
在 Thunderbird 中填写收件人邮箱地址后，会自动查询是否存在已发布的公钥，如果存在即可使用 PGP 加密发送邮件</p><p><img src="https://blog.violet.vin/api/v2/objects/image/j007z5wasfxmvtyh1b.png"/></p><h2 id="">关于隐私保护</h2><p>历史总是告诉我们人类不会吸取任何经验教训，那就不要等到泄露的时候才想起了隐私保护，到那个时候，保护不保护已经无所谓了。所以还是得在泄露之前提高隐私保护意识。</p></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/email-pgp-encryption#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/email-pgp-encryption</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/email-pgp-encryption</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Sat, 23 Aug 2025 13:42:48 GMT</pubDate></item><item><title><![CDATA[我的Anubis工具配置]]></title><description><![CDATA[<link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/s2estrlm4uw0vtpw3o.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/odlny1mni86rzvpdk5.png"/><link rel="preload" as="image" href="https://blog.violet.vin/api/v2/objects/image/4vp55nqd2cujabocdi.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://blog.violet.vin/posts/default/my-anubis-tool-configuration">https://blog.violet.vin/posts/default/my-anubis-tool-configuration</a></blockquote><div><h2 id="anubis">Anubis</h2><p>Anubis是一个网站防护工具，其工作原理类似常见的Cloudflare验证，会在用户进入网站之前对客户端进行检查。客户端需要完成一定难度的Hash计算，服务器验证计算结果后放行，Hash计算代表了客户端可能需要执行几千几万次的计算，而服务器验证只需执行一次，对服务器开销小。
当有网络爬虫、CC攻击想进入源站时，需要在攻击者的客户端（比如无头浏览器中）进行一定量的Hash计算，攻击者一般会在一台物理机中运行多个配置了代理的无头浏览器，这些Hash计算会拖垮攻击者的服务器，从而迫使攻击者放弃或降低攻击频率。
现代设备通常都具有一定的算力，这些任务对于这些客户端来说，通常只需要几毫秒或几秒钟即可完成，用户只需要等待一段时间，不需要进行任何操作，成功后会自动进入实际后端服务。</p><h2 id="">工作原理</h2><h3 id="hash">Hash计算</h3><p>和经典的比特币挖矿一致，客户端需要使用一个确定的字符串加上任意数字，进行 <code>sha256</code> 计算，得到的 64 位hash值的前x个数为 0，x就是difficulty</p><pre class="language-js lang-js"><code class="language-js lang-js">const hash = await sha256(`${challenge}${nonce}`);
</code></pre>
<h3 id="">整体流程</h3><p><img height="946" src="https://blog.violet.vin/api/v2/objects/image/s2estrlm4uw0vtpw3o.png" width="2646"/></p><p><img src="https://blog.violet.vin/api/v2/objects/image/odlny1mni86rzvpdk5.png"/></p><p>客户端第一次访问时，会根据访问者的IP、ASN、User-Agent，服务器的工作负载，计算出一个数值 <code>weight</code>，之后通过 <code>weight</code> 匹配不同难度的Hash计算任务给客户端。客户端完成计算后，由服务器进行验证，成功之后放行到真正的后端服务，同时返回 <code>Set-Cookies</code> 以保存一段时间验证结果，当用户下次访问时，可复用上次的验证结果。</p><h3 id="nginx">与NGINX搭配</h3><p><img src="https://blog.violet.vin/api/v2/objects/image/4vp55nqd2cujabocdi.png"/></p><p>流量从 80/443 端口进入之后，先交给Anubis进行拦截，验证完成之后再交还回NGINX进行后续流程。在单个服务器内通过unix socket进行交互。</p><h2 id="">安装/配置</h2><p>此处以Debian 12 系统为例</p><h3 id="anubis">安装Anubis</h3><h4 id="">下载并安装</h4><p>请在<a href="https://github.com/TecharoHQ/anubis/releases">Github</a>获取最新的版本号</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">wget -O /tmp/anubis.deb https://github.com/TecharoHQ/anubis/releases/download/v1.21.3/anubis_1.21.3_amd64.deb &amp;&amp; apt install /tmp/anubis.deb
</code></pre>
<p>不能直连Github，可以使用加速域名，或者手动下载上传到服务器</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">wget -O /tmp/anubis.deb https://ghfast.top/https://github.com/TecharoHQ/anubis/releases/download/v1.21.3/anubis_1.21.3_amd64.deb &amp;&amp; apt install /tmp/anubis.deb
</code></pre>
<p>修改 <code>/etc/anubis/default.env</code>，内容如下</p><pre class="language-txt lang-txt"><code class="language-txt lang-txt">BIND=/run/anubis/instance.sock
BIND_NETWORK=unix
SOCKET_MODE=0666
TARGET=unix:///run/nginx/nginx.sock
</code></pre>
<p>复制默认策略文件，暂不修改</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">cp /usr/share/doc/anubis/botPolicies.yaml /etc/anubis/botPolicies.yaml
</code></pre>
<h4 id="systemd">systemd运行</h4><p>创建service文件</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">vi /etc/systemd/system/anubis.service
</code></pre>
<pre class="language-service lang-service"><code class="language-service lang-service">[Unit]
Description=Anubis Bot Protection
After=network.target

[Service]
EnvironmentFile=/etc/anubis/default.env
ExecStart=/usr/bin/anubis \
  -bind /run/anubis/instance.sock \
  -bind-network unix \
  -socket-mode 0666 \
  -target unix:///run/nginx/nginx.sock \
  -metrics-bind 127.0.0.1:9091 \
  -metrics-bind-network tcp \
  -policy-fname /etc/anubis/botPolicies.yaml

Restart=always
User=www-data
Group=www-data

[Install]
WantedBy=multi-user.target
</code></pre>
<p>创建目录</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">mkdir -p /run/anubis /run/nginx
</code></pre>
<p>修改权限</p><p>此处的用户和NGINX相同</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">chown www-data:www-data /run/anubis /run/nginx
</code></pre>
<p>启用Anubis</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">systemctl enable --now anubis.service
</code></pre>
<p>确保已经成功运行</p><pre class="language-sh lang-sh"><code class="language-sh lang-sh">systemctl status anubis
</code></pre>
<h3 id="nginx">配置NGINX</h3><p>此处提供一份可用NGINX，请自行修改扩展</p><pre class="language-nginx lang-nginx"><code class="language-nginx lang-nginx">user  root;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    upstream anubis {
        server unix:/run/anubis/instance.sock;
    }

    server {
        listen 443 ssl http2;
        server_name uptime.vio.vin;

        ssl_certificate     /etc/ssl/violet/certs/all.vio.vin.cert.pem;
        ssl_certificate_key /etc/ssl/violet/certs/all.vio.vin.key.pem;

        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://anubis;
        }
    }

    server {
        listen unix:/run/nginx/nginx.sock;
        server_name uptime.vio.vin;

        location / {
            proxy_pass http://10.115.15.178:3001;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}
</code></pre>
<ul><li>upstream：定义上游服务器为anubis</li><li>第一个server：监听 443 入站连接，传输给anubis，传输客户端IP用于IP相关策略判断</li><li>第二个server：anubis验证通过之后，实际反向代理的位置</li></ul><p>至此，基础配置已完成，默认情况下低风险客户端难度为 2，高风险为 4</p><h2 id="bot">Bot策略</h2><p>官网文档：https://anubis.techaro.lol/docs/admin/policies
需要调整 <code>botPolicies.yaml</code> 文件
默认的<code>botPolicies.yaml</code> 配置文件：https://github.com/TecharoHQ/anubis/blob/main/data/botPolicies.yaml</p><p>bots中定义了多个规则，可以看到已经通过import导入了一部分规则，这部分的文件可以在 <code>/usr/share/doc/anubis/data/bots</code> 中找到</p><p>默认的规则如下，可以仿照这些规则写自己的规则</p><h3 id="">可配置匹配规则</h3><h4 id="">匹配请求头</h4><p><code>/usr/share/doc/anubis/data/bots/cloudflare-workers.yaml</code></p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: cloudflare-workers
  headers_regex:
    CF-Worker: .*
  action: WEIGH
  weight:
    adjust: 15
</code></pre>
<h4 id="user-agent">匹配User-Agent</h4><p><code>/usr/share/doc/anubis/data/bots/headless-browsers.yaml</code></p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: lightpanda
  user_agent_regex: ^LightPanda/.*$
  action: DENY
- name: headless-chrome
  user_agent_regex: HeadlessChrome
  action: DENY
- name: headless-chromium
  user_agent_regex: HeadlessChromium
  action: DENY
</code></pre>
<h4 id="">指定表达式</h4><p><code>/usr/share/doc/anubis/data/bots/aggressive-brazilian-scrapers.yaml</code></p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: deny-aggressive-brazilian-scrapers
  action: WEIGH
  weight:
    adjust: 20
  expression:
    any:
      # Internet Explorer should be out of support
      - userAgent.contains(&quot;MSIE&quot;)
      # Trident is the Internet Explorer browser engine
      - userAgent.contains(&quot;Trident&quot;)
      # Opera is a fork of chrome now
      - userAgent.contains(&quot;Presto&quot;)
      # Windows CE is discontinued
      - userAgent.contains(&quot;Windows CE&quot;)
      # Windows 95 is discontinued
      - userAgent.contains(&quot;Windows 95&quot;)
      # Windows 98 is discontinued
      - userAgent.contains(&quot;Windows 98&quot;)
      # Windows 9.x is discontinued
      - userAgent.contains(&quot;Win 9x&quot;)
      # Amazon does not have an Alexa Toolbar.
      - userAgent.contains(&quot;Alexa Toolbar&quot;)
      # This is not released, even Windows 11 calls itself Windows 10
      - userAgent.contains(&quot;Windows NT 11.0&quot;)
      # iPods are not in common use
      - userAgent.contains(&quot;iPod&quot;)

</code></pre>
<h4 id="ip">匹配客户端IP</h4><p><code>/usr/share/doc/anubis/data/clients/mistral-mistralai-user.yaml</code></p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml"># Acts on behalf of user requests
# https://docs.mistral.ai/robots/
- name: mistral-mistralai-user
  user_agent_regex: MistralAI-User/.+; \+https\://docs\.mistral\.ai/robots
  action: ALLOW
  # https://mistral.ai/mistralai-user-ips.json
  remote_addresses: [
    &quot;20.240.160.161/32&quot;,
    &quot;20.240.160.1/32&quot;,
  ]
</code></pre>
<h4 id="geoip">匹配GEOIP</h4><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: countries-with-aggressive-scrapers
  action: WEIGH
  geoip:
    countries:
      - BR
      - CN
  weight:
    adjust: 10
</code></pre>
<h4 id="asn">匹配ASN</h4><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: aggressive-asns-without-functional-abuse-contact
  action: WEIGH
  asns:
    match:
      - 13335 # Cloudflare
      - 136907 # Huawei Cloud
      - 45102 # Alibaba Cloud
  weight:
    adjust: 10
</code></pre>
<h3 id="">匹配后动作</h3><table><thead><tr><th> 动作        </th><th> 解释          </th></tr></thead><tbody><tr><td> ALLOW     </td><td> 允许，跳过后续所有检查 </td></tr><tr><td> DENY      </td><td> 拒绝访问        </td></tr><tr><td> CHALLENGE </td><td> 进行客户端挑战     </td></tr><tr><td> WEIGH     </td><td> 修改请求权重      </td></tr></tbody></table><p>ALLOW和DENY不再解释</p><h4 id="challenge">CHALLENGE</h4><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: generic-bot-catchall
  user_agent_regex: (?i:bot|crawler)
  action: CHALLENGE
  challenge:
    difficulty: 16 # impossible
    report_as: 4 # lie to the operator
    algorithm: slow # intentionally waste CPU cycles and time
</code></pre>
<ul><li><code>name</code>：名称，可自定义</li><li><code>user_agent_regex</code>：正则表达式匹配User-Agent</li><li><code>action</code>：动作，立即进行客户端挑战</li><li><code>challenge</code>：客户端挑战配置
<ul><li><code>difficulty</code>：难度，16 表示计算出的hash值前 16 位为 0，不可能完成（比特币的前导 0 个数为 19-20），在客户端完成 16 位的计算可能需要几万年甚至更久（攻击者看着 99%的CPU陷入沉思）</li><li><code>report_as</code>：用户在界面上看到的难度数值（你甚至可以骗他，这个进度条怎么一直卡在 99%不走呢）</li><li><code>algorithm</code>：采用的Hash算法，slow故意折磨CPU</li></ul></li></ul><h4 id="weigh">WEIGH</h4><p>调整请求的权重，正数为增加权重，负数为减少权重，后续会进入到 <code>thresholds</code> 中，针对不同的请求设置不同的CHALLENGE</p><p>0-10 的权重，进行快速算法，几乎不需要等待</p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">- name: mild-suspicion
  expression:
    all:
      - weight &gt; 0
      - weight &lt; 10
  action: CHALLENGE
  challenge:
    algorithm: metarefresh
    difficulty: 2
    report_as: 2
</code></pre>
<h3 id="">其他</h3><p>根据服务器负载动态调整</p><p>示例在配置文件中已给出，有需要可以启用</p><pre class="language-yaml lang-yaml"><code class="language-yaml lang-yaml">  ## System load based checks.
  # If the system is under high load, add weight.
  - name: high-load-average
    action: WEIGH
    expression: load_1m &gt;= 10.0 # make sure to end the load comparison in a .0
    weight:
      adjust: 20

  # If your backend service is running on the same operating system as Anubis,
  # you can uncomment this rule to make the challenge easier when the system is
  # under low load.
  #
  # If it is not, remove weight.
  - name: low-load-average
    action: WEIGH
    expression: load_15m &lt;= 4.0 # make sure to end the load comparison in a .0
    weight:
      adjust: -10
</code></pre>
<h3 id="">测试页面</h3><p>为了方便<del>在大家的浏览器中挖矿</del>方便大家测试，我准备了这些界面
建议用隐私窗口打开，否则会使用上一次的结果</p><table><thead><tr><th> 难度  </th><th> 地址                               </th></tr></thead><tbody><tr><td> 2   </td><td> <a href="https://pow.vio.vin/challenge/2">https://pow.vio.vin/challenge/2</a>  </td></tr><tr><td> 3   </td><td> <a href="https://pow.vio.vin/challenge/3">https://pow.vio.vin/challenge/3</a>  </td></tr><tr><td> 4   </td><td> <a href="https://pow.vio.vin/challenge/4">https://pow.vio.vin/challenge/4</a>  </td></tr><tr><td> 5   </td><td> <a href="https://pow.vio.vin/challenge/5">https://pow.vio.vin/challenge/5</a>  </td></tr><tr><td> 6   </td><td> <a href="https://pow.vio.vin/challenge/6">https://pow.vio.vin/challenge/6</a>  </td></tr><tr><td> 7   </td><td> <a href="https://pow.vio.vin/challenge/7">https://pow.vio.vin/challenge/7</a>  </td></tr><tr><td> 8   </td><td> <a href="https://pow.vio.vin/challenge/8">https://pow.vio.vin/challenge/8</a>  </td></tr><tr><td> 10  </td><td> <a href="https://pow.vio.vin/challenge/10">https://pow.vio.vin/challenge/10</a> </td></tr><tr><td> 20  </td><td> <a href="https://pow.vio.vin/challenge/20">https://pow.vio.vin/challenge/20</a> </td></tr></tbody></table><h2 id="">参考文献</h2><p><a href="https://lock.cmpxchg8b.com/anubis.html">https://lock.cmpxchg8b.com/anubis.html</a></p></div><p style="text-align:right"><a href="https://blog.violet.vin/posts/default/my-anubis-tool-configuration#comments">览毕，何不一言？</a></p></div>]]></description><link>https://blog.violet.vin/posts/default/my-anubis-tool-configuration</link><guid isPermaLink="true">https://blog.violet.vin/posts/default/my-anubis-tool-configuration</guid><dc:creator><![CDATA[violet]]></dc:creator><pubDate>Thu, 21 Aug 2025 11:50:03 GMT</pubDate></item></channel></rss>