<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>光昭</title>
  <link>https://www.pyrzo.com</link>
  <description></description>
  <language>zh-CN</language>
  <lastBuildDate>Sat, 11 Jul 2026 17:37:26 +0000</lastBuildDate>
  <atom:link href="https://www.pyrzo.com/rss.xml" rel="self" type="application/rss+xml"/>
  <item>
    <title>博客全新上线！基于 Java/Spring + Thymeleaf 编写</title>
    <link>https://www.pyrzo.com/posts/rebuilt-my-blog</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/rebuilt-my-blog</guid>
    <pubDate>Fri, 10 Jul 2026 13:56:25 +0000</pubDate>
    <description>博客已经正式迁移到自己造的轮子！</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>之前这个博客一直都是放在 WordPress 上的。WordPress 全能、完善，的确是个好程序。——我一向喜欢臃肿的程序。直到后来一次，我又打开了 MyAdmin，才发现数据库里乱得一批，post 表里还有一堆 {unknown} 的孤立垃圾数据，而我甚至不知道它们是怎么产生的。于是乎，点了一下 LSCache 插件中的“清理数据库”，结果把我的草稿全都删除了。</p>
<p>到这里，自己造轮子就有两个原因了：</p>
<ol>
<li>臃肿还是轻量真无所谓，但这数据库实在太脏了吧？</li>
<li>不仅脏，还打扫不干净。试着清理，反而还因为一个本应当无害的操作丢了数据。这样的大黑箱用起来我是真的害怕。</li>
</ol>
<p>学 Java 倒是有个小半年了，不过由于高中学业占用时间比较多（平常一周也就放一天的假），这半年下来其实也就学完了 JavaSE 外加 JavaWeb（SpringBoot、SQL）的入门罢了。</p>
<p>按理说我还得先把 Sping 全家桶学一遍。不过好在现在 AI 这么发达，实际上，SpringBoot 入完门就足以靠 VibeCoding 做项目了。而且按理说，能理清 controller，service/impl，dto，entity 等层的功能与关系，就足以 Vibe 出一个可维护的项目。</p>
<p>然后，就有了现在这个博客。</p>
<h2>技术栈</h2>
<h3>总览</h3>
<ul>
<li>后端框架：SpringBoot</li>
<li>安全框架：SpringSecurity</li>
<li>持久层：Spring Data JPA / Hibernate</li>
<li>MVC 层：JavaWeb</li>
<li>数据库：MySQL 8</li>
<li>模板引擎：Thymeleaf</li>
</ul>
<h3>SSR or CSR？</h3>
<p>在服务端渲染（SSR）和前后端分离的架构（也就是 CSR）之间，我犹豫了一下。按理说，前后端分离的架构速度只会特别快，因为整个 HTML 的骨架不包含任何动态内容。但如果我选择 CSR 的话，我还得学习 React、Vue 等一系列新技术，显然具有一定学习成本。</p>
<p>而 SSR 架构就不需要担心什么难度问题（然而代价都是较慢的响应时间），我这里使用了 Thymeleaf 作为模板渲染引擎。</p>
<p>不过我后来又发现了一些奇怪的现象：目前这个站点的 Speed Insight 分数极高，或许是因为样式少，文件小，所以没有阻塞吧。顺手又写了 /sitemap.xml 和 /robots.txt 之类的功能，所以 SEO 分数也不错：</p>
<p><img src="https://www.pyrzo.com/uploads/4cded22058ee45f78cfd9caf221c22f7.webp" alt="Speed Insight Mobile Score" /></p>
<p><img src="https://www.pyrzo.com/uploads/5639097dffc144c38f9d5dd333720223.webp" alt="Speed Insight Desktop Score" /></p>
<h3>Thymeleaf</h3>
<p>Thymeleaf 是一个现代服务器端的 Java 模板引擎，主要用于生成 HTML 网页。</p>
<p>它最突出的特点是 “自然模板”：模板文件本身是标准的 HTML，可以直接在浏览器中打开并正确显示（显示的是示例数据或静态占位内容），而无需启动服务器。这是因为 Thymeleaf 通过额外的自定义属性（如 th:text、th:each）来标注动态部分，这些属性在浏览器中会被忽略，只有经过服务器处理后才会被替换成真实数据。</p>
<p>例如，页脚的备案号是动态获取的：</p>
<pre><code>&lt;span th:text=&quot;${theme.footerIcp != null and !#strings.isEmpty(theme.footerIcp) ? theme.footerIcp : '浙ICP备2026002806号-1'}&quot;&gt;浙ICP备2026002806号-1&lt;/span&gt;
</code></pre>
<p>其中，<code>th:text</code> 的值是一个三元条件表达式：</p>
<pre><code>条件 ? 为真时的值 : 为假时的值
</code></pre>
<p>也就是上文提到的 Thymeleaf 的“自然模板”理念：</p>
<p>可以直接在浏览器中打开这个 HTML 文件，看到一个完整的备案号展示效果（使用默认值）；而一旦放到服务器上运行，Thymeleaf 就会根据实际配置动态替换为真实备案号，保留相同的外观。</p>
<h2>特点</h2>
<h3>MarkDown 编辑文章</h3>
<p>本来想做成类似 Wp 那样区块的形式存储文章，不过再造一个区块化编辑器的学习成本又高了，而且通用性兼容性也低。所以选择数据库直接存储 MD 格式的文本。</p>
<p>没有引入啥编辑器，文章编辑页面是直接塞了一个 textarea 元素，Entity 直接存 MD 文本。</p>
<p>至于前台的 HTML 渲染，则是服务端调用 CommonMark 工具，将 MD 转换为 HTML 文本再塞给 Thymeleaf 模板渲染。</p>
<h2>鸣谢名单</h2>
<p>DeepSeek-v4-pro</p>
<p>GPT-5.4</p>
<h2>其它</h2>
<p>Java 的占用还真是大啊，现在这个体量已经 340MiB 了，比我的 MySQL8 Docker 容器占用还大了。</p>
<p>你 Java 还是你 Java 👍</p>
<p>再附图一张：</p>
<p><img src="https://www.pyrzo.com/uploads/a790789f0f4f4faba78ee2b3354f08c5.png" alt="Dashboard" /></p>
]]></content:encoded>
    <category>网站建设</category>
  </item>
  <item>
    <title>Ubuntu Server 安装 Mihomo 并为 Docker 配置代理</title>
    <link>https://www.pyrzo.com/posts/ubuntu-server-proxy-docker</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/ubuntu-server-proxy-docker</guid>
    <pubDate>Sat, 11 Jul 2026 03:00:53 +0000</pubDate>
    <description>解决了一下国内服务器使用 Docker 服务的痛点（虽然也可以靠设置镜像地址解决）</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>1. 前言</h2>
<p>如果机场提供的是 Clash/Mihomo 订阅，并且节点类型包含：</p>
<ul>
<li><code>anytls</code></li>
<li><code>vless</code></li>
<li><code>reality</code></li>
</ul>
<p>那么通常不能使用老版 <code>clash</code>，应使用 <code>mihomo</code> 或 <code>clash-meta</code>。</p>
<p>典型报错如下：</p>
<pre><code class="language-text">Parse config error: proxy 0: unsupport proxy type: anytls
</code></pre>
<p>这说明内核压根不支持。所以本文使用 Mihomo。</p>
<hr />
<h2>2. 安装 Mihomo</h2>
<p>先确认服务器架构：</p>
<pre><code class="language-bash">uname -m
</code></pre>
<p>常见为 <code>x86_64</code>。</p>
<p>下载 <code>mihomo</code>：</p>
<pre><code class="language-bash">cd /usr/local/bin
wget -O mihomo.gz https://github.com/MetaCubeX/mihomo/releases/download/v1.19.28/mihomo-linux-amd64-compatible-v1.19.28.gz
gunzip mihomo.gz
chmod +x mihomo
/usr/local/bin/mihomo -v
</code></pre>
<hr />
<h2>3. 准备配置目录</h2>
<p>这里以 <code>/opt/clash</code> 为例：</p>
<pre><code class="language-bash">mkdir -p /opt/clash
</code></pre>
<p>将机场提供的 Clash/Mihomo 配置保存为：</p>
<pre><code class="language-bash">/opt/clash/config.yaml
</code></pre>
<p>或：</p>
<pre><code class="language-bash">/opt/clash/config.yml
</code></pre>
<p>Mihomo 启动时会在指定目录中读取配置文件。</p>
<p>注意：有些机场给的订阅地址拉下来是一堆 Base64 编码的节点列表，这种情况就需要将它先导入 Clash 软件，然后在把生成的配置文件拿去给服务器用。</p>
<hr />
<h2>4. 测试配置文件</h2>
<p>正式启动前，先测试配置是否合法：</p>
<pre><code class="language-bash">/usr/local/bin/mihomo -t -d /opt/clash
</code></pre>
<p>如果通过，说明配置文件可以被当前 Mihomo 正常解析。</p>
<hr />
<h2>5. 配置 systemd 服务</h2>
<p>创建服务文件：</p>
<pre><code class="language-bash">nano /etc/systemd/system/clash.service
</code></pre>
<p>写入以下内容：</p>
<pre><code class="language-ini">[Unit]
Description=Clash daemon
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mihomo -d /opt/clash
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
</code></pre>
<p>加载并启动服务：</p>
<pre><code class="language-bash">systemctl daemon-reload # 重载设置
systemctl enable --now clash # 启动 Mihomo 并设置开机自启动
systemctl status clash # 查看运行状态
</code></pre>
<p>查看是否设置为开机自启：</p>
<pre><code class="language-bash">systemctl is-enabled clash
</code></pre>
<p>如果输出 <code>enabled</code>，说明重启服务器后 Mihomo 会自动启动。</p>
<hr />
<h2>6. 常见配置示例</h2>
<p>一个可用的基础配置通常包含：</p>
<pre><code class="language-yaml">mixed-port: 7890
allow-lan: true
bind-address: '*'
mode: rule
log-level: info
external-controller: 127.0.0.1:9090
</code></pre>
<p>说明如下：</p>
<ul>
<li><code>mixed-port: 7890</code>：HTTP/SOCKS 混合代理端口</li>
<li><code>allow-lan: true</code>：允许局域网访问</li>
<li><code>bind-address: '*'</code>：监听所有地址</li>
<li><code>external-controller: 127.0.0.1:9090</code>：本机控制接口</li>
</ul>
<p>如果只需要本机控制接口，保留 <code>127.0.0.1:9090</code> 更安全。</p>
<hr />
<h2>7. 验证 Mihomo 是否正常工作</h2>
<p>查看监听端口：</p>
<pre><code class="language-bash">ss -lntp | grep 7890
ss -lntp | grep 9090
</code></pre>
<p>本机强制通过代理测试：</p>
<pre><code class="language-bash">curl -I -x http://127.0.0.1:7890 https://www.google.com
curl -I -x http://127.0.0.1:7890 https://api.openai.com
</code></pre>
<p>如果成功，说明：</p>
<ul>
<li>Mihomo 正在监听</li>
<li>至少有一个节点可用</li>
<li>代理功能正常</li>
</ul>
<p>查看日志：</p>
<pre><code class="language-bash">journalctl -u clash -n 100 --no-pager
</code></pre>
<p>实时查看日志：</p>
<pre><code class="language-bash">journalctl -u clash -f
</code></pre>
<hr />
<h2>8. 查看当前使用的节点</h2>
<p>Mihomo 提供了控制接口：</p>
<pre><code class="language-yaml">external-controller: 127.0.0.1:9090
</code></pre>
<p>可以通过 API 查看代理组和当前节点：</p>
<pre><code class="language-bash">curl http://127.0.0.1:9090/proxies
</code></pre>
<p>返回结果中重点关注主代理组，例如：</p>
<pre><code class="language-json">&quot;TaiShan Net&quot;: {
  &quot;type&quot;: &quot;Selector&quot;,
  &quot;now&quot;: &quot;自动选择&quot;
}
</code></pre>
<p>如果主组选中的是另一个组，例如 <code>自动选择</code>，还需要继续查询该组：</p>
<pre><code class="language-bash">curl http://127.0.0.1:9090/proxies/自动选择
</code></pre>
<p>如果安装了 <code>jq</code>，查看更方便：</p>
<pre><code class="language-bash">curl -s http://127.0.0.1:9090/proxies | jq '.proxies[&quot;TaiShan Net&quot;]'
curl -s http://127.0.0.1:9090/proxies | jq '.proxies[&quot;自动选择&quot;]'
</code></pre>
<hr />
<h2>9. Shell 临时代理与永久代理</h2>
<p>临时代理写法：</p>
<pre><code class="language-bash">export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export all_proxy=socks5://127.0.0.1:7890
</code></pre>
<p>这只对当前 shell 会话有效。退出终端、重新登录或重启服务器后会失效。</p>
<p>如果希望当前用户登录后自动生效，可以写入：</p>
<pre><code class="language-bash">~/.bashrc
</code></pre>
<p>例如：</p>
<pre><code class="language-bash">echo 'export http_proxy=http://127.0.0.1:7890' &gt;&gt; ~/.bashrc
echo 'export https_proxy=http://127.0.0.1:7890' &gt;&gt; ~/.bashrc
echo 'export all_proxy=socks5://127.0.0.1:7890' &gt;&gt; ~/.bashrc
source ~/.bashrc
</code></pre>
<hr />
<h2>10. 让 Docker 使用代理</h2>
<p>Docker 代理分两层：</p>
<ol>
<li>Docker daemon 拉镜像使用代理</li>
<li>容器内应用运行时使用代理</li>
</ol>
<p>这两者需要分别配置。本文只介绍第一种</p>
<hr />
<h2>11. Docker daemon 使用代理</h2>
<p>创建 Docker 的 systemd 覆盖配置：</p>
<pre><code class="language-bash">mkdir -p /etc/systemd/system/docker.service.d
nano /etc/systemd/system/docker.service.d/http-proxy.conf
</code></pre>
<p>写入：</p>
<pre><code class="language-ini">[Service]
Environment=&quot;HTTP_PROXY=http://127.0.0.1:7890&quot;
Environment=&quot;HTTPS_PROXY=http://127.0.0.1:7890&quot;
Environment=&quot;ALL_PROXY=socks5://127.0.0.1:7890&quot;
Environment=&quot;NO_PROXY=localhost,127.0.0.1,::1&quot;
</code></pre>
<p>重载并重启 Docker：</p>
<pre><code class="language-bash">systemctl daemon-reload
systemctl restart docker
</code></pre>
<p>确认生效：</p>
<pre><code class="language-bash">systemctl show --property=Environment docker
</code></pre>
<p>测试拉镜像：</p>
<pre><code class="language-bash">docker pull hello-world
</code></pre>
<p>说明：</p>
<ul>
<li>这里使用 <code>127.0.0.1:7890</code>，因为 Docker daemon 运行在宿主机上</li>
<li>该配置主要影响 <code>docker pull</code></li>
</ul>
<hr />
]]></content:encoded>
  </item>
  <item>
    <title>安装 OpenLiteSpeed 并搭建一个 WordPress 站点 – 从入门到入土</title>
    <link>https://www.pyrzo.com/posts/install-openlitespeed-and-run-a-wordpress-on-it</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/install-openlitespeed-and-run-a-wordpress-on-it</guid>
    <pubDate>Thu, 18 Jun 2026 13:48:29 +0000</pubDate>
    <description>想用 LiteSpeed Cache 插件？它在 Nginx 下几近残废。于是我甩掉宝塔这个“寄生虫”，纯终端裸装 OpenLiteSpeed + LSPHP，自签防扫、亲手配虚拟主机，从入门到入土——丢掉辅助轮，才能真正学会骑车。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言（碎碎念）</h2>
<p>我的 WordPress 程序一直跑在 LNMP 的环境中，虽说 Nginx 配合伪静态重写规则以及 wp super cache 插件的专家模式，直接返回缓存的 html 文件，优化得已经够快了。</p>
<p>但我其实一直很想试试 LiteSpeed Cache 插件的（WP Super Cache 插件的功能实在是少的可怜，可以说是简洁，但我都用 WP 这样臃肿的程序了，功能自然是越多越好）。不过这个插件的缓存功能依赖于 OpenLiteSpeed Web 服务端，NG 下根本无法使用 html 缓存功能。于是萌生了使用 OLS 作为 Web 服务端的想法。</p>
<p>尝试了使用宝塔面板安装 OpenLiteSpeed。但实际情况很糟糕。LS 是不与原生 PHP 兼容的，这点很重要。</p>
<p>本文环境：Ubuntu 24.04.3 Server。</p>
<p>本文默认你已经拥有一定 Linux 的操作基础，并对文件权限属性有基本的了解。</p>
<p>我们直接开始。</p>
<h2>思路梳理</h2>
<p>我们需要安装如下软件：OpenLiteSpeed（可能简称 LS/OLS）、MySQL、LSPHP、Redis，并在上面跑一个 WordPress。</p>
<p>其中，LSPHP 是包含有 LS API 的 PHP 的变体。包含了 PHP 的全部功能。要使用 LiteSpeed Cache 插件的话，需要使用 LSPHP。</p>
<h2>安装所需软件</h2>
<h3>安装 OpenLiteSpeed 与 LSPHP</h3>
<p>依照 OLS 官方文档进行：<a href="https://docs.openlitespeed.org/installation/">Installation | OpenLiteSpeed Documentation | OpenLiteSpeed Documentation</a></p>
<p>OpenLiteSpeed supports current and non-EOL versions of the following Linux distributions:</p>
<ul>
<li>
<p>CentOS*8, 9, 10</p>
</li>
<li>
<p>Debian 11, 12, 13</p>
</li>
<li>
<p>Ubuntu 22, 24, 26</p>
</li>
</ul>
<p>我们选择从软件源安装。</p>
<p>安装 OLS 软件源：</p>
<pre><code>sudo wget -O - https://repo.litespeed.sh | sudo bash
# 成功输出 LiteSpeed repository has been setup!
</code></pre>
<p>官方脚本，包安全的。</p>
<p>安装 OLS：</p>
<pre><code>sudo apt-get -y install openlitespeed
</code></pre>
<p>接下来我们安装 LSPHP。查看可用的 LSPHP 包及拓展：</p>
<pre><code>sudo apt-cache search lsphp
</code></pre>
<p>安装 LSPHP，同时指定一下我们需要的拓展。使用<code>apt list --installed | grep lsphp83</code>命令，发现 php83 php83-common php83-mysql php-opcache 这几个包已经自动安装。这里继续安装包含 Redis 在内的常用 WP 拓展：</p>
<pre><code>sudo apt install openlitespeed lsphp83-intl lsphp83-redis lsphp83-imagick lsphp83-curl
</code></pre>
<p>查看已安装 php83 包列表确认一下：</p>
<pre><code>root@akiubuntux:~# apt list --installed | grep lsphp83

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

