Podman 部署 Radicale + InfCloud 完整笔记

一、环境说明

  • 服务器配置:2核2G 云服务器
  • 后端服务:Radicale (CalDAV/CardDAV 服务器)
  • 前端界面:InfCloud (网页日历客户端)
  • 容器工具:Podman

二、Radicale 部署

2.1 创建目录结构

mkdir -p ~/radicale/{config,data}
cd ~/radicale

2.2 创建 Radicale 配置文件

创建 config 文件:

[server]
hosts = 0.0.0.0:5232

[auth]
type = htpasswd
htpasswd_filename = /data/users
htpasswd_encryption = bcrypt

[storage]
filesystem_folder = /data/collections

[web]
type = radicale.web.internal

[headers]
Access-Control-Allow-Origin = https://你的前端域名
Access-Control-Allow-Methods = GET, POST, OPTIONS, PROPFIND, PROPPATCH, REPORT, PUT, MOVE, DELETE, LOCK, UNLOCK
Access-Control-Allow-Headers = User-Agent, Authorization, Content-type, Depth, If-match, If-None-Match, Lock-Token, Timeout, Destination, Overwrite, Prefer, X-client, X-Requested-With
Access-Control-Expose-Headers = Etag, Preference-Applied
Access-Control-Allow-Credentials = true

2.3 创建 docker-compose.yml

version: '3.8'

services:
  radicale:
    image: tomsquest/docker-radicale:latest
    container_name: radicale
    restart: unless-stopped
    ports:
      - "5232:5232"
    volumes:
      - ./config:/config/config:ro
      - ./data:/data
    environment:
      - TZ=Asia/Shanghai
    mem_limit: 256m
    cpus: 0.5

2.4 启动并创建用户

# 启动服务
podman-compose up -d

# 创建用户(宿主机需安装 apache2-utils)
sudo apt install apache2-utils -y
htpasswd -B -c ./data/users zadmin

# 或直接在容器内创建
podman exec radicale htpasswd -B -c /data/users zadmin

# 重启服务
podman-compose restart radicale

# 查看日志
podman-compose logs radicale

三、InfCloud 部署

3.1 拉取镜像并运行

# 创建配置目录
mkdir -p ~/infcloud/config

# 运行容器
podman run -d \
  --name intelligent_kepler \
  -p 8080:80 \
  -v ~/infcloud/config:/srv/infcloud/config:ro \
  waja/infcloud:latest

3.2 复制配置文件

# 从容器复制默认配置
podman cp intelligent_kepler:/srv/infcloud/config/config.js ~/infcloud/config/config.js

# 或直接创建配置文件
cat > ~/infcloud/config/config.js << 'EOF'
var globalNetworkCheckSettings = {
    href: "https://你的Radicale域名/",
    timeOut: 90000,
    lockTimeOut: 10000,
    checkContentType: true,
    settingsAccount: true,
    delegation: true,
    additionalResources: [],
    hrefLabel: null,
    forceReadOnly: null,
    ignoreAlarms: false,
    backgroundCalendars: []
};

var globalInterfaceLanguage = 'zh_CN';
var globalTimeZone = 'Asia/Shanghai';
var globalUseHtml5Cache = false;  // 禁用缓存便于调试
var globalDebugMode = true;
EOF

# 重启容器
podman restart intelligent_kepler

四、Caddy 反向代理配置

4.1 Caddyfile 配置

# Radicale 后端 API
zrili.aab.com {
    reverse_proxy radicale:5232
}

# InfCloud 前端界面
zprili.aab.com {
    reverse_proxy intelligent_kepler:80
}

4.2 统一域名方案(推荐,避免跨域)

