Halo 是一个用 Java(Spring Boot)写的开源建站 / 博客系统,自带管理后台、主题市场和插件市场。它和 Hugo、Hexo 最大的区别是「动态」:文章存在数据库里,页面由服务端实时渲染,写文章、传图片、换主题都在浏览器后台完成。
核心特点与优势:
有后台:文章管理、附件库、页面、评论、用户权限都在可视化界面里,不用碰 Git 和命令行,手机浏览器也能写。
主题 / 插件市场:控制台里直接搜索安装主题和插件,评论、搜索、对象存储一类的功能靠插件补齐,不用改代码。
数据在数据库:支持 PostgreSQL、MySQL、MariaDB,也可以用内置 H2(生产环境不建议);备份是「数据库 + 附件目录」两件事。
开箱即用的博客结构:文章、分类、标签、独立页面、友链(插件)、归档都有现成实现。
部署方式多:Docker Compose、1Panel / 宝塔应用商店、单容器试跑都可以,官方镜像支持国内镜像源。
多用户与权限:可以给协作者分配角色,适合多人维护的站点。
代价也要说清楚:
| 维度 | Halo | Hugo / Hexo |
|---|---|---|
| 形态 | 动态,数据库 + 服务端渲染 | 静态,构建出 HTML |
| 写作方式 | 浏览器后台 | 本地 Markdown + Git |
| 部署 | 服务器 + Docker | 任意静态托管,含 GitHub Pages |
| 运维 | 数据库备份、版本升级 | 几乎为零 |
| 适合 | 想可视化运营、多人协作、要评论 | 想零成本、零运维、纯写作 |
Halo 只能部署在有公网 IP 的服务器上。最省事的是 Docker Compose + PostgreSQL,一条命令起站,再用 Nginx 做反向代理和 HTTPS。
安装 Docker(官方脚本):
bashcurl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable --now docker
docker compose version
Halo 的 external-url 决定后台生成的绝对链接、附件地址、邮件里的跳转,初始化前就要定下来。
http://服务器IP:8090,能跑通再换域名。A blog → 服务器IP,等 dig +short blog.example.com 返回正确 IP 再继续。DNS 服务商配置方式:
| 服务商 | 入口 | 记录 |
|---|---|---|
| Cloudflare | DNS → Records | A blog → IP,橙云/灰云按需,签证书期间用灰云 |
| 阿里云 / 腾讯云 | 云解析 DNS → 解析设置 | A blog → IP,TTL 600 |
| DNSPod | 域名解析 → 添加记录 | A blog → IP,TTL 600 |
新建目录并写文件:
bashmkdir -p ~/halo && cd ~/halo
docker-compose.yaml:
yamlservices:
halo:
image: halohub/halo:2.27.1
container_name: halo
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
volumes:
- ./halo2:/root/.halo2
ports:
- "127.0.0.1:8090:8090"
environment:
TZ: Asia/Shanghai
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb:5432/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=CHANGE_ME
- --spring.sql.init.platform=postgresql
- --halo.external-url=http://blog.example.com/
halodb:
image: postgres:15.4
container_name: halodb
restart: always
environment:
POSTGRES_DB: halo
POSTGRES_USER: halo
POSTGRES_PASSWORD: CHANGE_ME
TZ: Asia/Shanghai
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U halo -d halo"]
interval: 10s
timeout: 5s
retries: 5
几个要点:
2.27.1),不要用 latest,否则某天重启就悄悄升级了。安装前去 Halo 的 Releases 页确认当前最新 2.x。ports 写成 127.0.0.1:8090:8090,避免把 8090 暴露到公网;外部访问统一走 Nginx。external-url 必须以 / 结尾,并且和最终访问地址一致。先用 IP 测试就写 http://IP:8090/,配好域名后再改。docker compose down 再 up -d(改密码不能只重启)。registry.fit2cloud.com/halo/halo:2.27.1。spring.r2dbc.url 和 spring.sql.init.platform 改成对应驱动(mysql 或 mariadb)。bashdocker compose up -d docker compose logs -f halo
看到启动完成后访问 http://blog.example.com/console(或 http://IP:8090/console),进入初始化向导:
external-url 一致);初始化只在数据库为空时出现,账号密码务必记牢——Halo 没有默认账号。
/etc/nginx/sites-available/halo.conf:
nginxserver { listen 80; listen [::]:80; server_name blog.example.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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
bashsudo ln -s /etc/nginx/sites-available/halo.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
client_max_body_size 决定单次上传上限,1G 是为了传大附件;不设的话默认 1M,传图就会 413。
bashsudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d blog.example.com sudo certbot renew --dry-run
certbot 会在同一个 server 块里追加 443 和跳转规则,代理配置不受影响。
证书生效后,把 --halo.external-url 改成 https://blog.example.com/,然后:
bashdocker compose down docker compose up -d
不改这一步的典型症状:后台里文章封面、附件地址还是 http://,浏览器按混合内容拦截。
备份三样东西:
bashcd ~/halo
docker compose exec -T halodb pg_dump -U halo -d halo > backup-$(date +%F).sql
tar -czf halo2-$(date +%F).tar.gz halo2/
exec 加 -T 是为了关掉伪终端,否则重定向出来的 SQL 可能混入多余字符。
pg_dump(或控制台「系统 → 备份」入口,如果当前版本提供);./halo2 目录;/etc/letsencrypt。升级:
bashdocker compose pull docker compose up -d docker compose logs -f halo
升级前先备份,升级后进后台检查主题和插件是否有兼容提示。
dig 能解析到服务器 IPIP:8090 不通external-url 与最终域名、协议完全一致,且以 / 结尾/console 能正常登录client_max_body_size)certbot renew --dry-run 通过halo2/ 目录已做一次备份不想手敲 Docker 命令时,用 1Panel 的应用商店:
127.0.0.1:8090;https://域名/console 登录后台。面板路线的优势和代价:省掉 compose、Nginx、证书的手工步骤;出问题时多一层封装,日志和端口映射要去「容器」页看。
机器上只有 Docker、想 5 分钟看效果:
bashdocker run -it -d --name halo -p 8090:8090 \ -v ~/.halo2:/root/.halo2 \ -e TZ=Asia/Shanghai \ halohub/halo:2.27.1
默认用内置 H2 数据库,重启后数据在 ~/.halo2 里。官方明确说过 H2 不适合生产环境,只用于试用。
| 现象 | 原因 | 处理 |
|---|---|---|
| 8090 打不开 | 容器没起 / 端口只绑了 127.0.0.1 | docker compose ps、logs halo;外部走 Nginx |
初始化后链接跳到 127.0.0.1 | external-url 没改 | 改 compose 参数后 down + up -d |
| 上传图片 413 | Nginx 上传上限太小 | 调 client_max_body_size |
| 后台能开、保存失败 | 反向代理缺 X-Forwarded-Proto / Upgrade 头 | 按第 5 步完整配置 |
| 容器起不来,日志报数据库连接 | 密码不一致 / 数据库未就绪 | 两处密码对齐,确认 healthcheck 通过 |
| 证书申请失败 | DNS 未生效、80 被占、Cloudflare 橙云 | 先灰云、确认 80 可达 |
| 升级后主题报错 | 主题与核心版本不兼容 | 回滚镜像版本,或升级主题 |
| 内存不足容器被杀 | JVM + PostgreSQL 占用 | 加 swap 或升到 2G 内存 |
后台 → 设置 → 基本设置:站点标题、副标题、站点描述、Logo、favicon、备案号。备案号在国内服务器上是硬要求,填在页脚会显示。
外观:后台 → 主题 → 安装(市场或上传 zip)。装完在「主题设置」里改配色、菜单、首页布局,多数主题支持暗色模式。
后台有「评论」管理入口,评论组件由主题提供(部分主题需要在主题设置里开启)。国内访客为主时,主题通常支持 Twikoo、Waline、Giscus 等第三方方案,按主题文档填服务地址即可。
/sitemap.xml 与 /rss.xml 是否可访问(不同主题 / 插件提供的路径可能不同),有的话提交到搜索引擎。后台 → 用户 → 新建,分配角色(管理员 / 作者 / 访客)。多人维护时,给作者角色即可,不要共用管理员账号。
Halo 的写作模型和静态站完全不同:内容在数据库,任何浏览器登录后台就能写,不需要 Git、不需要构建。
浏览器打开 https://域名/console → 新建文章 → 写 → 发布 → 数据库保存 → 前台立即可见
桌面浏览器体验最好,可以多标签同时开文章、附件库、设置。需要批量导入时,用后台的导入功能(支持 Markdown 压缩包 / 单文件,按当前版本文档为准),导入前把 Markdown 的 front matter 对齐。
Halo 提供 REST API 和个人令牌(控制台 → 个人中心 → 个人令牌)。需要从本地脚本或其它系统推送文章时,用令牌调用文章创建接口即可,不用模拟登录。注意令牌等同密码,不要提交进仓库。
external-url、站点地址、附件 URL 三处要一起改。halo2/,回滚靠这两份。本文作者:Weee
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!