lsphp83-common/noble,now 8.3.31-2+noble all [installed,automatic]
lsphp83-igbinary/noble,now 3.2.16-6+noble amd64 [installed,automatic]
lsphp83-imagick/noble,now 3.8.1-1+noble amd64 [installed]
lsphp83-intl/noble,now 8.3.31-2+noble amd64 [installed]
lsphp83-mysql/noble,now 8.3.31-2+noble amd64 [installed,automatic]
lsphp83-opcache/noble,now 8.3.31-2+noble amd64 [installed,automatic]
lsphp83-redis/noble,now 6.3.0-1+noble amd64 [installed]
lsphp83/noble,now 8.3.31-2+noble amd64 [installed,automatic]
</code></pre>
<p>设置一下 OLS WebAdmin 密码：</p>
<pre><code>sudo /usr/local/lsws/admin/misc/admpass.sh
# 若设置成功则输出 Administrator's username/password is updated successfully!
</code></pre>
<p>我们访问<code>https://example.com:7080/</code>进入 WebAdmin。</p>
<h3>安装 MySQL</h3>
<p>直接使用 apt 安装 MySQL：</p>
<pre><code>apt-cache search mysql-server # 列出所有 MySQL 可用包
sudo apt-get install mysql-server-8.0 # 安装 MySQL 8.0
</code></pre>
<p>随后进行 MySQL 配置：</p>
<pre><code>sudo mysql_secure_installation
</code></pre>
<ul>
<li>
<p>是否验证密码强度，输入 y，提高安全性</p>
</li>
<li>
<p>询问强制的密码强度等级，输入 2 确认，也就是需要长度大于 8 位，包含数字、大小写、特殊符号的密码，且不能有常用单词</p>
</li>
<li>
<p>是否删除匿名用户（anonymous user），输入 y，删除</p>
</li>
<li>
<p>是否禁止 root 远程登录，y 禁止</p>
</li>
<li>
<p>y 移除 test database</p>
</li>
<li>
<p>Reload privilege tables now? 重载所有设置，输入 y</p>
</li>
</ul>
<h3>安装 Redis</h3>
<p>通过 apt 安装：</p>
<pre><code>sudo apt install redis-server -y # 安装 redis
redis-cli --version # 验证安装信息 - 输出 redis-cli 7.0.15
sudo systemctl status redis-server # 检查 redis 服务运行状态
</code></pre>
<p>确认软件自启动状态：</p>
<pre><code>systemctl is-enabled lshttpd # OpenLiteSpeed
systemctl is-enabled mysql # MySQL
systemctl is-enabled redis-server # Redis
</code></pre>
<h2>简略的配置调整</h2>
<h3>LSPHP 禁用函数</h3>
<p>官方文档中提到，LSPHP 安装在<code>/usr/local/lsws/lsphp83/bin/lsphp</code>目录，我们<code>cd /usr/local/lsws/lsphp83/etc/php/8.3/litespeed/</code>，<code>nano php.ini</code>编辑 php.ini 文件，说实话还是 ftp 方便点，第 333 行左右有一个<code>disable_functions</code>，我们修改一下：</p>
<pre><code>disable_functions = passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
</code></pre>
<p>以及 445 行左右<code>memory_limit</code>，我习惯直接修改为 256M。还有<code>max_execution_time</code>，我习惯改为 60。哦，还有最大文件上传限制，记得一定要调大些，不然连一个主题都上传不了。</p>
<p>重启 PHP：</p>
<pre><code>sudo touch /usr/local/lsws/admin/tmp/.lsphp_restart.txt
</code></pre>
<p>LSPHP 的重启方式很奇怪，不过独立运行模式下的 LSPHP 的重启就是创建这样一个文件。</p>
<h2>配置 OLS</h2>
<h3>添加监听器</h3>
<p>打开“监听器”选项卡，创建监听器。例如添加一个 HTTPS 监听器，监听地址 ANY IPv4，启用加密连接。这样就可以监听到 443 IPv4 的流量了。</p>
<h3>监听器自签证书</h3>
<p>这一步主要是为了防止我们的 IP 被网络上的扫描器扫到导致 IP 泄露。可以找个自签证书生成工具，例如<a href="https://bkssl.com/ssl/selfsign">在线生成自签名SSL证书</a>。把证书文件上传到<code>/usr/local/lsws/conf/cert</code>目录。注意自签证书的 CN（通用名）与 SAN 不要填你真实的域名，不然白搭了。然后在监听器 SSL 设置中指定证书与私钥文件。</p>
<h2>配置 Wordpress 虚拟主机</h2>
<h3>创建并添加映射</h3>
<p>OLS 中使用“虚拟主机”来管理网站。我们先创建一个目录用于存放站点文件，例如<code>sudo mkdir -p /usr/local/lsws/WordPress/html</code>，然后在 OLS 面板中添加一个虚拟主机，配置如下：</p>
<ul>
<li>
<p>虚拟主机名：<code>WordPress</code></p>
</li>
<li>
<p>虚拟主机根目录：<code>WordPress/</code></p>
</li>
<li>
<p>配置文件：<code>conf/vhosts/WordPress/vhconf.conf</code></p>
</li>
<li>
<p>启用脚本/外部应用程序：<code>是</code>- 指定在这个虚拟主机中是否允许运行脚本（非静态页面）。</p>
</li>
<li>
<p>访问管制：<code>是</code>- 指定是否可以通过此网站访问虚拟主机根目录（$VH_ROOT）之外的文件。</p>
</li>
</ul>
<p>tip：由于我们的 WP 包含动态文件，同时出于安全考虑，最后两个选项设置开启。（OLS 安装后会自动船舰一个脚本处理器定义关联 LSPHP。直接填写 WordPress/ 而非绝对路径的原因是 OLS 已支持相对路径）</p>
<p>点击保存，报错 file /usr/local/lsws/conf/vhosts/WordPress/vhconf.conf does not exist.，意为配置文件不存在。点击 CLICK TO CREATE 自动创建即可。然后保存。</p>
<p>然后切换到常规选项卡，<strong>文档根目录设置为 WordPress/html</strong>（注：这步很重要，不设置会导致访问 404）</p>
<h3>零散的其它设置</h3>
<p>接着转到重写页面，把启用重写和自动加载.htaccess打开。平滑重启 OLS 使配置生效。</p>
<p>然后回到监听器选项卡，添加一个虚拟主机映射，选择我们刚刚创建的 WordPress 虚拟主机，域名按实际情况填写即可。</p>
<h3>上传文件并设置权限</h3>
<p>下载 Wordpress 源码并复制到目标目录：</p>
<pre><code>cd /usr/local/lsws/WordPress
sudo wget &quot;https://cn.wordpress.org/latest-zh_CN.zip&quot;
sudo unzip latest-zh_CN.zip
sudo cp -R wordpress/* html/
</code></pre>
<p>如果提示<code>sudo: unzip: command not found</code>，<code>apt install unzip</code>安装一下 unzip 即可。复制完成后就可以删除刚刚产生的压缩包与 wordpress 文件夹了（强迫症这一块）</p>
<p>然后设置文件权限：</p>
<pre><code>sudo chown -R lsadm:nogroup /usr/local/lsws/WordPress
sudo chown -R nobody:nogroup /usr/local/lsws/WordPress/html
sudo find /usr/local/lsws/WordPress/ -type d -exec chmod 700 {} +
sudo find /usr/local/lsws/WordPress/ -type f -exec chmod 600 {} +
sudo chmod 710 /usr/local/lsws/WordPress
</code></pre>
<p>注：部分 Linux 发行版需要将 nogroup 更改为 nobody。权限解释：</p>
<ul>
<li>
<p>将<code>/usr/local/lsws/WordPress</code>整个目录及其下所有文件、子目录的所有者改为<code>lsadm</code>，组改为<code>nogroup</code>。</p>
</li>
<li>
<p><code>html</code>通常是 Web 服务器的文档根目录（存放上传的图片、静态文件、可能由 Web 写入的文件）。把所有权全交给<code>nogroup</code>，使得 Web 服务器进程（若以<code>nogroup</code>用户运行）能够自由读写该目录下的内容。</p>
</li>
<li>
<p>所有子目录只有其所有者能进入并操作，组（如<code>nogroup</code>）和其他用户完全无法访问。这增强了目录安全性，防止他人浏览目录结构。</p>
</li>
<li>
<p>所有文件仅允许其所有者读取和写入，组<code>nogroup</code>及其他人均不可读、不可写、不可执行。这样能保护配置文件、PHP 源码不被未授权读取。</p>
</li>
<li>
<p>组<code>nogroup</code>只拥有执行权限（<code>x</code>），可以“经过”该目录访问内部已知路径的文件，但<strong>无法列出目录内容</strong>（无<code>r</code>权限），进一步防止目录信息泄露。</p>
</li>
</ul>
<h3>虚拟主机 SSL 设置</h3>
<p>签一张你域名的 SSL 证书。这里不过多赘述，可以使用 certbot 等工具。部分 CF 用户可能需要下载 CF 提供的源服务器证书（如果 TLS/SSL 安全级别足够高）。</p>
<p>在上面监听器 SSL 相同目录，新建一个 .pem 与 .crt 文件，将证书内容粘贴进去。然后设置权限：</p>
<pre><code>cd /usr/local/lsws/conf/cert
sudo chown lsadm:nogroup pyrzo.*
sudo chmod 640 pyrzo.*
# 这里以 pyrzo.pem 与 pyrzo.crt 举例，应当根据实际情况修改
</code></pre>
<p>然后回到 OLS 的虚拟主机设置，编辑 SSL 设置：</p>
<ul>
<li>
<p>私钥文件：<code>conf/cert/pyrzo.pem</code></p>
</li>
<li>
<p>证书文件：<code>conf/cert/pyrzo.crt</code></p>
</li>
</ul>
<h3>伪静态设置</h3>
<p>OLS 伪静态规则遵循 Apache 引擎规范，这里直接套用：</p>
<pre><code>RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</code></pre>
<h2>创建数据库</h2>
<p>我们还需要创建一个数据库供 Wordpress 使用。由于APT 安装 MySQL 时，默认会为 MySQL 的 root 用户配置<code>auth_socket</code>插件，它允许操作系统当前的 root 用户无需密码就能以 MySQL root 账号登录。所以我们 SSH 终端中直接输入<code>mysql</code>即可进入 mysql 命令行操作。输入：</p>
<pre><code>CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 创建数据库
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'your_strong_password'; # 创建用户 wpuser
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost'; # 授予 wpuser 操作 wordpress 数据库之权力
FLUSH PRIVILEGES; #刷新权限表使修改生效
EXIT; # 退出 MySQL 命令行
</code></pre>
<p>其中记得要把<code>'your_strong_password'</code>替换为你想设置的用户密码，由于我们上面设置过了 MySQL 的密码安全检查，所以这里的密码必须要达到带有特殊符号的那一档复杂程度。使用这些信息连接数据库：<code>数据库名: wordpress</code>,<code>用户名: wpuser</code>,<code>密码: your_strong_password</code>。</p>
<h2>设置 crontab 任务</h2>
<p>我们需要关闭 wp 自带的 corn 并使用系统 corntab 和 curl 来优化 corn 性能。（默认情况下，每次访问都会触发 wp-corn 并检查一遍过期任务，这是浪费性能的）</p>
<p>在<code>wp-config.php</code>中, 添加下面的定义代码：</p>
<pre><code>define('DISABLE_WP_CRON', true);
</code></pre>
<p>输入<code>crontab -e</code>，选择 1 使用 nano 编辑器，然后文件末尾加入：</p>
<pre><code>*/15 * * * * curl --silent &quot;https://www.pyrzo.com/wp-cron.php?doing_wp_cron&quot; &gt; /dev/null 2&gt;&amp;1
</code></pre>
<p>然后保存。这样 corn 任务就会每隔十五分钟执行一次了。记得把域名改为你自己的。wget 一样可以使用。</p>
<h2>配置真实 IP 请求头</h2>
<p>我使用了 CDN，IP 需要从请求头中获取。OLS WebAdmin 里转了一圈，设置项简直不是给人读的，不过好在我们依然可以直接通过<code>wp-config.php</code>设置<code>REMOTE_ADDR</code>。</p>
<p>拿取 X-Forwarded-For 列表中第一个 IP。虽说不加上信任 IP 防止 IP 伪造是不安全的，但是我需要用到<code>REMOTE_ADDR</code>的地方只有主题的评论 IP 地理位置显示罢了，伪造也没什么问题。其余服务使用 X-Real-IP 获取 IP 即可。</p>
<pre><code>if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $list[0];
}
</code></pre>
<p>不过我后来琢磨了一下，服务器配置 - 常规 - 使用报头中的客户端IP 就是从 XFF 头中取第一个值，效果是一样的（小声）——但请务必设置受信任 IP 列表，防止 XFF IP 伪造。CF 的 IP 段可以在这里查询<a href="https://www.cloudflare.com/ips/">IP Ranges | Cloudflare</a>，其它 CDN 例如我使用的腾讯 EdgeOne 也有类似功能。在允许的 IP 后加 T 表示受信任。例如192.168.1.*T。</p>
<h2>安装 WP 并测试</h2>
<p>安装 LiteSpeed Cache 插件，并且启用 Redis 缓存。可以看到 PageInsight 的得分确实高。</p>
<h2>额外提示（大坑）</h2>
<h3>访客模式/访客优化</h3>
<p>请务必保持关闭。虽然这样可以让你的网站在 PageSpeed Insight 上获得 90 以上的高分，但它对人类访客大概率是不友好的。据网上反馈以及我自己测试，<strong>这两项设置开启后都会导致网站白屏、无限加载</strong>。所以一定要关闭，分数是没什么必要的，但真实体验是重要的。而且，不开启访客优化的情况下，一番调教，分数反而还更高了（？真是令人摸不着头脑啊）</p>
<h3>即时点击不起作用</h3>
<p>LiteSpeed Cache 有一个 Instant Click 选项，根据解释，是鼠标移至链接上方后开始预加载目标链接，但测试下来，这在我的站点上完全不起作用。触发的 prefetch 永远只有 0kb。</p>
<p>还好，我们可以使用 Flying Pages 插件。使用这个插件后，html 文件终于可以预加载了。</p>
<h2>小结优化效果展示</h2>
<p>OLS 简洁易用，配合上 LiteSpeed Cache 插件后性能也确实高了许多。</p>
<p>在不对 Web Server 进行优化（开箱即用）的情况下，PageSpeed Insght 评分如下（PageSpeed 模拟真实渲染过程，比单纯比 TTFB 大小有效得多）：</p>
<p>Nginx 配合 WP Super Cache 专家模式，存在 html 缓存文件的情况下，通过重写规则直接返回缓存内容而绕过 PHP——这已经是我用 Nginx 时做过最快的缓存优化了。移动端分数 33 分，桌面端分数 67 分。均分 50。</p>
<p>而换到本文的 OLS 配合插件使用后，在保证真实访客访问同样正常且告诉的情况下，移动端分数 71 分，桌面端分数 98 分。均分 84.5。</p>
<p>综上所述，移动端提升约<strong>115%</strong>，桌面端提升约<strong>46%</strong>，双端综合性能提升约<strong>69%</strong>。不难看出，OLS 配合 LSC 有着 WP Super Cache 配合 Nginx 不可比拟的差距（虽说 Nginx FastCGI Cache 和 OLS 服务器缓存差不多，但架不住插件强大啊）</p>
<p>后边我可能还会再出一篇文章来继续调优 OLS，看看性能还能不能上升。</p>
<h2>参考文章</h2>
<p><a href="https://www.liups.net/2026/06/openlitespeed-%E5%AE%89%E8%A3%85%E4%B8%8E%E5%BB%BA%E7%AB%99-%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B/">OpenLiteSpeed 安装与建站配置 详细教程 - Liups233</a>- 本文总体思路参考，但本文更加适合 Ubuntu 宝宝体质。</p>
<p><a href="https://www.cnblogs.com/zhaoyingjie/p/19023349">Linux（以 Ubuntu 为例）用命令行搭建 WordPress 博客的完整步骤 - 星河赵 - 博客园</a></p>
<p><a href="https://www.idcfavourites.com/archives/2052.html">LiteSpeed如何设置自定义标头跨越访问 - 主机收藏夹</a></p>
]]></content:encoded>
    <category>网站建设</category>
  </item>
  <item>
    <title>JavaWeb 大致入门</title>
    <link>https://www.pyrzo.com/posts/java-web-introduction</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/java-web-introduction</guid>
    <pubDate>Mon, 08 Jun 2026 11:04:35 +0000</pubDate>
    <description>从零起步，涵盖JS、Vue、Spring Boot到Axios与Maven。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>【全网首发AI+JavaWeb开发入门，Tlias教学管理系统项目实战全套视频教程，从需求分析、设计、前后端开发、测试、程序优化到项目部署一套搞定】 https://www.bilibili.com/video/BV1yGydYEE3H/?p=23share_source=copy_webvd_source=dfe79a2296fc694b4f7a30c0e180690b</p>
