DAViCal 1.1.13 排错 FAQ
DAViCal 1.1.13(Ubuntu 24.04.5 + Apache/PHP 8.3/PostgreSQL 16)实测排错 FAQ:状态码定位、日志、dbg 开关、配置加载顺序四步方法论,15 条问答覆盖 401/500/501/404/Database Error 页、ACL 403、sync-collection 命名空间、412 乐观锁、refresh-alarms Not Configured、cron 未执行与 apt 级联卸载恢复。
DAViCal 1.1.13 排错 FAQ
目标:沉淀 DAViCal 1.1.13(Ubuntu 24.04.5 + Apache 2.4.58 + PHP 8.3.6 + PostgreSQL 16.15)实测环境中踩过的全部故障:先给「状态码 → 日志 → 调试开关 → 配置加载顺序」四步排错方法论,再按认证权限、服务端错误、协议客户端、定时任务与升级四类整理 15 条 FAQ。每条都有实测复现命令、真实报错原文与修复验证,可直接照做。
一、环境信息
- 操作系统:Ubuntu 24.04.5 LTS(x86_64);Web:Apache/2.4.58 +
libapache2-mod-php8.3;PHP 8.3.6;PostgreSQL 16.15 - 应用:DAViCal 1.1.13 + AWL 0.65(代码
/usr/share/davical、/usr/share/awl),数据库 schema 1.3.6 - 域名与路径:
davical.example.com,CalDAV 入口/davical/caldav.php/,忙闲导出/davical/freebusy.php/ - 数据库:库
davical,角色davical_dba(DDL)/davical_app(DML),演示口令q1w2e3r4 - 配置文件:
/etc/davical/config.php(全局)、/etc/davical/davical.example.com-conf.php(域配置)、/etc/davical/administration.yml,正常权限640 root:www-data - 演示账号:
admin/q1,口令均q1w2e3r4
二、排错方法论:四步定位
2.1 第一步:用状态码把问题钉到某一层
DAViCal 栈是 Apache→PHP→DAViCal→PostgreSQL 四层串联,状态码能直接圈定故障层。以下判据全部来自本环境实测案例:
| 状态码/形态 | 故障层 | 实测案例(本文对应条目) |
|---|---|---|
401 + WWW-Authenticate: Basic | 认证挑战正常,问题在客户端凭据 | Q1 |
500 | PHP/数据库层:连接失败、配置错误 | Q2、Q6 |
501 + error.log AH00135 | Apache 层:WebDAV 扩展方法未注册,应用缺失 | Q7 |
404(应用路径) | 应用文件/包丢失 | Q7 |
200 但页面是 Database Error | 陷阱形态:HTTP 层活着、DB 层挂了 | Q6 |
403 + DAV: error XML | 协议语义错误(ACL/sync 请求体问题) | Q3、Q4、Q9 |
412 | 乐观锁正常拒绝,非故障 | Q10 |
201/204/207 | CalDAV 正常语义 | — |
2.2 第二步:看两份日志
access.log 记录请求语义层结果(第三列是认证用户名,- 表示未认证):
tail -3 /var/log/apache2/access.log
10.89.66.2 - - [01/Nov/2026:14:21:04 +0000] "GET /davical/caldav.php/q1/ HTTP/1.1" 401 258 "-" "curl/8.5.0"
10.89.66.2 - - [01/Nov/2026:14:27:11 +0000] "GET /davical/index.php HTTP/1.1" 200 1952 "-" "curl/8.5.0"
10.89.66.2 - q1 [01/Nov/2026:14:27:11 +0000] "PROPFIND /davical/caldav.php/q1/ HTTP/1.1" 207 667 "-" "curl/8.5.0"
error.log 记录 Apache/PHP 层异常,两个高价值关键字是 AH00135(方法不被识别)与 password authentication failed(数据库连接失败):
grep -E "AH00135|password authentication failed" /var/log/apache2/error.log | tail -2
[Sun Nov 01 14:22:43.429931 2026] [core:error] [pid 15110] [client 127.0.0.1:37780] AH00135: Invalid method in request MKCALENDAR /davical/caldav.php/admin/finalcheck/ HTTP/1.1
2.3 第三步:打开 PHP 调试开关 dbg
AWL 框架内置 dbg 配置组,默认整行注释。当前域配置中的实测现状:
grep -n dbg /etc/davical/davical.example.com-conf.php
7:// $c->dbg["request"] = 1; # 排障时临时开启,日志走 PHP error_log
排障时去掉行首 //(可加 sql、reg 等键)即可把请求/SQL 细节写入 PHP error_log(即 Apache error.log),看完务必注释回去——dbg 会把 SQL 与请求体写进日志,长期开启等于日志泄密。
2.4 第四步:理清配置加载顺序
DAViCal 配置分两层:/etc/davical/config.php 提供全局默认,/etc/davical/<域名>-conf.php 按请求 Host 头加载并覆盖全局同名项。本环境三条实测证据:
- 只改
config.php的数据库连接不生效——请求实际加载的是davical.example.com-conf.php(Q2 复现时踩坑确认); config.php缺失时,命令行脚本直接报Not Configured(Q13 实测);- 域配置存在但
www-data读不到时,Web 页报Undefined variable $connection_strings(Q6 实测)。
💡 技术拓展:多域名部署时
/etc/davical/下可同时存在多个<域名>-conf.php,各自可指向不同数据库或同库不同域(domain_name隔离数据)。本文环境为单域davical.example.com;实测另建calendar.example.com-conf.php后,带对应Host头访问返回该域的<title>Second DAViCal Domain</title>页面、未认证 OPTIONS 返回 401,两域互不干扰。
三、认证与权限类
Q1: 客户端反复弹密码框/日志大量 401,服务器坏了吗? A: 没有。未带凭据访问 CalDAV 路径的标准应答就是 401 挑战,实测:
curl -s -X OPTIONS http://davical.example.com/davical/caldav.php/admin/ -D - -o /dev/null
HTTP/1.1 401 Unauthorized
Date: Sun, 01 Nov 2026 14:32:13 GMT
Server: Apache/2.4.58 (Ubuntu)
WWW-Authenticate: Basic realm="DAViCal CalDAV Server"
Content-Length: 40
Content-Type: text/plain; ; charset="utf-8"
realm="DAViCal CalDAV Server" 出现即认证链路正常。带对凭据立刻变 200(2.2 的 access.log 里同一 URL 从 401 到 207 的对比即实测)。持续 401 排查顺序:账号是否被停用(管理界面用户状态)→ 口令是否含特殊字符被客户端转义错 → 是否把 davical_app 数据库角色口令当成了用户口令。
Q2: 带正确格式凭据仍 500,error.log 报 password authentication failed for user "davical_app"?
A: 这是服务端到数据库的认证失败,与登录用户无关:域配置里 pg_connect 串的口令和 PostgreSQL 角色 davical_app 的实际口令不一致。本环境实测在域配置写错口令后,OPTIONS 直接 500,报错落在 AwlDBDialect.php line 103。两种对齐方式任选:改 /etc/davical/davical.example.com-conf.php 的口令,或改库:
su postgres -c "psql -c \"ALTER ROLE davical_app PASSWORD 'q1w2e3r4';\""
修复验证(实测应得 200 与版本头):
curl -s -u admin:q1w2e3r4 -X OPTIONS http://davical.example.com/davical/caldav.php/admin/ -D - -o /dev/null | grep X-DAViCal-Version
X-DAViCal-Version: DAViCal/1.1.13; DB/1.3.6
⚠️ 改口令时注意
pg_hba.conf的认证方法顺序:本环境davical_app走scram-sha-256,只改ALTER ROLE不改配置串、或只改配置串不改角色,都会维持 500。
Q3: 用 ACL 方法给他人授权返回 403,错误体 Principal "/davical/caldav.php/" not found.?
A: principal 的 <D:href> 写错。必须是带用户名的完整集合路径,写成服务根路径就报 Principal not found。错误实测(q1 授权时 href 误写为 /davical/caldav.php/):
<?xml version="1.0" encoding="utf-8" ?>
<error xmlns="DAV:">
<recognized-principal/>Principal "/davical/caldav.php/" not found.
</error>
ACL=403
改成 /davical/caldav.php/admin/ 后同一请求实测 ACL_ADMIN=200,授权落库可查:
su postgres -c "psql davical -c 'select by_collection, to_principal, privileges, is_group from grants;'"
by_collection | to_principal | privileges | is_group
---------------+--------------+--------------------------+----------
1024 | 1 | 000000000000000000000000 |
(1 row)
Q4: 想撤销一条 ACL 授权,返回 403 且错误体只有一个空 <grant-only/>?
A: DAViCal 要求 ACL 请求携带授权(grant)语义,提交不含 <grant> 的 ACE(典型「撤销」写法)会被拒:实测错误体 <error xmlns="DAV:"><grant-only/></error>、ACL_REVOKE=403。正确做法是提交该集合的完整 ACE 集合(把不再需要的 principal 从新 ACE 列表中剔除后整体 PUT 式授权),或在管理界面操作共享。
Q5: ACL 返回 200 了,被授权人/匿名访问还是 401?
A: 先看 grants 表是否真的落库。本环境实测过一次「看似成功」的授权链:href 写错导致 ACL 已 403(Q3),grants 表查询返回 (0 rows),匿名读取自然仍是 ANON_AFTER=401。判据:select count(*) from grants; 有行、且 to_principal 对应被授权用户(admin 为 1),再验证被授权人 PROPFIND current-user-privilege-set 返回 read 权限集(实测 207)。
四、服务端错误类
Q6: 页面显示 Database Error,但 HTTP 状态码是 200,监控为什么不报警?
A: DAViCal 的数据库错误页不改状态码,这是监控最大的坑。实测把域配置改成 www-data 不可读(chmod 600)后:
curl -s -o /dev/null -w "ERRPAGE_STATUS=%{http_code}\n" http://davical.example.com/davical/index.php
curl -s -u admin:q1w2e3r4 -X OPTIONS -o /dev/null -w "ERRPAGE_CALDAV=%{http_code}\n" http://davical.example.com/davical/caldav.php/admin/
ERRPAGE_STATUS=200
ERRPAGE_CALDAV=200
页面内容报 PHP Undefined variable $connection_strings(AwlQuery.php line 55)——连不上数据库时 AWL 的初始化变量根本没赋值。修复只需把权限改回:
chown root:www-data /etc/davical/davical.example.com-conf.php
chmod 640 /etc/davical/davical.example.com-conf.php
修复后 /etc/davical 实测目录状态与页面恢复:
-rw-r----- 1 root www-data 336 Nov 1 14:13 config.php
-rw-r----- 1 root www-data 336 Nov 1 14:20 davical.example.com-conf.php
IDX=200 PF=207
监控规则应写成「200 且响应体不含 Database Error」而不是只看状态码。
Q7: MKCALENDAR 返回 501、error.log 报 AH00135: Invalid method、首页 404,一起坏了?
A: 一起坏说明共同上游塌了。本环境实录:apt-get remove -y php8.3-xml 时 apt 把 davical 包级联移除(输出节选 Removing php8.3-xml (8.3.6-0ubuntu0.24.04.13) ...),随后 MKCALENDAR 变 501(BROKEN= 501)、首页请求抛 urllib.error.HTTPError: HTTP Error 404: Not Found。补回 php-xml 后中间态是 OPT 200 VER None、MKCAL 501——Web 层活了但应用层还是空的,此时 ls /etc/php/8.3/apache2/mods-enabled/ 报 No such file or directory,PHP-Apache 挂接文件也被级联带走了。完整恢复:
apt-get install -y php8.3-xml
apt-get install -y davical
apt-get install -y davical 输出节选(实测首尾):
Preparing to unpack .../davical_1.1.12-2_all.deb ...
Unpacking davical (1.1.12-2) ...
Setting up davical (1.1.12-2) ...
实测复核 OPT 200 VER DAViCal/1.1.12; DB/1.3.5 DAV True——注意 apt 重装把代码回落到 1.1.12-2,需再恢复 1.1.13 代码目录并按 Q8 对齐 schema。排错要点:501+AH00135 先查 dpkg -l davical 与 PHP 扩展,而不是查 Apache 配置。
Q8: 升级代码后页面提示数据库需要升级,或响应头 DB/ 值和代码版本对不上?
A: DAViCal 升级代码后 schema 不会自动跟进,必须手工跑升级脚本。实测(已是最新时执行,幂等无害):
/usr/share/davical/dba/update-davical-database; echo "RC=$?"
The database is version 16.0 currently at revision 1.3.6.
No patches were applied.
Supported locales updated.
Updated view: dav_principal.sql applied.
CalDAV functions updated.
WARNING: no privileges were granted for "dav_id_seq"
RRULE functions updated.
Database permissions updated.
RC=0
No patches were applied. 表示 schema 已最新;若落后会顺序应用 /usr/share/davical/dba/patches/ 下的 1.x.y.sql。WARNING: no privileges were granted for "dav_id_seq" 是已知无害提示(权限已存在、GRANT 空操作),退出码 0 且页面正常即可忽略。跑完后用 OPTIONS 头复核 X-DAViCal-Version: DAViCal/1.1.13; DB/1.3.6 两个版本号对齐。
Q9: 数据库恢复(pg_restore 到新库)后页面全 500/权限报错?
A: 逻辑备份恢复只还原数据,davical_app 的 DML 权限需要重建——正是 Q8 升级脚本的 Database permissions updated. 干的事(按 appuser_permissions.txt 重授)。顺序:createdb -O davical_dba davical → pg_restore -d davical <dump>(实测 RC=0)→ 跑 update-davical-database → OPTIONS 复核 200。
五、协议与客户端类
Q10: sync-collection REPORT 返回 403,错误体 "urn:ietf:params:xml:ns:caldav:sync-collection" is not a supported report type?
A: 命名空间写错——sync-collection 属于 DAV: 命名空间(RFC 6578),不是 caldav 命名空间。错误实测请求体:
<?xml version="1.0" encoding="utf-8" ?>
<error xmlns="DAV:">
<supported-report/>"urn:ietf:params:xml:ns:caldav:sync-collection" is not a supported report type
</error>
改成 <D:sync-collection xmlns:D="DAV:"><D:sync-token/></D:sync-collection> 后实测 SYNC=207。客户端报「同步 403」基本就是这条。token 是不透明串且随变更递增(实测 data:,15 写入新条目后换回 data:,16),客户端只需持久化上一次返回值。
Q11: PUT 事件返回 412,客户端写入失败?
A: 412 是乐观锁的正常拒绝,不是故障:If-Match 携带的 ETag 与服务端当前值不一致(本环境实测错值 "deadbeef" → BADMATCH=412)。正确流程:先 GET 拿响应头 Etag: "e4bea4f07638cb2d84bac0b094ef1851",带真实 ETag 重发 PUT → 实测 GOODMATCH=204。客户端持续 412 说明本地缓存过期,应先同步再写。
Q12: DELETE 之后再 GET 返回 404,是不是没删干净?
A: 恰恰相反,这是删除成功的标准形态。实测链路:DEL=204 紧接 GET404=404。若 DELETE 后 GET 仍 200,才要怀疑集合级软删除或客户端缓存。
Q13: 忙闲查询拿不到数据,或结果和日历里看到的不一样?
A: 用对入口和参数格式。实测 GET /davical/freebusy.php/<用户>?start=<ISO时间>&end=<ISO时间>:
curl -s -u q1:q1w2e3r4 "http://davical.example.com/davical/freebusy.php/q1?start=2026-11-05T00:00:00&end=2026-11-06T00:00:00" | grep -E "FREEBUSY|METHOD"
BEGIN:VFREEBUSY
FREEBUSY:20261105T020000Z/20261105T030000Z
FREEBUSY:20261105T020000Z/20261105T030000Z
END:VFREEBUSY
返回只给忙区间、不含事件标题(隐私设计);查不到先核对窗口时区(参数是本地时间、输出是 UTC 的 Z 结尾)与事件是否落在窗口内。同一区间出现多行时,检查该事件是否被复制进了多个集合(本环境曾因 load_calendar.php 回灌演练产生同 UID 副本)。
六、定时任务与升级类
Q14: cron 里的 refresh-alarms.php 不干活,手工执行输出 <h1>DAViCal Not Configured</h1>?
A: 两个独立实测结论:其一,Not Configured 页是配置文件缺失的形态——实测把 /etc/davical/config.php 移走后脚本输出该 HTML 且退出码仍为 0(RC=0),恢复文件后输出为 0 字节。所以判成败要看输出是否为空,不能看退出码。其二,cron 条目根本不执行时,先查 cron 服务本身:最小化安装环境 apt-get install -y cron 后会出现 invoke-rc.d: policy-rc.d denied execution of start. 与 /usr/sbin/policy-rc.d returned 101, not running 'start cron.service',服务没被拉起。修复与验证(实测):
systemctl enable --now cron
Synchronizing state of cron.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable cron
systemctl is-active cron
active
/etc/cron.d/davical-ops 当前实测内容(每 5 分钟以 www-data 刷新提醒):
*/5 * * * * www-data php /usr/share/davical/scripts/refresh-alarms.php >/dev/null 2>&1
⚠️ 该行把输出重定向进了
/dev/null,Q14 前半段的Not Configured异常会被吞掉;重要环境建议改为追加写入日志文件再对非空输出告警。
Q15: apt-get install -y davical 提示 davical is already the newest version (1.1.12-2).,升不到 1.1.13?
A: Ubuntu 24.04 universe 仓库的 davical 冻结在 1.1.12-2(schema 1.3.5),这是渠道天花板而非本机状态问题——实测 apt-cache policy davical 的 Candidate 即 1.1.12-2。要上主线 1.1.13(schema 1.3.6)须用官网 tar.xz 部署,部署后按 Q8 跑 update-davical-database 对齐 schema,并用 OPTIONS 响应头 X-DAViCal-Version: DAViCal/1.1.13; DB/1.3.6 验收。反向注意:apt 渠道装回会让代码回退(Q7 实录),混用两套渠道前先备份数据库。
七、参考链接
- 平台站内:《DAViCal 介绍与选型指南》、《Ubuntu 24.04 安装 DAViCal 1.1.13 指南》(部署与 8 条安装期排障)、《DAViCal 1.1.13 日常运维手册》(巡检/备份/监控/升级回滚全链路,本文故障的现场取证均基于该手册环境)
- 同类组件排错对照:《Radicale 3.9 常用 CLI 命令与运维详解》、《Baikal 0.10.1 管理与运维实战》
- 官方:DAViCal 官网 https://www.davical.org/;升级脚本说明 https://wiki.davical.org/w/Update-davical-database
- 协议:RFC 4791(CalDAV)、RFC 6578(collection sync)、RFC 3744(WebDAV ACL)