<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Doveccl</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://ecl.me/</id>
  <link href="https://ecl.me/" rel="alternate"/>
  <link href="https://ecl.me/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Doveccl</rights>
  <subtitle>Doveccl's blog</subtitle>
  <title>DBLOG</title>
  <updated>2026-02-22T16:28:25.730Z</updated>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="软路由" scheme="https://ecl.me/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
    <category term="透明代理" scheme="https://ecl.me/tags/%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86/"/>
    <category term="Arch" scheme="https://ecl.me/tags/Arch/"/>
    <category term="IPv6" scheme="https://ecl.me/tags/IPv6/"/>
    <content>
      <![CDATA[<p>折腾软路由也有几年了，系统从 Debian 换到 Arch，运营商从电信换到广电又换到移动，透明代理工具也是在 mihomo (Clash.Meta) 和 sing-box 之间来回切换过不少次。这么长时间也积累了不少经验，于是打算在这一篇文章里一并记录下</p><span id="more"></span><h1 id="运营商的选择"><a class="markdownIt-Anchor" href="#运营商的选择"></a> 运营商的选择</h1><p>由于各地运营商的情况不尽相同，这里只说广州的情况：</p><ul><li>电信：贵，千兆档位是给开动态公网 v4 的，有动态公网 v6 封常用端口，稳定性最好</li><li>广电（aka 珠江宽频）：不给 v6，公网 v4 原来免费现在收 50 元/月，拉完了</li><li>移动：性价比高，新装不给光猫改桥接了，无公网 v4，有动态公网 v6 且不封 80, 443 端口</li><li>联通：价格应该跟广电差不多，没用过</li></ul><p>综合看下来广州移动算是一个不错的选择，晚高峰时期延迟（国内网站 / CN2 线路）也不错</p><h1 id="软路由系统的选择"><a class="markdownIt-Anchor" href="#软路由系统的选择"></a> 软路由系统的选择</h1><ul><li>其实 Debian 用来做软路由非常不错，而且官方源的软件版本一般都比较稳定，如果不想折腾的话选择 Debian 完全 OK，可直接参考<a href="/2023/04/22/use-debian-as-router/">之前的文章</a>，更推荐这种组合：Debian + <a href="#systemd-networkd">systemd-networkd</a> + <a href="#%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86%E9%85%8D%E7%BD%AE">sing-box</a></li><li>当然，都开始玩软路由了哪有不折腾的，Arch 的优势在于内核足够新且软件源更新比较勤，个人使用体验下来没那么容易滚挂，所以也是非常推荐的</li><li>至于 OpenWRT 和爱快（好像已经支持硬件直通了？）这些之前文章也有一些说明，如果技术能力不是很强或者不想折腾也是个不错的选择，就是可玩性没那么高罢了</li></ul><h1 id="arch-安装"><a class="markdownIt-Anchor" href="#arch-安装"></a> Arch 安装</h1><p>安装直接看这个就行 <a class="link"   href="https://wiki.archlinuxcn.org/wiki/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97" >https://wiki.archlinuxcn.org/wiki/安装指南<i class="fas fa-external-link-alt"></i></a> 注意事项如下：</p><ol><li>最好避免直接使用 <code>archinstall</code> 来安装系统</li><li>最好先通过 DHCP 配置好网络，如果运营商不给公网 v4 光猫改桥接意义不大</li><li>运行 <code>pacstrap</code> 时最好一并带上 <code>nftables</code> 包（如果需要路由器拨号再追加一个 <code>ppp</code> 包）</li><li>优先考虑 <code>systemd-boot</code> 作为引导，如果电脑不支持 EFI 再考虑  <code>grub2</code></li></ol><p>安装完成后，强烈推荐同时配置 <a class="link"   href="https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/" >archlinuxcn<i class="fas fa-external-link-alt"></i></a>，另外也别忘了把源都换成国内镜像</p><h1 id="路由器基础配置"><a class="markdownIt-Anchor" href="#路由器基础配置"></a> 路由器基础配置</h1><h2 id="sysctl"><a class="markdownIt-Anchor" href="#sysctl"></a> sysctl</h2><p>现行版本 Arch 已经不用 <code>/etc/sysctl.conf</code> 这个文件来进行配置了，直接创建并编辑 <code>/etc/sysctl.d/99-forward.conf</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">net.ipv6.conf.all.forwarding = 1</span><br></pre></td></tr></table></figure><p>只需要配置 IPv6 转发并不是因为不需要设置 IPv4 转发，而是如果使用 systemd-networkd 来配置网络会自动帮我们开启 IPv4 转发，无需额外的显式配置（其实理论上 IPv6 也无需显式指定，但是感觉内核有一点 bug，必须开了 all 才生效）</p><h2 id="systemd-networkd"><a class="markdownIt-Anchor" href="#systemd-networkd"></a> systemd-networkd</h2><p>先用 <code>ip a</code> 列一下物理网卡，决定好哪个用作 WAN 口，哪些需要组局域网桥（本文不讨论单网口旁路由，双网口机器不需要组网桥），这里仍然假设有四个网口：<code>eno1</code> 用作 WAN，<code>eno2 ~ eno4</code> 用作 LAN</p><p>先配置 <code>/etc/systemd/network/10-wan.network</code> WAN 口联网（除非有公网 v4 否则不推荐软路由拨号）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[Match]</span><br><span class="line">Name=eno1 # 软路由拨号，网口名改成 ppp0</span><br><span class="line"></span><br><span class="line">[Network]</span><br><span class="line">DHCP=yes # 软路由拨号，yes 改成 ipv6</span><br><span class="line">IPv6AcceptRA=yes</span><br><span class="line"># 软路由拨号则取消下一行注释，让 networkd 不要覆盖已存在的 v4 地址</span><br><span class="line"># KeepConfiguration=yes</span><br><span class="line"></span><br><span class="line">[DHCPv6]</span><br><span class="line">WithoutRA=solicit</span><br></pre></td></tr></table></figure><p>接着配置 <code>/etc/systemd/network/20-br0.netdev</code> 创建网桥</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[NetDev]</span><br><span class="line">Name=br0</span><br><span class="line">Kind=bridge</span><br></pre></td></tr></table></figure><p>然后配置 <code>/etc/systemd/network/30-lan.network</code> 绑定几个物理网口到网桥</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[Match]</span><br><span class="line">Name=eno2 eno3 eno4 # 注意改成自己的网口名</span><br><span class="line"></span><br><span class="line">[Network]</span><br><span class="line">Bridge=br0</span><br></pre></td></tr></table></figure><p>最后配置 <code>/etc/systemd/network/40-br0.network</code> 完善 LAN 信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">[Match]</span><br><span class="line">Name=br0</span><br><span class="line"></span><br><span class="line">[Network]</span><br><span class="line">Address=192.168.1.1/24 # 注意子网分配不要和光猫冲突</span><br><span class="line">IPMasquerade=ipv4 # 会同时开启 IPv4 转发和 NAT</span><br><span class="line">DHCPServer=yes</span><br><span class="line">IPv6SendRA=yes</span><br><span class="line">DHCPPrefixDelegation=yes # 自动尝试从 WAN 口拿 IPv6 子网前缀，开启此项需要较新版本的 systemd</span><br><span class="line"></span><br><span class="line"># 限制地址池，不限制则不写</span><br><span class="line">[DHCPServer]</span><br><span class="line">PoolOffset=10 # 从 192.168.1.10 开始分配地址</span><br><span class="line">PoolSize=200 # 至多分配 200 个地址</span><br><span class="line"></span><br><span class="line"># 这个配置块可重复多次，用于固定特定设备的内网 IPv4</span><br><span class="line">[DHCPServerStaticLease]</span><br><span class="line"># 在一些苹果移动设备和高版本安卓设备上，可能需要关掉随机 MAC 地址</span><br><span class="line">MACAddress=a1:b2:c3:d4:e5:f6</span><br><span class="line">Address=192.168.1.2</span><br></pre></td></tr></table></figure><p>注意：</p><ul><li>上述配置只会通告 SLAAC（无状态 IPv6 地址），而不开启 DHCPv6 Server（也没必要开）</li><li><code>networkd</code> 本身已经可以实现几乎全部 <code>ifupdown</code> + <code>dnsmasq</code> + <code>dhcp6c</code> 和部分 <code>nftables</code> 功能</li><li>通过 <code>systemctl enable --now systemd-networkd</code> 开机自启动网络服务</li><li>通过 <code>systemctl restart systemd-networkd</code> 重启服务刷新配置</li></ul><h2 id="nftables"><a class="markdownIt-Anchor" href="#nftables"></a> nftables</h2><p>虽然 <code>networkd</code> 已经接管了 NAT 部分的配置，但是仍然需要防火墙等的额外配置，直接编辑文件 <code>/etc/nftables.conf</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/nft -f</span><br><span class="line"></span><br><span class="line">destroy table inet mangle</span><br><span class="line">table inet mangle &#123;</span><br><span class="line">chain forward &#123;</span><br><span class="line">type filter hook forward priority mangle</span><br><span class="line"># 此配置对拨号上网非常重要，因为 Arch 的 ppp 包默认不会对 PPPoE 的 MTU 做修改</span><br><span class="line">oifname ppp* tcp flags syn tcp option maxseg size set rt mtu</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">destroy table inet filter</span><br><span class="line">table inet filter &#123;</span><br><span class="line">chain input &#123;</span><br><span class="line">type filter hook input priority filter</span><br><span class="line">ct state established,related accept</span><br><span class="line"># 在下面的第二个括号里填入希望开放给外网的端口即可</span><br><span class="line">iifname &#123; ppp*, en* &#125; tcp dport != &#123; 22, 80, 443 &#125; counter drop</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样的，需要仿照 <code>systemd-networkd</code> 的命令对 <code>nftables</code> 设置开机自启和重启</p><h1 id="透明代理配置"><a class="markdownIt-Anchor" href="#透明代理配置"></a> 透明代理配置</h1><p>这个时候 Arch 的优势就体现出来了，不管是 <code>mihomo</code> 还是 <code>sing-box</code> 都可以直接通过 archlinuxcn 仓库安装，而且更新非常及时。这里更推荐 <code>sing-box</code> 因为就连 <code>mihomo</code> 的 TUN 功能（透明代理的核心）底层实现也是 <code>sing-tun</code> (fork)</p><p>这里直接给出一个 <code>/etc/sing-box/config.json</code> 配置以供参考</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;log&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;level&quot;</span><span class="punctuation">:</span> <span class="string">&quot;info&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;dns&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;reverse_mapping&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="comment">// 如果需要 ssh github 这个配置会很有用</span></span><br><span class="line">    <span class="attr">&quot;servers&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;l&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;dhcp&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span> <span class="comment">// 如果是软路由拨号，这里手动改成运营商 DNS（不推荐公共 DNS 服务）</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;r&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;h3&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;server&quot;</span><span class="punctuation">:</span> <span class="string">&quot;v.recipes&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;domain_resolver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;l&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;rules&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ad&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;action&quot;</span><span class="punctuation">:</span> <span class="string">&quot;reject&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="string">&quot;cn&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;server&quot;</span><span class="punctuation">:</span> <span class="string">&quot;l&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="string">&quot;gfw&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;server&quot;</span><span class="punctuation">:</span> <span class="string">&quot;r&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ip:cn&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;server&quot;</span><span class="punctuation">:</span> <span class="string">&quot;l&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;inbounds&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mix&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mixed&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;listen&quot;</span><span class="punctuation">:</span> <span class="string">&quot;::&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;listen_port&quot;</span><span class="punctuation">:</span> <span class="number">7890</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;tun&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;auto_route&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;auto_redirect&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;address&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;172.18.0.1/30&quot;</span><span class="punctuation">,</span> <span class="string">&quot;fd00:172:18::1/126&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;route_exclude_address_set&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;ip:cn&quot;</span><span class="punctuation">]</span> <span class="comment">// 中国 IP 出站不走 TUN</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;outbounds&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span> <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;direct&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;direct&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;proxy&quot;</span></span><br><span class="line">      <span class="comment">// 这里填写自己的节点信息</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;route&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;auto_detect_interface&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;default_domain_resolver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;l&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;rules&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;action&quot;</span><span class="punctuation">:</span> <span class="string">&quot;sniff&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;protocol&quot;</span><span class="punctuation">:</span> <span class="string">&quot;dns&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;action&quot;</span><span class="punctuation">:</span> <span class="string">&quot;hijack-dns&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;ip_is_private&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span> <span class="attr">&quot;outbound&quot;</span><span class="punctuation">:</span> <span class="string">&quot;direct&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;protocol&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;bittorrent&quot;</span><span class="punctuation">,</span> <span class="string">&quot;stun&quot;</span><span class="punctuation">,</span> <span class="string">&quot;ntp&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;outbound&quot;</span><span class="punctuation">:</span> <span class="string">&quot;direct&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;gfw&quot;</span><span class="punctuation">,</span> <span class="string">&quot;google&quot;</span><span class="punctuation">,</span> <span class="string">&quot;ip:telegram&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="attr">&quot;outbound&quot;</span><span class="punctuation">:</span> <span class="string">&quot;proxy&quot;</span> <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span> <span class="attr">&quot;inbound&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mix&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;outbound&quot;</span><span class="punctuation">:</span> <span class="string">&quot;proxy&quot;</span> <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;rule_set&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;cn&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/cn.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;gfw&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/gfw.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;google&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/google.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ip:cn&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/cn.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ip:telegram&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/telegram.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ad&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;remote&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;format&quot;</span><span class="punctuation">:</span> <span class="string">&quot;binary&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://anti-ad.net/anti-ad-sing-box.srs&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>当然，如果是光猫拨号的话，也可以考虑 <a class="link"   href="https://github.com/daeuniverse/dae" >dae<i class="fas fa-external-link-alt"></i></a> 这种性能更好的方案，这个就纯看个人喜好了</p><h1 id="all-in-boom"><a class="markdownIt-Anchor" href="#all-in-boom"></a> All in Boom</h1><p>其实对于性能过剩的机器，还是很推荐装个 <code>docker</code> 跑额外服务的，挂个大容量盘做 NAS 也是个不错的选择，这里简单列一下我自己在用的一些服务</p><ul><li><a class="link"   href="https://github.com/qbittorrent/qBittorrent/wiki/#webui" >qBittorrent<i class="fas fa-external-link-alt"></i></a>: 用来挂 PT 站还是很不错的，而且像 byr 这种其实只是禁止了国内运营商地址访问网页，P2P 协议其实仍然可以直连，这个不需要 docker 直接 <code>pacman -S qbittorrent-nox</code> 就行</li><li><a class="link"   href="https://hub.docker.com/r/homeassistant/home-assistant" >Home Assistant<i class="fas fa-external-link-alt"></i></a>: 如果有很多米家的智能家居设备想要用 Apple Home 控制，如果想要写出高度自定义的自动化任务，这个还是非常推荐的</li><li><a class="link"   href="https://docs.immich.app/install/all-in-one" >immich<i class="fas fa-external-link-alt"></i></a>: 轻松实现多设备照片自动备份，如果对云盘的隐私协议存疑，可以尝试使用</li><li><a class="link"   href="https://jellyfin.org/docs/general/installation/container/" >Jellyfin<i class="fas fa-external-link-alt"></i></a>: 配合 PT 站 DIY 自己的影视资源库</li></ul><p>另外，<a class="link"   href="https://www.fnnas.com/" >飞牛<i class="fas fa-external-link-alt"></i></a> 似乎也是当下比较流行的一个选择，待我有空了折腾下试试</p>]]>
    </content>
    <id>https://ecl.me/2026/02/22/use-arch-as-router/</id>
    <link href="https://ecl.me/2026/02/22/use-arch-as-router/"/>
    <published>2026-02-22T09:00:00.000Z</published>
    <summary>
      <![CDATA[<p>折腾软路由也有几年了，系统从 Debian 换到 Arch，运营商从电信换到广电又换到移动，透明代理工具也是在 mihomo (Clash.Meta) 和 sing-box 之间来回切换过不少次。这么长时间也积累了不少经验，于是打算在这一篇文章里一并记录下</p>]]>
    </summary>
    <title>使用 Arch 搭建软路由</title>
    <updated>2026-02-22T16:28:25.730Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <content>
      <![CDATA[<p>也是有一年半没有更新过什么内容了，本来前段时间想要写一篇《使用 Arch 作为软路由》的，可惜广电太拉跨不给 IPv6 还收回了公网 IPv4，所以还是等后面换了新的运营商再一并记录好了。看着时间又到了年末，又发现 2024 一整年好像都没留下什么记录，于是打算随便写点什么</p><span id="more"></span><p>2025 年的世界发生了许多事情，2025 的我亦是如此，就简单列个时间线记录下吧</p><h2 id="春节"><a class="markdownIt-Anchor" href="#春节"></a> 春节</h2><p>似乎没有什么特别的事情发生，也就是清闲地刷刷视频，接收一些新奇的信息，然后就回去灰溜溜地上班了</p><h2 id="清明"><a class="markdownIt-Anchor" href="#清明"></a> 清明</h2><p>过节一向是懒得出远门的（除了回老家），但这次选择了飞上海。可以说是很仓促吧，但肯定也是下了些决心的</p><h2 id="劳动节"><a class="markdownIt-Anchor" href="#劳动节"></a> 劳动节</h2><p>从第二家公司离职，准备着节后去下家报道。五一选择回了趟老家，别的事情记忆有些模糊了，但依稀记得老妈在我临上车前讲的：“有啥事都可以跟我们说”</p><h2 id="端午节"><a class="markdownIt-Anchor" href="#端午节"></a> 端午节</h2><p>宅在家里，和父母通了很久的电话</p><h2 id="国庆节"><a class="markdownIt-Anchor" href="#国庆节"></a> 国庆节</h2><p>参加了两场婚礼，一场高中好哥们的，一场姐姐的，感慨万分</p><blockquote><p>过了这么多年，我还是那个谜语人，不过好在是也快进入人生下一阶段了，2026 继续好好生活吧</p></blockquote>]]>
    </content>
    <id>https://ecl.me/2025/12/31/2025-to-2026/</id>
    <link href="https://ecl.me/2025/12/31/2025-to-2026/"/>
    <published>2025-12-30T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>也是有一年半没有更新过什么内容了，本来前段时间想要写一篇《使用 Arch 作为软路由》的，可惜广电太拉跨不给 IPv6 还收回了公网 IPv4，所以还是等后面换了新的运营商再一并记录好了。看着时间又到了年末，又发现 2024 一整年好像都没留下什么记录，于是打算随便写点什么</p>]]>
    </summary>
    <title>2025 年末随笔</title>
    <updated>2026-02-22T16:28:25.710Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="Debian" scheme="https://ecl.me/tags/Debian/"/>
    <category term="软路由" scheme="https://ecl.me/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
    <category term="透明代理" scheme="https://ecl.me/tags/%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86/"/>
    <category term="Clash.Meta" scheme="https://ecl.me/tags/Clash-Meta/"/>
    <content>
      <![CDATA[<p>之前用 OpenWrt 的时候比较省心，装一个 Passwall(2) 之类的插件就可以实现透明代理，原理说白了也就是通过 tproxy 和一些 iptables 的重定向规则。iptables 这个东西难用已经是不争的事实了，我之前尝试在 Ubuntu/Debian 分别用 iptables/nftables 配置透明代理规则，试过了 mark 和 gid 等各种姿势，但不管怎么尝试总是会有流量出现回环，以及局域网设备流量不知去向的问题，所以索性省心一点用 Clash.Meta 内置的 TUN 模式来解决问题，同时相较于原版 Clash 也能够更好支持 VLESS 协议</p><span id="more"></span><p>基本的 Clash.Meta 配置文档在 <a class="link"   href="https://clash-meta.wiki/config/" >官网<i class="fas fa-external-link-alt"></i></a> 已经讲的比较清楚了，理论上来讲直接开启 TUN 就可以实现透明代理了，不过因为官网的文档基本上是针对单网口上网设备（比如手机、平板和 PC 之类）写的，对于多网口的路由器，还是有一些额外的配置需要注意</p><h1 id="内网-ip-出口"><a class="markdownIt-Anchor" href="#内网-ip-出口"></a> 内网 IP 出口</h1><p>在非网关单网口设备上，无论是访问 192.168.1.x 还是 114.114.114.114，出口的网卡都是同一个，那么 TUN 配置好 <code>auto-detect-interface: true</code> 一般就不会有什么大问题；对于路由器而言，就需要进行如下配置</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">interface-name:</span> <span class="string">ppp0</span></span><br><span class="line"></span><br><span class="line"><span class="attr">proxy-groups:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">LAN</span></span><br><span class="line">    <span class="attr">type:</span> <span class="string">select</span></span><br><span class="line">    <span class="attr">interface-name:</span> <span class="string">br0</span></span><br><span class="line">    <span class="attr">proxies:</span> [<span class="string">DIRECT</span>]</span><br><span class="line">  <span class="comment"># other groups</span></span><br><span class="line"></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">GEOIP,lan,LAN</span></span><br><span class="line">  <span class="comment"># other rules</span></span><br></pre></td></tr></table></figure><p>和上一篇文章一样，双网口设备 <code>br0</code> 需要改成对应 lan 接口名</p><h1 id="tun-协议栈的选择"><a class="markdownIt-Anchor" href="#tun-协议栈的选择"></a> TUN 协议栈的选择</h1><p>理论上来说对于 linux 系统，选择默认的 <code>stack: system</code> 就可以了，不过在我的测试过程中发现了一个很奇怪的问题：保持其他配置不变的情况下，使用 <code>system</code> 协议栈会导致小爱音箱出现“网络服务遇到问题”的错误提示；而换用 <code>gvisor</code> 则一切正常。目前尚未 Google 到相关的具体原因，Clash.Meta 的日志也比较正常看不出端倪，实际使用下来两种协议栈资源的消耗并没有很大区别，并且也都能够轻松跑满带宽，所以直接选用 <code>gvisor</code> 作为协议栈</p><h1 id="网段分组策略代理"><a class="markdownIt-Anchor" href="#网段分组策略代理"></a> 网段分组策略代理</h1><p>总有一些设备是完全不需要代理的（在 TUN 模式下直连流量还是会走一遍 Clash.Meta，不过问题不大），通过 dnsmasq 进行 mac ip 绑定，划分更小的网段</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># rule-proxy, 192.168.1.0/24</span><br><span class="line">dhcp-host=11:22:33:44:55:66,192.168.1.100 # phone1</span><br><span class="line">dhcp-host=77:88:99:aa:bb:cc,192.168.1.101 # pc1</span><br><span class="line"></span><br><span class="line"># direct, 192.168.2.0/24</span><br><span class="line">dhcp-host=66:55:44:33:22:11,192.168.2.100 # device1</span><br><span class="line">dhcp-host=cc:bb:aa:99:88:77,192.168.2.101 # device2</span><br></pre></td></tr></table></figure><p>然后 Clash.Meta 的规则就可以写成</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">rules:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">GEOIP,lan,LAN</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">SRC-IP-CIDR,192.168.2.0/24,DIRECT</span></span><br><span class="line">  <span class="comment"># other rules</span></span><br></pre></td></tr></table></figure><h1 id="docker-与健康检查"><a class="markdownIt-Anchor" href="#docker-与健康检查"></a> Docker 与健康检查</h1><p>使用 Docker Compose 来部署 Clash.Meta 会非常方便快捷</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">clash:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">clash</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">metacubex/clash-meta</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">network_mode:</span> <span class="string">host</span></span><br><span class="line">    <span class="attr">cap_add:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">NET_ADMIN</span></span><br><span class="line">    <span class="attr">devices:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/dev/net/tun:/dev/net/tun</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/path/to/clash_config:/root/.config/clash</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">CMD-SHELL</span>, <span class="string">&#x27;wget -O /dev/null google.com&#x27;</span>]</span><br></pre></td></tr></table></figure><p>这样 <code>docker stop clash</code> 和 <code>docker restart clash</code> 就能非常方便终止和重启服务，由于 <code>metacubex/clash-meta</code> 基于 <code>busybox</code> 镜像，本身就有 <code>wget</code> 命令可用于健康检查。<code>/dev/net/tun</code> 的设备映射和 <code>NET_ADMIN</code> 的权限是必不可少的（除非想要自己手动改路由表）</p>]]>
    </content>
    <id>https://ecl.me/2023/04/22/debian-router-enable-tun/</id>
    <link href="https://ecl.me/2023/04/22/debian-router-enable-tun/"/>
    <published>2023-04-22T14:39:06.000Z</published>
    <summary>
      <![CDATA[<p>之前用 OpenWrt 的时候比较省心，装一个 Passwall(2) 之类的插件就可以实现透明代理，原理说白了也就是通过 tproxy 和一些 iptables 的重定向规则。iptables 这个东西难用已经是不争的事实了，我之前尝试在 Ubuntu/Debian 分别用 iptables/nftables 配置透明代理规则，试过了 mark 和 gid 等各种姿势，但不管怎么尝试总是会有流量出现回环，以及局域网设备流量不知去向的问题，所以索性省心一点用 Clash.Meta 内置的 TUN 模式来解决问题，同时相较于原版 Clash 也能够更好支持 VLESS 协议</p>]]>
    </summary>
    <title>Debian 软路由实现透明代理</title>
    <updated>2026-02-22T16:28:25.714Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="Debian" scheme="https://ecl.me/tags/Debian/"/>
    <category term="软路由" scheme="https://ecl.me/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
    <category term="IPv6" scheme="https://ecl.me/tags/IPv6/"/>
    <content>
      <![CDATA[<p>前段时间入手了一台四网口 x86 小主机，然后就开始折腾 All in Boom。一开始我尝试过 PVE + 爱快 + OpenWrt + Ubuntu，也尝试过直接在爱快中使用虚拟机装 OpenWrt + Ubuntu，甚至尝试过 Ubuntu + Openwrt in Docker。终结果都不太理想，所以决定下来直接在 Debian 里实现路由器常规功能，然以在 Docker 里实现各种附加需求</p><span id="more"></span><h1 id="为什么选择-debian-做路由器"><a class="markdownIt-Anchor" href="#为什么选择-debian-做路由器"></a> 为什么选择 Debian 做路由器</h1><p>网上能够搜到的大多数文章都是从 ESXi 或者 PVE 开始，且不说前者本身就是闭源收费软件，他的最新版本（8.x）目前似乎并没有方法集成螃蟹网卡驱动，所以直接放弃掉；选 PVE 吧，那他本质上就是个 Debian + KVM + LXC，虚拟机尽管可以 PCI 硬件直通仍然比不上裸机来的丝滑顺畅，再加上还有个我几乎用不上的 LXC（毕竟 Docker Hub 还算是个好东西），所以真还不如 Debian 然后自己装 qemu-kvm 来的痛快（其实我确实也这么试过）；然后爱快虚拟机就更拉了，不能硬件直通导致我的硬盘读写速度不及网络带宽的一半</p><p>其实吧 Ubuntu 也没啥问题，甚至还自带了螃蟹网卡的驱动，就是吧它还自带一些额外的显卡驱动，让我在 4k 屏上看比蚂蚁还小的字快看瞎了，其次就是 netplan 用起来也并不那么顺手，再者吧就是 snap 我不喜欢（虽然可以卸载啦）</p><h1 id="安装前的准备"><a class="markdownIt-Anchor" href="#安装前的准备"></a> 安装前的准备</h1><p>因为装机意味着暂时性的断网，我又不想来回在弱电箱里把线接来接去，所以索性先下载好跟网络连接有关的依赖。对于 Debian 11 而言，除了下载 DVD installer 这个 iso 之外，还需要提前准备好 bridge-utils, libpcap0.8, ppp, pppoeconf 这几个 deb（libpcap0.8 是 ppp 的依赖，如果是双网卡机器那 bridge-utils 不需要），在写入移动盘后复制进去（还是推荐在 Windows 下用 Rufus 制作安装盘，dd 命令写特别是在 mac 里会导致后面无法复制文件），对于我这种螃蟹网卡的机器，除了上面的 deb 还需要额外准备一个 firmware-realtek 的包</p><h1 id="debian-安装过程"><a class="markdownIt-Anchor" href="#debian-安装过程"></a> Debian 安装过程</h1><p>略，注意安装时勾选上 openssh server 和基本系统就行，另外就是如果选中文，之后进系统会有无中文字体而导致的乱码问题，虽然 ssh 后就无所谓，但在局域网弄好之前可能会比较折磨</p><h1 id="组建局域网"><a class="markdownIt-Anchor" href="#组建局域网"></a> 组建局域网</h1><p>首先 <code>apt install ./*.deb</code> 把之前准备好的 deb 都装好，然后 <code>ip a</code> 确定一下自己网卡的命名，像我的机器四个网口按顺序依次是 <code>enp2s0</code>, <code>eno1</code>, <code>enp4s0</code>, <code>enp5s0</code>，当然是选择与众不同的那一个作为 wan 口，其他的桥接起来，<code>vim.basic /etc/network/interfaces</code> 编辑一下文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">auto lo</span><br><span class="line">iface lo inet loopback</span><br><span class="line"></span><br><span class="line">auto eno1</span><br><span class="line">iface eno1 inet manual</span><br><span class="line"></span><br><span class="line">auto br0</span><br><span class="line">iface br0 inet static</span><br><span class="line">  address 192.168.1.1</span><br><span class="line">  netmask 255.255.255.0</span><br><span class="line">  bridge-ports enp2s0 enp4s0 enp5s0</span><br></pre></td></tr></table></figure><p>双网卡的话 <code>bridge-ports</code> 那一行去掉然后 <code>br0</code> 改成对应 lan 接口名就行，之后 <code>/etc/t.d/networking restart</code> 重启一下网络，如果有需要 root 密码直接 ssh 的可能需要改一下 <code>/etc/ssh/sshd_config</code> 的配置，但我是提前准备好了 <code>~/.ssh/authorized_keys</code> 就无所谓这个</p><p>之后选一个 lan 口连电脑上，ip 改成路由器同网段就好，不出意外的话应该就能 ssh 进去了，我一般都是直接用 root 用户，没有 GUI 的系统基本上乱搞不坏</p><h1 id="公网连接-路由功能完善"><a class="markdownIt-Anchor" href="#公网连接-路由功能完善"></a> 公网连接 &amp; 路由功能完善</h1><p>一个基础的路由器需要实现拨号、DHCP 服务器、网关这三个基本功能，因为目前运营商基本都支持了 IPv6 所以与之相关的也需要进行一些额外的配置</p><h2 id="配置拨号上网"><a class="markdownIt-Anchor" href="#配置拨号上网"></a> 配置拨号上网</h2><p>这个比较简单，<code>pppoeconf</code> 之后按照提示操作就可以，除了输入账号密码基本上一路 yes 就行，不出意外的话再 <code>ip a</code> 就能看到名为 ppp0 的网卡以及运营商分配的 ip 了，这一步之后机器应该可以正常联网了，换用 <a class="link"   href="https://mirrors.tuna.tsinghua.edu.cn/help/debian/" >清华源<i class="fas fa-external-link-alt"></i></a> 这些也可以搞一下了</p><h2 id="启用网关ipv4-nat-和-ipv6-转发"><a class="markdownIt-Anchor" href="#启用网关ipv4-nat-和-ipv6-转发"></a> 启用网关（IPv4 NAT 和 IPv6 转发）</h2><h3 id="开启转发"><a class="markdownIt-Anchor" href="#开启转发"></a> 开启转发</h3><p>编辑 <code>/etc/sysctl.conf</code>，追加内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">net.ipv4.ip_forward=1</span><br><span class="line">net.ipv6.conf.all.forwarding=1</span><br><span class="line">net.ipv6.conf.default.accept_ra=2</span><br></pre></td></tr></table></figure><h3 id="配置-nat"><a class="markdownIt-Anchor" href="#配置-nat"></a> 配置 NAT</h3><p>因为 Debian 11 自带了 nftables 所以直接编辑 <code>/etc/nftables.conf</code> 追加以下内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">table ip nat &#123;</span><br><span class="line">chain postrouting &#123;</span><br><span class="line">type nat hook postrouting priority srcnat;</span><br><span class="line">oifname &#123; ppp0 &#125; masquerade</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后再 <code>systemctl enable --now nftables</code> 启用 nftables，不出意外的话如果电脑上手动配置好了网关和 DNS 服务器，就已经可以上网了，但此时机器还拿不到 IPv6 地址，而且不可能所有设备都手动配置这些信息，所以需要 DHCP 服务器</p><h2 id="ipv6-pd-获取"><a class="markdownIt-Anchor" href="#ipv6-pd-获取"></a> IPv6-PD 获取</h2><p>运行 <code>apt install -y wide-dhcpv6-client</code> 安装 dhcp6c，由于这个包最近一次更新是在 08 年，原来 init.d 那一套服务机制已经不太好使了，需要先手动 <code>systemctl disable wide-dhcpv6-client</code> 停掉老服务，然后编辑 <code>/etc/wide-dhcpv6/dhcp6c.conf</code> 文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">interface ppp0 &#123;</span><br><span class="line">send ia-pd 0;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">id-assoc pd 0 &#123;</span><br><span class="line">prefix-interface br0 &#123;</span><br><span class="line">sla-len 0;</span><br><span class="line">ifid 0;</span><br><span class="line">&#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>双网口机器的话 <code>br0</code> 换成 lan 接口名，然后手动创建服务 <code>/etc/systemd/system/dhcp6c.service</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Wide DHCPv6 Client</span><br><span class="line">After=network-online.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">ExecStart=/usr/sbin/dhcp6c -Df ppp0</span><br><span class="line">ExecReload=/bin/kill -HUP $MAINPID</span><br><span class="line">Restart=on-failure</span><br><span class="line">RestartSec=3</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><p>这样 <code>systemctl enable --now dhcp6c</code> 就可以保证它能够开机自启并失败重试了（因为 ppp0 的创建会比较晚，如果不能失败重试大概率会因为找不到 ppp0 而直接 fail），不出意外的话再次 <code>ip a</code> 应该能看到 lan 口对应的 IPv6 前缀了</p><h2 id="dhcp-slaac-服务搭建"><a class="markdownIt-Anchor" href="#dhcp-slaac-服务搭建"></a> DHCP / SLAAC 服务搭建</h2><p>首先 <code>apt install -y dnsmasq</code>，然后再编辑 <code>/etc/dnsmasq.conf</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">interface=br0</span><br><span class="line">port=53</span><br><span class="line">server=223.5.5.5</span><br><span class="line">server=119.29.29.29</span><br><span class="line">enable-ra</span><br><span class="line">dhcp-range=192.168.1.100,192.168.1.255</span><br><span class="line">dhcp-range=::1001,::10ff,constructor:br0</span><br></pre></td></tr></table></figure><p>同样的如果双网口 <code>br0</code> 改成对应 lan 接口名，然后 <code>systemctl enable --now dnsmasq</code>，再把电脑上的之前手动分配的 IP 改成全部自动获取应该就能看到路由器分配的 v4 和 v6 地址了。上面的配置写法告诉 dnsmasq 在通告里启用 M 和 O 标记用于分配 Stateful 地址，如果希望同时使用 Stateless 地址在 <code>constructor:br0</code> 后面加上 <code>,slaac</code> 即可。上面例子里只启用有状态地址分配是为了能够固定设备 IP 的后缀：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dhcp-host=11:22:33:44:55:66,192.168.1.10,[::10a] # device1</span><br><span class="line">dhcp-host=77:88:99:aa:bb:cc,192.168.1.15,[::10f] # device2</span><br></pre></td></tr></table></figure><h1 id="接下来"><a class="markdownIt-Anchor" href="#接下来"></a> 接下来</h1><p>这里还是推荐重启一下机器，确保一下所有路由基础功能都已经 OK。当然如果仅仅止步于此那么一台硬路由足够了，既然选择使用软路由，自然是需要有更多的折腾（比如透明代理，再比如媒体服务器，智能家居控制中心等），这个在后续文章里记录</p>]]>
    </content>
    <id>https://ecl.me/2023/04/22/use-debian-as-router/</id>
    <link href="https://ecl.me/2023/04/22/use-debian-as-router/"/>
    <published>2023-04-22T10:02:55.000Z</published>
    <summary>
      <![CDATA[<p>前段时间入手了一台四网口 x86 小主机，然后就开始折腾 All in Boom。一开始我尝试过 PVE + 爱快 + OpenWrt + Ubuntu，也尝试过直接在爱快中使用虚拟机装 OpenWrt + Ubuntu，甚至尝试过 Ubuntu + Openwrt in Docker。终结果都不太理想，所以决定下来直接在 Debian 里实现路由器常规功能，然以在 Docker 里实现各种附加需求</p>]]>
    </summary>
    <title>使用 Debian 搭建软路由</title>
    <updated>2026-02-22T16:28:25.730Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="博客折腾记录" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE%E8%AE%B0%E5%BD%95/"/>
    <category term="Vercel" scheme="https://ecl.me/tags/Vercel/"/>
    <category term="Hexo" scheme="https://ecl.me/tags/Hexo/"/>
    <category term="Cloudflare Pages" scheme="https://ecl.me/tags/Cloudflare-Pages/"/>
    <category term="Valine" scheme="https://ecl.me/tags/Valine/"/>
    <content>
      <![CDATA[<p>拖了一个月，也终于是想起来记录一下了</p><p>除了标题中提到的博客迁移之外，顺带说一说评论系统的比对选择，安全加固</p><p>另外还会提到 Vercel, Cloudflare Pages 等的对比使用感受</p><span id="more"></span><h1 id="背景"><a class="markdownIt-Anchor" href="#背景"></a> 背景</h1><p>由于不想继续负担高昂的香港云服务器费用，于是需要将我原来一堆线上的东西部署到别的地方，其中比较<s>重要</s>的就是博客了。宗旨是能白嫖尽量不花钱，另外也需要尽量保证线上服务的境内可用性</p><h1 id="方案选择"><a class="markdownIt-Anchor" href="#方案选择"></a> 方案选择</h1><p>市面上主流的方案：Github Pages, Vercel, Cloudflare Pages</p><p>先说 Github Pages，在我 student pack 到期之前，我就用的是私有仓库 + Github Pages + Cloudflare CDN 的方案，后来到期了无法白嫖，才转战的云服务器。另外由于 Cloudflare CDN 免费版的不稳定性，其实并不能很好的保证大陆地区顺畅访问，而我又不想将私有仓库转为公开，故直接放弃 Github Pages 方案</p><p>Vercel 的话实测下来访问速度还是很不错的，还有 Serverless Function 可以用，于是博客迁移就选择了 Vercel</p><p>Cloudflare Pages 相对于 Vercel 文档资源都会少一些，摸索起来会比较麻烦，不过我的另一个服务也尝试用了它，并且在 <a class="link"   href="https://github.com/doveccl/MusicBox" >Github<i class="fas fa-external-link-alt"></i></a> 上开源了（主要还是存个档便于以后有需求直接当参考，项目本身没啥意义）</p><h1 id="typecho-迁移到-hexo"><a class="markdownIt-Anchor" href="#typecho-迁移到-hexo"></a> Typecho 迁移到 Hexo</h1><p>主要是迁移文章和评论，最后评论选择 Valine（主要是这个主题只支持 Valine），网上能找的备份迁移工具效果不如人意，就自己弄了一个迁移一下数据</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> md5 <span class="keyword">from</span> <span class="string">&#x27;md5&#x27;</span></span><br><span class="line"><span class="keyword">import</span> moment <span class="keyword">from</span> <span class="string">&#x27;moment&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="variable constant_">AV</span> <span class="keyword">from</span> <span class="string">&#x27;leancloud-storage&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; promises &#125; <span class="keyword">from</span> <span class="string">&#x27;fs&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; promisify &#125; <span class="keyword">from</span> <span class="string">&#x27;util&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; createConnection &#125; <span class="keyword">from</span> <span class="string">&#x27;mysql&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dsn = <span class="string">&#x27;mysql://root:pass@localhost/typecho?charset=utf8mb4&#x27;</span></span><br><span class="line"><span class="variable constant_">AV</span>.<span class="title function_">init</span>(&#123;</span><br><span class="line">  <span class="attr">appId</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">  <span class="attr">appKey</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">  <span class="attr">serverURL</span>: <span class="string">&#x27;https://api.lncldglobal.com&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> conn = <span class="title function_">createConnection</span>(dsn)</span><br><span class="line"><span class="keyword">const</span> query = <span class="title function_">promisify</span>(conn.<span class="property">query</span>.<span class="title function_">bind</span>(conn))</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> metas = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">&#x27;select * from metas&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> contents = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">&#x27;select * from contents&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> comments = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">&#x27;select * from comments&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> relationships = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">&#x27;select * from relationships&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">await</span> promises.<span class="title function_">mkdir</span>(<span class="string">&#x27;./backup/raw&#x27;</span>, &#123; <span class="attr">recursive</span>: <span class="literal">true</span> &#125;)</span><br><span class="line"><span class="keyword">await</span> promises.<span class="title function_">writeFile</span>(<span class="string">&#x27;./backup/raw/metas.json&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(metas, <span class="literal">null</span>, <span class="number">2</span>))</span><br><span class="line"><span class="keyword">await</span> promises.<span class="title function_">writeFile</span>(<span class="string">&#x27;./backup/raw/contents.json&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(contents, <span class="literal">null</span>, <span class="number">2</span>))</span><br><span class="line"><span class="keyword">await</span> promises.<span class="title function_">writeFile</span>(<span class="string">&#x27;./backup/raw/comments.json&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(comments, <span class="literal">null</span>, <span class="number">2</span>))</span><br><span class="line"><span class="keyword">await</span> promises.<span class="title function_">writeFile</span>(<span class="string">&#x27;./backup/raw/relationships.json&#x27;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(relationships, <span class="literal">null</span>, <span class="number">2</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> tags = <span class="keyword">new</span> <span class="title class_">Map</span></span><br><span class="line"><span class="keyword">const</span> cats = <span class="keyword">new</span> <span class="title class_">Map</span></span><br><span class="line">metas.<span class="title function_">forEach</span>(<span class="function"><span class="params">m</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (m.<span class="property">type</span> === <span class="string">&#x27;tag&#x27;</span>)</span><br><span class="line">    tags.<span class="title function_">set</span>(m.<span class="property">mid</span>, m)</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    cats.<span class="title function_">set</span>(m.<span class="property">mid</span>, m)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> paths = <span class="keyword">new</span> <span class="title class_">Map</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Counter</span> = <span class="variable constant_">AV</span>.<span class="property">Object</span>.<span class="title function_">extend</span>(<span class="string">&#x27;Counter&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">const</span> c <span class="keyword">of</span> contents) &#123;</span><br><span class="line">  <span class="keyword">await</span> promises.<span class="title function_">mkdir</span>(<span class="string">`./backup/<span class="subst">$&#123;c.type&#125;</span>s`</span>, &#123; <span class="attr">recursive</span>: <span class="literal">true</span> &#125;)</span><br><span class="line">  <span class="keyword">const</span> rs = relationships.<span class="title function_">filter</span>(<span class="function"><span class="params">r</span> =&gt;</span> c.<span class="property">cid</span> === r.<span class="property">cid</span>)</span><br><span class="line">  promises.<span class="title function_">writeFile</span>(<span class="string">`./backup/<span class="subst">$&#123;c.type&#125;</span>s/<span class="subst">$&#123;c.slug&#125;</span>.md`</span>,</span><br><span class="line"><span class="string">`---</span></span><br><span class="line"><span class="string">title: <span class="subst">$&#123;c.title&#125;</span></span></span><br><span class="line"><span class="string">date: <span class="subst">$&#123;moment(<span class="number">1000</span> * c.created).format(<span class="string">&#x27;YYYY-MM-DD HH:mm:ss&#x27;</span>)&#125;</span></span></span><br><span class="line"><span class="string">updated: <span class="subst">$&#123;moment(<span class="number">1000</span> * c.modified).format(<span class="string">&#x27;YYYY-MM-DD HH:mm:ss&#x27;</span>)&#125;</span></span></span><br><span class="line"><span class="string">categories: [<span class="subst">$&#123;rs.filter(r =&gt; cats.has(r.mid)).map(r =&gt; cats.get(r.mid).name).join(<span class="string">&#x27;, &#x27;</span>)&#125;</span>]</span></span><br><span class="line"><span class="string">tags: [<span class="subst">$&#123;rs.filter(r =&gt; tags.has(r.mid)).map(r =&gt; tags.get(r.mid).name).join(<span class="string">&#x27;, &#x27;</span>)&#125;</span>]</span></span><br><span class="line"><span class="string">---</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"><span class="subst">$&#123;c.text.replace(<span class="string">&#x27;&lt;!--markdown--&gt;&#x27;</span>, <span class="string">&#x27;&#x27;</span>).replace(/\r\n/g, <span class="string">&#x27;\n&#x27;</span>)&#125;</span>`</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> path = c.<span class="property">type</span> === <span class="string">&#x27;page&#x27;</span> ?</span><br><span class="line">    <span class="string">`<span class="subst">$&#123;c.slug&#125;</span>.html`</span> :</span><br><span class="line">    <span class="string">`<span class="subst">$&#123;moment(<span class="number">1000</span> * c.created).format(<span class="string">&#x27;YYYY/MM/DD&#x27;</span>)&#125;</span>/<span class="subst">$&#123;c.slug&#125;</span>.html`</span></span><br><span class="line">  paths.<span class="title function_">set</span>(c.<span class="property">cid</span>, path)</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;insert views&#x27;</span>, path, c.<span class="property">views</span>)</span><br><span class="line">  <span class="keyword">const</span> o = <span class="keyword">new</span> <span class="title class_">Counter</span>()</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;time&#x27;</span>, c.<span class="property">views</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;title&#x27;</span>, c.<span class="property">title</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;url&#x27;</span>, path)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;xid&#x27;</span>, path)</span><br><span class="line">  <span class="keyword">await</span> o.<span class="title function_">save</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> coidObj = <span class="keyword">new</span> <span class="title class_">Map</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Comment</span> = <span class="variable constant_">AV</span>.<span class="property">Object</span>.<span class="title function_">extend</span>(<span class="string">&#x27;Comment&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">const</span> c <span class="keyword">of</span> comments) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;insert comment&#x27;</span>, c.<span class="property">author</span>, c.<span class="property">text</span>)</span><br><span class="line">  <span class="keyword">const</span> o = <span class="keyword">new</span> <span class="title class_">Comment</span>()</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;comment&#x27;</span>, c.<span class="property">text</span>.<span class="title function_">replace</span>(<span class="regexp">/\r/</span>, <span class="string">&#x27;&#x27;</span>))</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;date&#x27;</span>, <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="number">1000</span> * c.<span class="property">created</span>))</span><br><span class="line">  c.<span class="property">ip</span> &amp;&amp; o.<span class="title function_">set</span>(<span class="string">&#x27;ip&#x27;</span>, c.<span class="property">ip</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;link&#x27;</span>, c.<span class="property">url</span> ?? <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;mail&#x27;</span>, c.<span class="property">mail</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;mailMd5&#x27;</span>, <span class="title function_">md5</span>(c.<span class="property">mail</span>))</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;nick&#x27;</span>, c.<span class="property">author</span>)</span><br><span class="line">  <span class="keyword">if</span> (c.<span class="property">parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> p = coidObj.<span class="title function_">get</span>(c.<span class="property">parent</span>)</span><br><span class="line">    o.<span class="title function_">set</span>(<span class="string">&#x27;pid&#x27;</span>, p.<span class="title function_">getObjectId</span>())</span><br><span class="line">    o.<span class="title function_">set</span>(<span class="string">&#x27;rid&#x27;</span>, p.<span class="title function_">get</span>(<span class="string">&#x27;rid&#x27;</span>) || p.<span class="title function_">getObjectId</span>())</span><br><span class="line">  &#125;</span><br><span class="line">  c.<span class="property">agent</span> &amp;&amp; o.<span class="title function_">set</span>(<span class="string">&#x27;ua&#x27;</span>, c.<span class="property">agent</span>)</span><br><span class="line">  o.<span class="title function_">set</span>(<span class="string">&#x27;url&#x27;</span>, paths.<span class="title function_">get</span>(c.<span class="property">cid</span>))</span><br><span class="line">  coidObj.<span class="title function_">set</span>(c.<span class="property">coid</span>, <span class="keyword">await</span> o.<span class="title function_">save</span>())</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">process.<span class="title function_">exit</span>(<span class="number">0</span>)</span><br></pre></td></tr></table></figure><h1 id="valine-的安全加固"><a class="markdownIt-Anchor" href="#valine-的安全加固"></a> Valine 的安全加固</h1><p>由于众所周知的 <a class="link"   href="https://imnerd.org/valine-may-not-so-good.html" >安全问题<i class="fas fa-external-link-alt"></i></a>，直接使用肯定是问题比较大的，加之不太想去改主题的代码来换用评论系统，于是就借助 Vercel 来实现一个 api 的代理层，实际的 secret 这些并不写在前端，并且对一些写逻辑做更细粒度的权限管控</p><p>方法也很简单，首先将 Valine 的 <code>serverURLs</code> 配置改成 <code>/api/</code>, 这样所有评论和阅读统计的请求都会走到同域名 <code>/api/*</code>, 然后代理要用到的接口就好了，这里需要在 <code>vercel.json</code> 里预先加一条路由重写规则</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;rewrites&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/api/1.1/classes/Counter/:id&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;destination&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/api/1.1/classes/Counter&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>然后在 Vercel 的后台配置好 <code>LEAN_API</code>, <code>LEAN_ID</code>, <code>LEAN_KEY</code> 这些的环境变量</p><p>最后分别实现评论和阅读接口即可</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">VercelRequest</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@vercel/node&#x27;</span></span><br><span class="line"></span><br><span class="line">axios.<span class="property">defaults</span>.<span class="property">validateStatus</span> = <span class="function"><span class="params">s</span> =&gt;</span> s &lt; <span class="number">500</span></span><br><span class="line">axios.<span class="property">defaults</span>.<span class="property">baseURL</span> = process.<span class="property">env</span>.<span class="property">LEAN_API</span></span><br><span class="line">axios.<span class="property">defaults</span>.<span class="property">headers</span>.<span class="property">common</span>[<span class="string">&#x27;X-LC-Id&#x27;</span>] = process.<span class="property">env</span>.<span class="property">LEAN_ID</span> ?? <span class="string">&#x27;&#x27;</span></span><br><span class="line">axios.<span class="property">defaults</span>.<span class="property">headers</span>.<span class="property">common</span>[<span class="string">&#x27;X-LC-Key&#x27;</span>] = process.<span class="property">env</span>.<span class="property">LEAN_KEY</span> ?? <span class="string">&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">proxy</span>(<span class="params"><span class="attr">req</span>: <span class="title class_">VercelRequest</span></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> [path] = req.<span class="property">url</span>?.<span class="title function_">split</span>(<span class="string">&#x27;?&#x27;</span>) ?? [<span class="string">&#x27;&#x27;</span>]</span><br><span class="line">  <span class="keyword">return</span> (<span class="keyword">await</span> <span class="title function_">axios</span>(&#123;</span><br><span class="line">    <span class="attr">method</span>: req.<span class="property">method</span>,</span><br><span class="line">    <span class="attr">url</span>: path.<span class="title function_">replace</span>(<span class="regexp">/^\/api/</span>, <span class="string">&#x27;&#x27;</span>),</span><br><span class="line">    <span class="attr">params</span>: req.<span class="property">query</span>,</span><br><span class="line">    <span class="attr">data</span>: req.<span class="property">body</span></span><br><span class="line">  &#125;)).<span class="property">data</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="keyword">type</span> &#123; <span class="title class_">VercelResponse</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@vercel/node&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">desensitize</span>(<span class="params"><span class="attr">res</span>: <span class="title class_">VercelResponse</span>, <span class="attr">data</span>: <span class="title class_">Record</span>&lt;<span class="built_in">string</span>, <span class="built_in">unknown</span>&gt;</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; results &#125; = data</span><br><span class="line">  <span class="title class_">Array</span>.<span class="title function_">isArray</span>(results) &amp;&amp; results.<span class="title function_">forEach</span>(<span class="function"><span class="params">r</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">delete</span> r.<span class="property">ip</span></span><br><span class="line">    <span class="keyword">delete</span> r.<span class="property">mail</span></span><br><span class="line">    <span class="keyword">if</span> (r.<span class="property">date</span>?.<span class="property">iso</span>) &#123;</span><br><span class="line">      r.<span class="property">createdAt</span> = r.<span class="property">date</span>.<span class="property">iso</span></span><br><span class="line">      <span class="keyword">delete</span> r.<span class="property">date</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">  res.<span class="title function_">json</span>(data)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; proxy &#125; <span class="keyword">from</span> <span class="string">&#x27;./_proxy&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; desensitize &#125; <span class="keyword">from</span> <span class="string">&#x27;./_util&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">type</span> &#123; <span class="title class_">VercelRequest</span>, <span class="title class_">VercelResponse</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@vercel/node&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">async</span> <span class="keyword">function</span>(<span class="params"><span class="attr">req</span>: <span class="title class_">VercelRequest</span>, <span class="attr">res</span>: <span class="title class_">VercelResponse</span></span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (req.<span class="property">method</span> !== <span class="string">&#x27;GET&#x27;</span>) &#123;</span><br><span class="line">    res.<span class="title function_">json</span>(&#123; <span class="attr">code</span>: -<span class="number">405</span> &#125;)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> req.<span class="property">query</span>.<span class="property">cql</span> !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">    res.<span class="title function_">json</span>(&#123; <span class="attr">code</span>: -<span class="number">400</span> &#125;)</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!<span class="regexp">/^select /i</span>.<span class="title function_">test</span>(req.<span class="property">query</span>.<span class="property">cql</span>)) &#123;</span><br><span class="line">    res.<span class="title function_">json</span>(&#123; <span class="attr">code</span>: -<span class="number">403</span> &#125;)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="comment">// use date (if exists) insteadof createdAt</span></span><br><span class="line">    req.<span class="property">query</span>.<span class="property">cql</span> = req.<span class="property">query</span>.<span class="property">cql</span>.<span class="title function_">replace</span>(<span class="regexp">/^select /</span>, <span class="string">&#x27;select date, &#x27;</span>)</span><br><span class="line">    <span class="title function_">desensitize</span>(res, <span class="keyword">await</span> <span class="title function_">proxy</span>(req))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; proxy &#125; <span class="keyword">from</span> <span class="string">&#x27;../_proxy&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">type</span> &#123; <span class="title class_">VercelRequest</span>, <span class="title class_">VercelResponse</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@vercel/node&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">async</span> <span class="keyword">function</span>(<span class="params"><span class="attr">req</span>: <span class="title class_">VercelRequest</span>, <span class="attr">res</span>: <span class="title class_">VercelResponse</span></span>) &#123;</span><br><span class="line">  <span class="comment">// GET ?where=&#123;url,...&#125;&amp;count=1&amp;limit=0</span></span><br><span class="line">  <span class="comment">// POST ? &#123;url,nick,mail,ip,ua,...&#125;</span></span><br><span class="line">  <span class="keyword">if</span> (req.<span class="property">method</span> === <span class="string">&#x27;GET&#x27;</span>) &#123;</span><br><span class="line">    req.<span class="property">query</span>.<span class="property">count</span> = <span class="string">&#x27;1&#x27;</span></span><br><span class="line">    req.<span class="property">query</span>.<span class="property">limit</span> = <span class="string">&#x27;0&#x27;</span></span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (req.<span class="property">method</span> === <span class="string">&#x27;POST&#x27;</span>) &#123;</span><br><span class="line">    req.<span class="property">body</span>.<span class="property">ip</span> = req.<span class="property">headers</span>[<span class="string">&#x27;x-real-ip&#x27;</span>]</span><br><span class="line">    req.<span class="property">body</span>.<span class="property">ua</span> = req.<span class="property">headers</span>[<span class="string">&#x27;user-agent&#x27;</span>]</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    res.<span class="title function_">json</span>(&#123; <span class="attr">code</span>: -<span class="number">405</span> &#125;)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  res.<span class="title function_">json</span>(<span class="keyword">await</span> <span class="title function_">proxy</span>(req))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; proxy &#125; <span class="keyword">from</span> <span class="string">&#x27;../_proxy&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">type</span> &#123; <span class="title class_">VercelRequest</span>, <span class="title class_">VercelResponse</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@vercel/node&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">async</span> <span class="keyword">function</span>(<span class="params"><span class="attr">req</span>: <span class="title class_">VercelRequest</span>, <span class="attr">res</span>: <span class="title class_">VercelResponse</span></span>) &#123;</span><br><span class="line">  <span class="comment">// GET ?where=&#123;url&#125;</span></span><br><span class="line">  <span class="comment">// POST ? &#123;url,time,...&#125;</span></span><br><span class="line">  <span class="comment">// PUT :id? &#123;time:&#123;__op:&#x27;Increment&#x27;,amount:1&#125;&#125;</span></span><br><span class="line">  <span class="keyword">if</span> (req.<span class="property">method</span> === <span class="string">&#x27;POST&#x27;</span>) &#123;</span><br><span class="line">    req.<span class="property">body</span>.<span class="property">time</span> = <span class="number">1</span></span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (req.<span class="property">method</span> === <span class="string">&#x27;PUT&#x27;</span>) &#123;</span><br><span class="line">    req.<span class="property">body</span> = &#123; <span class="attr">time</span>: &#123; <span class="attr">__op</span>: <span class="string">&#x27;Increment&#x27;</span>, <span class="attr">amount</span>: <span class="number">1</span> &#125; &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (req.<span class="property">method</span> !== <span class="string">&#x27;GET&#x27;</span>) &#123;</span><br><span class="line">    res.<span class="title function_">json</span>(&#123; <span class="attr">code</span>: -<span class="number">405</span> &#125;)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  res.<span class="title function_">json</span>(<span class="keyword">await</span> <span class="title function_">proxy</span>(req))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>换用这个主题之前，还尝试过其他的主题，不过也是中途放弃掉了</p><p>确实也算是比较折腾了，如果以后有空了自己搞主题的话，感觉 <a class="link"   href="https://twikoo.js.org/" >Twikoo<i class="fas fa-external-link-alt"></i></a> 就挺不错的</p><h1 id="vercel-与-cloudflare-pages-的对比"><a class="markdownIt-Anchor" href="#vercel-与-cloudflare-pages-的对比"></a> Vercel 与 Cloudflare Pages 的对比</h1><p>网上都说 Vercel 比较快，不过就我本地的网络测试来看，其实不管是选择哪个，速度都挺快的。不过 Vercel 免费版的运行时限，资源上限这些似乎都相对要多一些，所以做的事情自然也更多一些。Cloudflare Pages 的优势是免费版自带 kv 存储，虽然容量不大，但对我的需求而言是够用的，省去了自己折腾 leancloud 或者 dynamodb 这种东西</p><p>两者都提供了本地调试工具，不过用起来各有各的坑。比如 Vercel 我一直想重定向非 <code>/api</code> 开头请求到 <code>/api</code> 未果，遂放弃；再比如 Cloudflare Pages 我想直接在本地读取云端的 kv 数据未果，只能在本地 mock 一个假的</p><h1 id="最后"><a class="markdownIt-Anchor" href="#最后"></a> 最后</h1><p>其实当初用云服务器最重要的理由是自由上网，线上服务这些都是附属的东西，而且也很容易找到一些免费的替代品</p><p>后来仔细想想，其实只要有个正经工作，用公司给的 VPN 不就好了么（只要不浏览一些奇奇怪怪的网站</p><p>于是乎腾讯云给的大额优惠券也就让它自己过期好了</p>]]>
    </content>
    <id>https://ecl.me/2022/07/01/use-vercel-build-new-blog/</id>
    <link href="https://ecl.me/2022/07/01/use-vercel-build-new-blog/"/>
    <published>2022-06-30T17:18:53.000Z</published>
    <summary>
      <![CDATA[<p>拖了一个月，也终于是想起来记录一下了</p>
<p>除了标题中提到的博客迁移之外，顺带说一说评论系统的比对选择，安全加固</p>
<p>另外还会提到 Vercel, Cloudflare Pages 等的对比使用感受</p>]]>
    </summary>
    <title>迁移博客到 Vercel 的记录</title>
    <updated>2022-06-30T17:18:53.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="回忆" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E5%9B%9E%E5%BF%86/"/>
    <category term="高考" scheme="https://ecl.me/tags/%E9%AB%98%E8%80%83/"/>
    <content>
      <![CDATA[<p>本来是打算昨天写的，不过昨天折腾新的博客（这个后续有计划写一篇总结一下坑点），实在是比较晚了，于是就放到今天来写了</p><p>说起来也是有趣，今年高考亲戚里有两人参加，一个是表妹，一个是外甥（父母两边兄弟姐妹的年龄差确实大）</p><p>由于近些年来并不怎么关注高考，导致我下午还以为今天高考就结束了，还给我姐发了条信息说：“有人解放了”</p><span id="more"></span><p>后来经过提醒才意识到现在不分文理之后，原来的综合都拆分成了小科目单独考，两天变三天</p><p>下午上班的时候听同事提了一嘴今年数学很难，下班路上我姐也跟我说数学很难，可能比我那一年数学还难，于是我到家第一时间就把试卷搜出来瞄了一眼，可能确实是老了吧，居然第二道选择题就没看懂 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>z</mi><mo>+</mo><mover accent="true"><mi>z</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">z + \bar{z}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.56778em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.04398em;">z</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span> 那个 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>z</mi></mrow><annotation encoding="application/x-tex">z</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span></span></span></span> 上的横线的意思，后面第一道数列大题也只在纸上画了一小会就放弃了</p><p>高中的东西是确实忘得差不多了，仔细一算距离自己高考也过去七年了（谁能想到七年后的自己……），这些年也偶尔的有梦见自己回到高考前，嗯就是高考前而不是在考场上，大致内容大概是放弃武大的学业跑回去重新读高中（每次醒过来都在疑惑梦中的自己是个什么脑回路）</p><p>抖音上都在回忆 2018 年的夏天，诚然那一年的夏天也确实承载了我不少的回忆。不过我觉得 2015 年的夏天也同样值得回忆，既然是回忆，那就认真的回忆一下吧</p><h1 id="201504"><a class="markdownIt-Anchor" href="#201504"></a> 2015.04</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/06/zizhao.jpg"                        alt=""                  ></p><p>这个是当时搞自主招生填表时候的截图，当年是取消保送生考试的第二年，我们这些苦逼的竞赛生除非进了国家队保送清北，否则也就只能乖乖回来高考。虽然说当时临近高考，但还是“忙里偷闲”，晚自习开溜跑到竞赛机房玩电脑，说是玩电脑其实啥也没干，就反复开关着浏览器，总之就是<s>比备考有意思</s></p><h1 id="201505"><a class="markdownIt-Anchor" href="#201505"></a> 2015.05</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/06/tieba.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/zhihu.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/sjtu.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/history.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/whu.jpg"                        alt=""                  ></p><p>终日沉迷贴吧和知乎（顺便关注自主招生和过往分数线）</p><h1 id="201506"><a class="markdownIt-Anchor" href="#201506"></a> 2015.06</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/06/station.jpg"                        alt="交车站"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/desk.jpg"                        alt="清华 (THU)"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/class.jpg"                        alt="黑板报"                  ></p><p>陪伴了我三年的公交车站、刻了 THU 的我的课桌、考前最后一次黑板报。之后就再也没有进过这间教室了（大概吧）</p><p>考试第一天，上午语文没什么感觉，反正自己的语文也就那样吧；倒是下午数学，当广播响起“距离考试结束还有十五分钟”的时候，我的答题卡刚刚反面（嗯，有整三道大题没开始做），着实是把我吓得不轻，后来也是抱着完了要复读了的心态草草把那三题能写的都写了一通，后来出来考场发现大家脸色都不太对，回去之后空间、贴吧也到处是关于 15 湖北数学的段子，也才让我放心了一些（所以那年均分 66）</p><p>反倒是经过了第一天的洗礼，第二天考试都没啥感觉，感觉就是都还行，可能确实没有第一天数学给人那么深的印象吧。当然对于一个自招学生而言，高考结束并不代表着解放</p><p><img                         lazyload                       alt="image"                       data-src="/images/2022/06/mdc.jpg"                        alt="武汉站的麦当劳"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/ilovesh.jpg"                        alt="上海"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/sh-road.jpg"                        alt="上海的汉口路"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/whu-door.jpg"                        alt="武大正门"                  ></p><p>上面就是我奔波于上海武汉两地参加自主招生（没有去广州是因为华南理工的时间和武大冲突了，选了武大，不过最终还是和广州结缘）。也不知道为啥一张上交的门都没拍（好像 14 年去复旦参加夏令营也没拍复旦），可能就真的是去上海旅游了两次吧（之后 18 年去 Google 面试，算是第三次旅游，大概就是跟上海无缘）</p><p>不过有一说一，上交的计算机学科因为被分到了物理大类里，笔试题目全是物理竞赛，人都要做吐了，确实也没抱太大的指望；在武大的话笔试题目就让人亲切很多，纸上写代码是我高中数学课上玩烂了的把戏，最后面试也是关于 SSL 非对称加密那一块侃侃而谈（虽然不见得有多高明）。反正最终的结果就是不出意外的话武大的自招过了（但是仍需要等高考分数）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2022/06/qzone.jpg"                        alt="QQ空间"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/group.jpg"                        alt="QQ群"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/06/submit.jpg"                        alt="填志愿"                  ></p><p>分数出来的当天也是相当精彩，首先是 QQ 空间和群都炸开了锅（上图那个“去读武大算了”最后真的去了武大，不过后来他也成功去了清华）。我自己看到成绩，整个人都错愕了，真的出现了生理上的不适，明明大早上起来还没吃什么东西，就开始作呕。因为当时上午分数线还没有出来，大家只知道自己的分数，所以都不开心。中午呢，班级最后的聚餐，大家兴致也都不算高，下午去 KTV 唱歌也是（就不放图了）。反正是直到下午到家之后，才看到一本线出来的消息（通过武大自招后，当年政策是需要高过一本线 50 分才算成功），一颗悬着的心也才放了下来</p><h1 id="之后"><a class="markdownIt-Anchor" href="#之后"></a> 之后</h1><p>后面就是各种捣鼓 Linux PHP、去杭州玩、初中同学聚会、去张家界玩之类的事情了，因为文章主题是高考，就不再接着往后说了，以后有心情了再看（估计也没有，但那个暑假确实是很充实快乐，再往后的日子里真的找不到那种感觉了）</p><h1 id="最后"><a class="markdownIt-Anchor" href="#最后"></a> 最后</h1><p>人生嘛，多多少少都有一些遗憾，就像我课桌里的那个清华一样，头几年还觉得羞耻，现在看也能拿出来发文章了。但是那些流过的时间，却是真的再也回不来了，所以为什么不过的开心一点呢？（callback 一下上一篇文章）</p>]]>
    </content>
    <id>https://ecl.me/2022/06/08/memory-of-gaokao/</id>
    <link href="https://ecl.me/2022/06/08/memory-of-gaokao/"/>
    <published>2022-06-08T15:38:43.000Z</published>
    <summary>
      <![CDATA[<p>本来是打算昨天写的，不过昨天折腾新的博客（这个后续有计划写一篇总结一下坑点），实在是比较晚了，于是就放到今天来写了</p>
<p>说起来也是有趣，今年高考亲戚里有两人参加，一个是表妹，一个是外甥（父母两边兄弟姐妹的年龄差确实大）</p>
<p>由于近些年来并不怎么关注高考，导致我下午还以为今天高考就结束了，还给我姐发了条信息说：“有人解放了”</p>]]>
    </summary>
    <title>又是一年高考</title>
    <updated>2026-02-22T16:28:25.726Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="牢骚时间" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E7%89%A2%E9%AA%9A%E6%97%B6%E9%97%B4/"/>
    <content>
      <![CDATA[<p>又是一万年没有更新了，最近不管是工作上的，还是旁的，都有一些烦心事，难免会让人烦躁，甚至有些 emo，还是想通过写点什么来平复一下心中的情绪</p><p>我其实一直标榜自己是一个佛系的人，什么都能看得开，但也许也是太高估自己了，反正内在的情绪总是有的，而且可能还挺大，大概只是表露出来的比较少</p><span id="more"></span><p>工作上呢，虽然说互联网行业确实是进入了寒冬，好在我所在部门还是依然坚挺，身边倒也没听说过确切的裁员的消息；不过看着总有三三两两的同事主动走掉（谁又说不是资本家的小把戏呢），也不免有些物是人非的沧桑感。可能大厂也是一座围城吧，不由得让人想象着外面的世界</p><p>其实单纯工作上的事情倒也不足以让我有感而发，毕竟工作的不顺意也不是第一次的事情了，也还算每次都能找到一两个倾诉的对象；自己呢，也能想出“路漫漫其修远兮”、“不在一根树上吊死”这样的话来安慰自己。旁的事情呢，时而云淡风轻，时而又让人头大</p><p>原本呢，以为没那么复杂，可能还是把人性想得过于简单，可能是我自己想的过于简单。总之最后带来的结果就是，开始唯唯诺诺了，开始畏手畏脚了，开始怀疑、纠结、躁郁。这些呢，倾诉的对象少了，可能也就只能依靠自己，上面提到工作中安慰自己的话，可能在这里也同样适用吧</p><p>不爱听欢快的歌可能也是有些原因的，总感觉私下夜深人静的时候，自己的骨子里，透露出的都是一些负面的东西；说来可笑，还经常安慰别人，同样的话未必能够安慰自己</p><p>那也只能，写写东西听听歌来排遣一下了，希望在不久的将来，这些事情都不是事了吧</p>]]>
    </content>
    <id>https://ecl.me/2022/03/27/be-happy/</id>
    <link href="https://ecl.me/2022/03/27/be-happy/"/>
    <published>2022-03-27T07:25:53.000Z</published>
    <summary>
      <![CDATA[<p>又是一万年没有更新了，最近不管是工作上的，还是旁的，都有一些烦心事，难免会让人烦躁，甚至有些 emo，还是想通过写点什么来平复一下心中的情绪</p>
<p>我其实一直标榜自己是一个佛系的人，什么都能看得开，但也许也是太高估自己了，反正内在的情绪总是有的，而且可能还挺大，大概只是表露出来的比较少</p>]]>
    </summary>
    <title>要开心一点啦</title>
    <updated>2022-03-27T07:25:53.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="博客折腾记录" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE%E8%AE%B0%E5%BD%95/"/>
    <category term="Typecho" scheme="https://ecl.me/tags/Typecho/"/>
    <category term="SQLite3" scheme="https://ecl.me/tags/SQLite3/"/>
    <category term="PostgreSQL" scheme="https://ecl.me/tags/PostgreSQL/"/>
    <category term="MySQL" scheme="https://ecl.me/tags/MySQL/"/>
    <content>
      <![CDATA[<p>工作日大半夜发文……</p><p>背景是给服务器额外弄了块云数据盘，并且兴致冲冲格成了 XFS，于是就想装个 PostgreSQL 玩玩，顺便就想把一些项目原本放在 SQLite3 中的数据迁移到<s>正规</s>的数据库</p><span id="more"></span><p>本来下班前已经完成了 SQLite3 到 PostgreSQL 的迁移，但是发现博客里有些插件会在 sql 里写 <code>int(10)</code> 这种东西，然后在只认 <code>integer</code> 的 PostgreSQL 上就光荣挂掉了（其实主要影响了可以忽略不计的阅读量统计，以及评论发表，<s>虽然也没啥评论</s>）</p><p>想一想还是用 MySQL 吧。于是上手五年没碰过的 MySQL，上来就遇到 MySQL8 默认鉴权方式的坑，最后在 Google 的帮助下才把 root@localhost 的鉴权改成了老的方式让 php 能用</p><p>然后新的问题又出现了，SQLite3 生成的 dump 文件里表名、字段名都是双引号 <code>&quot;</code>，但是 MySQL 里只认 <code>`</code> 不认 <code>&quot;</code>，本来想写一个正则替换了事结果发现事情并没有那么简单：可能还是误改到了 values 里面的一些东西，反正最后直接是 php 报错了</p><p>索性就写个脚本逐条拷贝算了（需要先运行 install.php 生成表结构）：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> util = <span class="built_in">require</span>(<span class="string">&#x27;util&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> mysql = <span class="built_in">require</span>(<span class="string">&#x27;mysql&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> sqilte3 = <span class="built_in">require</span>(<span class="string">&#x27;sqlite3&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dbpath = <span class="string">&#x27;/data/www/blog/usr/blog.db&#x27;</span></span><br><span class="line"><span class="comment">/** <span class="doctag">@type</span> Promise&lt;sqilte3.Database&gt; */</span></span><br><span class="line"><span class="keyword">const</span> linkSqlite = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">res, rej</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> db = <span class="keyword">new</span> sqilte3.<span class="title class_">Database</span>(dbpath, <span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">    err ? <span class="title function_">rej</span>(err) : <span class="title function_">res</span>(db)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> con = mysql.<span class="title function_">createConnection</span>(&#123;</span><br><span class="line">  <span class="attr">user</span>: <span class="string">&#x27;root&#x27;</span>,</span><br><span class="line">  <span class="attr">database</span>: <span class="string">&#x27;typecho&#x27;</span>,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> query = util.<span class="title function_">promisify</span>(con.<span class="property">query</span>.<span class="title function_">bind</span>(con))</span><br><span class="line"><span class="keyword">const</span> connect = util.<span class="title function_">promisify</span>(<span class="params">con.connect.bind(con)</span>)</span><br><span class="line"></span><br><span class="line">&#123;(<span class="title function_">async</span> () =&gt; &#123;</span><br><span class="line">  <span class="keyword">await</span> <span class="title function_">connect</span>()</span><br><span class="line">  <span class="keyword">const</span> lite = <span class="keyword">await</span> linkSqlite</span><br><span class="line">  <span class="keyword">const</span> all = util.<span class="title function_">promisify</span>(lite.<span class="property">all</span>.<span class="title function_">bind</span>(lite))</span><br><span class="line">  <span class="keyword">const</span> tbs = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">&#x27;show tables&#x27;</span>)</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> tb <span class="keyword">of</span> tbs) &#123;</span><br><span class="line">    <span class="keyword">const</span> table = <span class="title class_">Object</span>.<span class="title function_">values</span>(tb)[<span class="number">0</span>]</span><br><span class="line">    <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">`delete from <span class="subst">$&#123;table&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">const</span> cols = <span class="keyword">await</span> <span class="title function_">query</span>(<span class="string">`show columns from <span class="subst">$&#123;table&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">const</span> keys = cols.<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> x.<span class="property">Field</span>)</span><br><span class="line">    <span class="keyword">const</span> datas = <span class="keyword">await</span> <span class="title function_">all</span>(<span class="string">`select * from <span class="subst">$&#123;table&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">let</span> cnt = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> data <span class="keyword">of</span> datas) &#123;</span><br><span class="line">      cnt++</span><br><span class="line">      <span class="keyword">const</span> sql = mysql.<span class="title function_">format</span>(</span><br><span class="line">        <span class="string">`insert into \`<span class="subst">$&#123;table&#125;</span>\` (<span class="subst">$&#123;</span></span></span><br><span class="line"><span class="subst"><span class="string">          keys.map(k =&gt; <span class="string">`\`<span class="subst">$&#123;k&#125;</span>\``</span>).join(<span class="string">&#x27;,&#x27;</span>)</span></span></span><br><span class="line"><span class="subst"><span class="string">        &#125;</span>) values (<span class="subst">$&#123;</span></span></span><br><span class="line"><span class="subst"><span class="string">          keys.map(() =&gt; <span class="string">&#x27;?&#x27;</span>).join(<span class="string">&#x27;,&#x27;</span>)</span></span></span><br><span class="line"><span class="subst"><span class="string">        &#125;</span>)`</span>,</span><br><span class="line">        keys.<span class="title function_">map</span>(<span class="function"><span class="params">k</span> =&gt;</span> data[k])</span><br><span class="line">      )</span><br><span class="line">      <span class="keyword">await</span> <span class="title function_">query</span>(sql)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;insert to&#x27;</span>, table, <span class="string">&#x27;count&#x27;</span>, cnt)</span><br><span class="line">  &#125;</span><br><span class="line">  con.<span class="title function_">destroy</span>()</span><br><span class="line">&#125;)()&#125;</span><br></pre></td></tr></table></figure><p>顺利收工，睡觉！</p>]]>
    </content>
    <id>https://ecl.me/2021/04/08/blog-sqlite-to-mysql/</id>
    <link href="https://ecl.me/2021/04/08/blog-sqlite-to-mysql/"/>
    <published>2021-04-07T19:01:00.000Z</published>
    <summary>
      <![CDATA[<p>工作日大半夜发文……</p>
<p>背景是给服务器额外弄了块云数据盘，并且兴致冲冲格成了 XFS，于是就想装个 PostgreSQL 玩玩，顺便就想把一些项目原本放在 SQLite3 中的数据迁移到<s>正规</s>的数据库</p>]]>
    </summary>
    <title>Typecho 数据从 SQLite3 迁移至 MySQL</title>
    <updated>2022-06-07T09:05:39.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="服务器" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    <category term="Nginx" scheme="https://ecl.me/tags/Nginx/"/>
    <category term="VLESS" scheme="https://ecl.me/tags/VLESS/"/>
    <category term="SNI" scheme="https://ecl.me/tags/SNI/"/>
    <category term="HAProxy" scheme="https://ecl.me/tags/HAProxy/"/>
    <category term="proxy" scheme="https://ecl.me/tags/proxy/"/>
    <content>
      <![CDATA[<p>最近开始白嫖公司的香港云服务器了，与之前自购的美国 VPS 对比测试下来无论是在网络延时、稳定性还是性能都有了比较大的改善。秉承资源利用最大化的原则，这台服务器的流量不能仅用于访问 Google，所以干脆把之前托管在 Github Pages 上的博客（其实是 Student Pack 到期之后，免费用户的私有项目用不了 GitHub Pages），以及自己搞的一些奇奇怪怪的网站也都迁移了过来（原来跑在腾讯云 1Mbps 的境内服务器上，SSL 握手时间都能让人抓狂）。</p><span id="more"></span><h1 id="明确需求"><a class="markdownIt-Anchor" href="#明确需求"></a> 明确需求</h1><ul><li>访问 Google 要保证安全且快，这里选择 <a class="link"   href="https://github.com/v2fly/v2fly-github-io/blob/master/docs/config/protocols/vless.md" >VLESS<i class="fas fa-external-link-alt"></i></a> 方案</li><li>需要同时兼容多域名站点，这里有几个方案可选：单证书多域名 + VLESS 回落，前置 Nginx 分流，前置 HAProxy 分流</li></ul><h1 id="方案选则"><a class="markdownIt-Anchor" href="#方案选则"></a> 方案选则</h1><h2 id="vless-回落方案"><a class="markdownIt-Anchor" href="#vless-回落方案"></a> VLESS 回落方案</h2><p>由于 VLESS 本身不支持根据 SNI 来分流，需要支持多域名就需要签在同一张证书上。Let’s Encrypt 已经对泛域名证书有了比较完美的支持，配合 <a class="link"   href="https://github.com/acmesh-official/acme.sh" >acme.sh<i class="fas fa-external-link-alt"></i></a> 很容易实现单证书多域名（我所有的域名都在 Cloudflare 下解析）</p><p>然后这仍然有些一些问题，VLESS fallback 方案对 Typecho 的支持并不好（翻了一下其他博文，对 WordPress 之类的 php 程序支持也不行），所以无奈放弃这种方案（其实我也不太想将 VLESS 作为前置的 TCP 分流器）。于是开始尝试 Nginx 前置分流方案</p><h2 id="nginx-前置分流"><a class="markdownIt-Anchor" href="#nginx-前置分流"></a> Nginx 前置分流</h2><p>借助 Nginx 的 <code>ssl_preread</code> 模块来实现 SNI，配置起来也很简单，只需要增加 <code>stream</code> 块</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">stream</span> &#123;</span><br><span class="line">  <span class="attribute">map</span> <span class="variable">$ssl_preread_server_name</span> <span class="variable">$backend_name</span> &#123;</span><br><span class="line">    v2.example.<span class="attribute">com</span> vless;</span><br><span class="line">    <span class="attribute">default</span> web;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="section">upstream</span> web &#123;</span><br><span class="line">    <span class="attribute">server</span> <span class="number">127.0.0.1:8443</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="section">upstream</span> vless &#123;</span><br><span class="line">    <span class="attribute">server</span> <span class="number">127.0.0.1:10443</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> reuseport;</span><br><span class="line">    <span class="attribute">proxy_pass</span> <span class="variable">$backend_name</span>;</span><br><span class="line">    <span class="attribute">ssl_preread</span> <span class="literal">on</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后在站点配置里增加对上述 web 端口的监听即可</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">8443</span> ssl;</span><br><span class="line">  <span class="attribute">server_name</span> web1.example.com;</span><br><span class="line">  <span class="attribute">root</span> /home/www/web1;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl_certificate</span> /home/ssl/cert.pem;</span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /home/ssl/key.pem;</span><br><span class="line">&#125;</span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">8443</span> ssl;</span><br><span class="line">  <span class="attribute">server_name</span> web2.example.com;</span><br><span class="line">  <span class="attribute">root</span> /home/www/web2;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl_certificate</span> /home/ssl/cert.pem;</span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /home/ssl/key.pem;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其实这种方案本来也没什么问题，我开始也觉得可以就这样了。之后无意间发现博客后台记录的一些 client_ip 是 127.0.0.1，于是乎又不得不折腾 HAProxy 方案来分流</p><h2 id="haproxy-前置分流"><a class="markdownIt-Anchor" href="#haproxy-前置分流"></a> HAProxy 前置分流</h2><p>HAProxy 相较于 ngx_stream_ssl_preread_module 的优点就是可以为每一个不同的 backend 设置不一样的数据传递方式，正是因为 nginx 做不到这一点所以上一个方案才会被 pass 掉</p><p>正巧 Proxy Protocol 就是用来做这个事情的，正巧 HAProxy 和 Nginx 对这个的支持都不错。相比而言 HAProxy 的配置文件 <code>haproxy.cfg</code> 显得就比较简单一点：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">global</span><br><span class="line">  log /dev/log  local0</span><br><span class="line">  log /dev/log  local1 notice</span><br><span class="line">  chroot /var/lib/haproxy</span><br><span class="line">  user haproxy</span><br><span class="line">  group haproxy</span><br><span class="line">  daemon</span><br><span class="line"></span><br><span class="line">defaults</span><br><span class="line">  log global</span><br><span class="line">  mode tcp</span><br><span class="line">  option tcplog</span><br><span class="line">  option dontlognull</span><br><span class="line">  timeout connect 24h</span><br><span class="line">  timeout client 24h</span><br><span class="line">  timeout server 24h</span><br><span class="line"></span><br><span class="line">frontend ssl</span><br><span class="line">  mode tcp</span><br><span class="line">  bind *:443</span><br><span class="line"></span><br><span class="line">  tcp-request inspect-delay 3s</span><br><span class="line">  tcp-request content accept if &#123; req.ssl_hello_type 1 &#125;</span><br><span class="line"></span><br><span class="line">  use_backend vless if &#123; req_ssl_sni -i v2.example.com &#125;</span><br><span class="line">  default_backend nginx</span><br><span class="line"></span><br><span class="line">backend nginx</span><br><span class="line">  mode tcp</span><br><span class="line">  server nginx 127.0.0.1:8443 send-proxy</span><br><span class="line"></span><br><span class="line">backend vless</span><br><span class="line">  mode tcp</span><br><span class="line">  server vless 127.0.0.1:10443</span><br></pre></td></tr></table></figure><p>同样的对应 Nginx 站点配置也需要加上对 Proxy Protocol 的支持：</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">8443</span> ssl proxy_protocol;</span><br><span class="line">  <span class="attribute">server_name</span> web1.example.com;</span><br><span class="line">  <span class="attribute">root</span> /home/www/web1;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">set_real_ip_from</span> <span class="number">127.0.0.1</span>;</span><br><span class="line">  <span class="attribute">real_ip_header</span> proxy_protocol;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl_certificate</span> /home/ssl/cert.pem;</span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /home/ssl/key.pem;</span><br><span class="line">&#125;</span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">8443</span> ssl proxy_protocol;</span><br><span class="line">  <span class="attribute">server_name</span> web2.example.com;</span><br><span class="line">  <span class="attribute">root</span> /home/www/web2;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">set_real_ip_from</span> <span class="number">127.0.0.1</span>;</span><br><span class="line">  <span class="attribute">real_ip_header</span> proxy_protocol;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl_certificate</span> /home/ssl/cert.pem;</span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /home/ssl/key.pem;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="一些提示"><a class="markdownIt-Anchor" href="#一些提示"></a> 一些提示</h1><ol start="0"><li>部分软件的安装方式和文档基本都可以在 <a class="link"   href="https://github.com/v2fly" >https://github.com/v2fly<i class="fas fa-external-link-alt"></i></a> 找到</li><li>需要做 http 跳 https 的话直接 Nginx 监听 80 跳 <code>https://$server_name$request_uri</code> 即可</li><li>因为 Nginx 的跳转是默认使用的是绝对地址，上述配置存在 <code>https://web1.example.com/path</code> 跳 <code>https://web1.example.com:8443/path/</code> 的情况，需要使用 <code>absolute_redirect off</code> 设置为相对地址的跳转</li></ol><h1 id="更新"><a class="markdownIt-Anchor" href="#更新"></a> 更新</h1><h2 id="20210410-更新"><a class="markdownIt-Anchor" href="#20210410-更新"></a> 2021.04.10 更新</h2><p>翻阅 VLESS 文档无意间发现其入站支持 Proxy Protocol，果断卸载 HAProxy，用回上文中所说的 Nginx 分流方案，只需要在 <code>stream.server</code> 的配置块里新加一行 <code>proxy_protocol on</code>，同时 VLESS 的配置项 <code>streamSettings.tcpSettings</code> 中加入 <code>&quot;acceptProxyProtocol&quot;: true</code> 即可</p><h2 id="20220604-更新"><a class="markdownIt-Anchor" href="#20220604-更新"></a> 2022.06.04 更新</h2><p>翻阅 <a class="link"   href="https://github.com/XTLS/Xray-docs-next/blob/main/docs/config/features/fallback.md#fallbacks-%E9%85%8D%E7%BD%AE" >xray 文档<i class="fas fa-external-link-alt"></i></a> 发现已经支持了 SNI 分流功能，所以如果没有什么很复杂的负载均衡需求，完全靠 xray 也足够了</p>]]>
    </content>
    <id>https://ecl.me/2020/12/22/vless-with-multi-domain-sites/</id>
    <link href="https://ecl.me/2020/12/22/vless-with-multi-domain-sites/"/>
    <published>2020-12-22T12:34:00.000Z</published>
    <summary>
      <![CDATA[<p>最近开始白嫖公司的香港云服务器了，与之前自购的美国 VPS 对比测试下来无论是在网络延时、稳定性还是性能都有了比较大的改善。秉承资源利用最大化的原则，这台服务器的流量不能仅用于访问 Google，所以干脆把之前托管在 Github Pages 上的博客（其实是 Student Pack 到期之后，免费用户的私有项目用不了 GitHub Pages），以及自己搞的一些奇奇怪怪的网站也都迁移了过来（原来跑在腾讯云 1Mbps 的境内服务器上，SSL 握手时间都能让人抓狂）。</p>]]>
    </summary>
    <title>VLESS 与多域名 Nginx 站点共存的 SNI 分流配置方案</title>
    <updated>2021-04-09T16:52:31.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="博客折腾记录" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE%E8%AE%B0%E5%BD%95/"/>
    <category term="Typecho" scheme="https://ecl.me/tags/Typecho/"/>
    <category term="Jekyll" scheme="https://ecl.me/tags/Jekyll/"/>
    <content>
      <![CDATA[<p>原来使用 Typecho 写博客是觉得 Markdown 比方便，而且 Typecho 也确实十分简洁</p><p>问题出在我发现突然有一天我的博客无法在不挂梯子的情况下访问了，于是我就开始萌生使用 GitHub Pages 并且使用 Cloudflare 作为 CDN 的想法</p><span id="more"></span><h1 id="迁移文章"><a class="markdownIt-Anchor" href="#迁移文章"></a> 迁移文章</h1><p>直接用了别人现成的代码：<a class="link"   href="https://github.com/tcdw/typecho-to-md" >https://github.com/tcdw/typecho-to-md<i class="fas fa-external-link-alt"></i></a></p><p>根据文章的 date 属性进行批量改名来符合 Jekyll 的标准就行了</p><h1 id="迁移评论"><a class="markdownIt-Anchor" href="#迁移评论"></a> 迁移评论</h1><p>由于我的博客底下评论不是很多，所以我选择手写 Disqus 的 XML 导入文件</p><p>导入文件格式在这里可以找到：<a class="link"   href="https://help.disqus.com/developer/custom-xml-import-format" >https://help.disqus.com/developer/custom-xml-import-format<i class="fas fa-external-link-alt"></i></a></p><p>在评论数量比较多的情况下可以考虑写一个脚本生成，并不算很复杂</p><h1 id="关于主题"><a class="markdownIt-Anchor" href="#关于主题"></a> 关于主题</h1><p>在网上翻了很久的主题，感觉没有一个看得顺眼的，于是干脆自己写一个好了</p><p>经过了半天的学习和折腾，写出了一个还算有点样子的主题</p><p>由于之前发布题解需要用到数学公式渲染和代码高亮，于是也专门在主题中添加了支持</p><p>大概的效果如下</p><p class='katex-block'><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>x</mi><mo>=</mo><mfrac><mrow><mo>−</mo><mi>b</mi><mo>±</mo><msqrt><mrow><msup><mi>b</mi><mn>2</mn></msup><mo>−</mo><mn>4</mn><mi>a</mi><mi>c</mi></mrow></msqrt></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">x= \frac {-b \pm \sqrt {b^2 - 4ac}}{2a}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.276389em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.590389em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">a</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">−</span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">±</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.913389em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.740108em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">4</span><span class="mord mathnormal">a</span><span class="mord mathnormal">c</span></span></span><span style="top:-2.873389em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width='400em' height='1.08em' viewBox='0 0 400000 1080' preserveAspectRatio='xMinYMin slice'><path d='M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z'/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.12661100000000003em;"><span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>行内公式：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E = mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 我可以高亮</span></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">main</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Hello world&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">main</span>()</span><br></pre></td></tr></table></figure><p>顺便支持了一下音乐播放，用的是开源的轮子 Aplayer，用法是直接插入特定 class 标签</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;aplayer&quot;</span> <span class="attr">auto</span>=<span class="string">&quot;false&quot;</span>&gt;</span>[&#123;</span><br><span class="line">    &quot;name&quot;: &quot;尽头&quot;,</span><br><span class="line">    &quot;artist&quot;: &quot;赵方婧&quot;,</span><br><span class="line">    &quot;cover&quot;: &quot;/path/to/jintou.jpg&quot;,</span><br><span class="line">    &quot;url&quot;: &quot;/path/to/2017/11/jintou.mp3&quot;,</span><br><span class="line">    &quot;lrc&quot;: &quot;/path/to/2017/11/jintou.lrc&quot;</span><br><span class="line">&#125;]<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>更多配置可以参考 <a class="link"   href="https://aplayer.js.org/" >https://aplayer.js.org/<i class="fas fa-external-link-alt"></i></a></p><h2 id="开源"><a class="markdownIt-Anchor" href="#开源"></a> 开源</h2><p>头一次写主题，比较兴奋就开源了：<a class="link"   href="https://github.com/doveccl/DBLOG" >https://github.com/doveccl/DBLOG<i class="fas fa-external-link-alt"></i></a></p><p><strong>UPDATE</strong> 2020/12/18: 用上了香港服务器，又迁回 typecho 了</p>]]>
    </content>
    <id>https://ecl.me/2018/04/20/move-to-jekyll/</id>
    <link href="https://ecl.me/2018/04/20/move-to-jekyll/"/>
    <published>2018-04-20T11:28:00.000Z</published>
    <summary>
      <![CDATA[<p>原来使用 Typecho 写博客是觉得 Markdown 比方便，而且 Typecho 也确实十分简洁</p>
<p>问题出在我发现突然有一天我的博客无法在不挂梯子的情况下访问了，于是我就开始萌生使用 GitHub Pages 并且使用 Cloudflare 作为 CDN 的想法</p>]]>
    </summary>
    <title>博客迁移到 Jekyll 过程记录</title>
    <updated>2020-12-17T22:45:02.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="迎新春" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E8%BF%8E%E6%96%B0%E6%98%A5/"/>
    <category term="新年" scheme="https://ecl.me/tags/%E6%96%B0%E5%B9%B4/"/>
    <content>
      <![CDATA[<p>说起来也很长时间没有写东西了，本来应该在开年之后写点什么的，但也因为各种奇奇怪怪的事情一直没能有空闲</p><p>终于到了正月初八，应该是很多单位开始上班的第一天吧，我也终于闲下来（其实似乎之前也什么都没做）</p><span id="more"></span><p>一转眼已经是 2018 年，甚至连北京奥运会也是十年之前的事情了。十年之前的这个时候，应该是雪灾最严重的时候，那个时候我应该还在上小学。虽然时间总是能带走我们大部分的记忆，但总有那些刻骨铭心、一生也忘不掉的事情</p><p>回忆有时候真是个可怕的东西，总是给人留下了无限的遗憾，但你却不能从脑海中抹掉</p><p>临近小升初的时候，我妈曾预言过，我是那种小考总能考的很好，一到大考一定会出事的类型</p><ul><li>然后六年级那次期末却实一塌糊涂</li><li>之后中考一塌糊涂，但幸亏已经被预录</li><li>之后高考一塌糊涂，甚至分数比中考还底，但幸亏参加了自招</li></ul><p>总的来说学业这个东西，有惊无险，最后结果也还算可以，我对于之后的路也没有什么想法，就这样吧</p><p>对于一个中国青年而言，从出生到成年所经历的人生主线都是学习，其他的种种都是浮云。我无意评论这样是好是坏，我只是单纯觉得，有些东西一股脑儿放在大学去了解学习未免太过仓促。因为有的时候，我们甚至没能认清自己</p><p>我不想再像高中那样把所有的事情都交代详细。过去的事情，过去的一年，无论是怎样的，都已经过去了，就让它过去吧</p><p>下个学期可以说是非常安逸闲适了，课少，空闲多，甚至也没有做好实习的打算，感觉应该是学习生涯中少有的无所事事的学期。这样也好，毕竟之后也就不是学生了</p><p>无论如何，新的一年还是希望在各方面都能有所长，共勉吧</p>]]>
    </content>
    <id>https://ecl.me/2018/02/23/happy-dog-year/</id>
    <link href="https://ecl.me/2018/02/23/happy-dog-year/"/>
    <published>2018-02-22T17:32:00.000Z</published>
    <summary>
      <![CDATA[<p>说起来也很长时间没有写东西了，本来应该在开年之后写点什么的，但也因为各种奇奇怪怪的事情一直没能有空闲</p>
<p>终于到了正月初八，应该是很多单位开始上班的第一天吧，我也终于闲下来（其实似乎之前也什么都没做）</p>]]>
    </summary>
    <title>狗年大吉吧</title>
    <updated>2020-12-17T19:53:12.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="大学时光" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E5%A4%A7%E5%AD%A6%E6%97%B6%E5%85%89/"/>
    <category term="ICPC" scheme="https://ecl.me/tags/ICPC/"/>
    <category term="香港" scheme="https://ecl.me/tags/%E9%A6%99%E6%B8%AF/"/>
    <content>
      <![CDATA[<p>离开机舱，走在天河机场的大厅里，感受着 10℃ 的武汉。无论是身体，还是内心，都是凉凉的一片</p><p>虽然心里很清楚，这次的香港区域赛相比去年来了数不清的强队，但只拿了一个 Bronze 确实是心有不甘</p><span id="more"></span><p>毫无疑问这次比赛成了我以及某个队友的退役赛，之后没有精力大概也不会再参加什么程序设计相关的竞赛了</p><p>去往香港的时候心情还是不错的，从冬天瞬间到了夏天整个人都是清爽的，但还是要吐槽一下机场快线令人窒息的价格（从机场到九龙不到 20min 的车程收费 105 港币，约人民币 90 元；相比之下从街道口到天河机场的地铁收费六块钱让队友直呼社会主义真好）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/11/hk.jpg"                        alt="某地铁站出口"                  ></p><p>香港城市的发展其实并没有什么特别值得描写的，体感和对面的深圳并无很大区别，所以不表</p><p>不过香港的大学建筑都很棒，就拿比赛举办方香港理工大学来说，PolyU 的整个地面一层都是车道，而在上一层建立平台，供人行走，如下图拍摄地点就位于二层而不是地面</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/11/polyu1.jpg"                        alt="港理工1"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2017/11/polyu2.jpg"                        alt="港理工2"                  ></p><p>然后值得一提的是港理工的所有大楼都是连在一起的，可以在楼道和楼梯中穿梭来游览全校而不必出来走在平台上（不知道比我校的建筑风格高明到哪里去了）</p><p>比赛是由他们电子计算学系承办，除了没有提供免费餐券外，其它事情考虑的都还算周到。香港作为一个小赛区，来的队伍数量比不上沈阳那种大赛区，所以金银铜牌各发五个（听说别的赛区都是 10% + 20% + 30% 感觉有点亏）</p><p>其实这场比赛是手速场，作为老（chi）年（dai）选手觉得这很不ok，我队敲完七题代码时候已经过去了三小时，然而强队都已经敲了九道题了。然后结局是剩下两小时一道题也没做出来，队友表示再多给五分钟就能八题啦！然而并没有延长五分钟这种操作，比赛结束瞬间我大概觉得是要打铁了，不过最后还是以 14 名拿到了铜牌倒数第二。不管怎么说这场比赛所有通过的题目都是一次性提交通过，算是比较好的情况了。况且北大某队也只有一个铜牌，感觉比较平衡了（阿Q心态）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/11/ranklist.png"                        alt="最终排名"                  ></p><p>晚上被队友拖出去看了下维多利亚港的灯光秀，感觉也一般般（大概心境决定景物的美吧）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/11/light1.jpg"                        alt="灯光秀1"                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2017/11/light2.jpg"                        alt="灯光秀2"                  ></p><p>是时候准备期末等一堆子别的事情了</p><p>哎</p>]]>
    </content>
    <id>https://ecl.me/2017/11/21/acm-icpc-hongkong-2017/</id>
    <link href="https://ecl.me/2017/11/21/acm-icpc-hongkong-2017/"/>
    <published>2017-11-20T20:41:00.000Z</published>
    <summary>
      <![CDATA[<p>离开机舱，走在天河机场的大厅里，感受着 10℃ 的武汉。无论是身体，还是内心，都是凉凉的一片</p>
<p>虽然心里很清楚，这次的香港区域赛相比去年来了数不清的强队，但只拿了一个 Bronze 确实是心有不甘</p>]]>
    </summary>
    <title>ACM/ICPC 香港区域赛 酱油记</title>
    <updated>2020-12-21T10:20:05.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="大学时光" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E5%A4%A7%E5%AD%A6%E6%97%B6%E5%85%89/"/>
    <content>
      <![CDATA[<p>已经是第三个年头了呢</p><p>似乎比暑假时的心态还要平静</p><span id="more"></span><p>为什么呢</p><p>或许是找到了过去的感觉</p><p>或许是自我欺骗</p><p>不过总之</p><p>这样挺好的吧</p>]]>
    </content>
    <id>https://ecl.me/2017/09/08/new-grade/</id>
    <link href="https://ecl.me/2017/09/08/new-grade/"/>
    <published>2017-09-08T00:56:00.000Z</published>
    <summary>
      <![CDATA[<p>已经是第三个年头了呢</p>
<p>似乎比暑假时的心态还要平静</p>]]>
    </summary>
    <title>开学</title>
    <updated>2020-12-17T19:48:27.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="大学时光" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E5%A4%A7%E5%AD%A6%E6%97%B6%E5%85%89/"/>
    <category term="期末" scheme="https://ecl.me/tags/%E6%9C%9F%E6%9C%AB/"/>
    <category term="考试" scheme="https://ecl.me/tags/%E8%80%83%E8%AF%95/"/>
    <content>
      <![CDATA[<p>不知不觉中已经是六月了，又到了期末了呢</p><p>有一类人，总是过分高估自己的自觉性，而不幸的是我就正好属于这一类，我也记得年前对这个学期的憧憬与规划，只不过似乎不听课已经成了一种习惯吧，真是可怕的习惯，竟然不知不觉也在教室里浑浑噩噩玩了三个多月。想来也不必对下个学期做任何积极的指望了，考前能复（yu）习就行</p><span id="more"></span><p>当然，如果仅仅是为了说区区一个期末考试，大概也是没有必要专门开一篇文章来说的，毕竟这已经是老生常谈的问题。我记得在高中的时候，就已经有了写写画画的习惯，不过当时的话题基本只有竞赛和学习了吧，偶尔也会有一些别的东西，不过那大多都是苦逼高中生对这个世界的不满。当然，也有一些并不是很想说的东西，甚至那些东西还被同桌看过，现在想想还是有些后怕的，幸好现在我的那位同桌似乎早已经忘了高中有那么些琐碎的小事，甚至写满文字的笔记本就静静地躺在家中，也不知母上在何时会翻出来品味</p><p>高中写的东西，大概基本上都是散文和摘抄吧，零零散散夹杂着些小诗，有古代的，有现代的；有讽刺的，有抒情的。我记得那个时候特别喜欢写景，而且基本上都是低沉的论调，因为心情好的时候并不会有“写点什么”的想法。相比之下，现在的文风简直就差到了极点，没有任何修辞手法，连表达都显得干涩无力，有时候想要隐（jiao）晦（qing）地表达一些什么倒是显得有些困难了，不过我还是尽力尝试诉说一点东西吧，那些并不算能见光的，一直压抑着的东西。我想，这大概也就相当于对着空气来说吧，毕竟有些人大概是不会看到这些东西的</p><p>首先要从学期初去的汉口的日式温泉店“极乐汤”说起，也不知为啥就傻乎乎的去了两次呢，最大的感受大概是日式马桶圈很有意思，回来之后的最大感受是终于看清楚了一些东西，和上个学期的远观相比较，又加深了一些了解吧。阴差阳错，偏偏是已经结束了才刚刚开始，不过上帝总是喜欢开各种各样的玩笑，本来结束的东西又颇有戏剧性的继续了下去。要说这一种什么感觉，大概是，人在这里，心在那里吧。依稀记得这学期还是被强行拖出去了两个晚上，相比之前来说，这种感觉大概也更加明显了。只不过，一边是嘴里的槟郎，另一边是云雾里的山峰</p><p>另外，本学期也数次外出刷夜，也基本上除了 KTV 就是 KTV 了，确实蛮有趣的，竟也就这么过了一个学期，这大概就是所谓的表面吧。潜移默化，真是奇妙，竟然也渐渐的，更加清楚了，相比高中，相比大一做的各种各样现在看来可笑的事情，怕是要收敛的多了。所以，印象中曾经描写过的“月夜景色”也不复存在，饮酒“身未醉心先醉”的闹剧大概也不会上演</p><p>说起来至今，也已经真的数不清楚了，不过这也是头一次打破了我在前面的文章中预言吧。真的没有想到这么快又是两个月过去了，以为的事情并没有发生呢。现在看来决心倒是更为明确了，但是同时胆子也是越来越小了，并且之前的种种怕是也已经全然抛在了脑后。或许就是这样奇怪的似断非断联系，才能留给我更多的想象空间吧，也正是这样才让人总是在燃起希望的同时背负着深深的罪恶吧。因为这一切大概也全是在自导自演，甚至，还不是在现实里；甚至，连自己所知道的真相都不认同</p><p>不过这有什么关系呢，人一路走下来，没有点精神支柱，怕是也会显得过于无聊，就像我玩阴阳师一样，大概也是为了填补某些不得不结束掉的空缺。就像我更喜欢水群，怕也是典型的小孩子心态吧，有时想想，真是可爱，但也真是无用呢。无用到，总是在秘密的地方胡乱地写着一些奇怪的文字，就像现在一样，其实是可悲的</p><p>本来这也并不能算什么破事对吧，毕竟如果再过两年怕是又有一番新的光景，因为我清楚的知道这个学期已经要结束了，并不是因为期末让这个学期显得可怕。而是下个学期，下下个学期的种种似乎已经下了死亡宣判，我不是预言家，但是我清楚的知道我正在读过大学中最快乐的一个学期（或许也不是）。不过，这种事情，总是要看机缘的吧</p><p>嗯，今天抽了一个很漂亮的 SR 呢，我还是要自作多情的说一声谢谢吧</p><p>很快，都要结束了呢！</p>]]>
    </content>
    <id>https://ecl.me/2017/06/07/end-of-semester/</id>
    <link href="https://ecl.me/2017/06/07/end-of-semester/"/>
    <published>2017-06-07T01:18:00.000Z</published>
    <summary>
      <![CDATA[<p>不知不觉中已经是六月了，又到了期末了呢</p>
<p>有一类人，总是过分高估自己的自觉性，而不幸的是我就正好属于这一类，我也记得年前对这个学期的憧憬与规划，只不过似乎不听课已经成了一种习惯吧，真是可怕的习惯，竟然不知不觉也在教室里浑浑噩噩玩了三个多月。想来也不必对下个学期做任何积极的指望了，考前能复（yu）习就行</p>]]>
    </summary>
    <title>又是一年期末时</title>
    <updated>2020-12-17T19:45:47.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="大学时光" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E5%A4%A7%E5%AD%A6%E6%97%B6%E5%85%89/"/>
    <content>
      <![CDATA[<p>周六又一次来到了华科，虽然说这一年以来曾无数次往华科跑，但这确实也是第一次来华科参加比赛（大学以来）</p><p>华科，一个熟悉而又陌生的地方；一个我高中三年来过数次的地方。</p><span id="more"></span><p>曾经的 OIer，以 ACMer 的身份，又一次来华科比赛，还是在同样的大楼，同样的机房</p><p>熟悉，一切都是熟悉的，熟悉的楼、熟悉的电梯、熟悉的机房</p><p>陌生，一切又是陌生的，陌生的人，陌生的心情，陌生的想法</p>]]>
    </content>
    <id>https://ecl.me/2017/05/14/contest-again-in-hust/</id>
    <link href="https://ecl.me/2017/05/14/contest-again-in-hust/"/>
    <published>2017-05-14T01:42:00.000Z</published>
    <summary>
      <![CDATA[<p>周六又一次来到了华科，虽然说这一年以来曾无数次往华科跑，但这确实也是第一次来华科参加比赛（大学以来）</p>
<p>华科，一个熟悉而又陌生的地方；一个我高中三年来过数次的地方。</p>]]>
    </summary>
    <title>故地重“游”</title>
    <updated>2020-12-17T19:40:48.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="零碎日志" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E9%9B%B6%E7%A2%8E%E6%97%A5%E5%BF%97/"/>
    <category term="macOS" scheme="https://ecl.me/tags/macOS/"/>
    <content>
      <![CDATA[<p>可能是一个月前 <code>sudo rm -rf</code> 了 FaceTime 和 iMessage 吧，当然也可能是电脑里某垃圾软件的 debuff</p><p>总之最近经常长时间待机之后就无故重启，开机报错是驱动程序的问题，那就真的有必要重装一次系统了</p><span id="more"></span><p>由于手头只有一个 64G USB3.0 的 U盘，所以并不能备份太多的东西</p><ol><li><p>MAS 下载最新的 macOS Sierra 10.12.4 系统</p></li><li><p>用磁盘工具抹掉 U盘，设为 GUID 分区图，Mac OS 扩展（日志式），并命名为 macOS</p></li><li><p>输入如下命令写入镜像</p></li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> /Applications/Install\ macOS\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/macOS --applicationpath /Applications/Install\ macOS\ Sierra.app --nointeraction</span><br></pre></td></tr></table></figure><ol start="4"><li><p>U盘 新建 backup 目录，并复制需要备份的文件</p></li><li><p>重启，按住 option 从 U盘启动</p></li><li><p>抹盘</p></li><li><p>重装</p></li><li><p>忘记备份某项目代码</p></li><li><p>卒</p></li></ol>]]>
    </content>
    <id>https://ecl.me/2017/04/22/macos-reinstall/</id>
    <link href="https://ecl.me/2017/04/22/macos-reinstall/"/>
    <published>2017-04-21T17:20:00.000Z</published>
    <summary>
      <![CDATA[<p>可能是一个月前 <code>sudo rm -rf</code> 了 FaceTime 和 iMessage 吧，当然也可能是电脑里某垃圾软件的 debuff</p>
<p>总之最近经常长时间待机之后就无故重启，开机报错是驱动程序的问题，那就真的有必要重装一次系统了</p>]]>
    </summary>
    <title>macOS 全盘重装过程记录</title>
    <updated>2020-12-17T22:42:37.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="零碎日志" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E9%9B%B6%E7%A2%8E%E6%97%A5%E5%BF%97/"/>
    <category term="macOS" scheme="https://ecl.me/tags/macOS/"/>
    <category term="反汇编" scheme="https://ecl.me/tags/%E5%8F%8D%E6%B1%87%E7%BC%96/"/>
    <category term="QQ" scheme="https://ecl.me/tags/QQ/"/>
    <content>
      <![CDATA[<p>在 MAS 版本的 QQ 更新到版本 5.5.1 之后，终于支持撤回消息了（当然也就不能防撤回了）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/04/qq-on-mas.png"                        alt="macQQ"                  ></p><p>通过万能的 Google 查找了一下防撤回方法，没想到还真的找到了</p><span id="more"></span><h1 id="尝试一反编译二进制文件参考美女驱动型程序猿"><a class="markdownIt-Anchor" href="#尝试一反编译二进制文件参考美女驱动型程序猿"></a> 尝试一：反编译二进制文件（参考：<a class="link"   href="http://www.jianshu.com/p/271388f13cd0" >美女驱动型程序猿<i class="fas fa-external-link-alt"></i></a>）</h1><ol><li><p>安装 <a class="link"   href="http://xclient.info/s/hopper-disassembler.html" >Hopper Disassembler<i class="fas fa-external-link-alt"></i></a></p></li><li><p>用 Hopper Disassembler 打开 /Applications/QQ.app/Contents/MacOS/QQ</p><p>需要注意的是，当二进制文件被打开之后不要急于操作，要等待右下角 <code>Working</code> 消失，这个时间会非常长</p></li><li><p>在左边 <code>Labels</code> 一栏搜索 <code>handleRecallNotify</code> 关键词，得到如下结果</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/04/qq-bin.png"                        alt="qq-bin"                  ></p></li><li><p>选中 <code>push rbp</code> 这一行，按住 <code>Option + A</code> 并输入 <code>ret</code>，之后再点击 <code>Assembler and Go Next</code> 并按 <code>ESC</code> 结束编辑，大概意思是，直接让这个函数返回，不做任何操作（为啥每次都把 rbp 看成 rbq 呢？捂脸……）</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/04/qq-modify.png"                        alt="qq-modify"                  ></p></li><li><p>按住 <code>Shift + Command + E</code> 来输出新的二进制文件，会提示是否移除原有的签名，确认即可，这个时候把新的二进制文件复制到 /Applications/QQ.app/Contents/MacOS/ 把原来的替换掉就行</p></li></ol><p>P.S. 经过参考链接评论区提醒，在测试发现修后的 QQ 把缓存全都放到了 ~/Documents/，本来好好的文档目录多出了一堆乱七八糟的文件，对于强迫症患者而言是绝对不能忍的</p><h1 id="尝试二动态库注入-hook参考0xbbc"><a class="markdownIt-Anchor" href="#尝试二动态库注入-hook参考0xbbc"></a> 尝试二：动态库注入 hook（参考：<a class="link"   href="https://blog.0xbbc.com/2017/04/prevent-qq-message-recall-in-macos/" >0xBBC<i class="fas fa-external-link-alt"></i></a>）</h1><ol><li><p>新建 OC 源文件 <code>QQUnrecall.m</code></p> <figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="string">&lt;Foundation/Foundation.h&gt;</span></span></span><br><span class="line"><span class="meta">#import <span class="string">&lt;objc/runtime.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> handleRecallNotifyIsOnline(<span class="type">id</span> _i, SEL _s, <span class="type">void</span> * _p, <span class="type">BOOL</span> _b) &#123;</span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;已经阻止 QQ 撤回一条消息&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> clang diagnostic push</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> clang diagnostic ignored <span class="string">&quot;-Wundeclared-selector&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="type">void</span> __attribute__((constructor)) initialize(<span class="type">void</span>) &#123;</span><br><span class="line">method_setImplementation(</span><br><span class="line">class_getInstanceMethod(</span><br><span class="line"><span class="built_in">NSClassFromString</span>(<span class="string">@&quot;QQMessageRevokeEngine&quot;</span>),</span><br><span class="line"><span class="keyword">@selector</span>(handleRecallNotify:isOnline:)</span><br><span class="line">),</span><br><span class="line">(IMP)&amp;handleRecallNotifyIsOnline</span><br><span class="line">);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> clang diagnostic pop</span></span><br></pre></td></tr></table></figure></li><li><p>编译成动态库文件 <code>clang -dynamiclib -framework Foundation QQUnrecall.m -o libQQUnrecall.dylib</code></p></li><li><p>使用 <code>export DYLD_INSERT_LIBRARIES=libQQUnrecall.dylib</code> 后运行 <code>/Applications/QQ.app/Contents/MacOS/QQ</code> 得到如下测试结果</p><p><img                         lazyload                       alt="image"                       data-src="/images/2017/04/qq-unrecall-test.png"                        alt="qq-unrecall-test"                  ></p></li><li><p>简单包装一下避免每次通过终端启动 QQ</p> <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> QPATH <span class="string">&quot;/Applications/QQ.app/Contents/MacOS/&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LIBENV <span class="string">&quot;DYLD_INSERT_LIBRARIES&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LIBNAME <span class="string">&quot;libQQUnrecall.dylib&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> HOOK <span class="string">&quot;export &quot;</span> LIBENV <span class="string">&quot;=%s&quot;</span> LIBNAME</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RUN QPATH <span class="string">&quot;QQ&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> AND <span class="string">&quot; &amp;&amp; &quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CMD HOOK AND RUN</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> M 1024</span></span><br><span class="line"></span><br><span class="line"><span class="type">char</span> path[M], buff[M];</span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> len, i;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> **argv)</span> &#123;</span><br><span class="line"><span class="built_in">strcpy</span>(path, argv[<span class="number">0</span>]);</span><br><span class="line">len = <span class="built_in">strlen</span>(path);</span><br><span class="line"><span class="keyword">for</span> (i = len - <span class="number">1</span>; i; i--) &#123;</span><br><span class="line"><span class="keyword">if</span> (path[i] == <span class="string">&#x27;/&#x27;</span>)</span><br><span class="line"><span class="keyword">break</span> ;</span><br><span class="line">path[i] = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">sprintf</span>(buff, CMD, path);</span><br><span class="line">system(buff);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><p>P.S. 点击 <a class="link"   href="https://github.com/doveccl/QQU/releases" >这里<i class="fas fa-external-link-alt"></i></a> 下载成品（macOS 10.12 以下版本最好自行编译，否则可能会出现问题），理论上只要撤回函数名称和参数不改，对于所有版本 QQ 都可用此方法</p>]]>
    </content>
    <id>https://ecl.me/2017/04/18/mac-qq-unrecall/</id>
    <link href="https://ecl.me/2017/04/18/mac-qq-unrecall/"/>
    <published>2017-04-18T02:58:00.000Z</published>
    <summary>
      <![CDATA[<p>在 MAS 版本的 QQ 更新到版本 5.5.1 之后，终于支持撤回消息了（当然也就不能防撤回了）</p>
<p><img  
                       lazyload
                       alt="image"
                       data-src="/images/2017/04/qq-on-mas.png"
                        alt="macQQ" 
                 ></p>
<p>通过万能的 Google 查找了一下防撤回方法，没想到还真的找到了</p>]]>
    </summary>
    <title>Mac QQ 消息防撤回的尝试</title>
    <updated>2020-12-17T22:43:30.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="技术向" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/"/>
    <category term="服务器" scheme="https://ecl.me/categories/%E6%8A%80%E6%9C%AF%E5%90%91/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    <category term="SSL" scheme="https://ecl.me/tags/SSL/"/>
    <category term="Nginx" scheme="https://ecl.me/tags/Nginx/"/>
    <content>
      <![CDATA[<h1 id="安装-lets-encrypt"><a class="markdownIt-Anchor" href="#安装-lets-encrypt"></a> 安装 Let’s Encrypt</h1><ul><li>Debian / Ubuntu</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get install letsencrypt</span><br></pre></td></tr></table></figure><span id="more"></span><ul><li>Redhat / CentOS</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum install epel-release</span><br><span class="line"><span class="built_in">sudo</span> yum install letsencrypt</span><br></pre></td></tr></table></figure><ul><li>Others (python)</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> pip install letsencrypt</span><br></pre></td></tr></table></figure><h1 id="关闭-nginx-获取证书"><a class="markdownIt-Anchor" href="#关闭-nginx-获取证书"></a> 关闭 nginx &amp; 获取证书</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> service nginx stop</span><br><span class="line">letsencrypt certonly --standalone -d your.domian -d another.domian</span><br></pre></td></tr></table></figure><h1 id="修改配置"><a class="markdownIt-Anchor" href="#修改配置"></a> 修改配置</h1><h2 id="开启-https"><a class="markdownIt-Anchor" href="#开启-https"></a> 开启 https</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">443</span>;</span><br><span class="line">  <span class="attribute">listen</span> [::]:<span class="number">443</span>;</span><br><span class="line">  <span class="attribute">server_name</span> your.domain;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">ssl</span> <span class="literal">on</span>;</span><br><span class="line">  <span class="attribute">ssl_certificate</span> /etc/letsencrypt/live/your.domain/fullchain.pem;</span><br><span class="line">  <span class="attribute">ssl_certificate_key</span> /etc/letsencrypt/live/your.domain/privkey.pem;</span><br><span class="line">  <span class="attribute">ssl_protocols</span> SSLv3 TLSv1 TLSv1.<span class="number">1</span> TLSv1.<span class="number">2</span>;</span><br><span class="line">  <span class="attribute">ssl_ciphers</span> <span class="string">&quot;EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH&quot;</span>;</span><br><span class="line">  <span class="attribute">ssl_prefer_server_ciphers</span> <span class="literal">on</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment"># other config</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="开启重定向"><a class="markdownIt-Anchor" href="#开启重定向"></a> 开启重定向</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">  <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">  <span class="attribute">listen</span> [::]:<span class="number">80</span>;</span><br><span class="line">  <span class="attribute">server_name</span> your.domain;</span><br><span class="line">  <span class="attribute">return</span> <span class="number">301</span> https://<span class="variable">$server_name</span><span class="variable">$request_uri</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="开启-nginx-服务"><a class="markdownIt-Anchor" href="#开启-nginx-服务"></a> 开启 nginx 服务</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> service nginx start</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://ecl.me/2017/04/13/install-letsencrypt-certificate/</id>
    <link href="https://ecl.me/2017/04/13/install-letsencrypt-certificate/"/>
    <published>2017-04-13T02:16:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="安装-lets-encrypt"><a class="markdownIt-Anchor" href="#安装-lets-encrypt"></a> 安装 Let’s Encrypt</h1>
<ul>
<li>Debian / Ubuntu</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get install letsencrypt</span><br></pre></td></tr></table></figure>]]>
    </summary>
    <title>为网站配置 letsencrypt ssl 证书 (for nginx)</title>
    <updated>2020-12-17T22:53:10.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="随笔" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="牢骚时间" scheme="https://ecl.me/categories/%E9%9A%8F%E7%AC%94/%E7%89%A2%E9%AA%9A%E6%97%B6%E9%97%B4/"/>
    <content>
      <![CDATA[<p>又忍不住要来发骚了</p><p>这可能是这个学期最长的文章了吧</p><p>浑浑噩噩地坐在学院八楼报告厅里，却找不到一点可以做的事情，于是就写点东西吧</p><span id="more"></span><p>总的来说，这个学期过的是非常糟糕的，我记得开学之前曾经和宇飞说过这学期好好工作，不把所有的事情都堆在期末</p><p>然而结果是，到了第九周，我才发现自己甚至都没有翻开过三周后要结课考试科目的书</p><p>当然，这还不是最要命的，原本打算寒假就完成的某坑，我到昨天才初步完成服务端代码的重构，甚至连文档还来不及写</p><p>明明明天要交的作业都没有动，量还不少，但是却一点都不想做，在这里码着无聊的文字</p><p>或许，这就是颓废吧，可是，又能怎样呢</p><p>想必三年前的自己，也定不会想到三年后的自己是这番模样，更不会想到三年前的无知心态，终于也在三年后几个月的心理斗争之后，慢慢地被自己接受，认清</p><p>说起三年前，又不得不提到那个充满热情的年龄，那无数个备战 oi 的无忧（zhi）岁月。HBOI 2017 结束了，令人遗憾的是，又有一个满怀热情的理想被无情的现实击打，就像三年前的我一样。江月年年望相似，只是物是人非罢了</p><p>这个世界上每分每秒都在发生各种各样的不幸，区别是有些人垮了，有些人又重新占了起来。当事者的各种痛苦，在旁人看来或许也不过是饭后的谈资</p><p>当习惯了这个世界的冷酷之后，或许再去面对某些事情的时候，不会再去怨天怨地，哭闹上吊。相反的，平静，习惯，忘记</p><p>不知道从啥时候起，秘密可以肆无忌惮的公之于众，可以被当作任何人拿捏把玩的话柄</p><p>可是那又怎样呢，又能怎样呢</p><p>我没有勇气，单纯的害怕，单纯享受着现实。痛苦与快乐同在，现实与幻想同在。知足的，这就够了</p><p>没有什么事情是真的无缘无故，那些讲不出来的原因只不过是不想讲出来的秘密罢了</p><p>虽然这已经不是第一次我有如此强烈的愿望想要写点什么，不过我真的希望在未来很长一段时间里，我能够像现在这样，不要再去有新的想法，不再有新的想法去表达些什么</p><p>倘若真的控制不住，那么把一切都交给时间吧，交给未来吧，交给那些并不存在的幻想，交给一个美丽的童话</p><p>那是一个从未浮出水面的故事，故事里，到最后或许都只有一个人，因为，我不配，也不该</p><p>又能怎样呢，其实也不能</p>]]>
    </content>
    <id>https://ecl.me/2017/04/12/how-to-do/</id>
    <link href="https://ecl.me/2017/04/12/how-to-do/"/>
    <published>2017-04-11T17:11:00.000Z</published>
    <summary>
      <![CDATA[<p>又忍不住要来发骚了</p>
<p>这可能是这个学期最长的文章了吧</p>
<p>浑浑噩噩地坐在学院八楼报告厅里，却找不到一点可以做的事情，于是就写点东西吧</p>]]>
    </summary>
    <title>又能怎样呢</title>
    <updated>2020-12-17T19:29:10.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Doveccl</name>
    </author>
    <category term="题解" scheme="https://ecl.me/categories/%E9%A2%98%E8%A7%A3/"/>
    <category term="动态规划" scheme="https://ecl.me/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    <category term="矩阵" scheme="https://ecl.me/tags/%E7%9F%A9%E9%98%B5/"/>
    <category term="快速幂" scheme="https://ecl.me/tags/%E5%BF%AB%E9%80%9F%E5%B9%82/"/>
    <content>
      <![CDATA[<p>半年不碰 C++ 实力明显变弱</p><p>个人贡献三题，零罚时比较让人欣慰，至少手还算稳</p><p>（还是太弱了</p><span id="more"></span><h1 id="one-car-comes-and-one-car-goes"><a class="markdownIt-Anchor" href="#one-car-comes-and-one-car-goes"></a> One car comes and one car goes</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_A1.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_A2.jpg"                        alt=""                  ></p><p>听说是小学奥数题，没啥好说的</p><h1 id="color"><a class="markdownIt-Anchor" href="#color"></a> Color</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_B1.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_B2.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_B3.jpg"                        alt=""                  ></p><p>裸的树形 DP ，穷举一下每个点选各种 type 的种类数就好，剩下的就是乘法原理吧</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MOD 10000009</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> N 50000</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> M 30</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, s, t;</span><br><span class="line"></span><br><span class="line"><span class="type">bool</span> can[N][M];</span><br><span class="line">vector&lt;<span class="type">int</span>&gt; a[N];</span><br><span class="line"><span class="type">long</span> <span class="type">long</span> f[N][M];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">long</span> <span class="type">long</span> <span class="title">nis</span><span class="params">(<span class="type">int</span> c, <span class="type">int</span> i)</span> </span>&#123;</span><br><span class="line"><span class="type">static</span> <span class="type">int</span> ret;</span><br><span class="line">ret = f[c][<span class="number">0</span>] - f[c][i];</span><br><span class="line"><span class="keyword">return</span> ret &lt; <span class="number">0</span> ? ret + MOD : ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> t, <span class="type">int</span> p)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> len = a[t].<span class="built_in">size</span>(), c;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; len; i++)</span><br><span class="line"><span class="keyword">if</span> (a[t][i] != p) &#123;</span><br><span class="line"><span class="built_in">dfs</span>(a[t][i], t);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= m; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (can[t][i])</span><br><span class="line">f[t][i] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">continue</span> ;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt; len; j++) &#123;</span><br><span class="line"><span class="keyword">if</span> ((c = a[t][j]) == p)</span><br><span class="line"><span class="keyword">continue</span> ;</span><br><span class="line">f[t][i] *= <span class="built_in">nis</span>(c, i);</span><br><span class="line">f[t][i] %= MOD;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= m; i++) &#123;</span><br><span class="line">f[t][<span class="number">0</span>] += f[t][i];</span><br><span class="line">f[t][<span class="number">0</span>] %= MOD;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="built_in">srand</span>(<span class="built_in">time</span>(<span class="number">0</span>));</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (cin &gt;&gt; n &gt;&gt; m) &#123;</span><br><span class="line"><span class="built_in">memset</span>(f, <span class="number">0</span>, <span class="built_in">sizeof</span>(f));</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i++)</span><br><span class="line">a[i].<span class="built_in">clear</span>();</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; n; i++) &#123;</span><br><span class="line">cin &gt;&gt; s &gt;&gt; t;</span><br><span class="line">a[s].<span class="built_in">push_back</span>(t);</span><br><span class="line">a[t].<span class="built_in">push_back</span>(s);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i++)</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j &lt;= m; j++) &#123;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line">can[i][j] = t;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">dfs</span>(s = <span class="built_in">rand</span>() % n + <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">cout &lt;&lt; f[s][<span class="number">0</span>] &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="lost-in-whu"><a class="markdownIt-Anchor" href="#lost-in-whu"></a> Lost in WHU</h1><p><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_E1.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_E2.jpg"                        alt=""                  ><br /><img                         lazyload                       alt="image"                       data-src="/images/2022/05/2017WHU_E3.jpg"                        alt=""                  ></p><p>给一个无向图，问在 T 步之内有多少条路线从 1 走到 n</p><p>结论题，直接建立图的邻接矩阵，然后求矩阵 T 次幂就好</p><p>由于题目要求到了 n 就不能走出去，所以需要删掉 n 所有出边，然后 n 自环一下就好</p><p>但是由于太弱并不知道还有自环这种操作，一股脑删光了所有射出边，给邻接矩阵多加了一层，用一种十分不优雅的方式侥幸过了 XD</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> N 100</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MOD 1000000007LL</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">typedef</span> vector&lt;vector&lt;LL&gt;&gt; mat;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">(mat &amp;x, <span class="type">bool</span> I)</span> </span>&#123;</span><br><span class="line">x.<span class="built_in">resize</span>(n + <span class="number">1</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line">x[i].<span class="built_in">resize</span>(n + <span class="number">1</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= n; j++)</span><br><span class="line">x[i][j] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> (I) <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line">x[i][i] = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> mat <span class="title">mul</span><span class="params">(<span class="type">const</span> mat &amp;a, <span class="type">const</span> mat &amp;b)</span> </span>&#123;</span><br><span class="line">mat c; <span class="built_in">init</span>(c, <span class="literal">false</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= n; j++) &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt;= n; k++) &#123;</span><br><span class="line">c[i][j] += (a[i][k] * b[k][j]) % MOD;</span><br><span class="line">c[i][j] %= MOD;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> c;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> mat <span class="title">quick_mod</span><span class="params">(mat a, <span class="type">int</span> q)</span> </span>&#123;</span><br><span class="line">mat c; <span class="built_in">init</span>(c, <span class="literal">true</span>);</span><br><span class="line"><span class="keyword">while</span> (q) &#123;</span><br><span class="line"><span class="keyword">if</span> (q &amp; <span class="number">1</span>)</span><br><span class="line">c = <span class="built_in">mul</span>(a, c);</span><br><span class="line">a = <span class="built_in">mul</span>(a, a);</span><br><span class="line">q &gt;&gt;= <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> c;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">print</span><span class="params">(<span class="type">const</span> mat &amp;a)</span> </span>&#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++, cout &lt;&lt; endl)</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= n; j++)</span><br><span class="line">cout &lt;&lt; a[i][j] &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> x, y, t;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; m;</span><br><span class="line">mat a; <span class="built_in">init</span>(a, <span class="literal">false</span>);</span><br><span class="line"><span class="keyword">while</span> (m--) &#123;</span><br><span class="line">cin &gt;&gt; x &gt;&gt; y;</span><br><span class="line">x--, y--;</span><br><span class="line">a[x][y] = <span class="number">1</span>;</span><br><span class="line">a[y][x] = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++)</span><br><span class="line">a[n - <span class="number">1</span>][i] = <span class="number">0</span>;</span><br><span class="line">a[n - <span class="number">1</span>][n] = <span class="number">1</span>;</span><br><span class="line">a[n][n] = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">a = <span class="built_in">quick_mod</span>(a, t);</span><br><span class="line">a[<span class="number">0</span>][n] += a[<span class="number">0</span>][n - <span class="number">1</span>];</span><br><span class="line">cout &lt;&lt; a[<span class="number">0</span>][n] % MOD &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://ecl.me/2017/04/10/17cc-online/</id>
    <link href="https://ecl.me/2017/04/10/17cc-online/"/>
    <published>2017-04-09T18:35:00.000Z</published>
    <summary>
      <![CDATA[<p>半年不碰 C++ 实力明显变弱</p>
<p>个人贡献三题，零罚时比较让人欣慰，至少手还算稳</p>
<p>（还是太弱了</p>]]>
    </summary>
    <title>2017 Wuhan University Programming Contest (Online Round) 划水</title>
    <updated>2022-06-07T12:58:25.000Z</updated>
  </entry>
</feed>