<h2>VS Code</h2>
<p>推荐插件：</p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack">Java Extension Pack (Java 扩展包)</a></p>
<p><a href="https://marketplace.visualstudio.com/items?itemName=Pivotal.vscode-boot-dev-pack">Spring Boot Extension Pack</a></p>
<h2>JS</h2>
<h3>JS 引入方式</h3>
<p>一、内部脚本</p>
<p>使用script/script标签包裹。</p>
<p>一般置于 body 元素底部，以提升加载速度。</p>
<p>二、外部脚本</p>
<p>使用script src=&quot;src&quot;/script引用外部 JS 文件。标签不可自闭合。</p>
<h3>JS 对象</h3>
<h4>JSON</h4>
<ul>
<li>
<p>JSON 英文全称<strong>J</strong>ava<strong>S</strong>cript<strong>O</strong>bject<strong>N</strong>otation</p>
</li>
<li>
<p>JSON 是一种轻量级的数据交换格式。</p>
</li>
<li>
<p>JSON是独立的语言</p>
</li>
<li>
<p>JSON 易于理解。</p>
</li>
</ul>
<p>以下 JSON 语法定义了 sites 对象: 3 条网站信息（对象）的数组：</p>
<pre><code>{&quot;sites&quot;:[
    {&quot;name&quot;:&quot;Runoob&quot;, &quot;url&quot;:&quot;www.runoob.com&quot;}, 
    {&quot;name&quot;:&quot;Google&quot;, &quot;url&quot;:&quot;www.google.com&quot;},
    {&quot;name&quot;:&quot;Taobao&quot;, &quot;url&quot;:&quot;www.taobao.com&quot;}
]}
</code></pre>
<h4>BOM</h4>
<p>浏览器对话模型。</p>
<p>例如 windows、location。</p>
<h4>DOM</h4>
<p>文档对话模型。</p>
<p>通过可编程的对象模型，JavaScript 获得了足够的能力来创建动态的 HTML。</p>
<h3>核心语法</h3>
<p><strong>① 变量常量</strong></p>
<p>let 声明变量；const 声明常量。</p>
<p><strong>② 数据类型</strong></p>
<p>基本数据类型：</p>
<ul>
<li>
<p>number：数字(整数、小数、NaN(Not aNumber)）</p>
</li>
<li>
<p>boolean:布尔。true，false</p>
</li>
<li>
<p>null：对象为空。JavaScript是大小写敏感的，因此null、Null、NULL是完全不同的</p>
</li>
<li>
<p>undefined：当声明的变量未初始化时，该变量的默认值是undefined</p>
</li>
<li>
<p>string：字符串，单引号、双引号、反引号皆可，推荐使用单引号</p>
</li>
</ul>
<p>使用 typeof 可以获取数据类型。</p>
<p><strong>③ 函数</strong></p>
<p>JS 是弱类型语言，形参、返回值都不需要指定类型。在调用函数时，实参个数与形参个数可以不一致，但是建议一致。</p>
<p><strong>④自定义对象</strong></p>
<p>对象名、属性、属性值：</p>
<pre><code>var person = {
    firstName:&quot;John&quot;,
    lastName:&quot;Doe&quot;,
    age:50,
    eyeColor:&quot;blue&quot;
};
</code></pre>
<h3>事件监听</h3>
<p>JavaScript 可以在事件触发时，就立即调用一个函数做出响应，也称为事件绑定或注册事件。</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;input type=&quot;button&quot; id=&quot;btn&quot; value=&quot;按钮&quot;&gt;
    &lt;script&gt;
        document.querySelector('#btn').addEventListener('click', ()=&gt; {
            console.log(&quot;按钮被点击了&quot;);
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>这里使用 addEventListener 进行事件监听。</p>
<h3>JS 模块化</h3>
<p>在 JS 文件中引入另一个 JS 文件可以使用 import 导包：</p>
<pre><code>import ( printlog ) from &quot;./util.js&quot;; //从 util.js 中引入 printlog 函数
</code></pre>
<p>对于被引用的函数，需要加上 export 关键字：</p>
<pre><code>export function PrintLog(msg){
    console.log(msg)
}
</code></pre>
<p>我们还需要声明其为模块化 JS，否则浏览器会报错。</p>
<pre><code>&lt;script src=&quot;demo.js&quot; type=&quot;module&quot;&gt;&lt;/script&gt;
</code></pre>
<h2>Vue</h2>
<h3>快速入门</h3>
<p>当前十分流行的前端框架。</p>
<p>Vue是一款用于<strong>构建用户界面</strong>的<strong>渐进式</strong>的JavaScript框架。</p>
<p>它可以帮你把数据（JS）和页面（HTML）自动绑定起来。数据变了，页面自己就变，不用手动操作 DOM。</p>
<p>官网地址：<a href="https://cn.vuejs.org/">https://cn.vuejs.org/</a></p>
<p>Vue 示例：</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;title&gt;Hello Vue&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;h1&gt;{{ message }}&lt;/h1&gt;
    &lt;button @click=&quot;reverseMsg&quot;&gt;反转文字&lt;/button&gt;
  &lt;/div&gt;

  &lt;!-- 引入 Vue 3 --&gt;
  &lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
    const { createApp } = Vue

    createApp({
      data() {
        return {
          message: '你好，Vue！'
        }
      },
      methods: {
        reverseMsg() {
          this.message = this.message.split('').reverse().join('')
        }
      }
    }).mount('#app')
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>其中 {{ message }} 便是插值表达式，用来将数据渲染到页面中。</p>
<h4>使用 ES 模块构建版本导入 Vue</h4>
<pre><code>&lt;div id=&quot;app&quot;&gt;{{ message }}&lt;/div&gt;

&lt;script type=&quot;module&quot;&gt;
  import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

  createApp({
    setup() {
      const message = ref('Hello Vue!')
      return {
        message
      }
    }
  }).mount('#app')
&lt;/script&gt;
</code></pre>
<p>这里有一个 id 为 app 的区域，.mount 表示 Vue 接管这部分区域。</p>
<p>我们创建了 createApp 对象，编写了 setup 方法，同时方法体内部返回值——返回 message。</p>
<p>最后，页面上渲染的就是字符串 Hello Vue!。</p>
<h2>Ajax</h2>
<p>Asynchronous JavaScript and XML。异步的 Javascirpt 与 XML。</p>
<p>XML：（英语：Extensible Markup Language）可扩展标记语言，本质是一种数据格式，可以用来存储复杂的数据结构。</p>
<p>Axios 针对 Ajax 进行了封装，简化了书写，方便开发。</p>
<h2>Maven</h2>
<p>Apache 旗下一款开源项目，用于管理与构建 Java 代码。</p>
<p><a href="https://maven.apache.org/download.cgi">Download Apache Maven – Maven</a>下载。</p>
<p>也可以在 VS Code 中 ctrl + shift + p 快速创建一个 Spring Maven 项目。</p>
<h2>Web 入门</h2>
<h3>Spring Web 快速入门</h3>
<p>VS Code 创建一个 Spring Boot 项目，启动，访问 localhost:8080 即有页面返回。</p>
<p>这里快速入门一下：</p>
<p>创建 \src\main\java\com\example\demo\HelloController.java</p>
<pre><code>package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 标识该类是一个请求处理类
public class HelloController {
    @RequestMapping(&quot;/hello&quot;) // 处理 /hello 路径的请求
    public String hello(){
        System.out.println(&quot;Hello, Spring Boot !&quot;);
        return &quot;Hello, Spring Boot !&quot;;
    }
}
</code></pre>
<p>启动主类。或者如果你也使用 VS Code，可以在左侧找到 Spring Boot Dashboard，然后启动你的项目。</p>
<p>访问<code>localhost:8080/hello</code>，浏览器应当返回“Hello, Spring Boot !”。</p>
<h3>HTTP 协议</h3>
<h4>概述</h4>
<p>HTTP（Hypertext Transfer Protocol）是Web上客户端与服务器之间进行数据交换的基础应用层协议。</p>
<p>每个请求都是独立的，服务器默认不保留之前请求的上下文，这让协议简单、易扩展，但也需要 Cookie、Session 等机制来维持会话。</p>
<h4>报文结构</h4>
<p>HTTP 报文分为<strong>请求报文</strong>和<strong>响应报文</strong>，结构类似：</p>
<p><strong>请求报文</strong>：</p>
<pre><code>GET /index.html HTTP/1.1          ← 请求行（方法 路径 版本）
Host: www.example.com              ← 请求头（键值对）
User-Agent: Mozilla/5.0
Accept: text/html
                                   ← 空行（标志头部结束）
（可选的消息体，如 POST 的数据）
</code></pre>
<p><strong>响应报文</strong>：</p>
<pre><code>HTTP/1.1 200 OK                    ← 状态行（版本 状态码 原因短语）
Content-Type: text/html            ← 响应头
Content-Length: 1234
Set-Cookie: session=abc123
                                   ← 空行
&lt;html&gt; ... &lt;/html&gt;                ← 消息体
</code></pre>
<h4>请求方法（常见的 HTTP 动词）</h4>
<ul>
<li>
<p><strong>GET</strong>：获取资源，幂等、无副作用。</p>
</li>
<li>
<p><strong>POST</strong>：提交数据，创建资源，通常有消息体。</p>
</li>
<li>
<p><strong>PUT</strong>：整体更新指定资源，幂等。</p>
</li>
<li>
<p><strong>PATCH</strong>：部分更新资源。</p>
</li>
<li>
<p><strong>DELETE</strong>：删除资源。</p>
</li>
<li>
<p><strong>HEAD</strong>：只获取响应头，不返回主体。</p>
</li>
<li>
<p><strong>OPTIONS</strong>：查询服务器支持的请求方法（常用于 CORS 预检）。</p>
</li>
<li>
<p><strong>CONNECT</strong>：建立隧道（常用于 HTTPS 代理）。</p>
</li>
<li>
<p><strong>TRACE</strong>：回显请求，用于诊断。</p>
</li>
</ul>
<h4>重要头部字段（Headers）</h4>
<ul>
<li>
<p><strong>通用/请求头</strong>：<code>Host</code>（必需，指明域名）、<code>User-Agent</code>、<code>Accept</code>、<code>Authorization</code>、<code>Cookie</code></p>
</li>
<li>
<p><strong>响应头</strong>：<code>Set-Cookie</code>、<code>Location</code>（用于重定向）、<code>Server</code></p>
</li>
<li>
<p><strong>内容相关</strong>：<code>Content-Type</code>（如<code>application/json</code>）、<code>Content-Length</code>、<code>Content-Encoding</code>（gzip 等）</p>
</li>
<li>
<p><strong>缓存控制</strong>：<code>Cache-Control</code>、<code>ETag</code>、<code>Last-Modified</code>、<code>Expires</code></p>
</li>
<li>
<p><strong>CORS</strong>：<code>Access-Control-Allow-Origin</code>等</p>
</li>
</ul>
<h4>HTTPS</h4>
<p>HTTPS = HTTP over TLS/SSL，在 TCP 层之上增加加密、身份验证和完整性保护。它使用数字证书确保服务器身份，并加密通信数据，是当今 Web 安全的基础。HTTP/2 和 HTTP/3 基本都依赖加密（HTTP/2 在浏览器中强制使用 HTTPS）。</p>
<h3>Tomcat</h3>
<h4>简介</h4>
<p>Tomcat 是一个开源的 Servlet 容器 和轻量级 Web 服务器，由 Apache 软件基金会维护。通俗地说，它的核心工作就是接收 HTTP 请求，分发给 Java 程序处理，再把 HTTP 响应返回给客户端。</p>
<h4>简单使用</h4>
<p>直接在官网<a href="https://tomcat.apache.org/">Apache Tomcat® - Welcome</a>下载压缩包。</p>
<p>Windows 平台，解压后，在<code>/bin</code>目录中，使用<code>startup.bat</code>启动，<code>shutdown.bat</code>关闭。</p>
<p>我这里运行时命令行窗口闪了一下便关闭了，可以 cd 到 tomcat 所在目录，执行<code>catalina.bat run</code>捕捉报错信息：</p>
<pre><code>C:\Users\zhang\Desktop\apache-tomcat-10.1.55\bin&gt;catalina.bat run
Using CATALINA_BASE:   &quot;C:\Users\zhang\Desktop\apache-tomcat-10.1.55&quot;
Using CATALINA_HOME:   &quot;C:\Users\zhang\Desktop\apache-tomcat-10.1.55&quot;
Using CATALINA_TMPDIR: &quot;C:\Users\zhang\Desktop\apache-tomcat-10.1.55\temp&quot;
Using JRE_HOME:        &quot;C:\Program Files (x86)\Java\jdk1.8.0_481&quot;
Using CLASSPATH:       &quot;C:\Users\zhang\Desktop\apache-tomcat-10.1.55\bin\bootstrap.jar;C:\Users\zhang\Desktop\apache-tomcat-10.1.55\bin\tomcat-juli.jar&quot;
Using CATALINA_OPTS:   &quot;&quot;
Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMED
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
</code></pre>
<p><code>--add-opens</code>是 Java9 及以后的参数，所以无法启动 JVM 虚拟机。我们安装 Java 17，然后把 JAVA_HOME 系统变量更改为 Java 17 的安装位置。</p>
<p>访问<code>http://localhost:8080</code>可以看见 tomcat 的欢迎界面。</p>
<p>这里我又遇到了乱码问题，中文字符无法正常显示。解决起来也很简单，打开 Tomcat 的<code>conf/logging.properties</code>，找到<code>java.util.logging.ConsoleHandler.encoding = UTF-8</code>的配置，改成<code>GBK</code>即可让控制台输出正常中文。改完需重启，就可以看到一切正常了。</p>
<p>将站点程序放置在<code>webapps/</code>下即可部署。</p>
<h3>请求响应</h3>
<h4>概述</h4>
<p>Web 服务器中含有一个 Dispatcherservlet 类，它会将请求转发给对应的 Controller，称为核心控制器或前端控制器。</p>
<p>Dispatcherservlet 接收到请求后会将其封装为一个 Httpservletrequest 对象，也叫请求对象。响应数据被封装为 Httpservletresponse。</p>
<h4>请求</h4>
<h5>简单参数</h5>
<p>我们创建一个 Spring Boot 项目。</p>
<pre><code>package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;

@RestController
public class RequestController {
    @RequestMapping(&quot;/simpleParam&quot;)
    public String simpleParam(HttpServletRequest request) {
        // 依靠 request 对象获取请求参数
        String name = request.getParameter(&quot;name&quot;);
        String ageStr = request.getParameter(&quot;age&quot;);
        // 将 String 类型的 int 转换为 int 类型
        int age = Integer.parseInt(ageStr);
        // 输出 &amp; 返回
        System.out.println(name + &quot; : &quot; + age);
        return &quot;OK&quot;;
    }
}
</code></pre>
<p>访问后，控制台打印 name：age，返回 &quot;OK&quot;。</p>
<p>同时可以使用更加简便的写法，无需写<code>HttpServletRequest request</code>来手动取参：</p>
<pre><code>@RequestMapping(&quot;/simpleParam&quot;)
public String simpleParam(@RequestParam String name, @RequestParam int age) {
    System.out.println(name + &quot; : &quot; + age);
    return &quot;OK&quot;;
}
</code></pre>
<p>这时 Spring 内部会通过另一组参数解析器，自动从 request 中提取<code>name</code>和<code>age</code>并转好类型，连<code>Integer.parseInt</code>都省了。</p>
<p>又或者：</p>
<pre><code>    @RequestMapping(&quot;/simpleParam&quot;)
    public String simpleParam(String name, int age) {
        System.out.println(name + &quot; : &quot; + age);
        return &quot;OK&quot;;
    }
</code></pre>
<p>Spring MVC 做了参数的自动绑定和类型转换。我们不需要手动从 request 里取参数，只要<strong>方法参数的名字和 HTTP 参数名一致</strong>，Spring 就会自动把值注入进来，并尽可能转成我们需要的类型。所以，如果形参与请求参数名不一致，我们仍然需要使用 @RequestParam 映射参数。</p>
<p>启动后浏览器访问<code>localhost:8080/simpleParam?name=zhangsanage=18</code>即可看见 OK 字样。如果参数不正确或不完整，显示 Whitelabel Error Page 页面。</p>
<h5>实体参数</h5>
<p>我们新建一个 Pojo 目录，书写一个标准的 JavaBean 类，拥有 age 与 name 两个属性。</p>
<p>然后：</p>
<pre><code>    @RequestMapping(&quot;/simplePojo&quot;)
    public String simplePojo(User user) {
        System.out.println(user);
        return &quot;OK&quot;;
    }
</code></pre>
<p>即可将参数传入 user 对象。</p>
<h5>数组集合参数</h5>
<pre><code>    @RequestMapping(&quot;/arrayParam&quot;)
    public String arrayParam(String[] hobby) {
        System.out.println(Arrays.toString(hobby));
        return &quot;OK&quot;;
    }
</code></pre>
<h5>日期参数</h5>
<pre><code>    @RequestMapping(&quot;/dateParam&quot;)
    public String dateParam(@DateTimeFormat(pattern = &quot;yyyy-MM-dd HH:mm:ss&quot;)LocalDateTime updateTime) {
        System.out.println(updateTime);
        return &quot;OK&quot;;
    }
</code></pre>
<p>访问<code>localhost:8080/dateParam?updateTime=2010-04-30 11:45:14</code>，控制台打印<code>2010-04-30T11:45:14</code>。</p>
<h5>路径参数</h5>
<p>例如<code>/path/1</code>与<code>/path/2</code>。</p>
<pre><code>    @RequestMapping(&quot;path/{id}&quot;)
    public String pathParam(@PathVariable Integer id) {
        System.out.println(id);
        return &quot;OK&quot;;
    }
</code></pre>
<h4>响应</h4>
<p>可以构建一个 Result 类，return 时创建其对象并返回。方便管理与维护。</p>
<h3>分层解耦</h3>
<h4>三层架构</h4>
<p>数据访问层 DAO（Data Access Object | 持久层）、逻辑处理层 Service、接收/响应层 Controller。遵循单一职责原则。</p>
<h4>分层解耦</h4>
<p>高内聚、低耦合。</p>
<h4>控制反转与依赖转入</h4>
<p><strong>控制反转</strong>（Inversion Of Control），将对象的创建控制权从自身转移到外部（容器）。该容器叫作 IOC 容器。</p>
<p><strong>依赖注入</strong>（Dendency Injection），容器为应用提供运行时，所依赖的资源，称为依赖注入。</p>
<p><strong>Bean 对象</strong>是 IOC 容器中创建并管理的对象。</p>
<h4>IOCDI - 入门</h4>
<p>使用 @Component 注解将一个类交给 IOC 管理。</p>
<p>使用 @Autowired 注解找到该类型的 Bean 并完成依赖注入。</p>
]]></content:encoded>
  </item>
  <item>
    <title>Navidrome + 音流 APP：你的第一个自建音乐库</title>
    <link>https://www.pyrzo.com/posts/navidrome-and-streammusic</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/navidrome-and-streammusic</guid>
    <pubDate>Mon, 09 Feb 2026 13:56:30 +0000</pubDate>
    <description>厌倦订阅？用Navidrome+音流，零成本自建私人曲库。连上NAS全平台畅听，还折腾了歌词API——虽坑不少，却换来买断制自由与真·无忧播放。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>最近咸鱼上收了俩1T的机械盘，FnOS 里组了个镜像阵列，我又开始向往自建音乐库了——以前并不是一个 NAS 玩家，音乐全存在固态里着实有点烧钱。虽然原本打算换个程序的，不过我等了好久的飞牛音乐终究还是没有上线。那就重操我的 Navidrome 旧业吧。</p>
<p>可能有许多人都玩过 Jellifin、Emby 这样的自建流媒体服务。不过它们的流播貌似都并不专精于音乐——看电影啥的倒是不错。不过说 Navidrome 专精于音乐播放，倒也不对。Navidrome 虽然是网页使用，但依旧没有配套的多平台 APP，以及甚至没有一个同目录下同名 lrc 自动外挂的功能——每一首歌都需要我自己用 Fooba2000 把歌词内嵌进 Tag 里。</p>
<p>不过这些小问题都还在我能忍受的范围内，何况还有一款第三方的应用“音流”可以用（音流不仅可以对接 Navidrome，也可以对接 Jellyfin、Plex 之类的程序）</p>
<h2>Navidrome 安装</h2>
<p>说实话，我不认为 Docker 跑应用还需要安装教程。这里只摘抄一下<code>docker-compose.yml</code>：</p>
<pre><code>services:
  navidrome:
    image: deluan/navidrome:latest
    user: 1000:1000 # should be owner of volumes
    ports:
      - &quot;4533:4533&quot;
    restart: unless-stopped
    environment:
      # Optional: put your config options customization here. Examples:
      # ND_LOGLEVEL: debug
    volumes:
      - &quot;/path/to/data:/data&quot;
      - &quot;/path/to/your/music/folder:/music:ro&quot;
</code></pre>
<p><code>docker-compose.yml</code>文件内容也可以见于官方文档的 Installing with Docker 一章（<a href="https://www.navidrome.org/docs/installation/docker/">Installing with Docker | Navidrome</a>）或者如果你使用 1Panel、FnOS 之类的工具/系统，也可以直接在它们的应用商店内安装。</p>
<p><code>volumes</code>的部分，我是将 NAS 上的音乐文件夹 NFS 挂载至了我专门跑 Docker 的虚拟机，然后将持久化目录中的 /music 目录指定到了这个挂载路径。</p>
<h2>简单用用 Navidrome</h2>
<p>Navidrome 开箱即用，官方的 compose 文件默认端口<code>4533</code>，访问后创建一个管理员账户，即可开始使用。</p>
<p>朝容器的 /music 挂载目录里丢入音频文件，就会被 Navidrome 扫到。如果没有，也可以点击右上角<code>运行情况</code>，再点击<code>完全扫描</code>进行一个手动扫描。</p>
<p>个性化设置中可以设置语言选项，也可以切换主题。试了一圈，个人觉得<code>Ligera</code>主题最顺眼。——虽然不管哪个主题看起来都略显简陋。</p>
<h2>音流 APP</h2>
<p>音流是一款 NAS 音乐播放器，可以连接到您部署在 NAS 上的音乐服务，能让您在不同平台享受一致的音乐盛宴。</p>
<ol>
<li>
<p>目前支持的音乐服务: Subsonic,Navidrome,Emby,Jellyfin,AudioStation,Plex.</p>
</li>
<li>
<p>目前支持的平台: Android 6.0, iOS 14, macOS 10.14, Windows 10.</p>
</li>
</ol>
<p>特色功能：</p>
<ul>
<li>
<p>兼容多种音乐服务。</p>
</li>
<li>
<p>支持歌词显示，通过自定义 API 还可让不提供歌词接口的音乐服务也拥有显示歌词的能力！</p>
</li>
<li>
<p>使用 Flutter 构建，为您提供接近原生的使用体验，在跨平台适配上拥有无限的可能性。</p>
</li>
</ul>
<p>音流的基础功能免费使用，部分功能需要购买会员解锁。我也顺手买了一个，记得好像是 68 元来着，所以 本文中展示的内容可能与免费版有出入。虽说是“会员”，但其实这软件不是订阅制的而是买断制的。我一向喜欢买断制软件。具体功能差别可以看<a href="https://music.aqzscn.cn/docs/features">功能比较 | 音流</a>。</p>
<p>音流靠各平台的 API 对服务数据进行读取、修改等操作。初次打开音流会提示添加存储库，按照实际情况填写 Navidrome 地址、账户、密码就可以进入软件了。</p>
<p>我将主题修改为了浅色，控制栏类型修改为毛玻璃，算是调节到了我个人看着最顺眼的设置上了。——主题功能好像是要付费解锁的。</p>
<p>整个 UI 整洁、现代，手机横屏后也会自动切换视图。这里放几张图观赏一下：</p>
<p>不难发现，软件主页的 Navidrome 下方有一个“主路线”标签——备用路线功能也是会员才有的。目前用下来，大致逻辑推测是这样：第一个被添加的路线会被认为是主路线，后面添加的则是备用路线。主路线连接失败时会自动切换至备用路线，也可以手动切换路线。还可以单独为不同路线设置音频码率。看起来是个不错的功能，在家里直连内网流播，在外面连穿透地址转低码率流播还能省流量。不过我并没有这种需求，所以也并没有切实体验过。</p>
<h2>歌词 API</h2>
<p>上文也提到过了，Navidrome 不支持外挂歌词，一首一首内嵌真的很难受。</p>
<p>但后面发现了一个开源项目：LrcApi<a href="https://github.com/HisAtri/LrcApi">GitHub - HisAtri/LrcApi: A Flask API For StreamMusic.</a>，“A Flask API For<a href="https://github.com/gitbobobo/StreamMusic">StreamMusic</a>”说明其专门适配音流。</p>
<p>LrcApi 功能：</p>
<ul>
<li>
<p>支持酷狗/聚合API获取LRC歌词</p>
</li>
<li>
<p>支持text/json API</p>
</li>
<li>
<p>支持获取音乐/专辑/艺术家封面</p>
</li>
<li>
<p>默认监听28883端口，API地址<code>http://0.0.0.0:28883/lyrics</code>；新版API地址<code>http://0.0.0.0:28883/jsonapi</code>；封面API地址<code>http://0.0.0.0:28883/cover</code></p>
</li>
</ul>
<p>这里摘抄一下 README 中的<code>docker-compose.yml</code>：</p>
<pre><code>services:
  lrcapi:
    image: hisatri/lrcapi:latest
    container_name: lrcapi
    ports:
      - &quot;28883:28883&quot;
    volumes:
      - /home/user/music:/music
    environment:
      - API_AUTH=自定义一个鉴权key
    restart: always
</code></pre>
<p>API_AUTH 可以设置一个鉴权 key，填写在音流客户端的自定义API设置中的<code>验证信息</code>处即可。</p>
<hr />
<p>如果你正在使用Navidrome Docker，请将 /home/user/music:/music 中的 /home/user/music 修改为你在Navidrome中映射的主机路径；</p>
<p>换句话说，-v 参数与Navidrome保持一致即可。</p>
<p>然后访问<code>http://0.0.0.0:28883/lyrics</code>或新版API<code>http://0.0.0.0:28883/jsonapi</code></p>
<p>图片API地址为<code>http://0.0.0.0:28883/cover</code></p>
<p>注意：图片返回目前采用反向代理策略，可能存在一定的上下行流量消耗和延迟。</p>
<p>支持使用Nginx或Apache进行反向代理与SSL。</p>
<p>—— LrcApi 的 README</p>
<hr />
<p>不过说实话这个功能体验下来效果并不是特别好。——它成功工作了，但工作的并不是很好。</p>
<p>自定义 API 设置中明明有一个<code>优先使用音乐服务接口</code>（只有音乐服务接口无数据时才会从自定义 API 获取数据）的开关的，但是这玩意死活不认为我的无封面歌曲和专辑是无封面的——压根不会去拉取封面。——可能是因为返回默认封面也被算作是“音乐服务接口有数据”？真搞不懂为什么。</p>
<p>带着这个问题我翻了翻 Issue，结果发现这个项目在 25 年 1 月份时仓库主人就已经决定停止维护了。（<a href="https://github.com/HisAtri/LrcApi/issues/119">【项目中止说明】 · Issue #119 · HisAtri/LrcApi</a>）Oh my GOD R.I.P.🙏不过这项目目前还是一个勉强能继续用的状态。</p>
<p>开着这个功能吧，就无法获取封面，那这个 API 搭建起来的意义就找不到了；关掉这个功能吧，速度又会慢到不是常人所能忍受的了。真是怎么用都觉得有点拧巴。</p>
<p>——我最后还是选择牺牲一部分速度，关掉这个功能。毕竟歌曲流播的速度是不受影响的。</p>
<p>总之，这篇文章就到这里吧。我总算是又能无忧无虑的听音乐了。</p>
<h2><strong>版权申明</strong></h2>
<ul>
<li>
<p>本文作者：光昭</p>
</li>
<li>
<p>本文链接：<a href="https://www.pyrzo.com/posts/navidrome-and-streammusic/">https://www.pyrzo.com/posts/navidrome-and-streammusic/</a></p>
</li>
<li>
<p>版权声明：所有文章除特别声明外均系本人自主创作，转载及引用请联系作者，并注明出处（作者、原文链接等）。</p>
</li>
<li>
<p>部分图片、文字搜集于网络，若构成侵权请联系我，会尽快删除。</p>
</li>
</ul>
]]></content:encoded>
  </item>
  <item>
    <title>LINUX 通过 NUT 接入 UPS 配置教程</title>
    <link>https://www.pyrzo.com/posts/nut-configuration</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/nut-configuration</guid>
    <pubDate>Sat, 20 Dec 2025 11:45:59 +0000</pubDate>
    <description>APCUPSD反复报NOBATT逼疯你？同款 BK650M2-CH 换成 NUT 后终于清净了。中间还被驱动玄学报错卡住，重启才救回来。这篇踩坑记录带你丝滑迁移，UPS 关机从此不翻车。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>最近给 PVE 加了一个 UPS（由于是 APC 家的 BK650M2-CH，所以使用 APCUPSD 服务，详见<a href="https://www.pyrzo.com/posts/pve-apcupsd/">使用 APCUPSD 让 PVE 接入 UPS 获得断电保护 - 光昭</a>）但是后来发现 APCUPSD 服务总是会频繁报告 UPS 为 NOBATT 状态。后来在网上看见一篇文章（详见<a href="https://qiedd.com/1887.html">PVE 上使用 Nut 代替 Apcupsd (BK650M2-CH: ONBATT) - 企鹅大大的博客</a>,Reference[1]），也是 BK650M2-CH 的 NOBATT 问题，文中提到这是 APCUPSD 服务引起的，遂尝试换 NUT 服务，顺手水记录一篇文章。</p>
