Docker部署Caddy+Typecho(SQLite)问题排查与解决
Docker 部署 Caddy + Typecho (SQLite) 问题排查与解决
一、环境说明
- 服务器配置:1核1G 云服务器
镜像选择:
- Caddy:
caddy:2.8(作为反向代理和 Web 服务器) - Typecho:
docker.1ms.run/joyqi/typecho:nightly-php8.2-fpm-alpine(仅含 PHP-FPM,无 Nginx/Apache)
- Caddy:
- 数据库:SQLite(Typecho 内置支持)
二、遇到的问题及原因
问题 1:Podman 正常,Docker 无法访问
现象:
- Podman 环境下 Caddy 能正常反向代理 Typecho
- 相同配置迁移到 Docker 后无法访问
原因分析:
| 环境 | 用户命名空间 | 文件权限处理 |
|---|---|---|
| Podman(Rootless 模式) | 默认开启 | 容器内 www-data (UID 33) 映射为宿主机当前用户 (UID 1000),天然拥有文件读写权限 |
| Docker | 默认关闭 | 容器内 www-data (UID 33) 直接对应宿主机 UID 33,与宿主机用户(UID 1000)不匹配,导致权限问题 |
根本原因:Docker 默认不开启用户命名空间,容器内进程的用户 ID 直接映射到宿主机,造成文件权限不匹配。
问题 2:Caddy 配置被错误解析为普通反向代理
现象:
- 执行
caddy adapt查看配置,发现php_fastcgi被解析为普通的reverse_proxy - 浏览器访问 PHP 文件直接下载或显示空白
原因分析:
Caddyfile中存在格式问题(多余空格、制表符、BOM 字符等)php_fastcgi指令与{未在同一行- Caddy 版本差异导致语法解析不一致
验证方法:
docker exec caddy caddy adapt --config /etc/caddy/Caddyfile | grep -A5 "www.zhaopeng"正确输出应包含 "protocol": "fastcgi",而非普通的 reverse_proxy。
问题 3:Database Query Error(数据库写入失败)
现象:
- 前台页面可正常访问(只读操作)
- 登录后台时出现
Database Query Error Typecho 容器日志显示:
PHP Warning: SQLite3Stmt::execute(): Unable to execute statement: attempt to write a readonly database
原因分析:
数据库文件不存在或路径错误
- 配置文件中的数据库路径指向
/var/www/html/usr/xxx.db - 但容器内的实际数据目录是
/app/usr find /app/usr -name "*.db"无任何输出
- 配置文件中的数据库路径指向
文件权限不足
- Typecho 容器的 PHP-FPM 进程以
www-data用户运行 /app/usr目录对该用户没有写入权限- SQLite 数据库需要读写权限(不仅是读权限)
- Typecho 容器的 PHP-FPM 进程以
Caddy 未挂载 Typecho 文件目录
- Caddy 需要直接提供静态文件(CSS、JS、图片)
- 但 Caddy 容器无法访问 Typecho 的程序文件
- 导致静态资源 404,且 PHP 文件路径解析异常
验证命令:
# 检查数据库文件是否存在
docker exec typecho_blog find /app/usr -name "*.db"
# 检查目录权限
docker exec typecho_blog ls -la /app/usr/
# 查看 PHP 错误日志
docker logs typecho_blog --tail 30 | grep -i warning问题 4:Typecho 容器未开放 80 端口
现象:
- 尝试使用
reverse_proxy typecho:80无法访问 - 直接 curl 容器 80 端口无响应
验证结果:
docker exec typecho_blog netstat -tlnp
# 输出显示只有 9000 端口(PHP-FPM),没有 80 端口原因:使用的镜像 nightly-php8.2-fpm-alpine 只包含 PHP-FPM,不包含 Nginx 或 Apache,因此没有 Web 服务器监听 80 端口。
结论:必须使用 php_fastcgi typecho:9000 配置,不能使用普通的 reverse_proxy。
三、解决方案汇总
方案一:修复 Docker 文件权限(针对问题 1)
方法 A:创建自定义网络(已实施)
# docker-compose.yml
networks:
caddy_net:
driver: bridge
services:
caddy:
networks:
- caddy_net
typecho:
networks:
- caddy_net方法 B:修复容器内文件权限(关键步骤)
# 进入 Typecho 容器
docker exec -it typecho_blog /bin/sh
# 修改数据目录所有者为 www-data
chown -R www-data:www-data /app/usr
chmod -R 755 /app/usr
# 创建数据库文件(如不存在)
touch /app/usr/typecho.db
chown www-data:www-data /app/usr/typecho.db
chmod 644 /app/usr/typecho.db
exit
# 重启容器
docker compose restart typecho方案二:修正 Caddyfile 配置(针对问题 2、4)
正确的 Caddyfile 配置:
www.zhaopeng.site {
# 静态文件根目录(必须指向 Typecho 程序文件所在位置)
root * /var/www/html
# PHP 请求通过 FastCGI 转发给 Typecho 容器的 9000 端口
php_fastcgi typecho:9000 {
try_files {path} {path}/index.php /index.php?{query}
env PATH_INFO {http.path_info}
}
# Caddy 直接提供静态文件服务
file_server
encode gzip zstd
# 安全响应头
header {
X-Content-Type-Options nosniff
X-Frame-Options SAMEORIGIN
Referrer-Policy strict-origin-when-cross-origin
}
}
# 其他站点配置...关键点:
- 必须使用
php_fastcgi而非reverse_proxy root路径必须与 Caddy 挂载的 Typecho 文件路径一致- 确保
php_fastcgi和{在同一行,无多余空格
格式化配置:
docker exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile
docker exec caddy caddy reload --config /etc/caddy/Caddyfile方案三:共享文件目录挂载(针对问题 3)
修改 docker-compose.yml:
version: '3.8'
networks:
caddy_net:
driver: bridge
services:
caddy:
image: caddy:2.8
container_name: caddy_server
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./typecho_data:/var/www/html:ro # Caddy 只读挂载 Typecho 文件
- caddy_data:/data
- caddy_config:/config
networks:
- caddy_net
typecho:
image: docker.1ms.run/joyqi/typecho:nightly-php8.2-fpm-alpine
container_name: typecho_blog
restart: unless-stopped
volumes:
- ./typecho_data:/app/usr # Typecho 读写挂载数据目录
networks:
- caddy_net
volumes:
caddy_data:
caddy_config:说明:
- Caddy 和 Typecho 共享同一个宿主机目录
./typecho_data - Caddy 只读挂载(
:ro)用于提供静态文件 - Typecho 读写挂载用于运行 PHP 和写入 SQLite 数据库
方案四:修正 Typecho 配置文件(针对问题 3)
检查并修改 config.inc.php:
# 查看当前配置
docker exec typecho_blog cat /app/usr/config.inc.php正确的配置内容:
<?php
// 站点根路径
define('__TYPECHO_ROOT_DIR__', dirname(__FILE__));
// 插件目录
define('__TYPECHO_PLUGIN_DIR__', '/app/usr/plugins');
// 主题目录
define('__TYPECHO_THEME_DIR__', '/app/usr/themes');
// 后台目录
define('__TYPECHO_ADMIN_DIR__', '/admin/');
// 加载核心文件
require_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';
// 初始化
\Typecho\Common::init();
// 数据库配置(关键:路径指向 /app/usr/)
$db = new \Typecho\Db('Pdo_SQLite', 'typecho_');
$db->addServer(array (
'file' => '/app/usr/typecho.db', // 确保路径正确
), \Typecho\Db::READ | \Typecho\Db::WRITE);
\Typecho\Db::set($db);
?>一键修复命令:
# 备份原配置
docker exec typecho_blog cp /app/usr/config.inc.php /app/usr/config.inc.php.bak
# 修改数据库路径
docker exec typecho_blog sed -i "s|/var/www/html/usr/[^']*\.db|/app/usr/typecho.db|g" /app/usr/config.inc.php
# 修改插件和主题路径
docker exec typecho_blog sed -i "s|'/usr/plugins'|'/app/usr/plugins'|g" /app/usr/config.inc.php
docker exec typecho_blog sed -i "s|'/usr/themes'|'/app/usr/themes'|g" /app/usr/config.inc.php
# 创建数据库文件并修复权限
docker exec typecho_blog touch /app/usr/typecho.db
docker exec typecho_blog chown -R www-data:www-data /app/usr
docker exec typecho_blog chmod 755 /app/usr/typecho.db
# 重启容器
docker compose restart typecho四、安全加固建议
防止 SQLite 数据库文件被下载
在 Caddyfile 中添加:
www.zhaopeng.site {
# 拒绝直接访问 .db 文件
@dbFiles {
path *.db
}
handle @dbFiles {
respond 403
}
# 其他配置...
}五、镜像选择建议(针对 1核1G 服务器)
| 镜像 | 大小 | 内置 Web 服务器 | 推荐度 | 说明 |
|---|---|---|---|---|
joyqi/typecho:nightly-php8.2-fpm-alpine | 92.3MB | 无(仅 PHP-FPM) | ⭐⭐⭐⭐⭐ | 当前使用,配合 Caddy 性能最优 |
lufeidot/typecho:latest | 较小 | Nginx | ⭐⭐⭐⭐ | 内置 Nginx,一体化方案 |
joyqi/typecho:nightly-php8.2-apache | 508MB | Apache | ⭐ | 体积大,内存占用高,不推荐 |
结论:1核1G 服务器建议继续使用 fpm-alpine + Caddy 组合,资源占用最低,性能最好。
六、验证清单
完成以上修复后,执行以下验证:
# 1. 确认 Typecho 容器内数据库文件存在
docker exec typecho_blog ls -la /app/usr/*.db
# 2. 确认文件权限正确
docker exec typecho_blog ls -la /app/usr/ | head -5
# 3. 查看 Typecho 日志,确认无 Warning
docker logs typecho_blog --tail 20 | grep -i warning
# 4. 测试静态文件访问
curl -I https://www.zhaopeng.site/usr/themes/default/style.css
# 5. 测试 PHP 处理
curl -I https://www.zhaopeng.site/index.php
# 6. 浏览器访问后台登录
# https://www.zhaopeng.site/admin/login.php七、总结
| 问题 | 根本原因 | 解决方案 |
|---|---|---|
| Docker 无法访问 | 用户命名空间未开启,文件权限不匹配 | 修复容器内文件权限 (chown -R www-data:www-data) |
| Caddy 配置解析错误 | Caddyfile 格式问题 | 执行 caddy fmt 格式化配置 |
| Database Query Error | 数据库路径错误 + 无写入权限 | 修改 config.inc.php 路径 + 修复权限 |
| 80 端口未监听 | 镜像无内置 Web 服务器 | 必须使用 php_fastcgi 而非 reverse_proxy |
核心要点:
- Typecho 容器(
fpm-alpine镜像)只提供 PHP-FPM,必须配合 Caddy/Nginx 使用 - SQLite 数据库需要读写权限,不仅仅是读权限
- Caddy 和 Typecho 需要共享文件目录,Caddy 才能提供静态文件
- 配置文件中的数据库路径必须指向实际可写的目录(
/app/usr/)