Halo 2.27.1 配置参数详解
Halo 2.27.1 application.yaml 配置参数逐项详解:端口、R2DBC 数据库、工作目录、外部访问地址、静态资源缓存、附件缩略图、安全与会话、日志与 Actuator 监控,附官方默认值与生产实测回显。
Halo 2.27.1 配置参数详解
目标:把 Halo 2.27.1 的
application.yaml讲清楚——哪些键是 Halo 自己的、哪些来自 Spring Boot,默认值是多少,改了会怎样。文中所有"实测"均于 2026-10-27 在一台 Ubuntu 22.04.5 LTS 服务器上完成,Halo 以 JAR + systemd 方式运行,数据库为 PostgreSQL 14.24。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- JDK:Eclipse Temurin 21.0.13+9 LTS(
/usr/local/java) - Halo:2.27.1(
/opt/halo/halo-2.27.1.jar) - 数据库:PostgreSQL 14.24(127.0.0.1:5432,库名
halo) - 工作目录:
/root/.halo2 - 配置文件:
/root/.halo2/application.yaml - 服务端口:8090
- 管理账号(示例):
root/q1w2e3r4
二、配置文件的加载方式与优先级
Halo 的内置配置打包在 JAR 内(BOOT-INF/classes/application.yaml),外部配置文件通过启动参数追加:
/usr/local/java/bin/java -jar /opt/halo/halo.jar \
--spring.config.additional-location=optional:file:/root/.halo2/
生效优先级由低到高:
| 层级 | 来源 | 说明 |
|---|---|---|
| 1 | JAR 内置 application.yaml | Halo 与 Spring Boot 的默认值 |
| 2 | 数据库 profile(如 application-postgresql.yaml) | 由 spring.sql.init.platform 激活 |
| 3 | /root/.halo2/application.yaml | 运维最常改的一层 |
| 4 | 命令行 --key=value | 优先生效,适合临时覆盖 |
实测:修改 /root/.halo2/application.yaml 后执行 systemctl restart halo,约 20 秒内新配置生效;不重启则不会热加载。
Halo 2.27.1 内置的关键默认值(节选,均来自 JAR 内 application.yaml):
server:
port: 8090
forward-headers-strategy: native
compression:
enabled: true
spring:
r2dbc:
url: r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSE
username: admin
password: 123456
sql:
init:
mode: always
platform: h2
web:
resources:
cache:
cachecontrol:
max-age: 365d
cache:
type: caffeine
caffeine:
spec: expireAfterAccess=1h, maximumSize=10000
threads:
virtual:
enabled: true
halo:
work-dir: ${user.home}/.halo2
logging:
file:
name: ${halo.work-dir}/logs/halo.log
三、端口与外部访问地址
| 配置项 | 默认值 | 作用 |
|---|---|---|
server.port | 8090 | HTTP 监听端口 |
server.forward-headers-strategy | native | 信任反向代理传来的 X-Forwarded-* 头 |
halo.external-url | 无 | 站点对外访问地址,初始化时用于生成绝对链接 |
halo.use-absolute-permalink | false | 永久链接是否输出绝对地址 |
端口实测:把 server.port 改为 8091 并重启后:
== 8091 首页 HTTP 200
== 8090 首页 curl: (7) Failed to connect ... 000
即旧端口立即释放,新端口正常服务。修改端口属于"重启生效",不支持运行时热切换。
外部地址实测(重要):在 application.yaml 中写入 halo.external-url: https://docs.example.com 并重启,RSS 与 sitemap 输出的仍是旧地址:
== rss link <link>http://127.0.0.1:8090</link>
== sitemap <loc>http://127.0.0.1:8090/archives/hello-halo</loc>
随后把 halo.external-url 整行删除再重启,输出依然是 http://127.0.0.1:8090。结论:站点外部地址在初始化时已写入数据库中的系统设置,之后配置文件里的 halo.external-url 不再覆盖它;生产环境要换域名,请在控制台"设置 → 基本设置 → 站点地址"中修改,而不是反复改 YAML。
halo.use-absolute-permalink: true 实测对内容接口返回的 status.permalink 没有影响,仍为 /archives/hello-halo(相对路径);该开关主要影响主题渲染链接,除非确有跨域聚合需求,保持默认 false 即可。
四、数据库连接
| 配置项 | 默认值 | 作用 |
|---|---|---|
spring.r2dbc.url | r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSE | R2DBC 连接串 |
spring.r2dbc.username | admin(H2) | 数据库用户 |
spring.r2dbc.password | 123456(H2) | 数据库密码 |
spring.sql.init.platform | h2 | 数据库方言与建表脚本选择 |
spring.sql.init.mode | always | 启动时执行建表/迁移脚本 |
各数据库的连接串与平台名:
| 数据库 | spring.r2dbc.url | spring.sql.init.platform |
|---|---|---|
| H2 | r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSE | h2 |
| PostgreSQL | r2dbc:pool:postgresql://127.0.0.1:5432/halo | postgresql |
| MySQL | r2dbc:pool:mysql://127.0.0.1:3306/halo | mysql |
| MariaDB | r2dbc:pool:mariadb://127.0.0.1:3306/halo | mariadb |
内置 profile 的默认账号(仅作参考,生产必须改):
# application-postgresql.yaml
spring:
r2dbc:
url: r2dbc:pool:postgresql://localhost:5432/halo
username: postgres
password: openpostgresql
sql:
init:
platform: postgresql
实测切换:H2 首次启动到 Started HaloApplication 用时 7.196 秒;换成 PostgreSQL 后为 10.367 秒(多出的时间用于执行 extensions、migrations 建表与索引)。启动后 extensions 表约 196 行,所有文章、分类、标签、配置都以 JSON 形式存放在这一张表里。
连接池相关参数使用 Spring Boot 的 spring.r2dbc.pool.*(如 max-size、initial-size、max-idle-time),Halo 未额外改写默认值;单站点默认连接池足够,遇到高频写入再评估。
五、工作目录与日志
| 配置项 | 默认值 | 作用 |
|---|---|---|
halo.work-dir | ${user.home}/.halo2 | 数据、日志、附件的根目录 |
logging.file.name | ${halo.work-dir}/logs/halo.log | 日志文件路径 |
logging.logback.rollingpolicy.max-file-size | 10MB | 单个日志文件上限 |
logging.logback.rollingpolicy.total-size-cap | 1GB | 日志总容量上限 |
logging.logback.rollingpolicy.max-history | 0 | 保留的历史文件数(0 表示不额外保留) |
logging.level.run.halo | 未设置(INFO) | Halo 业务日志级别 |
工作目录下的实际结构(实测):
/root/.halo2/
├── application.yaml
├── attachments/ # 本地上传的附件
├── db/ # H2 数据文件(切到 PostgreSQL 后不再使用)
├── logs/halo.log # 应用日志
├── plugins/ # 插件
└── themes/ # 主题
把 logging.level.run.halo 设为 DEBUG 后重启,halo.log 中出现大量调试行,实测重启后累计 2712 行 DEBUG,样例行:
2026-10-27T13:55:19.468Z DEBUG 6042 --- [reactor-tcp-nio-4] r.h.a.e.ReactiveExtensionClientImpl : Successfully retrieved by names from db for content.halo.run/v1alpha1/Post in 11ms
生产环境建议维持 INFO;排查接口 403/404 问题时临时开到 DEBUG,定位后改回,否则日志增长很快(单文件 10MB 很快轮转)。
六、静态资源、压缩与缓存
| 配置项 | 默认值 | 作用 |
|---|---|---|
server.compression.enabled | true | 开启 gzip 响应压缩 |
spring.web.resources.cache.cachecontrol.max-age | 365d | 静态资源浏览器缓存时长 |
spring.web.resources.cache.cachecontrol.use-last-modified | true | 输出 Last-Modified 头 |
spring.thymeleaf.cache | true | 模板缓存(主题页面) |
spring.cache.type | caffeine | 进程内缓存实现 |
spring.cache.caffeine.spec | expireAfterAccess=1h, maximumSize=10000 | 缓存过期与容量 |
spring.http.codecs.max-in-memory-size | 10MB | 单次请求体/响应的内存缓冲上限 |
实测响应头:
$ curl -D- -o /dev/null -H "Accept-Encoding: gzip" \
http://127.0.0.1:8090/themes/theme-earth/assets/...css
HTTP/1.1 200 OK
Cache-Control: max-age=31536000
content-encoding: gzip
max-age=31536000 即 365 天,与 365d 对应。主题静态资源带 hash 文件名,长缓存是安全的;自己反代时不要额外覆盖 Cache-Control,否则主题升级后浏览器可能继续用旧文件。
Caffeine 缓存为进程内实现,重启即清空;单机多实例部署时各实例缓存互不共享,这在文章列表等场景会出现短暂不一致,属于预期行为。
七、附件存储与缩略图
| 配置项 | 默认值 | 作用 |
|---|---|---|
halo.attachment.resource-mappings[0].pathPattern | /upload/** | 附件访问路径 |
halo.attachment.resource-mappings[0].locations | migrate-from-1.x | 旧版附件目录映射 |
halo.attachment.thumbnail.disabled | false | 是否关闭缩略图 |
halo.attachment.thumbnail.concurrent-threads | 1 | 缩略图生成并发数 |
halo.attachment.thumbnail.quality | 未设置 | 缩略图质量(0–1) |
Halo 2.x 的存储策略(本地、S3、OSS)保存在数据库中,通过控制台"附件 → 存储策略"维护,不在 application.yaml 里配置;配置文件只负责 resource-mappings 这类资源映射。初始化后默认存在一条本地策略:
{"metadata":{"name":"default-policy"},"spec":{"configMapName":"default-policy-config","displayName":"本地存储","templateName":"local"}}
实测上传一张 70 字节的 PNG,返回体同时给出四种缩略图地址,说明 thumbnail.disabled 默认为 false 且已生效:
{"spec":{"displayName":"d5-upload.png","mediaType":"image/png","size":70},
"status":{"permalink":"/upload/d5-upload.png",
"thumbnails":{"S":"/upload/d5-upload.png?width=400","M":"/upload/d5-upload.png?width=800",
"L":"/upload/d5-upload.png?width=1200","XL":"/upload/d5-upload.png?width=1600"}}}
若服务器 CPU 较弱且不需要缩略图,可设 halo.attachment.thumbnail.disabled: true;并发数保持 1 可避免上传高峰把 CPU 打满。
八、安全与会话
| 配置项 | 默认值 | 作用 |
|---|---|---|
halo.security.basic-auth.disabled | true | 是否禁用接口的 HTTP Basic 认证 |
halo.security.remember-me.token-validity | 14d | "记住我"会话有效期 |
halo.security.two-factor-auth.disabled | false | 是否全局禁用两步验证 |
halo.security.frame-options.mode | SAMEORIGIN | X-Frame-Options 策略 |
halo.security.frame-options.disabled | false | 是否移除 X-Frame-Options |
halo.security.referrer-options.policy | strict-origin-when-cross-origin | Referrer-Policy 策略 |
halo.session.store-type | 未设置(内存) | 付费版可设为 redis |
Basic Auth 实测:默认状态下用 curl -u root:q1w2e3r4 访问 /apis/api.console.halo.run/v1alpha1/posts 返回 302(被当作未登录跳转);在配置中写入:
halo:
security:
basic-auth:
disabled: false
重启后再测:
== 正确口令 HTTP 200
== 错误口令 HTTP 401
也就是说默认关闭是有意为之;临时脚本化调用才需要打开,长期使用应改用个人访问令牌(PAT),避免把管理员口令写进脚本。
响应头实测(未登录访问接口时同样会带上):
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
登录成功后 Cookie 实测为 SESSION(HttpOnly 会话 Cookie)、XSRF-TOKEN 与 device_id(约 100 天)。会话默认存内存,重启后需要重新登录;付费版可通过 halo.session.store-type: redis 持久化会话,社区版无此能力。
登录接口配有 Resilience4j 限流(内置默认值),例如 authentication 为每分钟 3 次、signup 为每小时 3 次、comment-creation 为每分钟 10 次。实测连续 5 次错误口令均返回 302(表单登录走的是页面错误跳转,未触发 429),因此不要仅依赖限流防暴力破解,生产环境应在反向代理层加 IP 限速。
九、监控端点与接口文档
| 配置项 | 默认值 | 作用 |
|---|---|---|
management.endpoints.web.exposure.include | * | 暴露全部 Actuator 端点 |
management.endpoint.health.show-details | when-authorized | 未授权只返回汇总状态 |
management.endpoint.health.roles | super-role | 允许看详情的角色 |
management.endpoint.health.probes.enabled | true | 提供 liveness/readiness |
springdoc.api-docs.enabled | false | 是否暴露 OpenAPI 文档 |
实测健康检查:
# 匿名
$ curl http://127.0.0.1:8090/actuator/health
{"groups":["liveness","readiness"],"status":"UP"}
# 带超管 PAT
$ curl -H "Authorization: Bearer pat_xxx" http://127.0.0.1:8090/actuator/health
{"components":{"diskSpace":{...},"livenessState":{"status":"UP"},"ping":{"status":"UP"},
"r2dbc":{"details":{"database":"PostgreSQL","validationQuery":"validate(REMOTE)"},"status":"UP"},
"readinessState":{"status":"UP"},"ssl":{...}},"status":"UP"}
匿名请求 /actuator/metrics 返回 302(需登录),说明"全部暴露"不等于"全部公开",健康检查是唯一默认放行的端点。
springdoc.api-docs.enabled 默认关闭时 /v3/api-docs 返回 404;打开后:
springdoc:
api-docs:
enabled: true
重启实测 /v3/api-docs 返回 200,文档包含 331 个 path。仅在调试接口时临时开启,生产环境保持关闭,避免把内部接口清单暴露在外。
十、参数速查表
| 分类 | 配置项 | 默认值 | 修改后是否需重启 |
|---|---|---|---|
| 服务 | server.port | 8090 | 是 |
| 服务 | server.compression.enabled | true | 是 |
| 访问 | halo.external-url | 无 | 初始化后不再生效 |
| 访问 | halo.use-absolute-permalink | false | 是 |
| 数据库 | spring.r2dbc.url | H2 文件库 | 是 |
| 数据库 | spring.sql.init.platform | h2 | 是 |
| 目录 | halo.work-dir | ${user.home}/.halo2 | 是 |
| 日志 | logging.file.name | ${halo.work-dir}/logs/halo.log | 是 |
| 缓存 | spring.web.resources.cache.cachecontrol.max-age | 365d | 是 |
| 附件 | halo.attachment.thumbnail.disabled | false | 是 |
| 安全 | halo.security.basic-auth.disabled | true | 是 |
| 安全 | halo.security.remember-me.token-validity | 14d | 是 |
| 监控 | management.endpoints.web.exposure.include | * | 是 |
| 文档 | springdoc.api-docs.enabled | false | 是 |
调优建议:
- 内存:JVM 保持
-Xms256m -Xmx512m起步,实测单站常驻内存约 640MB(含系统缓存),堆上限 512MB 足够小型站点。 - 数据库:内容量或并发上来后换 PostgreSQL,并把备份纳入日常任务;H2 只适合验证。
- 域名:初始化前就把反向代理和域名配好,避免初始化后再改外部地址带来的链接不一致。
- 安全:关闭 Basic Auth、保持
X-Frame-Options: SAMEORIGIN、生产不开放springdoc。 - 日志:默认滚动策略下日志总量上限 1GB,长期运行建议外部采集并定期清理。
十一、常见问题
Q1:改了 halo.external-url,RSS/sitemap 还是旧地址?
A:实测确实如此。外部地址在初始化时已写入数据库系统设置,配置文件不再覆盖;请到控制台"设置 → 基本设置 → 站点地址"修改。
Q2:/v3/api-docs 一直 404?
A:Halo 默认关闭 Springdoc(springdoc.api-docs.enabled: false),这是预期行为;需要时临时开启并重启。
Q3:curl -u root:口令 调接口返回 302?
A:Basic Auth 默认禁用(halo.security.basic-auth.disabled: true)。改为 false 并重启后才会返回 200/401。
Q4:改完配置没反应?
A:所有参数均在启动时读取,必须重启进程;修改后可用 systemctl restart halo 并观察 logs/halo.log 中的 Started HaloApplication。
Q5:静态资源缓存多久?
A:默认 max-age=31536000(365 天),实测响应头一致;主题资源文件名带 hash,可放心长缓存。
十二、参考链接
- Halo 官方配置说明:https://docs.halo.run/guide/install/config
- Halo 项目仓库:https://github.com/halo-dev/halo
- Halo 2.27.1 发布页:https://github.com/halo-dev/halo/releases/tag/v2.27.1
- Spring Boot 配置属性参考:https://docs.spring.io/spring-boot/appendix/application-properties/index.html