1. 问题现象
访问 Halo 站点时返回 502 Bad Gateway(由 OpenResty 代理抛出)。
查看容器日志,发现 Halo 启动过程中抛出异常:
text
Caused by: io.r2dbc.spi.R2dbcBadGrammarException: [1061] [42000] Duplicate key name 'idx_customer_coupons_customer_status'随后还有其他类似索引(如
idx_customer_coupons_coupon_customer)的重复错误,导致应用无法启动。
2. 环境信息
Halo 镜像:
halohub/halo-pro:2.25.0MySQL 版本:
8.4.5(Docker 容器)部署工具:Docker Compose
网络:自定义外部网络
1panel-network宿主机:Ubuntu(1Panel 管理)
3. 根本原因分析
Halo 2.25.0 的数据库初始化脚本 schema-mysql.sql 中,多个 CREATE INDEX 语句未包含 IF NOT EXISTS 判断。如果数据库中已存在同名索引(可能源自之前失败的安装或残留),再次执行初始化脚本时就会报 Duplicate key name 错误,导致启动失败。
注:此问题在 Halo 社区中时有发生,官方未在 2.25.0 中修复,推荐使用启动参数
--spring.sql.init.continue-on-error=true绕过。
4. 尝试过的错误方案(供记录)
❌ 手动修改
schema-mysql.sql,添加IF NOT EXISTS:
虽然文件被挂载到容器内,但 Spring Boot 默认从 jar 包内部加载初始化脚本,外部挂载未生效。即使通过环境变量强制指定外部文件,也因 MySQL 驱动解析问题导致语法错误。❌ 删除重复索引:
手动删除customer_coupons表上的冲突索引(以及相关外键)虽然有效,但过程繁琐,且如果其他表也有类似索引,需反复操作,不具通用性。
5. 最终解决方案(推荐)
在 Halo 容器的启动命令中添加两个参数:
--spring.sql.init.continue-on-error=true:使 SQL 初始化脚本在遇到错误(如重复索引)时跳过并继续执行,而不是中断启动。--spring.r2dbc.properties.sslMode=disabled:禁用 SSL 连接,防止未来可能出现的 MySQL 连接卡死(特别针对旧版 MySQL 的兼容性问题)。
同时,移除任何外部挂载的 schema-mysql.sql 文件,避免干扰默认初始化流程。
修改后的 docker-compose.yml 核心片段
yaml
services:
halo:
image: halohub/halo-pro:2.25.0
container_name: halo-pro
restart: always
command:
- --spring.r2dbc.url=r2dbc:pool:mysql://mysql:3306/halo_85n664?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
- --spring.r2dbc.username=XXXXX
- --spring.r2dbc.password=XXXXxXXX
- --spring.sql.init.platform=mysql
- --spring.sql.init.continue-on-error=true # ← 关键
- --spring.r2dbc.properties.sslMode=disabled # ← 推荐
environment:
- JVM_OPTS=-Xms224m -Xmx384m
volumes:
- ./data:/root/.halo2
# 注意:不再挂载 schema-mysql.sql
ports:
- "8090:8090"
networks:
- 1panel-network
deploy:
resources:
limits:
cpus: 0.5
memory: 448M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s6. 操作步骤回顾
清理冲突索引(可选):
进入 MySQL 容器,删除
customer_coupons表上的重复索引(如有外键依赖,先删外键)。但最终解决方案中,
continue-on-error可以忽略这些索引,因此此步并非必需。
修改配置文件:
编辑
docker-compose.yml,添加两个command参数,移除外部挂载和环境变量。
重启容器:
bash
docker compose down docker compose up -d验证启动日志:
执行
docker logs -f halo-pro,观察是否出现Started Application in ...,且无ERROR。
访问站点:
浏览器访问
http://服务器IP:8090,正常显示 Halo 页面。