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

推荐订阅源

量子位
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
NISL@THU
NISL@THU
T
Threat Research - Cisco Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
Lohrmann on Cybersecurity
V
Visual Studio Blog
Cyberwarzone
Cyberwarzone
D
Docker
The Hacker News
The Hacker News
C
CERT Recently Published Vulnerability Notes
Vercel News
Vercel News
Project Zero
Project Zero
S
Schneier on Security
aimingoo的专栏
aimingoo的专栏
I
Intezer
腾讯CDC
M
MIT News - Artificial intelligence
Hugging Face - Blog
Hugging Face - Blog
P
Palo Alto Networks Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
AWS News Blog
AWS News Blog
GbyAI
GbyAI
MongoDB | Blog
MongoDB | Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Vulnerabilities – Threatpost
G
Google Developers Blog
N
Netflix TechBlog - Medium
The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
A
Arctic Wolf
S
Securelist
酷 壳 – CoolShell
酷 壳 – CoolShell
Cisco Talos Blog
Cisco Talos Blog
Recent Announcements
Recent Announcements
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LINUX DO - 热门话题
T
Threatpost
Latest news
Latest news
Blog — PlanetScale
Blog — PlanetScale
Security Latest
Security Latest
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
The GitHub Blog
The GitHub Blog
T
Tor Project blog
P
Proofpoint News Feed

蛋蛋之家

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 又拍云文件管理插件修改版使用指南:新增自定义目录结构功能 华为鸿蒙6.0回退4.2记录 最近小公主情绪不佳 劳动节的家乡景色 烟台山公园一游 群晖搭建ChatGPT Web 推荐脚本:ChatGPT - 提示选择器 Activation Method for JetBrains Products (English version) JetBrains 系列产品激活方法 疫情三年后再进校园 修复searchEngineJump在谷歌搜索页面不生效问题 事情既然发生了,可以是遗憾,不要去后悔。 侄女的试唱会比赛 新一代图片编码格式测试 省科技馆之行 Typora Windows版破解补丁及主题推荐 在Typora中使用PicList上传图片 域名ICP备案之变更网站 Ubuntu 系统如何使用 root 用户登录 中国联通——让一切自由连不通 如何选购适合的口罩? 今天移动营业厅遇到一个小姐姐,真的好美 它不乐意 如何解决Typecho文章不是Markdown语法创建问题 探手抓住这一天的尾巴,为自己庆生 收到腾讯云自媒体分享计划2月份礼品 尝试百度Spider抓取异常问题 甲骨文DD重装系统及失联救砖教程 终于MrDoc升级v0.8.7成功了 Windows 端口查询及杀死进程 甲骨文实例开通与X-UI安装 国艺花鸟市场的悠闲 在思源笔记中使用群晖Synology C2对象存储服务 MrDoc升级v0.8.7失败 居居的手工作品 Linux系统时间同步命令小结 AList安装指南 宝塔面板降级 v7.7.0 及解除强制绑定手机、免费安装专业版插件的方法 修复群晖Synology Drive client右键菜单缺失问题 Windows11 展开折叠的右键菜单为传统模式 在 Windows 下批量将 Markdown 文档转为 Word 文档 Typecho的一些修改记录 Markdown语法——Mermaid 有两种新方案—CloudFlare官方免费CNAME接入教程 居居的新冠历程 群辉安装Transmission套件、增强汉化WebUI并备份做种列表 群晖 docker 部署思源笔记 Office for Mac 2019 License Installer 公众号通过api发送小程序消息 Windows 10下 iTunes 备份默认存储路径修改 Excel查找返回多个值,并将返回的值放在同一个单元格里面 七牛云测试域名失效后如何下载空间中的文件 入手三星860 evo 500g SSD固态硬盘 分享一套耐看的鼠标指针 如何重置OmniFocus数据库 Office for Mac 2016 License Installer Mac下配置终端+iTerm 2主题 如何制作苹果系统安装U盘 LNMP部署typecho,开启SSL、强制开启https Stylish样式如何设置为特定网址不生效? Typecho插件错误号:42S01的解决方法 电动车被偷了 热火 R150 上手开箱 UltraMon 3.3.0 汉化+注册机 如何用 MWeb 发布 Typecho 文章 测试 Mweb 发布到印象笔记功能 忘记了iPhone访问限制的密码该怎么办? 新玩具KAREE电子烟,先试试 Mac mini 2011 开启Handoff方法 见微知著 浅谈手游创新 PhoneClean Pro授权注册激活码
从 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 版本下实测通过。