<h2>相关概念</h2>
<p>老传统。</p>
<h3>NUT 简介</h3>
<p>NUT（<strong>Network UPS Tools</strong>）是一个开源的跨平台软件套件，用于管理不同品牌和型号的<strong>不间断电源（UPS）</strong>。它通过监控UPS状态，在断电时安全关闭连接的设备（如服务器、网络设备等），防止数据丢失或硬件损坏。</p>
<h3>NUT 架构</h3>
<p>NUT 分为三层：</p>
<ul>
<li>
<p>nut-driver：驱动层， 用于与 UPS 通信并获取 UPS 信息。</p>
</li>
<li>
<p>nut-server：服务层，用于对外提供 UPS 信息。</p>
</li>
<li>
<p>nut-monitor：监控层，可实现监控 UPS 电量并实现自动关机。</p>
</li>
</ul>
<h2>配置教程</h2>
<h3>安装 NUT</h3>
<pre><code>apt update -y &amp;&amp; apt install nut
</code></pre>
<h3>扫描 NUT 设备</h3>
<pre><code>nut-scanner
</code></pre>
<p>输出类似如下内容：</p>
<pre><code>[nutdev1]
        driver = &quot;usbhid-ups&quot;
        port = &quot;auto&quot;
        vendorid = &quot;****&quot;
        productid = &quot;****&quot;
        product = &quot;Back-UPS BK650M2_CH&quot;
        ......
</code></pre>
<h3>配置 NUT</h3>
<p>NUT 需要设置一个 UPS 名与密码，本文中以</p>
<ul>
<li>
<p>UPS 名：myups</p>
</li>
<li>
<p>ups 用户：upsuser</p>
</li>
</ul>
<h4>编辑 ups.conf</h4>
<p>编辑 ups.conf 文件：</p>
<pre><code>nano /etc/nut/ups.conf
</code></pre>
<p>修改 upsname：</p>
<pre><code>#maxretry = 3
[myups]
  driver = usbhid-ups
  port = auto
  desc = &quot;My UPS&quot;
</code></pre>
<h4>启动及自启动 nut-driver</h4>
<pre><code>/sbin/upsdrvctl start
</code></pre>
<p>这里我遇到过 libusb1: Could not open any HID devices...Driver failed to start (exit status=1) 之类的报错，兜兜转转一圈后在 Github Issues 中找到了与我一样的问题，部分用户给出的解决办法是“full reboot”，我尝试重启 PVE 节点以及我的 UPS 后，一切正常了。</p>
<p>真玄学。</p>
<h4>配置用户文件</h4>
<pre><code>nano /etc/nut/upsd.users
</code></pre>
<p>最下方加入如下内容：</p>
<pre><code>[upsuser]
     password = PASSWD
     upsmon primary
     actions = SET
     instcmds = ALL
# 将 PASSWD 替换成你自己想要的密码
</code></pre>
<h4>配置运行模式</h4>
<pre><code>nano /etc/nut/nut.conf
</code></pre>
<p>将 Mode 修改为 standalone（此外 NUT 还有 netserver 运行模式，可以了解一下）</p>
<pre><code>MODE=standalone
</code></pre>
<h4>启动及自启动 nut-server</h4>
<pre><code>/sbin/upsd
</code></pre>
<h4>查看配置</h4>
<pre><code># upsc upsname
# upsname 即你设置的 UPS 名，本文中为 myups
# 所以最终需要执行
upsc myups
</code></pre>
<p>输出如下：</p>
<h3>设置自动关机</h3>
<p>即配置 nut-monitor。</p>
<h4>编辑 upsmon.conf</h4>
<pre><code>nano /etc/nut/upsmon.conf
</code></pre>
<p>在 MONITOR 块添加，格式如下或见文件内注释：</p>
<pre><code>MONITOR myups@localhost 1 upsuser PASSWD primary
# PASSWD 即为你前面设置的密码
</code></pre>
<p>部分配置项：</p>
<ul>
<li>
<p>DEADTIME：UPS 掉线阈值，默认为 15s</p>
</li>
<li>
<p>FINALDELAY：等待多久后，shutdown 宿主机</p>
</li>
</ul>
<h4>启动及自启动 nut-monitor</h4>
<pre><code>systemctl start nut-monitor.service &amp;&amp; systemctl enable nut-monitor.service
</code></pre>
<h4>启动 NUT</h4>
<p>为了让系统服务单元在启动时启动，我们添加 systemd。</p>
<pre><code>systemctl start nut.target &amp;&amp; systemctl enable nut.target &amp;&amp; systemctl enable nut-driver.target &amp;&amp; systemctl start nut-driver.target
</code></pre>
<h2>电力故障模拟测试</h2>
<p>拔掉 UPS 连接市电的电源，观察其是否会按预期自动关机。</p>
<h2>Reference</h2>
<p>[1]<a href="https://qiedd.com/1887.html">PVE 上使用 Nut 代替 Apcupsd (BK650M2-CH: ONBATT) - 企鹅大大的博客</a></p>
<p>[2]<a href="https://wiki.archlinux.org/title/Network_UPS_Tools">Network UPS Tools - ArchWiki</a></p>
<h2>版权申明</h2>
<ul>
<li>
<p>本文作者：光昭</p>
</li>
<li>
<p>本文链接：<a href="https://www.pyrzo.com/posts/nut-configuration">https://www.pyrzo.com/posts/nut-configuration</a></p>
</li>
<li>
<p>版权声明：所有文章除特别声明外均系本人自主创作，转载及引用请联系作者，并注明出处（作者、原文链接等）。</p>
</li>
<li>
<p>部分图片、文字搜集于网络，若构成侵权请联系我，会尽快删除。</p>
</li>
</ul>
]]></content:encoded>
  </item>
  <item>
    <title>使用 APCUPSD 让 PVE 接入 UPS 获得断电保护</title>
    <link>https://www.pyrzo.com/posts/pve-apcupsd</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/pve-apcupsd</guid>
    <pubDate>Sat, 06 Dec 2025 06:18:40 +0000</pubDate>
    <description>想让你的 PVE 在断电时安全自动关机？上手一台 APC UPS，装个 apcupsd，几条命令就能搞定。跟着我一步步配好参数，拔电实测，从此告别数据焦虑。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>最近一直想整台 UPS 给 PVE 玩玩，正巧又看见了<a href="https://zhuanlan.zhihu.com/p/537027469">玩转PVE：连接施耐德UPS实现自动关机 - 知乎</a>这篇文章，折腾属性大发，当即买了台 APC 的 UPS 回来玩。</p>
<p>本文内容参考上述文章并扩充一些内容。本文作记录分享/教学用均可。</p>
<h2>环境介绍</h2>
<p>以下是本文环境：</p>
<ul>
<li>
<p>PVE 9.1.1</p>
</li>
<li>
<p>UPS：APC BK650M2-CH</p>
</li>
</ul>
<h2>概念科普</h2>
<h3>APCUPSD</h3>
<p><strong>apcupsd</strong>是一款<strong>开源、跨平台</strong>的软件，全称是<em>APC UPS Daemon</em>。它的核心功能是<strong>监控和管理美国电力转换公司（APC，现属于施耐德电气）的不间断电源（UPS）设备</strong>，确保在停电或电力异常时，受保护的计算机或服务器能够<strong>安全、自动地关机</strong>，从而防止数据丢失或硬件损坏。</p>
<ul>
<li>
<p><strong>守护进程</strong>：<code>apcupsd</code>作为一个后台服务（daemon）运行。</p>
</li>
<li>
<p><strong>通信</strong>：通过USB/串口等与UPS硬件保持通信，定期查询状态。</p>
</li>
<li>
<p><strong>事件触发</strong>：当检测到预设的“危险”条件（如市电断电且电池电量低于某个阈值）时，触发关机序列。</p>
</li>
<li>
<p><strong>执行关机</strong>：按照配置，在电池耗尽前预留足够时间，向系统发送关机命令。</p>
</li>
</ul>
<h2>正式开始</h2>
<h3>一、安装 APCUPSD 服务</h3>
<p>SSH 或通过其他方式连接到 PVE 主机的 SHELL。然后执行：</p>
<pre><code>apt-get install apcupsd -y
</code></pre>
<p>执行后将安装 APCUPSD</p>
<h3>二、编辑 APCUPSD 服务配置文件</h3>
<p>我们编辑<code>/etc/apcupsd/apcupsd.conf</code>，编辑器挑一个顺手即可，这里以 nano 为例：</p>
<pre><code>nano /etc/apcupsd/apcupsd.conf
</code></pre>
<h3>二【附】、配置项解释</h3>
<p>忽略掉注释行文字，剩下的就是配置项了：</p>
<ul>
<li>UPSCABLE usb</li>
</ul>
<p>此项配置 UPS 与 PVE 的连接线材类型。一般使用 USB 连接，这里默认即可。</p>
<ul>
<li>UPSTYPE usb</li>
</ul>
<p>UPS 与 PVE 连接方式。默认无需修改。</p>
<ul>
<li>DEVICE /dev/ttyS0</li>
</ul>
<p>指定的设备路径。若使用 USB 连接，<strong>请务必将此行注释掉。</strong>（特别提醒：注释后遇到问题可以翻阅本文第六章即常见问题解决方案）</p>
<p>我们再向下翻，可以看见一些如下配置项。这些配置项是电力故障时的设置。</p>
<pre><code>#
# ======== Configuration parameters used during power failures ==========
#

