新闻详情

新闻详情

首页 / 资讯中心 / 详情

用Halo自建博客:从托管平台到Docker部署的完整实践

发布时间:2026/9/26 16:46:57来源:尧图网络
用Halo自建博客:从托管平台到Docker部署的完整实践
管理自己博客的第七年我在托管平台上写到第150篇文章的时候决定把数据搬回自己手里。这中间反复比较过的方案不少最后选定的是 Halo 这套开源博客系统。如果你也是那种不想被平台规则牵着走、又不想花太多精力维护服务器的人自建站这个方向值得认真考虑而 Halo 大概率是你能找到的、上手成本最低且后台观感最接近正规商业产品的开源方案。这篇文章不打算把官方文档重新翻译一遍。我会按照实际搭站的顺序把新手从选型、部署、配置、写作到日常维护会遇到的关键问题全部讲一遍顺带把我踩过的坑和最后采用的方案一并说清楚。无论你之前有没有接触过 Linux 和 Docker只要照着下面的链路走一遍基本都能把站点跑起来。1. 我在托管平台写到第 150 篇时为什么决定自建站1.1 托管博客那些看不见的代价很多博主最开始用第三方平台写作图的是省事注册账号、选个模板、直接开写。但当你写到几十上百篇之后有几个问题会越来越明显。首先是数据和自定义能力的归属问题。平台上的文章数据、阅读数据、评论数据都存放在别人的系统里你随时可能因为某个规则调整、某个改版被迫改变自己的排版习惯或内容方向。前几年我经历过一次平台模板大改版老文章里的自定义样式全部失效排版乱成一锅粥那时候就意识到真正属于自己的内容资产必须放在自己控制的服务器上。其次是广告和推荐算法的干扰。托管平台为了商业化会在你的文章下方插入推荐内容。读者是来读你的文章的结果页面上三分之一的位置被猜你喜欢的其他流量占据那体验其实很伤害内容作者和读者之间的信任。第三是扩展能力受限。你想要的评论区改造、页面定制、友链管理、统计报表平台只会给你有限的开放接口。想实现一个按标签显示归档卡片这种小需求要么等平台开发要么就得换到更开放的系统里自建站。1.2 Halo 打动我的几个关键点在决定自建站后我花了一个周末把市面主流的个人博客搭建方式过了一遍最终选择 Halo 的主要原因有三个。第一个原因是它的后台做得足够现代。Halo 2.x 的控制台界面完全是新一代产品的设计思路左侧菜单、卡片式管理、拖拽式页面管理都有不是那种十几年前的后台风格。对从托管平台搬家过来的用户来说这个后台的学习成本几乎为零。第二个原因是部署方式非常符合 2024 年之后的服务器环境。官方提供 Docker 镜像一条 docker compose 命令就能把博客系统连同数据库一起拉起来。我后面会详细讲这套配置但先给结论即便你从来没建过站只要会基本的 Linux 命令跟着文档走也能在两小时内上线。第三个原因是它的内容表达力足够强。Markdown 写作、文章别名、自定义页面、菜单管理、多分类多标签这些个人博客的常规刚需全部开箱即用不需要额外装一堆插件才能凑齐。2. 选型对比WordPress、Hexo、Halo 到底怎么选2.1 四类建站方案横向看个人博客自建站领域方案基本可以分成四大流派。方案技术门槛运行方式写作体验主题/插件生态维护成本WordPress低PHP MySQL需长驻服务器后台可视化编辑 经典编辑器偏传统生态巨大插件鱼龙混杂中高插件和核心要不断更新Halo低JavaSpring BootDocker 友好后台 Markdown界面现代化生态稳健官方应用市场持续更新低Docker 升级干净利落Hexo/Hugo中Node/Golang 构建静态 HTML本地写 Markdown命令发布主题丰富但交互功能需自己集成低但评论、搜索等依赖第三方服务Typecho低PHP SQLite/MySQL轻量简洁主题不少插件维护动态一般中如果你纯粹追求写文章的轻快感Hexo、Hugo 这类静态方案确实有优势。但它们有个绕不开的短板评论系统、浏览量统计、全文搜索、动态页面这些需要服务端支持的能力都得额外接第三方服务或者写脚本生成。折腾到后面复杂度未必比动态博客低。WordPress 的问题不是功能不够而是功能过剩。它本来是一个内容管理平台但庞大的插件生态和安全补丁节奏要求站长得持续关注。我见过不少朋友用 WordPress 搭好站后一个月忘记升级结果服务器被扫到漏洞爆破的案例。2.2 我选 Halo 而不是 WordPress 的真实理由我最早考虑过 WordPress因为它在中文互联网里的教程最多遇到问题搜索答案最容易。但实际试用之后放弃了主要原因有两点。第一是后台体验。WordPress 默认后台的信息密度太低左侧菜单项极多新用户很容易迷失在文章、页面、媒体、外观、插件、用户、设置、工具这些菜单里。个人博客只需要一个清爽的内容管理空间Halo 的后台恰好就是这个定位。第二是安全问题。WordPress 的插件生态虽然庞大但质量参差不齐。很多免费插件常年不更新存在已知漏洞你甚至不知道哪些插件正在处理用户上传的文件。Halo 有官方应用市场机制插件经过基本审核上架社区规模更聚焦攻击面相对小很多。第三点是我个人的偏好我日常工作经常接触 Java 技术栈Halo 基于 Spring Boot 3 和响应式编程重构的 2.x 版本出了问题我能看懂日志甚至可以自己改源码重新打包。这种可控感是闭源托管平台给不了的。3. 动手部署之前先把 Halo 2.x 的运行机制搞清楚3.1 1.x 和 2.x同一名字下的两代产品很多网上教程还在用 Halo 1.x 的部署方式新手如果没注意版本很容易照搬出问题。这里必须先说清楚Halo 1.x 和 2.x 是两代差异非常大的产品。1.x 基于 Spring Boot 2 和 Java 8/11数据库连接用的是 JDBC数据目录默认存放在~/.halo。2.x 重构之后基于 Spring Boot 3、Java 17 和响应式编程模型数据库连接方式改为 R2DBC数据目录默认变成了~/.halo2。主题和插件完全不兼容1.x 的主题不能直接放进 2.x 使用。所以在搜索部署教程时优先看官方文档或者明确标注了2.x的教程。版本选错了后面会遇到一堆莫名其妙的兼容问题。3.2 理解端口、数据库与数据卷Halo 默认监听 8090 端口通过浏览器访问http://服务器IP:8090就能进入初始化页面。这个端口可以在配置里改但如果没有特殊需求保持默认最省事。数据库方面Halo 2.x 默认内置 H2 数据库。H2 是文件型数据库开箱即用适合体验和测试。但如果站点计划长期运营我更推荐从一开始就接 MySQL 8.x 或 PostgreSQL。原因很简单H2 在异常断电、文件锁处理这些场景下不够稳而且备份恢复时不够直观。用 Docker 部署时官方文档推荐在同一个 compose 文件里把 Halo 服务和 MySQL 服务一起定义网络互通配置最简洁。还有一个重要参数halo.external-url。这个参数是告诉 Halo 你的站点对外地址是什么比如https://blog.example.com。如果你做反向代理却没有设置这个参数Halo 生成的固定链接、站点地图、邮件通知里的链接都会变成服务器内网地址或者错误的协议头。这个问题我在 4.4 节会详细讲是真的能让你抓狂半小时的坑。4. Docker Compose 部署 Halo 的完整记录含踩坑链路4.1 服务器与域名准备最低配置建议 1 核 2G 内存实际体验下来更舒服的是 2 核 4G。原因在于 Java 应用本身空闲时就会占用几百 MB 内存加上 MySQL、Nginx 和缓存1G 内存的机器有点紧绷。操作系统我推荐 Ubuntu 22.04 LTS 或 Debian 12CentOS 7 虽然还能用但官方源已进入 EOL 阶段新装系统不建议再选它。在云厂商控制台安全组里放行 80、443 端口SSH 端口 22 保持默认即可。域名解析上建议把blog.你的域名.com解析到服务器 IP等 Nginx 配好后再申请免费证书。直接裸域名也可以但后续如果要迁移或者加 CDN子域名的灵活性更高。4.2 docker compose 配置逐行解析在服务器上新建一个目录比如/opt/halo-deploy在里面创建docker-compose.yml。下面是我实际使用的配置注释里有每个关键字段的作用version: 3.6 services: halo: image: halobuild/halo:2.20 container_name: halo restart: on-failure:3 depends_on: - halodb environment: - HALO_ACTIVE_PROFILEprod - JVM_OPTS-Xmx512m -Xms256m command: - --spring.r2dbc.urlr2dbc:pool:mysql://halodb:3306/halo - --spring.r2dbc.usernamehalo - --spring.r2dbc.passwordhalo_password - --halo.external-urlhttps://blog.example.com volumes: - /opt/halo-deploy/halo:/root/.halo2 ports: - 8090:8090 healthcheck: test: [CMD, curl, -f, http://localhost:8090/actuator/health] interval: 30s timeout: 3s retries: 5 halodb: image: mysql:8.2.0 container_name: halodb restart: on-failure:3 command: - --default-authentication-plugincaching_sha2_password - --character-set-serverutf8mb4 - --collation-serverutf8mb4_general_ci environment: - MYSQL_ROOT_PASSWORDroot_password - MYSQL_DATABASEhalo - MYSQL_USERhalo - MYSQL_PASSWORDhalo_password volumes: - /opt/halo-deploy/mysql:/var/lib/mysql有几点要特别说明。halobuild/halo:2.20是 Halo 官方镜像正式上线时不要直接用latest标签因为大版本升级可能带来不兼容变化写死版本号方便后续可控升级。--spring.r2dbc.url这里指定的是 Halo 连接 MySQL 的响应式数据源地址。r2dbc:pool:mysql://halodb:3306/halo中的halodb对应的是 compose 服务名Docker 内部网络会自动解析到这个容器 IP不需要写服务器公网 IP。JVM_OPTS-Xmx512m -Xms256m限制了 Java 堆内存最大 512MB。2G 内存的服务器跑这套配置没问题如果想留更多内存给系统缓存这个值可以保持不动。数据卷挂载是把容器内的/root/.halo2目录映射到宿主机/opt/halo-deploy/halo。Halo 的所有配置、主题、插件、上传文件都在这个目录下必须持久化。MySQL 数据卷同理映射到/opt/halo-deploy/mysql。4.3 初始化设置与反向代理配置写好之后在/opt/halo-deploy目录下执行docker compose up -d首次执行会拉取镜像等待几十秒后访问http://服务器IP:8090就能看到 Halo 的初始化引导页。设置管理员用户名、密码、邮箱填写博客标题初始化就完成了。默认情况下管理后台路径是/console前台首页是/。到这里站点已经能跑了但直接用 IP 加端口访问既不好记也不安全所以还需要用 Nginx 做反向代理。安装 Nginx 后在/etc/nginx/sites-available/blog.conf写入server { listen 80; server_name blog.example.com; location / { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }接着用 Certbot 申请免费证书sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d blog.example.comCertbot 会自动修改 Nginx 配置并续期证书这一步是 HTTPS 最省心的方案。之后访问https://blog.example.com即可。4.4 我踩过的一个典型连环坑第一次部署到域名对接环节时我遇到了一个非常典型的问题HTTPS 配置好后前台文章页能打开但后台登录成功后跳回的链接一直回到http://127.0.0.1:8090浏览器直接显示拒绝了我们的连接请求。排查链路是这样的第一步检查 Nginx 配置确认proxy_pass和Host头没问题。第二步查看 Halo 容器日志日志里没有任何错误。第三步直接访问后台控制台发现控制台能加载说明服务本身是好的。第四步回到 compose 里的command段发现我根本没有配置--halo.external-url。Halo 在生成绝对链接时只能从请求头里猜协议和域名经过代理层后猜到的却是内网地址。修复方法很简单在command里加上对外地址再重启--halo.external-urlhttps://blog.example.com改完配置后重新执行docker compose up -d一切正常。这个坑的教训是配置反向代理的项目必须在应用层显式声明对外 URL而不是依赖代理自动传递。5. 主题、插件和写作流把 Halo 调成趁手工具5.1 主题系统怎么玩Halo 的后台自带应用市场直接在主题页面浏览、安装、启用不需要手动下载文件包。默认推荐的几个主题像 Earth、Ship、Stack 之类的设计风格都比较现代支持浅色深色切换、自定义导航菜单、侧边栏组件。主题安装后一般在外观-主题设置里可以调整主色调、首页文案、社交链接、底部信息这些。如果想要更细的定制有两个途径一个是自定义 CSS适合只改颜色、间距的小改动另一个是直接在主题目录下编辑模板文件适合对前端技术有基础的作者。个人建议不要在主题里堆太多花哨组件。博客的核心是阅读体验正文排版、代码高亮、图片灯箱这三样做扎实比什么特效都重要。5.2 我常用的几个插件Halo 2.x 的插件机制非常强大官方应用市场里能找到大部分个人博客所需的能力。我自己目前常驻的插件有这些评论增强类插件实现嵌套回复、邮件通知、反垃圾过滤。文章目录插件自动提取正文标题生成 TOC 侧边栏。友链管理插件前台展示友链卡片。图片灯箱插件点击正文图片放大浏览。站点统计插件展示文章数、评论数、访问量。安装插件同样在后台应用市场一键完成。需要注意插件不是越多越好每个插件都会带来额外的渲染开销和安全面保持够用就好的原则。5.3 我从托管平台搬过来的写作流内容迁移是我很重视的一步。Halo 后台支持 Markdown 导入但不同平台导出的格式差异很大图片链接往往还是绝对地址。我当时的做法是先把平台文章导出成 Markdown 文件再用脚本把图片批量下载到本地最后通过 Halo 后台的文章导入功能逐个导入。实际写作时Halo 编辑器的 Markdown 支持很完整代码块有指定语言的高亮图片可以直接粘贴自动上传到服务器。长文写作我会用 Typora 在本地写好再粘贴到后台编辑器微调格式。文章发布的常规习惯是打上分类和标签Halo 的分类支持层级结构适合逐渐积累知识库型的博客。6. 上线不是终点备份、升级和日常排错经验6.1 一套真正靠谱的备份方案建站最容易忽略的就是备份。很多人的博客倒闭不是因为内容不行而是服务器故障导致数据丢失又没有可恢复的备份。我目前采用三层备份数据库备份MySQL 定时任务执行mysqldump保留最近 7 天。文件备份用tar打包/opt/halo-deploy/halo目录因为主题、插件配置、上传图片都在里面。异地备份每天凌晨把以上两个备份文件通过rsync同步到对象存储或者另一台小机器。定时任务可以写到 crontab 里比如每天凌晨 2 点执行0 2 * * * mysqldump -h 127.0.0.1 -u halo -phalo_password halo /backup/halo_$(date \%F).sql tar -czf /backup/halo_files_$(date \%F).tar.gz -C /opt/halo-deploy halo恢复时先恢复数据库再恢复文件目录然后重启 Halo 容器即可。务必备份前先停写保证数据一致性。6.2 升级小版本和大版本各要注意什么Halo 官方发布新版本比较勤快小版本升级通常是 Bug 修复和安全更新。我的升级流程是先做一次完整备份。修改docker-compose.yml里的镜像版本号。执行docker compose pull拉新镜像。执行docker compose up -d重建容器。打开控制台检查首页、后台、文章编辑是否正常。大版本升级比如从 2.20 升到 2.21或其他大版本跨度则一定要先看官方 Release Notes。特别是 1.x 升到 2.x官方提供了迁移工具但操作路径完全不同不是简单换镜像能解决的。建议升级前先在另一台机器备份环境做预演确认插件主题都兼容后再生产操作。6.3 三个高频问题的排查链路我把运行大半年遇到的几个痛点整理一下这些都是有共性的问题一容器一直重启日志报数据库连接失败。先看 MySQL 容器是否存活docker ps。如果 MySQL 正常再检查spring.r2dbc的用户名密码是否和MYSQL_USER/MYSQL_PASSWORD一致。问题二前台样式错乱图片加载失败。多半是external-url没有正确配置或者 Nginx 缺少X-Forwarded-Proto头导致 Halo 不知道当前是 HTTPS。按 4.4 节的方法排查即可。问题三后台登录后 302 跳转到一个奇怪的网址。同样与external-url相关但也可能是浏览器缓存了旧链接。用无痕窗口重试是判断新旧问题最快的方式。个人体会是自建站遇到问题时优先去看容器日志docker logs halo --tail 100大部分线索都能在里面找到比到处乱猜高效得多。最后再分享一个实用习惯每次改动配置前先把/opt/halo-deploy目录整个复制一份加日期后缀。这个习惯让我在几次试验性配置失败后都能快速回滚比写任何运维文档都管用。Halo 这套系统本身很稳定你要做的就是给它搭好一个可以随时后悔的环境。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从孤岛到星系:MCP集成网格治理AI Agent的架构实践 2026/9/26 18:25:10

