ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker私有化部署Halo博客:从零到HTTPS完整指南

Docker私有化部署Halo博客:从零到HTTPS完整指南 标题里我把话就说完了这是我在自己的服务器上用Docker部署的Halo博客系统已经稳定跑了两年多。私有化部署听起来门槛很高但真上手你会发现它比你在某个平台注册个号开始写文章还快而且从第一行代码到最后一篇随笔所有数据都握在自己手里。今天就把整套流程从零讲透包括怎么选服务器、装Docker、启动Halo、绑域名、上HTTPS、备份迁移以及我踩过的所有坑。这篇内容适合两类人一是受够了各种写作平台广告和审核规则想拥有一个完全受自己控制的博客的写字的人二是对Docker有兴趣但一直没找到适合练手项目的开发者。Halo恰好是同时满足这两类需求的解——它是一个Java写的开源博客系统API干净、插件生态成熟、官方默认主题走极简路线配合Docker的部署方式就算你完全没接触过Linux照着操作也能把博客跑起来。1. 为什么最终选了 Halo Docker1.1 从“写在平台上”到“写给自己”先说个扎心的事实你在公众号、知乎、或者各种笔记App里写了几年内容哪天平台改规则、关功能、甚至直接停服你的文字和数据要迁出来非常麻烦。我自己就经历过一次笔记软件停服导出数据折腾了整整一个周末从那以后就铁了心要搞一个自己的博客。私有化部署解决的就是这个“数据主权”问题。服务器是你租的数据库在你机器上文章导出导入随时可以做想改样式改栏目改接口都行。这种感觉和借住在别人家完全不同——你只是在互联网上租了一小块地皮但这块地皮上的房子产权完全是你自己的。当然自己搭博客也意味着服务器费用、维护成本、安全补丁都得自己管。但如果你只在上面跑一个Halo一台2核2G的云服务器绰绰有余一年的费用甚至比很多写作软件的会员费还便宜。这笔账怎么算都划算。1.2 对比了一圈WordPress太重静态博客太折腾选型阶段我把主流方案都过了一遍简单说说当时的判断给还在纠结的你做个参考。WordPress功能确实全面主题插件多到数不清但问题恰恰出在“全面”上默认编辑器体验一般插件装多了页面加载越来越慢还时不时要处理安全更新和小漏洞。再加上我身边不止一个朋友被各种花哨主题折腾到怀疑人生我直接划掉了这个选项。静态博客Hexo、Hugo这类也很心动渲染出来的页面那叫一个干净部署也简单扔到对象存储或者GitHub Pages上就能访问。但静态博客的痛点在于“写”的体验没有后台编辑器通常得在本地写好Markdown再跑命令生成、推送手机端基本没法用。我写东西经常是碎片时间这个工作流对我来说太不友好了。Halo是我试了一圈之后留下的答案。它默认就是一个带后台的博客系统打开浏览器就能写文章Markdown体验顺畅默认主题走的是清爽路线。而且因为基础是Java生态运行非常稳定不像某些轻量方案跑着跑着就内存溢出了。最关键的是它支持插件机制需要评论、图床、统计之类的功能装一个插件就行不需要自己改代码。1.3 Docker 让“部署”变得像“装App”一样简单聊完博客方案再聊部署方式。很多人一听“部署”两个字就头大其实Docker已经把门槛压得非常低了。你可以把Docker理解成集装箱运输镜像Image就是标准化的货物容器Container就是正在运行的货物实例而数据卷Volume是挂在外面的货柜怎么搬都不会丢。有了这套抽象你不再需要关心服务器上装的是哪个操作系统、缺哪个依赖库、Java版本是不是匹配这些在镜像里全都打包好了。用Docker部署Halo有个特别实在的好处升级和回滚都非常干净。想升级博客版本就拉一个新版本的镜像停旧容器起新容器万一升级出问题了把旧镜像的标签换回来几分钟就回滚了。如果是传统那种直接在服务器上装Java、装数据库、再跑一个进程的方式升级一次往往心惊胆战不敢轻易动。另外一个隐藏优势是环境的一致性。你在本地测试能跑通的配置推到服务器上通常也能跑通因为Docker镜像屏蔽了底层系统的差异。这个特性对新手来说太重要了意味着网上教程里的命令可以直接抄作业不用在“为什么我的Ubuntu跑不起来”这个问题上浪费半天。2. 部署前你要心里有数的几件事2.1 服务器选型和系统准备先说最低配置结论个人博客用Halo2核2G的云服务器完全够。我的博客跑了两年多日常内存占用不到1GCPU更是很少有波动。如果你打算同时跑多个应用比如还要挂一个Vaultwarden或者监控面板那可以升到2核4G但纯粹写博客2G已经绰绰有余。操作系统我推荐Ubuntu 22.04 LTS或者Debian 12这两个系统的Docker支持最省心。选系统的时候注意两点一是不要选“已停止维护”的老版本比如CentOS 7这类已经过了生命周期装新版本Docker会遇到各种源的问题二是建议选带公网IP的独立服务器而不是只给你一个内网地址的虚拟主机否则后面域名绑定会麻烦很多。服务器到手之后第一步是更新系统包然后创建自己的登录用户不建议直接用root干活万一手指一抖输错命令影响面太大。我习惯创建一个叫deploy的用户把需要用到的目录权限都给它日常操作就用这个账号。2.2 安装 Docker 环境的正确姿势Docker安装方式有几种我只推荐最稳妥的官方脚本安装方式curl -fsSL https://get.docker.com | sh这行命令会自动检测系统环境配置好Docker官方软件源并安装最新社区版。安装完成后先别急着用执行一下这个命令确认没有白装docker version能看到Client和Server两行信息就说明Docker服务已经正常跑起来了。如果只有Client没有Server试试启动服务sudo systemctl enable --now docker这里有个新手几乎必踩的坑默认情况下只有root或者sudo权限才能执行docker命令每次敲命令都加sudo真的很烦。解决办法是把当前用户加入docker组sudo usermod -aG docker $USER newgrp docker重新登录之后再执行docker version就不需要加sudo了。注意加入docker组等同于给了这个用户很高的系统权限因为Docker本身能挂载目录、接管网络所以这个操作最好只在自己日常用的账号上做不要给多人共享的服务器账号乱加。2.3 动手前必须理解的三个概念在敲第一条部署命令之前我建议你先花五分钟弄清楚三个核心概念省得后面出问题一脸懵。第一是镜像和容器的区别。镜像是一份只读的模板容器是镜像运行起来后的实际进程。你可以把镜像理解成手机App的安装包容器就是App安装好之后在桌面上运行的那个图标。我们从一个镜像可以创建多个容器互不影响。第二是数据卷的挂载。容器内部的文件系统是临时的删除容器数据就没了所以必须把重要数据目录挂载到宿主机上。比如Halo在容器里的工作目录是/root/.halo2我们把它映射到服务器的/opt/halo目录这样即使容器删了重建数据和附件都还在宿主机上这就是“数据不丢”的底气。第三是端口映射。Halo容器内部监听8090端口但这个端口只在容器内部要让外部访问必须把它映射到宿主机的端口上也就是启动命令里的-p 8090:8090。前面那个8090是宿主机端口外面访问的是它后面那个8090是容器端口Halo进程监听的地址。搞懂这三个概念后面无论部署什么应用你都能知道命令里每个参数在干什么。3. 用Docker把Halo跑起来全流程实操3.1 目录规划和端口规划正式部署前花两分钟做个规划能省掉后面很多麻烦。我习惯把所有Docker应用的数据都放到一个统一目录下比如/opt然后按应用名字分子目录。Halo的数据目录就定为/opt/halo这里面会放Halo的配置、H2数据库文件、附件、主题和插件相当于整个博客的家当都在这一个目录里。端口方面Halo默认监听8090端口这也是官方文档的统一约定。除非8080或8090已经被其他服务占用否则不建议换端口——换了虽然也能用但很多文档、插件、反向代理配置都是按默认端口写的保持一致能让查问题时少一个变量。还有一个很多人忽略的点云服务器的安全组。如果你用的是阿里云、腾讯云这类服务商控制台里的安全组规则默认可能只放行了80、443和22端口。就算你在服务器上把8090端口开放了安全组没放行外部依然访问不了。所以在启动Halo之前先去云控制台确认一下8090端口或者你最终对外暴露的端口已经在安全组规则里放行。3.2 一条 docker run 命令把博客拉起来规划好了就动手。我的启动命令是这样的docker run -d \ --name halo \ -p 8090:8090 \ -v /opt/halo:/root/.halo2 \ --restartalways \ halohub/halo:2.x逐条解释一下不是让你死记硬背而是让你知道每个参数到底在干什么。-d是让容器在后台运行不会占着你的终端。--name halo给容器起个名字以后启停、查看日志都靠这个名字。-p 8090:8090就是刚才说的端口映射。-v /opt/halo:/root/.halo2把宿主机的数据目录挂载进容器的工作目录这是数据持久化最关键的一步。--restartalways表示服务器重启后Docker会自动把Halo容器带起来省的服务器一重启博客就断线你还要手动登录去启动。关于镜像版本这里特别提醒一下安装命令里的2.x要替换成实际的版本号建议去Halo官方仓库页面看一眼最新的稳定版本标签。比如当前稳定版是2.20.x就写halohub/halo:2.20。不建议直接用latest标签因为无法预期它什么时候更新生产环境更要避免这种不确定性。命令执行成功后输入docker ps应该能看到halo容器处于Up状态。第一次启动需要一点时间初始化数据库和默认配置大约十秒左右然后打开浏览器访问http://你的服务器IP:8090就能看到Halo的初始化页面了。初始化页面会让你设置管理员用户名和密码以及博客的标题。注意密码设置页面会要求一定复杂度但不用设置得像银行账户那样变态毕竟你后面还可以绑HTTPS、设置登录防护插件。初始化完成后你会进入一个非常简洁的后台界面这就是接下来每天写作的地方。3.3 认真推荐用 docker compose 管理你的部署docker run一条命令确实能跑起来但如果你打算长期用我强烈建议升级到docker compose的方式。它本质上是把容器的所有配置写进一个YAML文件里好处是显式、可版本管理、改动可控。在/opt/halo目录下新建一个docker-compose.yml文件内容如下services: halo: image: halohub/halo:2.20 container_name: halo restart: always ports: - 8090:8090 volumes: - /opt/halo:/root/.halo2保存后在同一个目录执行docker compose up -d效果和刚才的docker run完全一样但以后所有改动都围绕这个文件展开。升级版本时把image那一行的版本号改一下然后执行docker compose pull docker compose up -d命令会自动拉新镜像、重建容器并且因为数据卷挂载没变所有文章数据原样保留。删除容器也更干净一条docker compose down就能把容器移除数据目录还在随时可以重新拉起来。我第一次部署时图省事用的docker run后来要加环境变量、调整参数发现那串命令越来越长改起来头疼。换成compose之后所有配置都摊在文件里清清楚楚哪怕是半年后再来看也知道当初到底怎么部署的。4. 极简博客的“标配”域名、HTTPS与访问优化4.1 从“IP:8090”变成自己的域名博客跑起来之后用IP加端口访问总觉得不是那么回事而且8090端口真的不够好看。配一个域名让博客看起来像“正式项目”这个步骤建议尽早做。先去域名注册商那里买一个域名一年几十块钱的就够用不追求什么特殊后缀com、net、top都行。买完之后在域名解析控制台添加一条A记录主机记录填www或者记录值填你的服务器公网IPTTL用默认值。然后回到服务器上确认80端口和443端口是放行的。域名解析生效后先别急着配HTTPS用http://你的域名试试能不能访问到Nginx默认页如果响应了说明域名到服务器的通路已经通了。4.2 用Nginx做反向代理把博客藏到标准端口后面有了域名之后下一步就是把外部访问统一收敛到80/443端口再由Nginx反向代理转发到容器内部的8090。这样做的理由有两个一是80/443是访问者默认预期的端口不需要在网址里手动敲:8090二是后续挂HTTPS证书Nginx是承担证书生命周期的理想位置不用改Halo容器本身。Nginx可以装在宿主机上也可以再起一个Nginx容器。我个人倾向于宿主机直接装一个因为Nginx本身非常轻量而且宿主机层的配置省去一层容器间网络通信的复杂度。sudo apt install nginx然后在/etc/nginx/conf.d/下新建一个halo.conf文件写入server { listen 80; server_name your-domain.com; client_max_body_size 1024m; 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; } }client_max_body_size这个配置容易被忽视它的作用是允许上传大附件比如你传一个几十MB的图片或者PDF如果默认的1M限制没改上传会直接报错。我一开始没设这个参数后来传一张手机原图就被Nginx拒绝了排查了半天才想起来是上传大小限制的问题。改完配置后执行nginx -t sudo systemctl reload nginx配置文件没问题的话现在就可以通过http://你的域名访问博客了。接下来是HTTPS证书。推荐用acme.sh这种方式签免费证书步骤大概是curl https://get.acme.sh | sh source ~/.bashrc ~/.acme.sh/acme.sh --issue -d your-domain.com -w /var/www/html --nginx签发成功后把证书安装到Nginx目录~/.acme.sh/acme.sh --install-cert -d your-domain.com \ --key-file /etc/nginx/cert/your-domain.com.key \ --fullchain-file /etc/nginx/cert/your-domain.com.pem \ --reloadcmd systemctl reload nginx然后更新之前那个halo.conf加上443监听和证书路径server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/nginx/cert/your-domain.com.pem; ssl_certificate_key /etc/nginx/cert/your-domain.com.key; client_max_body_size 1024m; 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; } } server { listen 80; server_name your-domain.com; return 301 https://$host$request_uri; }最后把域名解析换成HTTPS以后访问博客就是一把小锁头加绿色地址栏写作和访客浏览都更放心。4.3 备份与迁移私有化最容易被偷懒但最不能偷懒的事有了自己的数据就得想清楚备份策略。我原来也觉得“服务器不会出事吧”直到有次手滑删了目录才真正明白什么叫欲哭无泪。后来我给自己定了一条铁律每周全量备份一次数据目录动任何配置之前先手动备份一次。Halo的数据备份非常简单因为所有东西都在/opt/halo这个目录里。数据库文件、附件、主题、插件配置全都在里面你只需要打包这一个目录tar -czvf halo-backup-$(date %F).tar.gz /opt/halo把这个tar包同步到对象存储或者另一台机器上即可。如果你有对象存储配合restic或者rclone这类工具可以做增量备份和自动同步我的做法是用cron每周日凌晨跑一个脚本把备份推到对象存储日志发到Telegram这样连“我忘了备份”这件事都不会发生。迁移到新服务器就更简单了新机器装好Docker把备份包解压到/opt/halo再启动一个同样参数的Halo容器访问新地址博客连附件带插件全部恢复如初。整个过程通常不超过十分钟这就是Docker加数据卷挂载最大的红利。5. 常见问题与排障速查表5.1 镜像拉取太慢或拉取失败这个问题几乎所有国内用户都会遇到。默认从Docker Hub拉取镜像的速度很不稳定解决办法是配置镜像加速器。在/etc/docker/daemon.json里添加镜像加速器地址{ registry-mirrors: [https://你的加速器地址] }国内主流云厂商都提供免费的容器镜像加速服务注册后就能拿到专属地址。配置好之后执行sudo systemctl daemon-reload sudo systemctl restart docker然后重新拉镜像速度会有非常明显的提升。5.2 端口访问不通思路全乱端口不通的排查顺序非常固定按顺序查一遍基本就能定位。第一步查容器状态docker ps看容器是不是Up状态如果在Restarting看日志找原因。第二步在服务器本地试试curl http://127.0.0.1:8090如果能返回页面说明容器没问题问题出在外部链路上。第三步查防火墙sudo ufw status看看有没有把8090端口放行。第四步查云控制台的安全组规则这个最容易被忽略很多服务商默认不放开非标准端口。这几步走完90%的端口问题都能定位。我的经验是绝大多数“部署成功但访问不了”的问题都出在安全组或者防火墙上面跟Halo本身没什么关系。5.3 忘记后台密码Halo没有提供像WordPress那样方便的“忘记密码”邮件重置链接万一密码忘了最稳妥的办法是直接操作数据库。Halo默认的H2数据库文件就在/opt/halo/db目录下。用h2.jar工具连接数据库找到用户表把密码字段替换成新生成的BCrypt哈希值即可。生成BCrypt哈希可以用Halo的encode命令比如进入容器执行docker exec -it halo /opt/halo/bin/halo encode --password yournewpassword拿到输出的一长串哈希之后再到数据库里更新对应用户的password字段重启容器新密码就能用了。说实话这个操作有点门槛所以更建议的做法是定期备份数据库忘记密码时干脆恢复一次数据备份或者如果有管理权限直接新建一个管理员账号再删掉旧的。5.4 升级版本后网站打不开/插件不兼容升级Halo版本理论上很平滑因为官方做了数据库自动迁移但插件生态偶尔会拖后腿。升级完发现页面白屏先看容器日志docker logs halo日志里通常能看到具体的异常堆栈如果指向某个插件最直接的解决办法是停用那个插件可以通过数据库修改插件状态或者先降级回旧版本等插件适配。为了应对这种情况升级前务必做好三件事备份/opt/halo整个目录、确认新版镜像tag存在、留出十分钟的空档期。有备份在手升级这件事的风险就完全是可控的。6. 把Halo调教成真正“极简”的写作工具6.1 主题能少装就少装Halo的主题商店里确实有不少漂亮的主题但你真开始写东西之后会发现花里胡哨的样式很快就腻了。我目前用的还是官方默认主题改了一下页面宽度和字号整体就很好看了。默认主题的排版逻辑是内容优先标题、正文、代码块、引用都处理得很清楚没有多余的装饰。对于写作来说这个状态其实是最好的——你不会被页面样式分散注意力访客也能把焦点放在文字本身。6.2 插件只装踩坑之后真需要的那几个插件也是一样的逻辑。Halo的插件机制很强但不需要一开始就全都装上。我的建议是先裸跑一个月过程中产生明确需求了再装。比如你发现评论区被垃圾消息刷屏了再装评论防护插件你觉得后台默认编辑器不够顺手再换Markdown编辑器插件。我现在生产环境上只有三个插件一个是评论系统增强一个是定时备份一个是代码高亮。这个数量级下整个后台打开速度极快也不用担心插件之间的兼容性问题。6.3 写作工作流以Markdown为核心Halo的编辑器天然支持Markdown你可以直接在后台写也可以先用本地的Typora这类工具写好再粘贴进去。我的习惯是长文先在本地写用Markdown把结构打好再复制到Halo的编辑器里微调一下格式。短文就直接在后台写打开页面就能敲字不用开多余的App。如果你经常用手机记录灵感Halo也有对应的移动端适配后台界面在手机上浏览基本可用写短文完全没问题。总之整个工作流非常轻从打开后台到发布一篇文章五分钟以内肯定能完成。6.4 坚持写作才是博客的终极维护跑到现在这个节点技术层面的工作其实已经结束了——服务器稳定、HTTPS没问题、备份在自动跑。接下来最难的只有一件事持续写。我自己的体会是把博客当成一个陪自己成长的记录本而不是一个需要运营的“产品”反而能坚持得更久。偶尔一个月写一篇也好一年后回看那些记录会发现那些琐碎的思考其实已经拼出了一条清晰的轨迹。这就是Docker私有化部署Halo最大的意义把所有技术门槛都压到最低让你只需要面对真正重要的事情——写下去。希望这篇文章能帮你把博客跑起来也希望你能比我更早地体会到“拥有自己领地”的踏实感。
返回列表