# The ONBATTERYDELAY is the time in seconds from when a power failure
#   is detected until we react to it with an onbattery event.
#
#   This means that, apccontrol will be called with the powerout argument
#   immediately when a power failure is detected.  However, the
#   onbattery argument is passed to apccontrol only after the
#   ONBATTERYDELAY time.  If you don't want to be annoyed by short
#   powerfailures, make sure that apccontrol powerout does nothing
#   i.e. comment out the wall.
ONBATTERYDELAY 6

#
# Note: BATTERYLEVEL, MINUTES, and TIMEOUT work in conjunction, so
# the first that occurs will cause the initation of a shutdown.
#

# If during a power failure, the remaining battery percentage
# (as reported by the UPS) is below or equal to BATTERYLEVEL,
# apcupsd will initiate a system shutdown.
BATTERYLEVEL 5

# If during a power failure, the remaining runtime in minutes
# (as calculated internally by the UPS) is below or equal to MINUTES,
# apcupsd, will initiate a system shutdown.
MINUTES 3

# If during a power failure, the UPS has run on batteries for TIMEOUT
# many seconds or longer, apcupsd will initiate a system shutdown.
# A value of 0 disables this timer.
#
#  Note, if you have a Smart UPS, you will most likely want to disable
#    this timer by setting it to zero. That way, you UPS will continue
#    on batteries until either the % charge remaing drops to or below BATTERYLEVEL,
#    or the remaining battery runtime drops to or below MINUTES.  Of course,
#    if you are testing, setting this to 60 causes a quick system shutdown
#    if you pull the power plug.
#  If you have an older dumb UPS, you will want to set this to less than
#    the time you know you can run on batteries.
TIMEOUT 0
</code></pre>
<p>对其中配置项解释如下：</p>
<p>【名称】【含义】【单位】ONBATTERYDELAY断电多少时间后才识别为正在使用电池，防止短时间断电导致错误秒/sBATTERYLEVEL电池电量低于多少时关闭主机，建议修改为95百分比/%MINUTES当电池剩余后备时间为多少时关闭主机分钟/minTIMEOUT断电时间（默认 0 即关闭）分钟/min</p>
<p>注：若 BATTERYLEVEL、MINUTES、TIMEOUT 三个配置均被设置，则满足默认其中一个条件时便触发关机。</p>
<p>编辑完成后，按下键盘上的 ctrl+o 保存文件，随后按下 ctrl+x 退出编辑器。</p>
<h2>三、启动服务并设置开机自启</h2>
<p>启动 apcupsd 服务：</p>
<pre><code>systemctl start apcupsd.service
</code></pre>
<p>设置服务开机自启动：</p>
<pre><code>systemctl enable apcupsd.service
</code></pre>
<p>查看服务运行状态：</p>
<pre><code>systemctl status apcupsd.service
</code></pre>
<h2>四、查看 UPS 状态</h2>
<p>执行：</p>
<pre><code>apcaccess 
</code></pre>
<p>打印类似如下内容：</p>
<pre><code>root@pve:~# apcaccess
APC      : 001,035,0824
DATE     : 2025-12-06 13:50:00 +0800
HOSTNAME : pve
VERSION  : 3.14.14 (31 May 2016) debian
UPSNAME  : pve
CABLE    : USB Cable
DRIVER   : USB UPS Driver
UPSMODE  : Stand Alone
STARTTIME: 2025-12-06 13:49:58 +0800
MODEL    : Back-UPS BK650M2_CH
STATUS   : ONLINE
LINEV    : 220.0 Volts
LOADPCT  : 15.0 Percent
BCHARGE  : 99.0 Percent
TIMELEFT : 39.6 Minutes
MBATTCHG : 25 Percent
MINTIMEL : 3 Minutes
MAXTIME  : 0 Seconds
SENSE    : Low
LOTRANS  : 160.0 Volts
HITRANS  : 278.0 Volts
ALARMDEL : 30 Seconds
BATTV    : 13.5 Volts
LASTXFER : No transfers since turnon
NUMXFERS : 0
TONBATT  : 0 Seconds
CUMONBATT: 0 Seconds
XOFFBATT : N/A
SELFTEST : OK
STATFLAG : 0x05000008
SERIALNO : 9B2536A51882
BATTDATE : 2001-01-01
NOMINV   : 220 Volts
NOMBATTV : 12.0 Volts
NOMPOWER : 390 Watts
END APC  : 2025-12-06 13:50:04 +0800
</code></pre>
<p>STATUS : ONLINE 说明 UPS 已被成功连接至 PVE。若该栏显示为 COMMLOST 则表示通信丢失，可以移步至本文 六、常见问题排查 一章。</p>
<h2>五、模拟电力故障测试</h2>
<p>执行 systemctl status apcupsd.service，然后拔掉 UPS 与市电连接的电源，status变成了ONBATT。</p>
<h2>六、常见问题</h2>
<p>Q：我执行 apcaccess 后看见 STATUS : COMMLOST？</p>
<p>A：如果你根据本文进行操作并遇到这个问题（我实操时也遇到了），大概率是配置文件的缘故。我们前面不是该过一个 DEVICE /dev/ttyS0 吗？当时说是要注释掉，但实际上我发现这样会造成 COMMLOST 状态。尝试将这行取消注释而直接留空后恢复正常。由于参考文章中表示要注释且我并未做详细对照试验，所以保留了这一或许是错误的内容。</p>
<h2>版权声明</h2>
<ul>
<li>
<p>本文作者：<a href="https://www.pyrzo.com/">光昭</a></p>
</li>
<li>
<p>本文链接：<a href="https://www.pyrzo.com/posts/pve-apcupsd">https://www.pyrzo.com/posts/pve-apcupsd</a></p>
</li>
<li>
<p>版权声明：所有文章除特别声明外均系本人自主创作，转载及引用请联系作者，并注明出处（作者、原文链接等）。</p>
</li>
<li>
<p>部分图片搜集于网络，若构成侵权请联系我，会尽快删除图片。</p>
</li>
</ul>
]]></content:encoded>
  </item>
  <item>
    <title>balenaEtcher 烧录后 U 盘无法操作的解决方案</title>
    <link>https://www.pyrzo.com/posts/balenaetcher-replication-restoration</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/balenaetcher-replication-restoration</guid>
    <pubDate>Sat, 13 Sep 2025 13:10:05 +0000</pubDate>
    <description>烧录镜像后，U 盘突然变成三个无法操作的分区？磁盘管理也无能为力。别急着扔，一个隐藏的命令行工具就能让它起死回生。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>一开始，我使用 balenaEtcher 烧录了我的 PVE 系统镜像，一切都很好。但当我尝试再次使用这个 U 盘时，问题出现了：U 盘被划为三块分区，在磁盘管理器中也无法对磁盘进行初始化，整个 U 盘变成一种无法操作的状态。</p>
<p>经过一番寻觅，很快便找到了解决方案，可以使用 diskpart 工具对其进行擦除操作，随后就可以再次新建简单卷并当作一个正常 U 盘再次使用了。</p>
<h2>解决</h2>
<h3>擦除数据</h3>
<p><strong>此步骤将擦除你 U 盘中所有的现有数据。</strong></p>
<p>按下<code>win+r</code>组合键调出运行，输入 diskpart 后回车，然后得到一个 CMD 窗口。</p>
<p>查看计算机连接的所有磁盘：</p>
<pre><code>list disk
</code></pre>
<p>得到类似如下的输出：</p>
<pre><code>  磁盘 ###  状态           大小     可用     Dyn  Gpt
  --------  -------------  -------  -------  ---  ---
  磁盘 0    联机              931 GB  1024 KB        *
  磁盘 1    联机               28 GB    27 GB        *
</code></pre>
<p>我们可以依据磁盘的大小来确定哪个是我们烧录过的 U 盘，本文这里是 磁盘 1。</p>
<p>随后再输入</p>
<pre><code>select disk 1
# 选择磁盘 1
# 将数字照你的实际情况修改
</code></pre>
<p>然后使用 cleanall 擦除 U 盘上所有数据：</p>
<pre><code>clean all
</code></pre>
<p>随后再回到磁盘管理器查看，就会发现 U 盘已经变成空盘可以正常被操作了。</p>
<h3>新建简单卷</h3>
<p>右键左下角 Win 徽标，选择磁盘管理器，然后右键 U 盘的灰色未分配区域即可重新分区并正常使用。</p>
]]></content:encoded>
  </item>
  <item>
    <title>Sunshine + Moonlight 串流一站式指南：告别延迟，实现跨设备高清游戏串流</title>
    <link>https://www.pyrzo.com/posts/sunshine-moonlight</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/sunshine-moonlight</guid>
    <pubDate>Sun, 07 Sep 2025 05:01:51 +0000</pubDate>
    <description>告别妥协画质与高昂订阅，用Sunshine+Moonlight，无论任何显卡，都能在手机、平板、电视上低延迟畅玩3A大作。这个免费开源方案，让你随时随地跨设备享受丝滑游戏。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>引言</h2>
<p>你是否也曾幻想过这样的场景？</p>
<p>周末的午后，你不想再正襟危坐在书房冰冷的电脑椅上，而是想慵懒地陷在客厅舒适的沙发里，在巨大的电视屏幕上体验《艾尔登法环》的壮阔世界；或是晚上睡前，想用手边的iPad或安卓平板，继续征战《博德之门3》的冒险，而无需重新下载几十个G的游戏。</p>
<p>这些看似美好的愿望，在过去却总是被“游戏串流”这道技术门槛所阻拦。也许你尝试过Steam Link，却为它的延迟和画质妥协而感到失望；或许你曾是NVIDIA Gamestream的忠实用户，却因其突然停止支持而倍感无奈；又或者，你被其他商业串流方案昂贵的订阅费用和复杂的设置直接劝退。</p>
<p>而现在，一切都不一样了。我们可以使用 Sunshine + Moonlight 这套强大的方案来实现低延迟高帧率的游戏画面串流。无论你是想从PC串流到手机、平板、笔记本，还是电视盒子，无论你用的是NVIDIA、AMD还是Intel显卡，它都将带你轻松跨越设备与平台的壁垒。</p>
<p>串流与传统远程桌面的设计理念不同。串流可以给你带来最低的延迟反馈与最高的画质和帧率——它是专为游戏而生的所以可能还有专门适配与优化；而后者则更注重办公的功能性。</p>
<p>（本文后半部分也会粗略介绍一下远程串流的解决方案）</p>
<h2>搭建环境介绍</h2>
<p>我的 Sunshine 服务端被安装在一台虚拟化出来且直通了 GPU 的一台 Windos 虚拟机上。当然，一个更好的选择是单独放置一台物理机。</p>
<ul>
<li>
<p>Windows GTX1650（下文称主机或远程主机）</p>
</li>
<li>
<p>Sunshine 2025.628.4510（下文称服务端）</p>
</li>
<li>
<p>Moonlight 6.1.0（下文称客户端）</p>
</li>
</ul>
<h2>在开始之前</h2>
<h3>注意事项</h3>
<ol>
<li>
<p>Nvidia 显卡的串流延迟可能是 AMD 显卡同代方案的 二分之一 甚至更低。所以十分建议您使用 Nvida 显卡，即使任何显卡都是被此方案支持的。</p>
</li>
<li>
<p>有线连接远比无线连接稳定得多。如果您发现您的网络传输帧率频繁卡顿或是有频繁的速率过低告警，可能就是因为您正在使用无线连接导致的。</p>
</li>
</ol>
<h3>概念科普</h3>
<h4>Moonlight</h4>
<ul>
<li>
<p>源自NVIDIA Gamestream，但现已支持所有GPU。</p>
</li>
<li>
<p>几乎全平台的客户端（Windows, macOS, Linux, Android, iOS, 甚至游戏主机）。</p>
</li>
<li>
<p>提供极致的低延迟和画质体验。</p>
</li>
</ul>
<h4>Sunshine</h4>
<ul>
<li>
<p>一个开源、跨平台的游戏串流服务端。</p>
</li>
<li>
<p>替代已停更的NVIDIA Gamestream服务端。</p>
</li>
<li>
<p>支持AMD, Intel, NVIDIA显卡。</p>
</li>
</ul>
<h4>组合优势</h4>
<ul>
<li>
<p><strong>完全免费且开源。</strong></p>
</li>
<li>
<p>**超低延迟和高性能：**媲美甚至超越商业方案。</p>
</li>
<li>
<p>**极高的兼容性：**不限显卡品牌，不限客户端设备。</p>
</li>
<li>
<p><strong>高度可定制化。</strong></p>
</li>
</ul>
<h2>准备工作</h2>
<h3>硬件要求</h3>
<ul>
<li>
<p>**主机（Server - 运行Sunshine的PC）：**一台性能强大的Windows/Linux PC（用于游戏），支持硬件编码的GPU（NVIDIA NVENC, AMD AMF, Intel Quick Sync）。</p>
</li>
<li>
<p>**客户端（Client - 运行Moonlight的设备）：**电脑、手机、平板、电视盒子等。</p>
</li>
<li>
<p>**网络要求：****强烈建议所有设备使用有线（以太网）连接。**最低要求5GHz Wi-Fi。分析有线与无线的延迟差异。</p>
</li>
</ul>
<h2>安装配置及使用</h2>
<h3>Sunshine</h3>
<p>仓库地址：</p>
<p>[ghcard path=&quot;LizardByte/Sunshine&quot;][/ghcard]</p>
<p>在<a href="https://github.com/LizardByte/Sunshine/releases">此处</a>下载 Sunshine（服务端），建议不要使用带有<code>Pre-release</code>（预览版）标签字样的发布，而是下滑找到绿色的<code>Latest</code>标签。</p>
<p>远程主机一般是 Win 系统，所以直接下载 sunshine-windows-installer.exe 并在远程主机上运行安装即可。Sunshine 会被作为服务注册安装，随开机自动启动。</p>
<p>你可以方便的通过 WebUI 管理 Sunshine（即安装完成后自动打开的<a href="https://localhost:47990/">localhost:47990</a>）第一次访问可能会提示不安全（因为证书是自签的），以 Edge/Chrome 浏览器为例，点击“高级”，再点击“继续访问”即可。</p>
<p>此时会要求你创建一个账户，用于日后的管理面板访问鉴权。只需输入账户密码再确认一次密码，即可使用设置的账密登录 Sunshine Web UI。</p>
<p>管理页面默认以英文显示。如果您不是特别习惯英语，Sunshine 的 Web UI 也同样提供了包括中文在内的多语言支持。在<code>Configuration</code>栏的<code>General</code>标签页中有一个<code>Local</code>选项，将其改为简体中文，保存设置后软件会自动重启以使设置生效。</p>
<h3>Moonlight</h3>
<p>官网地址：</p>
<p><a href="https://moonlight-stream.org/">moonlight-stream.org</a></p>
<p>接下来我们需要在设备上安装 Moonlight 作为客户端连接到远程主机。</p>
<p>Windows：直接在 Github 仓库<a href="https://github.com/moonlight-stream/moonlight-qt/releases">Releases · moonlight-stream/moonlight-qt</a>中下载<code>MoonlightSetup</code>程序并安装即可。</p>
<p>安卓：<a href="https://github.com/moonlight-stream/moonlight-android/releases">Releases · moonlight-stream/moonlight-android</a>下载。一般选择<code>nonRoot-release</code>。</p>
<p>IOS：App Store 搜索并安装。</p>
<p>启动 Moonlight 后，软件会自动在本地局域网内寻找可用的远程主机，我们只需要等待设备被搜索到之后，点击设备图标，然后拿着得到的一串数字（配对码）到 Sunshine 管理面板的<code>PIN码</code>页面中填入它并设置设备名，即可完成配对。</p>
<p>客户端可以设置画质、帧率、码率等主要设置与其它性能或偏好设置。如果无特殊需求保持默认即可。若发现连接过程中频繁提示连接速率过低则请尝试降低码率或是确保自己的设备通过网线连接至网络（无线连接的稳定性欠佳，来自 ax200 无线网卡，会周期性丢包）</p>
<h2>常用快捷键</h2>
<p>（送给第一次用时甚至不知道怎么退出串流的我）</p>
<p>PC 客户端：</p>
<ul>
<li>
<p>Ctrl+Alt+Shift+Q - 退出流式处理会话（让游戏在主机PC上运行）</p>
</li>
<li>
<p>Ctrl+Alt+Shift+Z - 切换鼠标和键盘捕获</p>
</li>
<li>
<p>Ctrl+Alt+Shift+X - 在全屏和窗口模式之间切换</p>
</li>
<li>
<p>Ctrl+Alt+Shift+S - 打开性能统计信息叠加（Steam Link 或 Raspberry Pi 不支持）</p>
</li>
<li>
<p>Ctrl+Alt+Shift+M - 切换鼠标模式（指针捕获或直接控制）</p>
</li>
<li>
<p>Ctrl+Alt+Shift+V - 在主机上键入剪贴板文本</p>
</li>
<li>
<p>Ctrl+Alt+Shift+D - 最小化流窗口</p>
</li>
<li>
<p>Ctrl+Alt+Shift+C - 在远程桌面鼠标模式下切换本地光标显示（由于 GameStream 限制，远程光标将始终显示）</p>
</li>
<li>
<p>Ctrl+Alt+Shift+L - 切换将鼠标指针锁定到视频区域（需要启用“优化鼠标以进行远程桌面而不是游戏”复选框）</p>
</li>
</ul>
<p>翻译自<a href="https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide#keyboardmousegamepad-input-options">Setup Guide · moonlight-stream/moonlight-docs Wiki</a>，可能有部分错误，可以自行查阅文档链接中的内容。</p>
<h2>显卡欺骗器</h2>
<p>如果你想要的是一台云电脑般的云主机，那么你可能需要一颗显卡欺骗器。显卡在无显示器信号的情况下不会输出任何画面（串流画面黑屏），所以串流也不会成功。而显卡欺骗器则向显卡发送显示器信号从而使显卡正常工作。淘宝上随便买一颗即可，价格相对低廉，分辨率一般都可调。</p>
<p>如果您不想使用显卡欺骗器或者认为欺骗显卡很没道德心（雾），可以尝试使用虚拟桌面软件——例如 Parsec-vdd。虚拟屏幕软件是通过创建一个不存在的屏幕让显卡认为你接了显示器。</p>
<p>二者在功能性上并无较大差别，不过由于前者是物理层面解决方案，我可能会更加推荐欺骗器。当然，后者的功能一定更加强大的（况且这不要钱）</p>
<h2>网络</h2>
<p>一般来说，大部分人的使用场景是同局域网的串流，所以带宽几乎不成问题。需要注意的只是网络稳定性，<strong>推荐使用有线连接</strong>，稳定性与延迟都优于无线连接。</p>
<p>一般来说，1080p@60 的画面需要 20Mbps，1440p@60 需要 40Mbps，4k@60 需要 80Mbps，4k@120 则需要 113Mbps。</p>
<p>对于公网串流，其影响因素包括物理/链路距离、是否跨运营商、高峰期堵塞等。跨运营商可能会遭到 QoS，所以建议让主机网络与客户端网络同属同意运营商，二者物理距离越短越好。</p>
<h2>公网串流方案</h2>
<p>由于 Sunshine 徐娅 6 个以上对等端口，并且协议包含http，所以内网穿透起来十分麻烦。这里介绍虚拟组网与公网 IP 方案。</p>
<h3>虚拟组网</h3>
<p>你也可以叫它虚拟局域网，这是最方便简单的方案。</p>
<p><strong>虚拟局域网（VLAN）</strong>，简单来说，就是通过技术手段，将<strong>一个物理上的局域网</strong>，划分成<strong>多个逻辑上独立的、隔离的“小局域网”</strong>。</p>
<p>不过请注意，VLAN 与 VPN 的概念并不相同。前者是 P2P 端到端及 NAT 打洞技术为主，中继流量为辅；而后者则是通过建立加密隧道连接不同网络的设备。</p>
<p>常见的软件有 ZeroTier、Tailscale 等。基本都是开箱即用且无需任何公网服务。</p>
<p>这类软件原理流程如下：</p>
<ul>
<li>
<p>首先尝试 NAT 打洞，若成功则直接建立端到端连接（速度高）</p>
</li>
<li>
<p>若打洞失败则将流量发送至中继服务器（速度低）</p>
</li>
</ul>
<p>所以，虚拟局域网的方案虽然方便，但存在着一些不确定因素——如果您的网络状况特别逆天，就会走速度极慢延迟极高的中继了。</p>
<h3>公网 IP</h3>
<p>公网 IP 分有 IPv4 与 IPv6 两种。</p>
<h4>IPv4</h4>
<p>由于 IPv4 地址早已耗尽，所以目前大多数设备的 IPv4 地址都是结合了 NAT 技术的（例如您的手机与电脑虽然在局域网中各自拥有独立的内网 IP，但它们的公网 IP 可能是相同的）</p>
<p>所以如果您需要通过 IPv4 进行连接，可以尝试联系您的运营商申请一个（不要说要做什么什么服务，说要拉监控就行）（移动用户申请公网 IPv4 比较难——除非你加钱）</p>
<p>公网 IP 申请下来之后，还需要将自己的光猫改为桥接模式，用路由器拨号上网并开启路由器的 Upnp 功能（Universal Plug and Play，它允许网络设备自动配置并相互连接，无需手动设置）再在 Sunshine 的<code>Configuration</code>的<code>Network</code>页面中开启 Upnp。</p>
<p>最后，在 Moonlight 中直接输入远程主机的 IPv4 地址，如果一切顺利就可以顺利串流了。</p>
<h4>IPv6</h4>
<p>如果您是移动用户或是出于某些原因无法得到 IPv4 独立地址，可以尝试使用 IPv6。</p>
<p>IPv6 作为解决 IPv4 地址耗尽问题的新一代 IP 协议，地址充足，一般不会被 NAT（要是 IPv6 的地址都要 NAT 的话，那运营商就真的逆天了）</p>
<p>在<code>ip.sb</code>得到自己的 IPv6 地址，填入 Moonlight 后同样可以连接（需要在 Sunshine的Configuration-Network下面开启IPv4 + IPv6选项）。</p>
<p>不过，部分路由器可能针对公网的入站流量有拦截规则（虽然我的路由器没有），您就需要到路由器管理界面中放行需要使用的端口。Sunshine 所使用的端口可以在<code>Configuration</code>的<code>Network</code>页面查看。</p>
<p>不过请注意：如果您需要通过 IPv6 连接主机，那么您的客户端也必须具备一个可用的 IPv6 地址（IPv4 与 IPv6 是两个独立协议，并不互通）您在外出门时，如果不使用移动数据，几乎不可能有 IPv6 地址。</p>
<h2>如何远程唤醒（无人值守）</h2>
<h3>开机卡</h3>
<p>可以网购一个远程开机卡，插在主机上之后即可在外面远程开机。</p>
<h3>WOL</h3>
<p>也可以拿出一台闲置的小设备（24*7 运行，例如树莓派等），在上面运行一个 Frp 客户端（自建内网穿透服务可参考<a href="https://www.pyrzo.com/posts/nps-frp-guidence/">https://www.pyrzo.com/posts/nps-frp-guidence/</a>）。出门在外时，只需要通过 frp 连接到家里的树莓派，再用树莓派通过 WOL 协议唤醒主机即可。</p>
<h3>智能插座</h3>
<p>当然，也可以购买一个小米智能插座，这种智能插座可以通过 Wi-fi 连接至网络。我们只需要在主机 BIOS 里设置电源为上电自动开机，然后通过米家软件控制智能插座的电源，也可以达到一样的效果。</p>
<h2>版权申明</h2>
<ul>
<li>
<p>本文作者：<a href="https://www.pyrzo.com/">光昭</a></p>
</li>
<li>
<p>本文链接：<a href="https://www.pyrzo.com/posts/sunshine-moonlight">https://www.pyrzo.com/posts/sunshine-moonlight</a></p>
</li>
<li>
<p>版权声明：所有文章除特别声明外均系本人自主创作，转载及引用请联系作者，并注明出处（作者、原文链接等）。</p>
</li>
<li>
<p>部分图片搜集于网络，若构成侵权请联系我，会尽快删除图片</p>
</li>
</ul>
]]></content:encoded>
  </item>
  <item>
    <title>关于 Wordfence 优化防火墙 .user.ini 文件无法修改的解决方法</title>
    <link>https://www.pyrzo.com/posts/wdfence-user-ini</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/wdfence-user-ini</guid>
    <pubDate>Sat, 06 Sep 2025 15:42:54 +0000</pubDate>
    <description>你的Wordfence优化总卡在.user.ini无法修改？别被644权限骗了——文件其实被系统暗中“上锁”。用一条root命令即可秒解，改完再锁回去，安全又利落。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>如果网站运行在 PHP 上，那么一般在根目录会生成一个 .user.ini 配置文件。宝塔对此文件的描述是 PHP 用户配置文件（防跨站）</p>
