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)
  • 数据库: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

原因分析

  1. 数据库文件不存在或路径错误

    • 配置文件中的数据库路径指向 /var/www/html/usr/xxx.db
    • 但容器内的实际数据目录是 /app/usr
    • find /app/usr -name "*.db" 无任何输出
  2. 文件权限不足

    • Typecho 容器的 PHP-FPM 进程以 www-data 用户运行
    • /app/usr 目录对该用户没有写入权限
    • SQLite 数据库需要读写权限(不仅是读权限)
  3. 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-alpine92.3MB无(仅 PHP-FPM)⭐⭐⭐⭐⭐当前使用,配合 Caddy 性能最优
lufeidot/typecho:latest较小Nginx⭐⭐⭐⭐内置 Nginx,一体化方案
joyqi/typecho:nightly-php8.2-apache508MBApache体积大,内存占用高,不推荐

结论: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

核心要点

  1. Typecho 容器(fpm-alpine 镜像)只提供 PHP-FPM,必须配合 Caddy/Nginx 使用
  2. SQLite 数据库需要读写权限,不仅仅是读权限
  3. Caddy 和 Typecho 需要共享文件目录,Caddy 才能提供静态文件
  4. 配置文件中的数据库路径必须指向实际可写的目录/app/usr/

标签: none

添加新评论