zri.aab.com {
    # InfCloud 前端
    handle / {
        reverse_proxy infcloud:80
    }
    
    # Radicale 后端 API
    handle /caldav/* {
        reverse_proxy radicale:5232
    }
    
    # Radicale 管理界面
    handle /.web/* {
        reverse_proxy radicale:5232
    }
}

4.3 重载配置

sudo systemctl reload caddy

五、常见问题与解决方案

5.1 CORS 跨域问题

错误信息

Access to XMLHttpRequest at 'https://...' from origin 'https://...' has been blocked by CORS policy

解决方案:确保 Radicale 配置中包含完整的 CORS 头,特别是 X-client

Access-Control-Allow-Headers = User-Agent, Authorization, Content-type, Depth, If-match, If-None-Match, Lock-Token, Timeout, Destination, Overwrite, Prefer, X-client, X-Requested-With

5.2 配置文件语法错误

错误信息

config.js:335 Uncaught SyntaxError: Unexpected token ':'

解决方案

  • 检查是否有多余的逗号
  • 检查是否使用中文标点
  • 确保变量使用 var 声明

5.3 URL 拼接错误

错误信息

REPORT https://zadmin@zrili.aab.comzadmin/

解决方案

  • 确保 href 末尾有斜杠:https://domain/
  • 清除浏览器缓存和 AppCache
  • 设置 globalUseHtml5Cache = false

5.4 清除 HTML5 AppCache

Chrome/Edge

  1. 访问 chrome://appcache-internals/
  2. 找到对应站点,点击 Remove

强制刷新

  • 右键点击刷新按钮 → 「清空缓存并硬性重新加载」

5.5 容器内命令找不到

问题htpasswd: command not found

解决方案

# 使用完整路径
podman exec radicale /usr/bin/htpasswd -B -c /data/users zadmin

# 或使用 Python 生成密码
podman exec radicale python3 -c "import bcrypt; print(bcrypt.hashpw(b'password', bcrypt.gensalt()).decode())"

六、备选方案:CalDavZAP

如果 InfCloud 问题难以解决,可以使用 CalDavZAP:

6.1 部署 CalDavZAP

# 创建目录
mkdir -p ~/caldavzap && cd ~/caldavzap

# 下载并解压
wget https://www.inf-it.com/CalDavZAP_0.13.1.zip
unzip CalDavZAP_0.13.1.zip
rm CalDavZAP_0.13.1.zip

# 配置
cp config.js.example config.js
sed -i "s|var globalNetworkCheckSettings = {.*|var globalNetworkCheckSettings = { href: 'https://你的Radicale域名',|" config.js

# 使用 Nginx 容器托管
podman run -d \
  --name caldavzap \
  -p 8082:80 \
  -v $(pwd):/usr/share/nginx/html:ro \
  nginx:alpine

6.2 访问地址

http://你的服务器IP:8082

七、常用命令速查

7.1 容器管理

# 查看容器状态
podman ps -a

# 查看日志
podman logs radicale
podman logs intelligent_kepler

# 进入容器
podman exec -it radicale /bin/sh
podman exec -it intelligent_kepler /bin/sh

# 重启容器
podman restart radicale intelligent_kepler

# 停止并删除
podman stop radicale intelligent_kepler
podman rm radicale intelligent_kepler

7.2 网络测试

# 从容器内测试连通性
podman exec intelligent_kepler wget -O- http://radicale:5232/

# 带认证测试
curl -u zadmin:密码 https://你的域名/.web/

# 检查 CORS 头
curl -I https://你的域名/.web/ | grep -i "access-control"

7.3 配置文件检查

# 查看 Radicale 配置
cat ~/radicale/config

# 查看 InfCloud 配置
cat ~/infcloud/config/config.js

# 查看用户文件
cat ~/radicale/data/users

八、架构最佳实践

8.1 推荐架构(无跨域问题)

统一域名: https://calendar.example.com

├── /           → InfCloud 前端
├── /caldav/*   → Radicale API
└── /.web/*     → Radicale 管理界面

8.2 跨域架构(需配置 CORS)

├── https://frontend.example.com  → InfCloud 前端
└── https://backend.example.com   → Radicale API

8.3 安全建议

  1. 始终使用 HTTPS(Caddy 自动提供)
  2. 使用 bcrypt 加密密码htpasswd_encryption = bcrypt
  3. 限制容器资源mem_limit: 256m, cpus: 0.5
  4. 添加安全选项security_opt: no-new-privileges:true
  5. 定期备份数据目录~/radicale/data/

九、故障排查清单

  • [ ] Radicale 容器是否运行:podman ps | grep radicale
  • [ ] 用户文件是否存在:podman exec radicale cat /data/users
  • [ ] CORS 头是否完整(包含 X-client
  • [ ] config.jshref 是否正确(末尾有斜杠)
  • [ ] 浏览器缓存是否清除(包括 AppCache)
  • [ ] 两个容器是否在同一网络
  • [ ] Caddy 配置是否正确重载
  • [ ] 域名 DNS 是否解析到正确 IP
  • [ ] 防火墙端口是否开放(80, 443, 5232)

十、参考资料

标签: none

添加新评论