<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nginx on 我的博客</title><link>https://aswzblog.me/tags/nginx/</link><description>Recent content in Nginx on 我的博客</description><image><title>我的博客</title><url>https://aswzblog.me/images/og-default.svg</url><link>https://aswzblog.me/images/og-default.svg</link></image><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 26 May 2026 23:00:00 +0800</lastBuildDate><atom:link href="https://aswzblog.me/tags/nginx/index.xml" rel="self" type="application/rss+xml"/><item><title>博客升级血泪史：SEO、WebP、Cloudflare 踩坑全记录</title><link>https://aswzblog.me/posts/2026-05-26-blog-upgrade-journey/</link><pubDate>Tue, 26 May 2026 23:00:00 +0800</pubDate><guid>https://aswzblog.me/posts/2026-05-26-blog-upgrade-journey/</guid><description>SEO 全栈升级、Nginx 调参、CDN 接入失败、DNS 反复横跳的踩坑全记录</description><content:encoded><![CDATA[<p>原本只是想让博客&quot;做大一点&quot;，结果一个下午经历了 SEO 全栈升级、Nginx 调参、CDN 接入失败、DNS 反复横跳，最终回归朴实。</p>
<h2 id="起点2c2g-服务器能走多远">起点：2C2G 服务器能走多远？</h2>
<p>我的博客架在腾讯云 2 核 2G 的轻量服务器上，Ubuntu 20.04 + Nginx + Hugo，域名是 <code>aswzblog.me</code>。日常访问量约等于零，但人要有梦想。</p>
<p>和 AI 搭档分析后发现，2C2G 跑静态博客完全够用——瓶颈不在硬件，在于没有做优化。于是开干。</p>
<h2 id="seo-全家桶">SEO 全家桶</h2>
<p>PaperMod 主题的 SEO 底子不错，但需要 <code>--environment production</code> 才会输出 OG 标签和 JSON-LD 结构化数据。之前的 CI 部署脚本只跑了 <code>hugo --minify</code>，所以搜索引擎看到的页面是裸的。</p>
<p>改动：</p>
<ul>
<li><strong>JSON-LD 结构化数据</strong>：BlogPosting + BreadcrumbList，搜索引擎富摘要</li>
<li><strong>OpenGraph 默认图</strong>：写了个 SVG 模板，没配封面图的文章也能优雅分享。覆盖了 PaperMod 的 <code>opengraph.html</code>，加了一行回退逻辑——没有文章封面 → 没有页面图片 → 用站点默认 OG 图</li>
<li><strong>Meta Description</strong>：文章没写 description 时自动用前 160 字摘要填充</li>
<li><strong>RSS 全文输出</strong>：<code>ShowFullTextinRSS: true</code>，RSS 读者不用跳转就能看完</li>
</ul>
<p>这些改动一行服务器操作都不需要，纯 Hugo 模板 + 配置。</p>
<h2 id="webp-自动转换">WebP 自动转换</h2>
<p>博客里的截图都是 PNG，一篇文章三张图加起来 400 多 KB。在 Hugo 的 markup render hook 里加了一层：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="p">{{</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nf">in</span><span class="w"> </span><span class="p">(</span><span class="nx">slice</span><span class="w"> </span><span class="s">&#34;jpg&#34;</span><span class="w"> </span><span class="s">&#34;jpeg&#34;</span><span class="w"> </span><span class="s">&#34;png&#34;</span><span class="p">)</span><span class="w"> </span><span class="err">$</span><span class="nx">img</span><span class="p">.</span><span class="nx">MediaType</span><span class="p">.</span><span class="nx">SubType</span><span class="w"> </span><span class="p">}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="p">{{</span><span class="w"> </span><span class="err">$</span><span class="nx">webp</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="err">$</span><span class="nx">img</span><span class="p">.</span><span class="nx">Process</span><span class="w"> </span><span class="s">&#34;webp q82&#34;</span><span class="w"> </span><span class="p">}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="p">&lt;</span><span class="nx">picture</span><span class="p">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">&lt;</span><span class="nx">source</span><span class="w"> </span><span class="nx">srcset</span><span class="p">=</span><span class="s">&#34;{{ $webp.RelPermalink }}&#34;</span><span class="w"> </span><span class="kd">type</span><span class="p">=</span><span class="s">&#34;image/webp&#34;</span><span class="p">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">&lt;</span><span class="nx">img</span><span class="w"> </span><span class="nx">src</span><span class="p">=</span><span class="s">&#34;...&#34;</span><span class="w"> </span><span class="nx">loading</span><span class="p">=</span><span class="s">&#34;lazy&#34;</span><span class="w"> </span><span class="nx">decoding</span><span class="p">=</span><span class="s">&#34;async&#34;</span><span class="p">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="p">&lt;</span><span class="o">/</span><span class="nx">picture</span><span class="p">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">{{</span><span class="w"> </span><span class="nx">end</span><span class="w"> </span><span class="p">}}</span><span class="w">
</span></span></span></code></pre></div><p>效果立竿见影——213KB 的 PNG 转成 69KB 的 WebP，体积减少 68%。Hugo 在构建时处理，不影响服务器性能。</p>
<h2 id="nginx-上手段">Nginx 上手段</h2>
<p>原先的 Nginx 配置就是装完系统默认的，gzip 参数全注释、没有安全头、没有缓存策略。SSH 上去改了一波：</p>
<ul>
<li>gzip 全开 + <code>gzip_static on</code></li>
<li>安全头：<code>X-Content-Type-Options</code>、<code>X-Frame-Options</code>、<code>Referrer-Policy</code></li>
<li>指纹化资源缓存 1 年，图片缓存 30 天，RSS/sitemap 缓存 1 小时</li>
<li><code>server_tokens off</code> 隐藏版本号</li>
</ul>
<p>配完 <code>sudo nginx -t &amp;&amp; sudo systemctl reload</code>，平滑重载。</p>
<h2 id="cloudflare-翻车">Cloudflare 翻车</h2>
<p>前面都顺风顺水，到了 CDN 环节开始出事。</p>
<p>域名接入 Cloudflare、DNS 切过去、代理打开，然后——网站挂了。</p>
<p>Cloudflare 返回 525 错误：SSL 握手失败。</p>
<p>排查过程：</p>
<ol>
<li><strong>是不是端口没开？</strong> 不是，80 和 443 都通，TCP 能连上。</li>
<li><strong>是不是 Nginx 配置有问题？</strong> 不是，从服务器本地 curl 完全正常。</li>
<li><strong>是不是 SSL 证书有问题？</strong> 不是，Let&rsquo;s Encrypt 证书有效，中国 IP 能正常访问。</li>
<li><strong>是不是腾讯云安全组？</strong> 不是，端口放的是 <code>0.0.0.0/0</code>。</li>
</ol>
<p>最后用 <code>openssl s_client</code> 对照测试才发现：<strong>不带 SNI 的 SSL 连接成功，带 SNI 的被拦截</strong>。</p>
<p>腾讯云防火墙在 DPI 层面检测到境外 IP 的 TLS SNI 握手，直接静默丢弃。Cloudflare 的边缘节点连源站时必然会发 SNI，所以必死。Flexible 模式也不优雅。</p>
<p>折腾了两小时，最终决定：<strong>不搞 CDN 了</strong>。</p>
<h2 id="回归简单">回归简单</h2>
<p>把 DNS 从 Cloudflare 迁回阿里云 <code>dns31.hichina.com</code>，加上 A 记录指向服务器 IP。十分钟生效。</p>
<p>最终架构：</p>
<pre tabindex="0"><code>用户 → 阿里云 DNS → 腾讯云 2C2G → Nginx 直出静态文件
</code></pre><p>没有 CDN、没有中间层、没有代理。配合 Nginx 的 gzip + 缓存 + 安全头，现阶段完全够用了。</p>
<hr>
<h2 id="收获">收获</h2>
<ol>
<li><strong>Hugo 的模板系统真的很强</strong>：SEO、图片处理、RSS 全文，全部可以通过覆盖主题模板实现，不需要改主题源码。</li>
<li><strong>WebP 值得无脑开</strong>：PNG → WebP 减少 60-80% 体积，而且 Hugo 构建时处理，零运行时开销。</li>
<li><strong>中国服务器 + Cloudflare = 看运气</strong>：腾讯云/阿里云的安全产品可能在网络层拦截境外 SSL 流量，不是改 Nginx 能解决的。服务国内用户的话直连就够了。</li>
<li><strong>AI 搭档做运维是真的爽</strong>：SSH、Nginx 配置、DNS 排查，全程对话完成，根本不用记命令。</li>
</ol>
<p>以后流量大了再说 CDN，现在，先写文章。</p>
]]></content:encoded></item></channel></rss>