从孤岛到星系:MCP集成网格治理AI Agent的架构实践

1. 从十几条点对点直连开始崩坏:MCP 孤岛是如何形成的1.1 一个很真实的办公场景:研发、设计、安全各接各的先说一个我上个月刚从一家中型企业亲眼看到的现场。这家公司技术氛围不错,已经有不少团队在用 AI Agent 干活:研发团队接了…

阅读更多 →
Vue项目版本号比较实战:semver插件用法与避坑指南 2026/9/26 18:25:10

Vue项目版本号比较实战:semver插件用法与避坑指南

1. 先想清楚:Vue项目里到底哪些地方需要版本号上个月帮同事排查一个诡异的线上问题:用户报告“组件库升级后页面白屏”,但本地和测试环境都复现不了。查到最后,原因居然是某个依赖在发布时把0.4.8直接跳到了0.5.0,而项…

阅读更多 →
操作系统复习:以资源管理为主线搭建知识骨架 2026/9/26 18:25:10

操作系统复习:以资源管理为主线搭建知识骨架

1. 先别急着背名词,把操作系统的骨架搭起来复习操作系统的时候,我一度觉得这是所有课程里最让人心里没底的一门。倒不是因为它难,而是知识点太散:今天讲进程调度,明天讲内存分页,后天又跑到磁盘算法去了&am…

阅读更多 →
VSCode插件开发:Webview加载外部项目实战与TaoToken配置 2026/9/26 18:25:10

VSCode插件开发:Webview加载外部项目实战与TaoToken配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
多Agent协作系统权限失控复盘:从抱团劫持到安全设计 2026/9/26 18:25:10

多Agent协作系统权限失控复盘:从抱团劫持到安全设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Claude Code模板体系:CLAUDE.md、斜杠命令与Agent Skills工程实践 2026/9/26 18:25:03

Claude Code模板体系:CLAUDE.md、斜杠命令与Agent Skills工程实践

先说个实在话:claude-code-templates 这个标题,落地到实际场景里,指的是一套围绕 Claude Code 构建的可复用配置、命令、技能与自动化脚本的集合。我自己在终端里用 Claude Code 写项目有一段时间了,最深的体会是:这个…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