惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
M
MIT News - Artificial intelligence
MyScale Blog
MyScale Blog
博客园_首页
G
Google Developers Blog
博客园 - 【当耐特】
美团技术团队
博客园 - 聂微东
Stack Overflow Blog
Stack Overflow Blog
Vercel News
Vercel News
小众软件
小众软件
博客园 - 司徒正美
雷峰网
雷峰网
T
Tailwind CSS Blog
V
V2EX
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
罗磊的独立博客
量子位
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
A
About on SuperTechFans
Hugging Face - Blog
Hugging Face - Blog

蛋蛋之家

SUMIFS和LET函数——让 Excel 自己动起来 Halo 博客晚间卡顿排查记:从"玄学卡顿"到"真凶落网" 我用这个开源项目,把 AI 绘画提示词变成了"代码"——awesome-gpt-image-2 深度体验报告 群晖部署 LX Music Server:浏览器就是你的音乐播放器【详细版】 500道Word题库太痛苦?于是我写了个智能学习平台 别用一个人的奔跑,耗尽两个人的余生——《你凭什么认为我会一直喜欢你呢》 博客评论自动填充新方案:兼容 Vue/React 响应式绑定与跨架构填充逻辑 2026 生产级指南:Halo 2.x + PostgreSQL 自动化部署与性能优化手册 Typecho 迁移 Halo 完整教程:数据库视图解决表前缀 + 自动提取封面图 + 去重检测 我的 CodeBuddy 装备库:218个技能全公开 + 使用心得 为博客添加自定义评论表情 Comment2Bark:Typecho评论推送到Bark插件 又拍云插件 UpyunFile v1.2 更新:修复 Typecho 1.3.0 兼容性问题 手把手修复RSS 403:从PHP警告到Cloudflare拦截的全链路排查 网站被镜像怎么办?2026年反镜像攻防实战指南 VLESS + Reality + Vision:2026 极致隐蔽节点搭建全解析 给OpenList和Alist加上液态玻璃效果,颜值直接拉满! 网页截图瞬间“赛博飞升”?手把手教你根治 Windows HDR 截图发白 群晖 NAS 影音终极方案:Docker Rclone + OpenList 完美挂载 Plex 全攻略 一个简洁高效的SVG图标库 告别重复劳动!一键填充评论的神奇书签脚本 - 蛋蛋之家 解锁思源笔记的隐藏力量:siyuan-patch 深度体验与技术实现 Oracle Cloud 自救指南:旧手机丢失后如何绕过 MFA 重新登录【更新2026年最新政策】 本站已加入“萌国ICP备案”联萌!😄 Excel 月报自动化指南:告别重复劳动,让数据主动为你服务 梦呓:为异地女友准备的2周年惊喜礼物 Typecho 多吉云插件优化:更灵活的存储目录配置 甲骨文云硬盘扩容指南:从50G到200G的“免费午餐”怎么吃? ⏰ 时间同步:当你的服务器开始“穿越”时,如何优雅地把它拉回现实 Typecho 又拍云文件管理插件修改版使用指南:新增自定义目录结构功能
从 Typecho 转向 Halo 2.x:全能型 Nginx 架构与 SEO 无损迁...
吴蛋蛋 · 2026-04-24 · via 蛋蛋之家

前言

我最近完成了一项“大工程”:将个人博客从传统的 Typecho 平台迁移到了基于 Docker 的 Halo 2.x。

这次迁移并非简单的“搬家”,因为我面临着几个复杂的现实挑战:

  1. SEO 权重保卫战:旧文章链接必须通过 301 永久重定向到新路径。

  2. 多项目共存:根目录下还有多个独立的 PHP 小工具(如 Speedtest、图片托管等)不能中断。

  3. 性能极致追求:利用手头 ARM 4H24G 的高配服务器,实现物理级动静分离。

在反复踩坑 403 错误和 Nginx 配置冲突后,我整理出了这套“终极方案”。


image
Typecho 转 Halo 2.X

核心挑战与解决方案

1. URL 重定向,比想象中麻烦

Typecho 的文章我使用的路径是 /slug/,而 Halo 必须要有前缀,综合考虑之后,我决定使用 /p/slug。为了不让朋友们的收藏夹失效,也不让搜索引擎抓取到 404,我们需要利用 Nginx 的正则匹配实现自动化跳转。以下是需要避坑的地方:

  • 有的 URL 末尾带斜杠,有的不带

  • 分类页面、独立页面、文章页面的规则全都不一样

  • 最坑的是,如果不小心把 /admin 也重定向了,后台直接进不去

我一开始用宝塔的反代插件自动生成,结果生成的 rewrite 规则优先级完全不对,要么 404,要么循环重定向。最后干脆放弃插件,直接手写 Nginx 配置。

后面又改回 archives 了,主题默认写死了,我太怕麻烦了...

2. 绕过“空目录 403 错误”

由于 Halo 运行在 Docker 容器中,宿主机的网站根目录通常是空的。Nginx 默认会尝试在本地找 index.php,找不到且禁止列出目录时就会报 403。
方案:在 Nginx 中对首页进行“精确匹配”,直接转发给后端,不经过本地文件系统。

3. 物理级动静分离

Halo 虽然强大,但用 Java 处理静态资源(图片、CSS)效率不如 Nginx。通过 Docker 的卷挂载(Volumes),我们可以让 Nginx 直接读取磁盘上的附件,速度提升显著。

通过 location ~ ^/(themes|plugins|attachments)/ 块,我们让 Nginx 直接从磁盘读取图片、字体和脚本。这不仅大幅降低了 Halo 容器的 I/O 压力,还通过 Access-Control-Allow-Origin "*" 解决了部分主题在预加载字体时可能出现的跨域警告。