<p>该文件权限为 644/root，尝试修改文件后发现无法直接修改权限。这其实是因为出于某些安全考虑，该文件被锁定导致的。</p>
<p>开始前，请确保你拥有 root 权限与远程命令执行的能力。</p>
<h2>解决方法</h2>
<p>我们需要使用<code>chattr</code>命令用于修改文件或目录的隐藏属性，只有 root 用户可以使用。<code>-i</code>参数用于取消文件或目录的不可修改属性。（<code>+i</code>反之）</p>
<p>连接到你的服务器终端。先移动到站点所在根目录。例如：</p>
<pre><code>cd /www/wwwroot/www.pyrzo.com/
# 请将 /www/wwwroot/www.pyrzo.com/ 替换为你网站的实际路径
</code></pre>
<p>随后执行以下命令解锁 .user.ini 文件：</p>
<pre><code>chattr -i .user.ini
</code></pre>
<p>现在就可以随意更改 .user.ini 文件的权限了，我们更改为 755/root。随后回到 Wordfence 或是其它 WP 插件，再次执行对 .user.ini 文件的更改操作，此时应当就成功了。</p>
<p><strong>当然，为了安全着想，请不要忘记在操作完成后重新将修改回 644/root 并将文件再次锁定。</strong></p>
<pre><code>chattr +i .user.ini
</code></pre>
]]></content:encoded>
    <category>网站建设</category>
  </item>
  <item>
    <title>PVE 固定网口名防止插拔显卡或其他 PCI 设备导致后台失联</title>
    <link>https://www.pyrzo.com/posts/pve-internet-name-immobilization</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/pve-internet-name-immobilization</guid>
    <pubDate>Thu, 14 Aug 2025 14:20:25 +0000</pubDate>
    <description>插块显卡网口竟罢工？Linux的混沌命名规则专坑折腾党！只需绑定MAC地址，让网卡名从此“焊死”，失联悲剧不再上演。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>文章修缮</h2>
<p>PVE 9 以后的版本，默认便以网卡名固定地址，所以不存在网卡 PCI 位置改变导致 PVE 失联的情况。</p>
<h2>前言</h2>
<p>有一天我打算<a href="https://www.pyrzo.com/posts/pve-gpu-passthrough-guidence/">折腾一下显卡直通</a>，插上显卡之后，嘿，您猜怎么着？我的网口居然不亮了。</p>
<p>那真是老北京人出门不走地道——中了邪了。</p>
<h2>原理</h2>
<p>一张显卡居然能影响到网口？是的，这里是混沌邪恶的 Linux。</p>
<p>Linux 插拔显卡或 PCIE 网卡等 PCI 设备会导致网卡的物理位置变更，而网卡名又是根据设备物理位置而定的，所以这就会导致 PCI 设备变更后网口名改变导致系统没网。</p>
<p>其实早期linux设备名是不会变的，后来的“可预测设备名”，本质上是为了让每个设备的命名方式根据其在硬件通道上的真实位置进行。</p>
<p>不论怎么样，本篇文章来讲解 PVE 固定网卡名的方法。本文的原理是绑定网卡名与 MAC 地址，这样网卡名就不会因物理位置变动而改变了。</p>
<h2>获取网卡名与 MAC 地址</h2>
<p>在 PVE 终端执行**<code>ip a</code>**，得到类似如下输出：</p>
<pre><code>......
2: enp6s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel master vmbr0 state UP group default qlen 1000
    link/ether 10:ff:e0:83:88:de brd ff:ff:ff:ff:ff:ff
    altname enx10ffe08388de
3: vmbr0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:ff:e0:83:88:de brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.99/24 scope global vmbr0
       valid_lft forever preferred_lft forever
    inet6 fe80::12ff:e0ff:fe83:88de/64 scope link proto kernel_ll
       valid_lft forever preferred_lft forever
......
</code></pre>
<p>其中，<code>enp6s0</code>是网卡名，也是我们一会需要用到的。而<code>vmbr0</code>只是网桥，忽略即可，这里放出来是为了方便你们定位。</p>
<p>我这里的情况如下，请你更具你的实际情况为准：</p>
<ul>
<li>
<p>网卡名：<code>enp6s0</code></p>
</li>
<li>
<p>MAC 地址：<code>10:ff:e0:83:88:de</code></p>
</li>
</ul>
<p>注意 MAC 地址别记错成 IPv6 地址了。两样信息记录下来一会用。</p>
<p>注：如果您的网口名是 eno1 等形式也是正常现象，这个是 bios 内定义的板上网卡。这个在逻辑上是板上网卡，但也有可能是插入的网卡。纯粹是 bios 定义。总之，继续进行之后的步骤即可。</p>
<h2>创建 MAC 与网卡名的绑定文件</h2>
<p>使用以下命令编辑文件：</p>
<pre><code>nano /usr/lib/systemd/network/50-custom-net0.link
</code></pre>
<p>在其中粘贴以下内容：</p>
<pre><code>[Match]
MACAddress=10:ff:e0:83:88:de
[Link]
Name=enp6s0
</code></pre>
<p>上方是刚刚的 MAC 地址，下方则是网卡名。</p>
<p>ctrl+o 保存文件，ctrl+x 退出编辑。</p>
<h2>后记</h2>
<p>至此，你的网卡名应当就不会因为插拔显卡、网卡等 PCI 设备而再次变动了，失联率也会大大降低。</p>
<h2>巨人的肩膀</h2>
<p>参考：</p>
<p><a href="https://www.bilibili.com/video/BV1qyTtzrE4G/?share_source=copy_web&amp;vd_source=f600ce8b8a3ef5c17bc738ca1acc8182">【ProxmoxVE必备技能：固定网卡名称防止增减PCIE设备失联】</a></p>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>PVE 8/9 显卡直通通用一站式教程/指南</title>
    <link>https://www.pyrzo.com/posts/pve-gpu-passthrough-guidence</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/pve-gpu-passthrough-guidence</guid>
    <pubDate>Thu, 14 Aug 2025 06:40:58 +0000</pubDate>
    <description>你知道吗？PVE 9 起已默认开启硬件直通，不用再折腾 grub 文件！这篇一站式指南带你从零完成显卡直通，简单几步，轻松搞定。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>2025/11/29 文章修缮</h2>
<p>内容更正：自 PVE9 开始，系统已默认开启了硬件直通。也就是说，如果您是 PVE 9.0 之后的用户，无需执行编辑 /etc/default/grub 文件的步骤。</p>
<h2>前言</h2>
<p>本文只讨论显卡的直通（Passthrough）操作，不包含核显虚拟化（SR-IOV）。</p>
<h2>必要信息</h2>
<ul>
<li>
<p>本文基于 PVE 8.4，测试后发现 PVE 9 也支持（9.0.10）额外信息见页首 2025/11/29 文章修缮章。</p>
</li>
<li>
<p>请确保所使用的 硬件设备 支持 Intel VT-D 或者 AMD AMD-V ，<strong>并且在 BIOS 中已经启用</strong>。</p>
</li>
<li>
<p>本文默认您已拥有一定 Linux 系统操作基础。（指不是只会复制代码）</p>
</li>
</ul>
<h2>开启IOMMU</h2>
<h3>编辑文件</h3>
<p>使用自己顺手的编辑工具（例如 nano）编辑**<code>/etc/default/grub</code>**文件。</p>
<p>修改 GRUB_CMDLINE_LINUX_DEFAULT 配置项：</p>
<pre><code>AMD 平台修改为：
GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet amd_iommu=on iommu=pt initcall_blacklist=sysfb_init pcie_acs_override=downstream&quot;
Intel 平台修改为：
GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet intel_iommu=on iommu=pt initcall_blacklist=sysfb_init pcie_acs_override=downstream&quot;
</code></pre>
<h3>更新 GRUB</h3>
<p>使用以下命令更新 GRUB：</p>
<pre><code>proxmox-boot-tool refresh
</code></pre>
<h3>加载对应内核模块</h3>
<p>编辑**<code>/etc/modules</code>**</p>
<p>添加如下字样：</p>
<pre><code>vfio
vfio_iommu_type1
vfio_pci
# vfio_virqfd
</code></pre>
<p>如果您使用较新的 PVE 版本，可能会发现该文件内容如下：</p>
<pre><code># /etc/modules is obsolete and has been replaced by /etc/modules-load.d/.
# Please see modules-load.d(5) and modprobe.d(5) for details.
#
# Updating this file still works, but it is undocumented and unsupported.
</code></pre>
<p>意思是这个文件已被<code>/etc/modules-load.d/.</code>取代，修改这个文件仍然起作用，但它将不再在文档里出现，也不被官方支持。不过这并不对我们的直通有什么影响，所以继续下一步。</p>
<p>随后使用<code>**reboot**</code>重启 PVE。</p>
<h3>检验设置</h3>
<p>输入**<code>dmesg | grep iommu</code>**，若设置正确，应当由类似如下的打印内容：</p>
<pre><code>root@pve:~# dmesg | grep iommu
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.14.8-2-pve root=/dev/mapper/pve-root ro quiet amd_iommu=on iommu=pt initcall_blacklist=sysfb_init pcie_acs_override=downstream
[    0.029753] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-6.14.8-2-pve root=/dev/mapper/pve-root ro quiet amd_iommu=on iommu=pt initcall_blacklist=sysfb_init pcie_acs_override=downstream
[    0.265777] iommu: Default domain type: Passthrough (set via kernel command line)
[    0.294219] pci 0000:00:00.0: Adding to iommu group 0
[    0.294232] pci 0000:00:01.0: Adding to iommu group 1
[    0.294240] pci 0000:00:01.1: Adding to iommu group 2
[    0.294247] pci 0000:00:01.2: Adding to iommu group 3
[    0.294257] pci 0000:00:02.0: Adding to iommu group 4
[    0.294264] pci 0000:00:02.1: Adding to iommu group 5
[    0.294272] pci 0000:00:03.0: Adding to iommu group 6
[    0.294280] pci 0000:00:04.0: Adding to iommu group 7
[    0.294291] pci 0000:00:08.0: Adding to iommu group 8
[    0.294297] pci 0000:00:08.1: Adding to iommu group 9
[    0.294303] pci 0000:00:08.3: Adding to iommu group 10
[    0.294314] pci 0000:00:14.0: Adding to iommu group 11
[    0.294319] pci 0000:00:14.3: Adding to iommu group 11
[    0.294346] pci 0000:00:18.0: Adding to iommu group 12
[    0.294346] pci 0000:00:18.1: Adding to iommu group 12
[    0.294362] pci 0000:00:18.2: Adding to iommu group 12
[    0.294367] pci 0000:00:18.3: Adding to iommu group 12
[    0.294373] pci 0000:00:18.4: Adding to iommu group 12
[    0.294379] pci 0000:00:18.5: Adding to iommu group 12
[    0.294385] pci 0000:00:18.6: Adding to iommu group 12
[    0.294390] pci 0000:00:18.7: Adding to iommu group 12
[    0.294409] pci 0000:01:00.0: Adding to iommu group 13
[    0.294424] pci 0000:01:00.1: Adding to iommu group 13
[    0.294431] pci 0000:02:00.0: Adding to iommu group 14
[    0.294438] pci 0000:03:00.0: Adding to iommu group 15
[    0.294453] pci 0000:04:00.0: Adding to iommu group 16
[    0.294465] pci 0000:04:01.0: Adding to iommu group 17
[    0.294476] pci 0000:04:02.0: Adding to iommu group 18
[    0.294487] pci 0000:04:03.0: Adding to iommu group 19
[    0.294498] pci 0000:04:04.0: Adding to iommu group 20
[    0.294510] pci 0000:04:05.0: Adding to iommu group 21
[    0.294521] pci 0000:04:06.0: Adding to iommu group 22
[    0.294532] pci 0000:04:07.0: Adding to iommu group 23
[    0.294545] pci 0000:04:08.0: Adding to iommu group 24
[    0.294557] pci 0000:04:09.0: Adding to iommu group 25
[    0.294568] pci 0000:04:0a.0: Adding to iommu group 26
[    0.294578] pci 0000:04:0b.0: Adding to iommu group 27
[    0.294591] pci 0000:04:0c.0: Adding to iommu group 28
[    0.294603] pci 0000:04:0d.0: Adding to iommu group 29
[    0.294617] pci 0000:06:00.0: Adding to iommu group 30
[    0.294629] pci 0000:11:00.0: Adding to iommu group 31
[    0.294641] pci 0000:12:00.0: Adding to iommu group 32
[    0.294660] pci 0000:13:00.0: Adding to iommu group 33
[    0.294667] pci 0000:13:00.1: Adding to iommu group 34
[    0.294675] pci 0000:13:00.2: Adding to iommu group 35
[    0.294684] pci 0000:13:00.3: Adding to iommu group 36
[    0.294691] pci 0000:13:00.4: Adding to iommu group 37
[    0.294699] pci 0000:13:00.6: Adding to iommu group 38
[    0.294706] pci 0000:14:00.0: Adding to iommu group 39
[    2.213208] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).
</code></pre>
<h2>直通显卡</h2>
<h3>屏蔽显卡驱动</h3>
<p>编辑**<code>/etc/modprobe.d/pve-blacklist.conf</code>**，按对应硬件添加对应内容：</p>
<pre><code># Nvidia
blacklist nvidiafb
blacklist nouveau
blacklist nvidia

