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 级联卸载恢复。

DAViCalDAViCalCalDAVCardDAVPHPPostgreSQLApache运维监控2026/11/01

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
500PHP/数据库层:连接失败、配置错误Q2、Q6
501 + error.log AH00135Apache 层:WebDAV 扩展方法未注册,应用缺失Q7
404(应用路径)应用文件/包丢失Q7
200 但页面是 Database Error陷阱形态:HTTP 层活着、DB 层挂了Q6
403 + DAV: error XML协议语义错误(ACL/sync 请求体问题)Q3、Q4、Q9
412乐观锁正常拒绝,非故障Q10
201/204/207CalDAV 正常语义—

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 头加载并覆盖全局同名项。本环境三条实测证据:

  1. 只改 config.php 的数据库连接不生效——请求实际加载的是 davical.example.com-conf.php(Q2 复现时踩坑确认);
  2. config.php 缺失时,命令行脚本直接报 Not Configured(Q13 实测);
  3. 域配置存在但 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 1.1.13 排错 FAQ - Quzuo