Halo 2.27.1 配置参数详解

Halo 2.27.1 application.yaml 配置参数逐项详解:端口、R2DBC 数据库、工作目录、外部访问地址、静态资源缓存、附件缩略图、安全与会话、日志与 Actuator 监控,附官方默认值与生产实测回显。

HaloHaloCMS建站JavaSpring Boot2026/10/27

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/

生效优先级由低到高:

层级来源说明
1JAR 内置 application.yamlHalo 与 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.port8090HTTP 监听端口
server.forward-headers-strategynative信任反向代理传来的 X-Forwarded-* 头
halo.external-url无站点对外访问地址,初始化时用于生成绝对链接
halo.use-absolute-permalinkfalse永久链接是否输出绝对地址

端口实测:把 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.urlr2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSER2DBC 连接串
spring.r2dbc.usernameadmin(H2)数据库用户
spring.r2dbc.password123456(H2)数据库密码
spring.sql.init.platformh2数据库方言与建表脚本选择
spring.sql.init.modealways启动时执行建表/迁移脚本

各数据库的连接串与平台名:

数据库spring.r2dbc.urlspring.sql.init.platform
H2r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSEh2
PostgreSQLr2dbc:pool:postgresql://127.0.0.1:5432/halopostgresql
MySQLr2dbc:pool:mysql://127.0.0.1:3306/halomysql
MariaDBr2dbc:pool:mariadb://127.0.0.1:3306/halomariadb

内置 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-size10MB单个日志文件上限
logging.logback.rollingpolicy.total-size-cap1GB日志总容量上限
logging.logback.rollingpolicy.max-history0保留的历史文件数(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.enabledtrue开启 gzip 响应压缩
spring.web.resources.cache.cachecontrol.max-age365d静态资源浏览器缓存时长
spring.web.resources.cache.cachecontrol.use-last-modifiedtrue输出 Last-Modified 头
spring.thymeleaf.cachetrue模板缓存(主题页面)
spring.cache.typecaffeine进程内缓存实现
spring.cache.caffeine.specexpireAfterAccess=1h, maximumSize=10000缓存过期与容量
spring.http.codecs.max-in-memory-size10MB单次请求体/响应的内存缓冲上限

实测响应头:

$ 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].locationsmigrate-from-1.x旧版附件目录映射
halo.attachment.thumbnail.disabledfalse是否关闭缩略图
halo.attachment.thumbnail.concurrent-threads1缩略图生成并发数
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.disabledtrue是否禁用接口的 HTTP Basic 认证
halo.security.remember-me.token-validity14d"记住我"会话有效期
halo.security.two-factor-auth.disabledfalse是否全局禁用两步验证
halo.security.frame-options.modeSAMEORIGINX-Frame-Options 策略
halo.security.frame-options.disabledfalse是否移除 X-Frame-Options
halo.security.referrer-options.policystrict-origin-when-cross-originReferrer-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-detailswhen-authorized未授权只返回汇总状态
management.endpoint.health.rolessuper-role允许看详情的角色
management.endpoint.health.probes.enabledtrue提供 liveness/readiness
springdoc.api-docs.enabledfalse是否暴露 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.port8090是
服务server.compression.enabledtrue是
访问halo.external-url无初始化后不再生效
访问halo.use-absolute-permalinkfalse是
数据库spring.r2dbc.urlH2 文件库是
数据库spring.sql.init.platformh2是
目录halo.work-dir${user.home}/.halo2是
日志logging.file.name${halo.work-dir}/logs/halo.log是
缓存spring.web.resources.cache.cachecontrol.max-age365d是
附件halo.attachment.thumbnail.disabledfalse是
安全halo.security.basic-auth.disabledtrue是
安全halo.security.remember-me.token-validity14d是
监控management.endpoints.web.exposure.include*是
文档springdoc.api-docs.enabledfalse是

调优建议:

  1. 内存:JVM 保持 -Xms256m -Xmx512m 起步,实测单站常驻内存约 640MB(含系统缓存),堆上限 512MB 足够小型站点。
  2. 数据库:内容量或并发上来后换 PostgreSQL,并把备份纳入日常任务;H2 只适合验证。
  3. 域名:初始化前就把反向代理和域名配好,避免初始化后再改外部地址带来的链接不一致。
  4. 安全:关闭 Basic Auth、保持 X-Frame-Options: SAMEORIGIN、生产不开放 springdoc。
  5. 日志:默认滚动策略下日志总量上限 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,可放心长缓存。

十二、参考链接