# AMD
blacklist amdgpu
blacklist radeon

# Intel UHD
#blacklist snd_hda_codec_hdmi
#blacklist snd_hda_intel
#blacklist snd_hda_codec
#blacklist snd_hda_core
</code></pre>
<h3>忽略显卡警告</h3>
<p><strong>Nvidia专属</strong>，主要在<strong>Win</strong>中遇到一些应用，列如<em><strong>GeForce Experience</strong></em>、<em><strong>Passmark Performance Test</strong></em>和<em><strong>SiSoftware Sandra</strong></em>。</p>
<p><em>为什么这么做？</em></p>
<p>因为 Tips：&quot;Some Windows applications like GeForce Experience, Passmark Performance Test and SiSoftware Sandra can crash the VM. You need to add&quot;（大意：一些 Win 平台的应用，像是 GeForce Experience, Passmark Performance Test and SiSoftware Sandra 等软件可能会导致 VM 崩溃，所以你需要添加（以下信息）） ——<a href="https://pve.proxmox.com/wiki/PCI_Passthrough">PVE 官方 GPU Passthrough 文档</a></p>
<p>编辑<code>**/etc/modprobe.d/kvm.conf**</code>，添加如下内容：</p>
<pre><code>options kvm ignore_msrs=1 report_ignored_msrs=0
</code></pre>
<h3>配置 VFIO</h3>
<p>主要用于 显示输出 和 音频输出 分开。</p>
<h4>确定显卡 ID</h4>
<p>执行**<code>lspci -nn | grep VGA</code>**，我这里信息如下：</p>
<pre><code>01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU117 [GeForce GTX 1650] [10de:1f82] (rev a1)
13:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Granite Ridge [Radeon Graphics] [1002:13c0] (rev c6)
</code></pre>
<p>这里可以看到我的独显 ID 是 01:00（13:00.0 是 AMD 的核显）</p>
<h4>获取 设备ID 和 音频ID</h4>
<p>输入**<code>lspci -n -s 01:00</code>**（我的是 01:00，您应当改为您的实际情况）</p>
<pre><code>01:00.0 0300: 10dg:1fa2 (rev a1)
01:00.1 0403: 10dg:10fd (rev a1)
</code></pre>
<h4>编辑文件</h4>
<p>将<em><strong>设备ID</strong></em>（<code>10dg:1fa2</code>） 和<em><strong>音频ID</strong></em>（<code>10dg:10fd</code>） 写入到<code>**/etc/modprobe.d/vfio.conf**</code>：</p>
<pre><code>options vfio-pci ids=10dg:1fa2,10dg:10fd
</code></pre>
<h3>更新内核</h3>
<pre><code>update-initramfs -u
</code></pre>
<p>随后使用 reboot 重启主机。</p>
<h3>检验设置生效</h3>
<p>使用以下命令：</p>
<pre><code>lspci -nnk
</code></pre>
<p>找到显卡的位置，输出应当如下：</p>
<pre><code>01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU117 [GeForce GTX 1650] [10de:1f82] (rev a1)
        Subsystem: Micro-Star International Co., Ltd. [MSI] Device [1462:8d92]
        Kernel driver in use: vfio-pci
        Kernel modules: nvidiafb, nouveau
01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:10fa] (rev a1)
        Subsystem: Micro-Star International Co., Ltd. [MSI] Device [1462:8d92]
        Kernel driver in use: vfio-pci
        Kernel modules: snd_hda_intel
</code></pre>
<p>（结果中有<code>**Kernel driver in use: vfio-pci**</code>即为成功）</p>
<h2>创建虚拟机</h2>
<p>与平常一样创建即可。但有以下几个设置需要修改：</p>
<ul>
<li>
<p>机型：q35</p>
</li>
<li>
<p>BIOS：OVMF（UEFI）</p>
</li>
</ul>
<p>其余设置均可按照自己喜好设置。</p>
<p>随后编辑虚拟机的设置：</p>
<ol>
<li>
<p>选择<strong>虚拟机</strong>， 并点击<strong>硬件</strong></p>
</li>
<li>
<p>点击<strong>添加</strong>， 然后点击<strong>PCI设备</strong></p>
</li>
<li>
<p>选择<code>**原始设备**</code>，在<strong>设备</strong>中选择需要直通的显卡</p>
</li>
<li>
<p>启用<em><strong>所有功能</strong></em>、<em><strong>主GPU</strong></em>、<em><strong>ROM-Bar</strong></em>、<em><strong>PCI-Express</strong></em></p>
</li>
<li>
<p>添加</p>
</li>
</ol>
<p>至此，显卡的直通操作就完成了。你可以打开虚拟机并安装驱动使用显卡了。</p>
<h2>参考文档</h2>
<p><a href="https://www.cnblogs.com/MAENESA/p/18005241">https://www.cnblogs.com/MAENESA/p/18005241</a>—— 本文总体思路参考</p>
<p><a href="https://pve.proxmox.com/wiki/PCI_Passthrough">PCI Passthrough - Proxmox VE</a>—— PVE 官方的显卡直通文档</p>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>我的 AdGuard Home DNS 设置与黑名单列表分享</title>
    <link>https://www.pyrzo.com/posts/my-adguardhome-dns-settings-and-blacklist</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/my-adguardhome-dns-settings-and-blacklist</guid>
    <pubDate>Wed, 13 Aug 2025 15:55:48 +0000</pubDate>
    <description>想让家中所有设备（包括智能冰箱、吸尘器）都远离广告与追踪？我的一台 AdGuard Home 就做到了，无需每个设备装客户端。本文分享我的 DNS 防劫持设置与专为中国网络优化的过滤黑名单，助你轻松打造纯净网络。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>前言</h2>
<p>在自己的 PVE 主机上起了台 LXC 容器跑 AdGuard Home，一开始甚至遇到了 DNS 无法使用的情况，后来发现是 DNS 设置导致。</p>
<h2>AdGuard Home是什么</h2>
<p>如果您尚不知道这是什么，这里就按惯例做个介绍：</p>
<p>AdGuard Home 是一款全网广告拦截与反跟踪软件。在您将其安装完毕后，它将保护您所有家用设备，同时您不再需要安装任何客户端软件。随着物联网与连接设备的兴起，掌控您自己的整个网络环境变得越来越重要。</p>
<ul>
<li>
<p>AdGuard Home 作为 DNS 服务器以重新路由跟踪域到 &quot;黑洞&quot;，从而防止您的设备连接这些服务器。其是基于我们的公共 AdGuard DNS 服务器之上— 这两者共用大量的常用代码。</p>
</li>
<li>
<p>运行您自己的 AdGuard Home 服务器比使用公共 DNS 能做得更多： 决定某些服务器是否应该被拦截； 监控您的网络活动； 添加您自己的过滤器规则 。 未来，AdGuard Home 将不止是一个 DNS 服务器。</p>
</li>
<li>
<p>无论您去哪儿，不管是在您的智能电话上，还是在如智能冰箱，智能吸尘器等智能产品上，广告和跟踪器都在跟随您。即使您对收集您数据的公司无任何反对意见，跟踪也很危险。广告更不好 —它们长期成为各种恶意软件，病毒，勒索软件，钓鱼和跟踪器的门户。 AdGuard Home 为在您网络上的所有设备提供统一的广告/跟踪器拦截的解决方案。</p>
</li>
<li>
<p>当前您可在 MacOS，Linux（x32 / x64）和 Raspberry Pi 上安装 AdGuard Home。您无需了解技术细节 — 我们的 GitHub 仓库 上有专门的安装过程描述。此外，我们的维基百科上有安装 AG DNS 到 VPS 和 Raspberry Pi 的详细指导。</p>
</li>
</ul>
<p>——官网：<a href="https://adguard.com/zh_cn/adguard-home/overview.html">AdGuard Home| 适用于任何操作系统（Windows，macOS，Linux）的网络软件</a></p>
<h2>DNS 设置</h2>
<h3>上游 DNS</h3>
<p>我配置的上游 DNS 为 DoH，可以输入以下内容：</p>
<pre><code>https://dns.alidns.com/dns-query #阿里云 DNS
https://sm2.doh.pub/dns-query #腾讯云 DNS
https://doh.360.cn/dns-query #360 DNS
</code></pre>
<p>DoH 通过 https 协议连接，混在普通流量中，不容易被劫持。</p>
<h3>Bootstrap DNS 服务器</h3>
<p>DNS 服务器的 IP 地址，用于解析指定为上游的 DoH/DoT 解析器的 IP 地址。不允许添加注释。</p>
<p>这个大可填写你所在地区的运营商 DNS，一般网上能找出来。没有可以填写 8.8.8.8 这类公共 DNS 或者自己路由器网关地址（例如我的 192.168.10.1，每个人的网络环境并不相同所以请以你的实际情况为准）</p>
<h3>DNS 缓存配置</h3>
<p>覆盖最小 TTL 值：86400</p>
<p>覆盖最大 TTL 值：864000</p>
<p>勾选 DNS 乐观缓存。</p>
<h2>DNS 黑名单列表</h2>
<p>AdGuard Home 已预置两个封锁清单：AdGuard DNS filter 与 AdAway Default Blocklist。</p>
<p>这里推荐一个：</p>
<h1>封锁清单并不是越多越好，如果您并没有特殊需求仅使用默认清单就足够了。</h1>
<pre><code>名称：CHN: anti-AD 
https://adguardteam.github.io/HostlistsRegistry/assets/filter_21.txt
# anti-AD 对中国的优化规则
名称：anti-ad-easylist
https://anti-ad.net/easylist.txt
# anti-AD 通用的国际广告规则
</code></pre>
]]></content:encoded>
  </item>
  <item>
    <title>PVE9 升级教程、实况：无翻车</title>
    <link>https://www.pyrzo.com/posts/pve9-update</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/pve9-update</guid>
    <pubDate>Sun, 10 Aug 2025 16:01:33 +0000</pubDate>
    <description>AIO 主机升级 PVE9 全程实录：直通 SATA、GPU 一切正常，真正零翻车！</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>概况</h2>
<p>最近，PVE 为我们带来了全新的 PVE9（虽然对于个人玩家并没有什么新功能，主要是组件更新）</p>
<ul>
<li>
<p><strong>基于 Debian 13 “Trixie”</strong></p>
</li>
<li>
<p><strong>内核版本：6.14.8-2</strong></p>
</li>
<li>
<p><strong>QEMU 10.0.2</strong></p>
</li>
<li>
<p>LXC 6.0.4</p>
</li>
<li>
<p>ZFS 2.3.3</p>
</li>
<li>
<p>Ceph Squid 19.2.3</p>
</li>
</ul>
<p>而我将会把我的这台 AIO 升级到最新的 PVE9。这台机器目前为 PVE8.4.9，直通设备有 SATA 控制器及一张 GPU。后续升级完成后二者均正常。</p>
<h2>升级前的准备</h2>
<p>[warning]升级有风险！升级先备份！！！[/warning]</p>
<p>更新可能会导致网卡名变更，进而导致后台失联。强烈建议您先进行固定网卡名的操作。可以参考我这篇文章操作：<a href="https://www.pyrzo.com/posts/pve-internet-name-immobilization/">PVE 固定网口名防止插拔显卡或其他 PCI 设备导致后台失联 - 光昭</a></p>
<h3>升级前检查</h3>
<p>请务必先更新至最新的 PVE 8.4.9，并根据本文内容使用 checklist 检查更新条件。</p>
<p>如果您还不是 8.4.9，请先更新：</p>
<pre><code>apt update
apt dist-upgrade
</code></pre>
<p>进行 checklist 检查更新兼容性：</p>
<pre><code>pve8to9
</code></pre>
<p>执行该命令后会进行一系列检查，最后得到类似如下结果：</p>
<pre><code>TOTAL: 51
PASSED: 40
SKIPPED: 5
WARNING: 4
FAILURES: 0
</code></pre>
<p>若有错误，请在更新前手动修复它。一般情况下 WARNING 的存在并不会对升级造成影响，例如 system-boot（确保自己是 GRUB 引导即可。如果您不知道什么是 GRUB 大可直接忽略这条）、microcode（安装是否并无影响）等。</p>
<h3>更新至 PVE9 的软件源</h3>
<p>使用以下脚本：</p>
<pre><code>wget http://share.geekxw.top/pve9yuan.sh -O pve9yuan.sh &amp;&amp; chmod +x pve9yuan.sh &amp;&amp; ./pve9yuan.sh
#无 Ceph 源
</code></pre>
<h3>升级至 PVE9</h3>
<pre><code>apt update
apt dist-upgrade
</code></pre>
<p>执行过程中可能会遇到选项，通常情况下回车默认即可，也可以更具自己实际情况与需求来。</p>
<p>更新完成后并重启 PVE 主机。您应当看见内核版本被升级为 Linux 6.14.8-2-pve。至此，升级也完成了，接下来您应当测试各项功能查看其运行状况是否符合预期。</p>
<h3>可选操作</h3>
<pre><code>apt autoremove
#删除无用的软件
bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/kernel-clean.sh)&quot;
#删除无用的内核
</code></pre>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>Promox VE 直通 SATA 控制器</title>
    <link>https://www.pyrzo.com/posts/promox-ve-direct-access-sata-controller</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/promox-ve-direct-access-sata-controller</guid>
    <pubDate>Mon, 28 Jul 2025 15:22:26 +0000</pubDate>
    <description>想让虚拟机直接掌控SATA硬盘，实现TrueNAS休眠与S.M.A.R.T.监控？这篇Proxmox VE直通指南，带你冒险解锁硬件潜能——但操作不当可能让宿主机无法开机！</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>使用场景</h2>
<p>有虚拟机需要使用原始硬盘（例如 TrueNAS 获取 S.M.A.R.T. 信息与硬盘休眠）时，我们不仅可以直通硬盘给虚拟机，还可以尝试直通 SATA 控制器给虚拟机。</p>
<h2>警告</h2>
<p>[warning]请确保您的 PVE 系统没有被安装在机械硬盘或是 SATA 控制器下的硬盘里，否则操作后可能导致 PVE 无法开机！[/warning]</p>
<p>若您确保自己的直通操作不会干扰到宿主机系统，那么请接着往下看。</p>
<h2>开启直通</h2>
<p>开启 VT-d</p>
<p>Intel 平台需要 b75 以上芯片组（酷睿 4 代以上）</p>
<p>与 VT-X 不同，VT-X 是虚拟化功能，而 VT-d 是 I/O 虚拟化功能。</p>
<p>AMD 平台是 iommu 或者叫 SRIVO（部分 OEM 主板的称法）</p>
<p>开启 iommu</p>
<p>我们编辑 /etc/default/grub 文件。可以使用 vi 或 nano，顺手就好。</p>
<p>找到如下配置项：</p>
<p>GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet&quot;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet&quot;</p>
<p>Intel 平台请修改为：</p>
<p>GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet intel_iommu=on iommu=pt&quot;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet intel_iommu=on iommu=pt&quot;</p>
<p>AMD 平台请修改为：</p>
<p>GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet amd_iommu=on iommu=pt&quot;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet amd_iommu=on iommu=pt&quot;</p>
<p>如果你需要显卡直通，建议在cmdline再加一句video=vesafb:off video=efifb:off video=simplefb:off，加了之后，pve重启进内核后停留在一个画面，这是正常情况</p>
<p>GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet amd_iommu=on iommu=pt video=vesafb:off video=efifb:off video=simplefb:off&quot;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet amd_iommu=on iommu=pt video=vesafb:off video=efifb:off video=simplefb:off&quot;</p>
<p>更新 Grub</p>
<p>使用命令更新：</p>
<p>update-grubupdate-grub</p>
<p>加载相应内核模块</p>
<p>依次执行以下命令：</p>
<p>echo vfio &gt;&gt; /etc/modules
echo vfio_iommu_type1 &gt;&gt; /etc/modules
echo vfio_pci &gt;&gt; /etc/modules
echo vfio_virqfd &gt;&gt; /etc/modulesecho vfio &gt;&gt; /etc/modules
echo vfio_iommu_type1 &gt;&gt; /etc/modules
echo vfio_pci &gt;&gt; /etc/modules
echo vfio_virqfd &gt;&gt; /etc/modules</p>
<p>更新内核参数：</p>
<p>update-initramfs -k all -uupdate-initramfs -k all -u</p>
<p>重启宿主机</p>
<p>rebootreboot</p>
<h2>验证</h2>
<p>重启后于终端输入：</p>
<p>dmesg | grep iommudmesg | grep iommu</p>
<p>若输出类似内容则成代表成功：</p>
<p>[ 1.341100] pci 0000:00:00.0: Adding to iommu group 0
[ 1.341116] pci 0000:00:01.0: Adding to iommu group 1
[ 1.341126] pci 0000:00:02.0: Adding to iommu group 2
[ 1.341137] pci 0000:00:14.0: Adding to iommu group 3
[ 1.341146] pci 0000:00:17.0: Adding to iommu group 4[ 1.341100] pci 0000:00:00.0: Adding to iommu group 0
[ 1.341116] pci 0000:00:01.0: Adding to iommu group 1
[ 1.341126] pci 0000:00:02.0: Adding to iommu group 2
[ 1.341137] pci 0000:00:14.0: Adding to iommu group 3
[ 1.341146] pci 0000:00:17.0: Adding to iommu group 4</p>
<p>再输入：</p>
<p>find /sys/kernel/iommu_groups/ -type lfind /sys/kernel/iommu_groups/ -type l</p>
<p>若出现很多直通组则代表成功。无内容反之。</p>
<p>最后，选择需要设置的虚拟机，点击 硬件 &gt; 添加 &gt; PCI设备 &gt; 选择 SATA Controller（SATA 控制器），最后点击“添加”把 SATA Controller（SATA 控制器）添加给相应的系统后，完成重启，PVE硬件直通的设置就生效了。</p>
<p>[warning]如果您在添加硬件没有找到 SATA Controller 字样，请接着往下看[/warning]</p>
<p>我们执行：</p>
<p>lspcilspci</p>
<p>会看到一堆输出。里面应当包含了 SATA Controller。例如我的是 11:00.0。输出示例如下：</p>
<p>...
11:00.0 SATA controller: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller (rev 01)
......
11:00.0 SATA controller: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller (rev 01)
...</p>
<p>您可以根绝输出内容来判断自己应当如何设置直通。</p>
<h2>巨人的肩膀</h2>
<p><a href="https://blog.csdn.net/weixin_48107526/article/details/131395172">Proxmox VE 设置硬盘直通_pve硬盘直通-CSDN博客</a></p>
<p><a href="https://www.jianshu.com/p/cc7c6c8c3ed9">pve 在amd平台开启sata硬件直通, 且使fnos硬盘自动休眠 - 简书</a></p>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>PVE 虚拟机启用 Qemu 代理（QEMU Guest Agent）</title>
    <link>https://www.pyrzo.com/posts/pve-vms-enable-qemu-guest-agent</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/pve-vms-enable-qemu-guest-agent</guid>
    <pubDate>Fri, 25 Jul 2025 08:57:55 +0000</pubDate>
    <description>想用PVE像VMware那样直接查看虚拟机IP？给KVM也装上“VMware Tools”——Qemu Guest Agent，一行命令搞定，管理更省心。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>什么是 QEMU Guest Agent</h2>
