- Dockerfile 82%
- Shell 18%
| radicale | ||
| .dockerignore | ||
| compose.yml | ||
| Dockerfile | ||
| nginx.conf | ||
| README.md | ||
| update.sh | ||
Radicale vCards:Podman 部署
Bun Alpine 在构建阶段生成 vCards,Python Alpine 运行 Radicale 3.9.0;外部 Nginx 负责 HTTPS。
目录与设计
| 文件或容器路径 | 用途 |
|---|---|
Dockerfile |
多阶段构建;最终镜像不包含 Bun、Git 或 vCards 源仓库 |
compose.yml |
使用已构建镜像启动服务,仅发布 127.0.0.1:5232 |
radicale/config → /etc/radicale/config |
服务配置 |
radicale/rights → /etc/radicale/rights |
只读权限规则 |
/var/lib/radicale/collections/collection-root/cn |
上游 radicale/ios 数据 |
/var/lib/radicale/collections/collection-root/cnmacos |
上游 radicale/macos 数据 |
/usr/share/vcards/revision |
本次构建使用的 vCards Git 提交 |
nginx.conf |
同机 Nginx 的 HTTP 跳转、HTTPS 和 CardDAV 反代示例 |
update.sh |
拉取上游、重建镜像,成功后替换容器 |
提供公开、只读的黄页:auth = none 不校验密码,rights 仅允许 cn 和 cnmacos 读取各自的数据。用户名是数据选择方式,不构成密码保护。客户端不能创建、修改或删除联系人。
不挂载数据卷:通讯录随镜像发布,Radicale 的锁文件和缓存写入容器可写层。重建容器后缓存及同步历史重置,客户端可能重新全量同步。不要把空目录或旧卷挂到 /var/lib/radicale/collections,否则会遮住镜像中的通讯录;也不要直接加 read_only: true,否则缓存和锁无法写入。
安装、构建、启动
安装工具(已安装可跳过):
sudo apt update
sudo apt install -y podman podman-compose unzip curl
将压缩包放到 VPS,解压到当前用户的主目录:
cd /opt
git clone https://git.forge.st/dallaslu/vcards-radicale
cd "vcards-radicale"
podman build --pull=always -t localhost/vcards-radicale:latest .
podman-compose -f compose.yml up -d
podman-compose -f compose.yml logs -f
构建和运行始终使用同一个宿主机用户,不要混用 podman 和 sudo podman。默认可使用普通用户的 rootless Podman;容器内进程另外使用 UID/GID 10001,无需在宿主机创建同名账户。
基础镜像从 Docker Hub 拉取;构建还需要访问 GitHub、Alpine 软件源、Bun 包源及 PyPI。运行服务不需要拉取 vCards 源仓库。
如需固定数据版本,可给 VCARDS_REF 传入兼容当前 Bun/ios/macos 构建结构的提交 SHA:
podman build --pull=always --build-arg VCARDS_REF=实际提交SHA -t localhost/vcards-radicale:latest .
Nginx
Radicale 在容器内监听 0.0.0.0:5232,宿主机仅发布 127.0.0.1:5232;这两个地址分别属于不同网络空间。Nginx 如果也在独立容器内,必须改为共享容器网络并通过服务名访问。
独立域名的根路径直接转发,不设置 /radicale 前缀;示例清除了客户端传入的 X-Script-Name。Nginx 默认传递 Authorization 请求头,示例没有启用 Nginx Basic Auth。
验证与客户端
在 VPS 上检查:
podman port vcards-radicale
curl -i -u cn:cn -X PROPFIND -H 'Depth: 1' http://127.0.0.1:5232/cn/
端口应映射到 127.0.0.1:5232,CardDAV 请求应返回 207 Multi-Status,响应列出地址簿。经 Nginx 再验证:
curl -i -u cn:cn -X PROPFIND -H 'Depth: 1' https://vcards.example.com/cn/
客户端服务器填写 https://vcards.example.com;iOS 使用用户名 cn,macOS 使用 cnmacos,密码可填写 cn。其它 CardDAV 客户端可根据是否需要分组选择相应账户。浏览器访问同一地址可打开 Radicale Web 界面。
更新
cd /opt/radicale
sh ./update.sh
脚本先用 --no-cache 构建当前上游,成功后才 up -d --force-recreate。仅 restart 不会替换容器镜像,也不会更新数据。RUN git clone 的构建缓存不会因远端分支更新而自动失效。替换容器会有短暂服务中断。
如需每周一 05:00 更新,可在运行 Podman 的同一用户下执行 crontab -e,添加以下内容;时间按 VPS 的系统时区解释:
0 5 * * 1 /bin/sh "/opt/vcards-radicale/update.sh" >> "/opt/vcards-radicale/update.log" 2>&1
查看运行数据的提交版本:
podman exec vcards-radicale cat /usr/share/vcards/revision
开机恢复
Compose 的 restart: always 负责进程退出重启;Podman 在宿主机重启后恢复容器,还需启用相应的 systemd 服务。普通用户 rootless 运行时,在该用户的登录会话中执行:
sudo loginctl enable-linger "$(id -un)"
systemctl --user enable podman-restart.service
若构建、运行都使用 root,则对应执行 sudo systemctl enable podman-restart.service。
验证范围
已在本地安装 Radicale 3.9.0,使用所附 config/rights 和临时样例通讯录执行 13 个 HTTP 检查:Web 页面、两套主目录发现、联系人读取、CardDAV REPORT 均正常;其它用户名、跨账户访问及 PUT/DELETE/MKCOL 被拒绝;并确认生成锁文件和缓存。Compose YAML 和更新脚本语法已检查。验证环境没有 Podman/Nginx,未实际执行完整镜像构建、上游通讯录生成或 HTTPS 联调。