4. 解决宝塔保存报错

宝塔面板在保存配置文件时,会扫描 #SSL-START 块内是否包含特定的 error_page 404 注释行。这也是一个需要注意的地方。

5. 404的问题与解决方案

默认情况下,Nginx 的 proxy_intercept_errors on 会直接抛出 Nginx 自带的 404.html。

方案通过 @seo_logic 逻辑:

  • 先尝试帮找回旧文章(SEO 补全)。

  • 如果确实找不到,则通过 proxy_intercept_errors off 再次转发,此时 Nginx 会“闭嘴”,让 Halo 后端吐出主题 404 页面。


终极 Nginx 配置文件

以下是经过多次迭代、能够完美运行在宝塔面板环境下的主配置文件(已脱敏)。

server
{
    listen 80;
    listen 443 ssl;
    http2 on;
    server_name yourdomain.com; # 替换为你的域名
    index index.php index.html index.htm;
    root /www/wwwroot/your_site_folder; # 替换为你的站点根目录
    include /www/server/panel/vhost/nginx/extension/yourdomain.com/*.conf;

    # ==========================================================
    # 【1. 基础 MIME 类型】
    # ==========================================================
    include mime.types;
    types {
        application/javascript        js cjs mjs;
        image/svg+xml                 svg;
    }

    # ==========================================================
    # 【2. SSL 配置区】(保持宝塔兼容性)
    # ==========================================================
    #SSL-START
    #error_page 404/404.html;
    ssl_certificate    /path/to/your/fullchain.pem; # 替换为实际证书路径
    ssl_certificate_key    /path/to/your/privkey.pem;  # 替换为实际密钥路径
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    # ... 其他 SSL 优化参数 ...
    #SSL-END

    # ==========================================================
    # 【3. 业务路由分发】
    # ==========================================================
    
    # 首页直连
    location = / {
        proxy_pass http://127.0.0.1:8090;
        proxy_set_header Host $http_host;
        # ... 常用 Proxy Header ...
    }

    # 静态资源直读
    location ~ ^/(themes|plugins|attachments)/ {
        root /www/wwwroot/your_site_folder/data;
        add_header Access-Control-Allow-Origin "*";
        access_log off;
        expires 30d;
        try_files $uri @halo_proxy;
    }

    # 兼容本地 PHP 工具
    location ~ ^/(tool_folder1|tool_folder2) {
        try_files $uri $uri/ /index.php?$query_string;
        include enable-php-83.conf;
    }

    location / {
        try_files $uri $uri/ @halo_proxy;
    }

    # ==========================================================
    # 【4. SEO 重定向映射】
    # ==========================================================
    rewrite ^/feed/?$ /rss.xml permanent;
    rewrite ^/archive/?$ /archives permanent;
    rewrite ^/cross/?$ /moments permanent;
    
    # 标签与分类映射 (请根据实际情况替换 category_name)
    rewrite ^/tag/([^/]+)/?$ /tags/$1 permanent;
    rewrite ^/(category1|category2|category3)/?$ /categories/$1 permanent;

    # ==========================================================
    # 【5. 后端代理与错误拦截】
    # ==========================================================
    location @halo_proxy {
        proxy_pass http://127.0.0.1:8090;
        proxy_set_header Host $http_host;
        # ... WebSocket 支持配置 ...

        proxy_intercept_errors on;
        error_page 404 = @seo_logic;
    }

    # ==========================================================
    # 【6. SEO 自动补全逻辑】
    # ==========================================================
    location @seo_logic {
        # 排除列表
        if ($uri ~* "^/(archives/|categories/|tags/|moments|admin|api|login|rss|search|attachments/|themes/|plugins/)") {
            set $fallback "yes";
        }
        
        if ($uri ~* "\.") {
            set $fallback "yes";
        }

        if ($fallback != "yes") {
            rewrite ^/([^/]+)/?$ /archives/$1 permanent;
        }

        # 终极兜底:显示后端自定义 404
        proxy_pass http://127.0.0.1:8090;
        proxy_intercept_errors off;
        proxy_set_header Host $http_host;
    }

    # ==========================================================
    # 【7. 系统错误页】
    # ==========================================================
    #ERROR-PAGE-START
    error_page 502 /502.html;
    # ...
    #ERROR-PAGE-END

    access_log  /www/wwwlogs/yourdomain.com.log;
    error_log  /www/wwwlogs/yourdomain.com.error.log;
}

迁移后的避坑总结

  1. 不要依赖宝塔的反向代理插件:对于复杂的 301 跳转需求,插件生成的代码往往会产生优先级冲突。直接修改“配置文件”是最稳妥的选择。

  2. 正则排除很重要:在做文章重定向时,务必排除掉 /admin、/api 等 Halo 系统路径,否则你会发现后台无法登录。

  3. 权限检查:动静分离使用 alias 映射时,确保网站运行用户(通常是 www)对 Docker 挂载的物理目录有读取权限。

  4. JVM 调优:如果你有像我一样充裕的内存(24G),别忘了在 docker-compose.yml 中给 Halo 分配足够的内存(如 -Xmx2048m),这样在处理高并发请求时会更从容。

结语

从 Typecho 到 Halo 的迁移,不只是博客程序的更换,更是对站点架构的一次全面梳理。通过 Nginx 的灵活配置,我们既能享受新程序带来的便利,又能通过“动静分离”和“重定向优化”保障站点的访问体验与搜索权重。

希望这篇指南能帮助你打造一个更稳固、专业的 Halo 博客。修改完成后,记得在宝塔面板中重载 Nginx 配置即可生效,必要时重启一下 Nginx!


本文所涉及的 Nginx 配置已在 1.28.3 版本下实测通过。