<p>Qemu Guest Agent 简称 QGA，是运行在虚拟机内部的一个守护程序（<code>qemu-guest-agent.service</code>），他可以管理应用程序，执行宿主机发出的命令。</p>
<p>其实这很好理解，就是个传话的。VMware 有 VMware Tools，而 PVE 属于 KVM 系虚拟化，也有对应的 Qemu Guest Agent。</p>
<h2>启用 Qemu 代理</h2>
<h3>虚拟机中安装 Qemu Guest Agent</h3>
<p>需要先在虚拟机中安装 Qemu Guest Agent。</p>
<p><strong>（Debian12 虚拟机可能已经自动安装了该程序。）</strong></p>
<p>CentOS：</p>
<pre><code class="language-bash">yum install qemu-guest-agent -y

Debian 与 Ubuntu：

```bash
apt install qemu-guest-agent -y
</code></pre>
<p>Windows：</p>
<p>在 <code>virtio-win</code> 驱动盘中找到如下或类似目录：</p>
<pre><code class="language-text">\guest-agent
</code></pre>
<p>32 位机器运行 <code>i386</code>，64 位机器运行 <code>x86_64</code>。如果您不知道如何选择，直接运行后者即可。</p>
<p>PVE 虚拟机设置中启用 QEMU 代理设置
虚拟机管理，移到“选项”选项卡，找到 QEMU Guest Agent 选项，勾选“使用 QEMU Guest Agent”。停止再启动虚拟机，就可以使设置生效了。</p>
<p>生效后即可在 <code>IPs</code> 查看各网卡的 IP 地址。</p>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>All In One 家里云第一步：我的 PVE 服务器配置选型历程与心得</title>
    <link>https://www.pyrzo.com/posts/aio-z</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/aio-z</guid>
    <pubDate>Mon, 14 Jul 2025 14:47:19 +0000</pubDate>
    <description>把多台服务器塞进一台大黑壳，省钱又好玩？我抱着炸机风险入了 All In One 的坑。从 PVE 选型到 3k6 消费级塔式配置，这颗 9600X 仅 60W，月电费 20 元。刀把心路，供你参考。</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>一切的始发点</h2>
<p>那不过是一个平常的午后。慵懒的阳光在天空招摇着，整个世界都是惬意的。</p>
<p>但我的世界就没有这么惬意了。因为我总是有一堆服务需要不间断跑着，有的是 Win 有的是 Lin，甚至还有一些受限于云的特性所以我用不上的专用系统。而我又正好喜欢功能隔离（不同用途的服务不塞在一台小鸡里）</p>
<p>绝望的我在B站上近乎疯狂地浏览。终于我找到了一个叫做“AIO”（All In One）的神奇国度，也有不少人叫它AIB（All In Boom，即一台物理节点爆炸，全家虚拟机停机）。</p>
<p>我也觉得 AIB 这个调侃称呼已经道出了 AIO 的缺点。但我的钱包可不这么觉得。</p>
<p>AIO 多省钱啊？</p>
<p>于是我们，</p>
<p>一拍即合！</p>
<h2>什么是All In One？</h2>
<p>我也没找到相对官方、准确的解释。</p>
<p>但我觉得，AIO其实就是把原本需要多台机器实现的功能，通过虚拟化技术，全部在一台机器上运行。</p>
<p>优点就是高效率，省钱。而缺点前面也提到过一点，就是容易因为某个操作问题导致所有服务全部爆炸。</p>
<p>不过，我认为只要不把网络整合进去，就算是炸起来，恢复速度也是相当快的。</p>
<p>既然是虚拟化，那我们就需要一个能够为我们提供虚拟环境的底层操作系统。目前主流有三种方案：</p>
<ul>
<li>ESXI：功能强大，相对稳定。但是不免费，并且不开源，所以不能享受 Linux 的系统生态。</li>
<li>PVE：开源的虚拟化系统。基于 Debian 开发，如果熟悉 Linux 的话，维护起来也比较方便。</li>
<li>Hyper-v：微软的一种虚拟化技术。需要运行在 Windows 系统之上。</li>
</ul>
<p>这里我直接选择了PVE。PVE 属于 KVM 系虚拟化环境。</p>
<p>虽然ESXI不需要跑在现有操作系统上，所以理论性能应当略高，但毕竟要钱，而且闭源系统毫无折腾性可言了。当然，如果你财力充裕，并且一心求稳，ESXI也未必不是一个更好的选择。</p>
<p>安装PVE......应该都会的咯？</p>
<h2>机器形态</h2>
<p>先仔细决定好机器形态是很重要的。因为这可能是日后影响你 AIO 体验的重要因素之一。</p>
<p>一般而言，这里有几种形态可供选择：</p>
<ul>
<li>小主机：占用空间小，待机功耗低。如果你只是跑一些轻量服务，或者是需要小体积机器，或许是个不错的选择。</li>
<li>塔式：体积稍大，但随之而来的是比小主机更高的功耗、空间。不过其拥有良好的拓展性与散热性能，如果你的目标服务需要中高性能，这个也不错。</li>
<li>机架式、刀片式等专用服务器机箱：如果你家里有单独房间放机柜，有极高的多核性能追求，你可能可以尝试选择服务器级的CPU与其余硬件，来换取超多的核心数或是超强的拓展力。</li>
</ul>
<p>我即想要不是很弱的性能，又想要静音与便宜。最后选择了塔式机箱搭配消费级硬件。</p>
<h2>硬件选型</h2>
<p>叠甲：个人方案，配出来纯纯刀把机器，这里放出来只是分享一下，并讲一下我所买的硬件的特点与坑。你应当按照自己的想法来配自己的机器。</p>
<p>这里是我的配置清单：</p>
<ul>
<li>CPU：9600X 盒装</li>
<li>CPU 散热：倚天 P60T 性能版 v3</li>
<li>主板：技嘉 B650M H</li>
<li>内存：英睿达 D5 6000 16G*2 套条</li>
<li>硬盘：致钛 Tiplus 7100 1T</li>
<li>电源：尘雨科技 玄武 550v4</li>
<li>机箱：长城 阿基米德 KM-7B</li>
<li>机箱风扇：尘雨科技 玄冥·普 12cm *4（前三后一）</li>
</ul>
<p>整套约 3k6，我打赌这大概率没你的游戏 PC 贵。（毕竟暂时不用买显卡）</p>
<h3>机箱（阿基米德 KM-7B）</h3>
<p>既然前面说了形态很重要，那就先选机箱好了。</p>
<p>我在众多全塔机箱中挑了一阵。有一款机箱让我很满意：</p>
<p>阿基米德 KM-7B。</p>
<p>通体金属外壳，纯黑配色，非侧透网孔侧板，看起来就是沉稳霸气，尤其讨我这个完全不喜欢灯光的人的喜欢。</p>
<p>不过更让我看中的是他强大的拓展性。最多支持安装 13 个 3.5 寸机械硬盘，最大能塞下 E-ATX 主板。显卡限长 280mm，拆下与显卡冲突的硬盘架后可达 417mm。CPU 散热器限高 180mm。拥有 7 个 PCIE 槽位。</p>
<p>散热就不必多说了，良好的散热能力应当是每个大机箱都有的优点。而 KM-7B 支持安装后部 120 水冷，顶部 360 水冷（虽然我也用不起用不上水冷），前面板支持最多 3 个 14cm 规格的风扇。</p>
<p>反正我也不喜欢什么花花绿绿的，这么个大黑铁皮壳子在我眼里就是一个字：帅。</p>
<h3>CPU（9600X）</h3>
<p>接下来就是次重要的 CPU 了。</p>
<p>我还得顺带开一个 MC 服务器（比较吃性能），所以我需要的是一颗中端 U。我便把目光锁定在了 1k 价位。</p>
<p>写这篇文章的时候，1k 价位的 CPU无非就这几个：</p>
<ul>
<li>Intel 的 i5-14600K/KF</li>
<li>AMD 9600X</li>
<li>AMD 7700X</li>
</ul>
<p>先从劳英与 AMD 中选一个。由于13/14 代酷睿一直在渲染“缩肛”焦虑（英特尔工艺问题导致的体质差容易坏，具体可以自己查查），一开始是 i9 缩，后边是 i7/i9 缩，现在是不少人都说自己 i5 也在缩了。虽然这里有着幸存者偏差效应，但既然买了有祸患，为什么还要买呢。（不然你猜猜为什么14600KF 比 12600KF 性能更强却更加便宜，总不能当英特尔做慈善吧？）</p>
<p>那剩下的只有 7700X 与 9600X 了。这俩 CPU 性能差距不大，无非是前者 8C16T 后者 6C12T、前者 ZEN4 架构后者 ZEN5 架构罢了。秉着买新不买旧的原则（而且看极客湾之前的视频，ZEN5 的祖传积热似乎得到了较大改善，再说了这里是 AMD，你开 AUTO 就是百元风冷都压得住）</p>
<p>9600X 频率为 3.9 GHz 至最大 5.4 GHz。默认热设计功耗（TDP）为 75W。</p>
<p>那么，我就选择 9600X 盒装了。</p>
<p>后续测试时，虚拟机中 CPU-Z 跑分单核成绩为 851 分。</p>
<h3>散热（库里奥 倚天 P60T 性能版）</h3>
<p>这个不用说，双塔六热管，风冷之王，不是第一也得排第二。我买的是纯黑版，纯黑的比别的银色的白色的还要贵一点。</p>
<p>配合 9600X，室温30℃时，能够做到待机 45-50℃。看到这里，待机温度 35 的英特尔用户不要惊讶，因为 AMD 一直都是这么烫。但是降十度和不缩肛，我还是偏向于选择后者。</p>
<p>不过 AMD 积热是积热，但是功耗都是远小于英特尔的。所以我这里买 P60T 也是刀把行为。AMD 这几十瓦的功耗，随便一个百元单塔都能稳压（前提是你不超频）</p>
<p>顺带一提，v3 相较于 v2 的噪音表现提升了不止一点点。</p>
<h3>主板（技嘉 B650M H）</h3>
<p>我对主板其实不是很熟悉，反正要求是能开机就行。毕竟我就 AUTO 用用我难道还会去要求它的供电、用料吗？只要这板子不掉电就够了。</p>
<p>线下买 CPU 的时候，老板给我推荐了技嘉 B650M H 这款板子。虽然大家可能都知道技嘉之前的那什么辱华事件，但它只卖600元一张我干嘛不买它？难不成去买隔壁的拒保星和打人硕吗？</p>
<p>不管黑板白板，有性价比的，就是好主板。</p>
<h3>内存（英睿达 D5 6000）</h3>
<p>内存没啥好说的，D5 平台随便搞个 6000 频率就好。反正 AMD 自己都不推荐高频内存。</p>
<p>选择英睿达主要是因为便宜，而且不带灯条的它拥有着较小的高度，正好能够和我的双塔散热器共存。</p>
<p>其实追求便宜还可以看看国产颗粒，但兼容性一定会是个问题。所以我买美光也不买长鑫。</p>
<p>插句题外话，玩 AIO 的话，32G 真的不够，至少对我来说根本不够用。</p>
<h3>硬盘（致钛 Tiplus 7100 1T）</h3>
<p>选这个硬盘不为什么，只是因为我以前从来没用过这么好的硬盘。抽了些预算放到了刀把上。</p>
<p>这款硬盘作为 PCIE 4.0 固态的旗舰产品，不论速度还是售后都非常能打。</p>
<p>但是不知道它这个 S.M.A.R.T. 里的通电时长是如何累计的，我开了半个月了，也只有 60h。不过只有读写累计正常就可以（具体可以了解一下 TBW）</p>
<h3>电源（尘雨科技 玄武 550v4）</h3>
<p>很多人配服务器，第一句话绝对是“省什么，也不能省了电源”。但其实这句话也仅仅局限在选个大牌子。</p>
<p>要真论起性价比来，我并不认为大厂的垃圾会比小厂的旗舰好上多少。尤其是这个小厂既有性价比又有售后的情况下。在这样的对局里，大厂低端货既没有堆料，也没有性价比，买了做什么？</p>
<p>这里选择的玄武 550v4，两百元就有不虚标不爆炸的 550W 电源能买，而且铭牌上输出功率甚至标定了 600W，这意味着厂家是反向虚标（这里点名长城航嘉的低端系列，大牌子的低端货用料不佳还虚标，估计玄武的出现让这类电源不太好过了）</p>
<p>我还提到了售后好。我不鼓吹多少，我只说一件事：只要你向客服报备，你就可以把电源拆开看看用料再装回去，反正玄武也不像别家还弄个防撕贴。而这一切，完全不影响你的保修。可见玄武的良心之处也在于售后。</p>
<p>最后，玄武电源质保五年（加几十块钱可选质保十年）</p>
<p>不过如果你也想买玄武，最好选择纯数字版本（例如我这款550）。像是 SE 系列由于采用的铜包铝端子线设计，网络上已经出现了不少的烧接口反馈。为了你的硬件安全，建议不要吝啬这几十块钱。</p>
<h3>机箱风扇（尘雨科技 玄冥普）</h3>
<p>没错，依旧选择了尘雨科技旗下的玄冥普。这款风扇依旧是低价路线，但参数并不粗糙。虽然是这样一个低价风扇，但和同行比起来，还是太良心了。</p>
<ul>
<li>风扇转速 2100 RPM ±10%</li>
<li>最大风量 88.88 CFM（风量确实在同价位里算是蛮大的了）</li>
<li>最大风压 2.8MM H2O</li>
<li>音噪 36.5 分贝</li>
<li>轴承 FDB/HDB</li>
<li>接口 4PIN PWM</li>
</ul>
<p>玄冥普其实只是在它的价位，该有的都有，不该缩的尽量不缩，做到了物有所值，是个正经的廉价产品，买了不吃亏。</p>
<p>但是关键就在这里，跟玄冥普的差不多价位的对手，大部分都连物有所值都做不到，不是缩电机就是缩轴承，不是吵得没法用就是一年半载就坏，属于把垃圾当产品卖。很多消费者用惯了垃圾，以为风扇就这样。而玄冥普在这样的环境下就是比较良心的产品了。</p>
<h2>写在最后</h2>
<p>整篇文章到这里其实也该结束了。我的这套配置其实充其量就是一个倒把机，不过我想把我的心路历程记录下来，说不定可以帮助和我犹豫在同一个地方的朋友。</p>
<p>机器运行基本功率为 60W，一个月电费约 20 元。</p>
]]></content:encoded>
    <category>Proxmox</category>
  </item>
  <item>
    <title>print(‘Hello world’)</title>
    <link>https://www.pyrzo.com/posts/where-all-the-miracles-begin</link>
    <guid isPermaLink="true">https://www.pyrzo.com/posts/where-all-the-miracles-begin</guid>
    <pubDate>Sat, 15 Mar 2025 06:30:49 +0000</pubDate>
    <description>所有奇迹的始发点</description>
    <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2>Hola,world.</h2>
<hr />
<p>Across the Great Wall we can reach every corner in the world.</p>
<p>越过长城，走向世界。</p>
<hr />
<h2>关于这段历史？</h2>
<blockquote>
<p>中国第一封电子邮件的发出时间有1986年8月25日和1987年9月14日之争，发送者有吴为民、王运丰等人之争。</p>
<p>1986年8月25日，瑞士日内瓦时间4点11分，北京时间11点11分，由当时任高能物理所ALEPH组组长的吴为民，从北京710所的 IBM-PC 机上发给 ALEPH 的领导，位于瑞士日内瓦西欧核子中心的诺贝尔奖获得者斯坦伯格(JackSteinberger)的电子邮件(E-mail)是中国第一封国际电子邮件。</p>
<p>1987年9月，措恩教授在北京出席一个科技研讨会。经过一番调试后，他将北京的计算机应用技术研究所和卡尔斯鲁厄大学计算机中心实现了计算机联结。9月20日，他起草了这封电子邮件，并与中国的王运丰教授一起署名后发出，成功地传到卡尔斯鲁厄大学的一台计算机上。</p>
<p>“Across the Great Wall we can reach every corner in the world.（越过长城，走向世界）”这是1987年9月20日从北京向海外发出的中国第一封电子邮件。这也预示着，互联网时代悄然叩响了中国的大门。</p>
<p>——Baidu 百科</p>
</blockquote>
]]></content:encoded>
    <category>网站建设</category>
  </item>
</channel>
</rss>