SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

Hướng dẫn tự host CalDAV server trên VPS với Radicale

Tự xây dựng CalDAV server trên VPS để đồng bộ lịch cá nhân không cần Google. Hướng dẫn cấu hình Radicale, TLS, cơ chế discovery và cách kết nối client ổn định cho mọi thiết bị.

Bạn đang xây dựng cái gì

Một lịch tự host là một CalDAV server chạy trên VPS do bạn kiểm soát, nằm sau TLS, với mỗi người dùng một tài khoản đăng nhập. Điện thoại trong túi và laptop trên bàn của bạn sẽ hiển thị cùng một sự kiện, và laptop của người thân cũng vậy. Không có tài khoản Google nào nằm ở giữa.

Đây là công việc khác với một trang đặt lịch tự host. Trang đặt lịch dành cho người lạ: nó công khai các khoảng thời gian trống của bạn và cho phép người khác chọn một lịch hẹn. Server lịch dành cho thiết bị của chính bạn: nó lưu trữ các sự kiện và đồng bộ hóa mọi client. Người dùng thường chạy cả hai, khi đó công cụ đặt lịch sẽ đọc trạng thái rảnh/bận từ CalDAV server mà bạn xây dựng ở đây.

Việc cài đặt rất nhỏ gọn. Radicale chỉ là một gói Python với khoảng mười dòng cấu hình. Điều quyết định liệu hệ thống có hoạt động ổn định sau tháng đầu tiên hay không chính là TLS, cơ chế discovery, bộ sưu tập theo người dùng và sao lưu. Những phần này chiếm phần lớn nội dung bên dưới.

CalDAV là gì và tại sao nó quan trọng?

CalDAV là giao thức đồng bộ lịch qua HTTP. Nó được định nghĩa trong RFC 4791 như các phần mở rộng của WebDAV (web distributed authoring and versioning, một tập hợp các phương thức HTTP bổ sung được định nghĩa trong RFC 4918). Một lịch là một tập hợp, hoạt động giống như một thư mục. Một sự kiện là một file bên trong đó, được viết bằng định dạng văn bản iCalendar (RFC 5545), cùng định dạng với các .ics tệp đính kèm trong email của bạn.

Các client sử dụng HTTP thông thường với một vài phương thức bổ sung. PROPFIND hỏi những gì có ở đây và các thuộc tính của nó là gì. REPORT yêu cầu một lát cắt đã lọc, ví dụ như mọi sự kiện trong một phạm vi ngày. PUT ghi một sự kiện và DELETE xóa nó. Mỗi sự kiện mang một dòng UID, và định danh đó là cách hai thiết bị xác nhận chúng đang xem cùng một sự kiện thay vì một bản sao.

Tính di động là lợi ích thu được, và đó là lý do duy nhất để bận tâm. iOS, macOS, Thunderbird, Evolution và Android thông qua DAVx⁵ đều hỗ trợ CalDAV. Dữ liệu của bạn không bị ràng buộc với máy chủ mà bạn đã chọn hôm nay. Hãy di chuyển các file sang một máy chủ CalDAV khác, trỏ các client vào hostname mới, và không có gì khác thay đổi.

CardDAV đi kèm theo đó. Nó có cùng ý tưởng cho danh bạ, được định nghĩa trong RFC 6352 và lưu trữ các file vCard thay vì các sự kiện. Mọi máy chủ bên dưới đều phục vụ cả hai giao thức từ cùng một tài khoản, vì vậy khi lịch đã hoạt động, sổ địa chỉ chỉ là một thao tác đánh dấu chọn.

Bạn nên chạy CalDAV server nào?

Radicale là lựa chọn gọn nhẹ nhất mà vẫn hoạt động tốt. Nó chạy bằng Python, không cần database, và lưu trữ dữ liệu dưới dạng các file văn bản thuần túy trong một thư mục. Hướng dẫn này sử dụng Radicale vì lịch cá nhân trong gia đình không cần gì hơn thế, và vì nó rất ít khi gặp sự cố vào lúc 3 giờ sáng.

Baikal là tùy chọn có bảng điều khiển quản trị qua web. Nó chạy trên PHP và thư viện sabre/dav, lưu trữ người dùng và lịch trong SQLite hoặc MySQL, cho phép bạn thêm người dùng qua trình duyệt thay vì dùng CLI. Hãy chọn nó khi các tài khoản thường xuyên thay đổi.

Nextcloud là lựa chọn phù hợp khi lịch chỉ là một trong nhiều tính năng bạn cần. Bạn sẽ có lịch, danh bạ, lưu trữ file và ứng dụng di động, nhưng phải đánh đổi bằng việc duy trì PHP-FPM, một database và một trình chạy background job. Nếu thấy cấu hình này quá nặng nề so với nhu cầu thực tế, các giải pháp thay thế Nextcloud nhẹ hơn sẽ phù hợp hơn, và tự host đồng bộ file sẽ giải quyết phần còn lại của những lý do khiến mọi người cài đặt Nextcloud.

DAViCal là tùy chọn sử dụng PostgreSQL lâu đời. Nó chỉ đáng xem xét nếu bạn đã chạy sẵn PostgreSQL và muốn lưu trữ dữ liệu lịch ngay trong đó.

Cài đặt Radicale trên Ubuntu 24.04

Radicale 3.5.10 là bản release hiện tại tính đến tháng 8 năm 2026. Hãy cài đặt nó vào một virtual environment riêng.

sudo apt update
sudo apt install -y python3-venv apache2-utils nginx
sudo useradd --system --user-group --home-dir / --shell /usr/sbin/nologin radicale
sudo install -d -o radicale -g radicale -m 750 /var/lib/radicale/collections
sudo install -d -m 750 -o root -g radicale /etc/radicale
sudo python3 -m venv /opt/radicale/venv
sudo /opt/radicale/venv/bin/pip install --upgrade radicale

Việc sử dụng virtual environment không phải là vấn đề phong cách. sudo pip install radicale vào Python của hệ thống sẽ dừng lại với error: externally-managed-environment, vì Ubuntu đánh dấu Python của nó là thuộc quyền quản lý của apt để pip không thể ghi đè lên các file đã đóng gói.

Chạy lệnh /etc/radicale/config:

[server]
hosts = 127.0.0.1:5232

[auth]
type = htpasswd
htpasswd_filename = /etc/radicale/users
htpasswd_encryption = autodetect

[storage]
filesystem_folder = /var/lib/radicale/collections

hosts bind vào loopback một cách có chủ đích. nginx thực hiện TLS termination và chuyển tiếp đến cổng đó, vì vậy Radicale không bao giờ trực tiếp đối mặt với internet. Ví dụ upstream của 0.0.0.0:5232 xuất bản một dịch vụ không mã hóa chấp nhận mật khẩu, đây là sai lầm duy nhất cần lưu ý ở đây.

Bây giờ là phần tài khoản. -5 chọn SHA-512 crypt, thứ mà Radicale đọc bằng htpasswd_encryption = autodetect mà không cần thêm module nào:

sudo htpasswd -5 -c /etc/radicale/users you
sudo htpasswd -5 /etc/radicale/users partner
sudo chown root:radicale /etc/radicale/users
sudo chmod 640 /etc/radicale/users

-c tạo file và xóa sạch nội dung cũ. Chỉ dùng nó cho người dùng đầu tiên. Chạy htpasswd -5 -c lần nữa sau vài tháng sẽ xóa mọi tài khoản được thêm sau người đầu tiên, và triệu chứng là một người đồng bộ bình thường trong khi những người khác nhận được prompt mật khẩu không bao giờ kết thúc. Bcrypt cũng hoạt động tốt, và nó cần cài đặt thêm radicale[bcrypt].

Tạo /etc/systemd/system/radicale.service, được điều chỉnh từ unit trong tài liệu của Radicale:

[Unit]
Description=CalDAV and CardDAV server
After=network.target
Requires=network.target

[Service]
ExecStart=/opt/radicale/venv/bin/python -m radicale
Restart=on-failure
User=radicale
UMask=0027
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
NoNewPrivileges=true
ReadWritePaths=/var/lib/radicale/

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now radicale
curl -i http://127.0.0.1:5232/

Kết quả bình thường là 401 Unauthorized với header WWW-Authenticate: dịch vụ đang lắng nghe và xác thực đã được bật. Connection refused nghĩa là nó chưa bao giờ khởi động, và journalctl -u radicale -n 50 nêu tên tùy chọn mà nó từ chối. ProtectSystem=strict mount filesystem ở chế độ chỉ đọc (read only) cho dịch vụ này, vì vậy ReadWritePaths=/var/lib/radicale/ là dòng cho phép nó lưu sự kiện. Bỏ dòng đó đi thì các thao tác đọc vẫn hoạt động trong khi mọi thao tác ghi đều thất bại.

TLS là bắt buộc vì client từ chối plaintext

CalDAV xác thực bằng HTTP Basic, phương thức này gửi user:password dưới dạng base64 trong mỗi request. Base64 chỉ là mã hóa (encoding), không phải bảo mật (encryption). Nếu dùng HTTP thường, bạn đang gửi mật khẩu qua mọi mạng trung gian giữa điện thoại và máy chủ trong suốt quá trình đồng bộ.

Các client sẽ ép buộc bạn thực hiện điều này. Tài liệu của Radicale lưu ý rằng macOS Calendar.app có thể âm thầm từ chối gửi thông tin xác thực qua HTTP không bảo mật, và iOS cũng hoạt động tương tự. Tài khoản trông có vẻ đã được cấu hình nhưng không bao giờ đồng bộ, và không có thông báo lỗi nào để kiểm tra.

Trước tiên, hãy trỏ một bản ghi A cho cal.example.com về VPS, vì cơ quan cấp chứng chỉ sẽ kiểm tra bản ghi này. Sau đó tạo /etc/nginx/sites-available/cal.example.com:

server {
    listen 80;
    server_name cal.example.com;

    location / {
        proxy_pass        http://localhost:5232/;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto $scheme;
        proxy_set_header  Host $http_host;
        proxy_pass_header Authorization;
    }

    location = /.well-known/caldav  { return 301 https://$host/; }
    location = /.well-known/carddav { return 301 https://$host/; }
}

Bốn dòng proxy header này lấy từ tài liệu của Radicale. Hãy giữ nguyên chúng.

sudo ln -s /etc/nginx/sites-available/cal.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cal.example.com
curl -i -u you https://cal.example.com/

nginx -t sẽ in ra syntax is oktest is successful. Chỉ reload sau khi lệnh này chạy thành công, vì nếu reload với file cấu hình lỗi, hệ thống sẽ tiếp tục chạy cấu hình cũ và che giấu sai sót cho đến lần khởi động lại tiếp theo. Certbot sẽ tự động sửa file cấu hình site: nó cài đặt chứng chỉ, chuyển block sang cổng 443 và thêm redirect từ cổng 80. Lệnh curl cuối cùng sẽ yêu cầu mật khẩu và trả về 200, đây là giao diện web của chính Radicale. Lỗi 502 Bad Gateway nghĩa là nginx đang chạy nhưng Radicale không lắng nghe trên cổng 5232.

Tại sao việc thêm tài khoản trên điện thoại lại thất bại?

Lý do là cơ chế discovery. RFC 6764 mô tả cách client chuyển đổi hostname thành URL lịch. Nó tìm kiếm bản ghi _caldavs._tcp SRV, sau đó truy vấn https://cal.example.com/.well-known/caldav và chờ đợi một lệnh redirect đến root của DAV. Từ đó, nó yêu cầu current-user-principal, rồi đến calendar-home-set của principal đó, và chỉ khi đó nó mới thấy các lịch của bạn. Điện thoại chỉ cung cấp một trường duy nhất cho server, nên mọi bước phải hoạt động tự động mà không cần can thiệp.

curl -sI https://cal.example.com/.well-known/caldav

Phản hồi hợp lệ là HTTP/2 301 kèm theo header location: https://cal.example.com/. Một mã 404 tại đó là lý do tại sao iOS báo không thể xác minh thông tin tài khoản trong khi Thunderbird trên cùng mạng vẫn hoạt động: Thunderbird sử dụng chính URL đầy đủ mà bạn đã nhập, nên nó không cần đến lệnh redirect.

Đích đến của lệnh redirect phụ thuộc vào server. Radicale chạy tại root của site sẽ redirect đến /. Baikal cung cấp sẵn các quy tắc mẫu để redirect đến /dav.php với trạng thái 308. Nextcloud redirect đến /remote.php/dav/.

Tạo lịch và chia sẻ với đối tác

Nhiều client không hỗ trợ tạo lịch mà chỉ có thể subscribe. Hãy mở https://cal.example.com/ trên trình duyệt, đăng nhập bằng you và tạo lịch tại đó. Trên ổ đĩa, lịch sẽ nằm tại /var/lib/radicale/collections/collection-root/you/ với tên thư mục là một định danh được tạo tự động.

Backend quyền mặc định của Radicale là owner_only: một tài khoản đã xác thực có thể đọc và ghi các collection của chính mình trong /USERNAME/ và không thể truy cập nơi khác. Đối với hầu hết các hộ gia đình, đây là thiết lập phù hợp. Cách đơn giản nhất để chia sẻ lịch là dùng một tài khoản thứ ba. Hãy tạo household bằng htpasswd, tạo lịch chia sẻ dưới tài khoản đó, rồi thêm lịch này vào mỗi thiết bị như một tài khoản CalDAV thứ hai. Cách này hoạt động trên mọi client, bao gồm cả iOS, vì lịch nằm trong thư mục home của chính tài khoản đó.

Khi bạn cần kiểm soát chi tiết hơn, hãy chuyển sang sử dụng quyền dựa trên quy tắc (rule-based rights). Thêm nội dung sau vào /etc/radicale/config:

[rights]
type = from_file
file = /etc/radicale/rights

Sau đó cấu hình /etc/radicale/rights dựa trên ví dụ trong tài liệu của Radicale:

[root]
user: .+
collection:
permissions: R

[principal]
user: .+
collection: {user}
permissions: RW

[own-calendars]
user: .+
collection: {user}/[^/]+
permissions: rw

[shared-household]
user: you|partner
collection: you/2f0a9c1e-1f4c-4c2b-9a1b-0d2f7a5c9e11
permissions: rw

Các chữ cái viết hoa và viết thường có ý nghĩa khác nhau. RW dùng để đọc và ghi các collection không phải là lịch hoặc sổ địa chỉ, đây chính là thư mục principal. rw dùng để đọc và ghi chính các lịch đó. Hãy thay thế định danh đó bằng tên thư mục thực tế của lịch từ đường dẫn lưu trữ nêu trên.

Một hạn chế thực tế: client chỉ đọc tập hợp calendar home sẽ không hiển thị lịch nằm dưới đường dẫn của người dùng khác, vì quá trình discovery không quét đến đó. Thunderbird và DAVx⁵ có thể thêm lịch bằng URL đầy đủ. iOS thì không làm được, đó là lý do tại sao mô hình tài khoản chia sẻ là cách luôn hoạt động ổn định.

Thiết lập các client, vì đây là nơi các lịch tự host thường bị lỗi

iPhone và iPad. Mở Settings, sau đó chọn Calendar (nằm trong mục Apps trên các phiên bản iOS gần đây), chọn Calendar Accounts, Add Account, Other, Add CalDAV Account. Server là cal.example.com, sau đó nhập user name và password. Description chỉ là nhãn hiển thị. Nếu máy không cho lưu, hãy mở lại tài khoản đó: chế độ xem nâng cao (advanced view) sẽ hiển thị Use SSL, cổng và URL tài khoản đầy đủ, việc dán trực tiếp URL sẽ bỏ qua bước tự động dò tìm.

Android. Không có client CalDAV tích hợp sẵn. Hãy cài đặt DAVx⁵ từ F-Droid hoặc Google Play, thêm tài khoản bằng URL cơ sở https://cal.example.com/ với user name của bạn, sau đó đánh dấu chọn các lịch muốn đồng bộ. DAVx⁵ ghi dữ liệu vào nhà cung cấp lịch của Android, vì vậy các sự kiện sẽ xuất hiện trong bất kỳ ứng dụng lịch nào bạn đang sử dụng.

Thunderbird. Chọn New Calendar, On the Network, sau đó nhập user name và vị trí https://cal.example.com/. Ứng dụng sẽ liệt kê những gì tìm thấy và hỏi bạn muốn thêm lịch nào.

macOS. Mở System Settings, Internet Accounts, Add Other Account, CalDAV, đặt Account Type thành Manual, sau đó nhập user name, password và địa chỉ server tương tự.

CalDAV là giao thức dạng polling (truy vấn). Đặc tả kỹ thuật không có cơ chế push, vì vậy một sự kiện bạn thêm trên laptop sẽ xuất hiện trên điện thoại vào lần đồng bộ tiếp theo thay vì ngay lập tức. Hãy đặt khoảng thời gian đồng bộ (interval) trong mỗi client sao cho phù hợp với nhu cầu, và lưu ý rằng khoảng thời gian càng ngắn trên điện thoại thì càng tốn pin.

Sao lưu kho dữ liệu, vốn chỉ là các file

Với Radicale, lịch của bạn là một thư mục chứa các .ics file, mỗi file tương ứng với một sự kiện, cộng thêm một file thuộc tính nhỏ cho mỗi bộ sưu tập. Bất kỳ công cụ nào sao chép thư mục đều có thể dùng để sao lưu, và bạn có thể mở bản sao lưu bằng less để xác nhận nó chứa các sự kiện thực tế. Đây là một lợi thế thực sự so với việc dump database mà bạn không thể đọc được.

sudo systemctl stop radicale
sudo tar czf /root/radicale-$(date +%F).tar.gz -C /var/lib/radicale collections
sudo systemctl start radicale

Hãy dừng service trong vài giây để thực hiện lưu trữ, nhằm tránh việc client đang ghi dữ liệu dở dang khi các file được đọc. Sau đó, hãy sao chép bản lưu trữ ra khỏi máy chủ, vì bản sao lưu nằm trên cùng một VPS sẽ không còn nếu xảy ra sự cố mà bạn đang phòng ngừa. Việc khôi phục thực hiện ngược lại: giải nén, sudo chown -R radicale:radicale /var/lib/radicale/collections, và khởi động lại service. Mỗi client cũng lưu một bản sao cục bộ của lịch, vì vậy một chiếc laptop chưa đồng bộ kể từ khi xảy ra sự cố chính là bản sao thứ hai cho dữ liệu của bạn.

Khi nào nên chọn Baikal hoặc Nextcloud

Baikal 0.12.1 được phát hành vào ngày 5 tháng 8 năm 2026 và yêu cầu PHP 8.2 trở lên. Hãy giải nén nó bên ngoài web root và chỉ expose thư mục html của nó:

sudo apt install -y php-fpm php-sqlite3 php-xml php-mbstring php-curl unzip
cd /tmp
curl -LO https://github.com/sabre-io/Baikal/releases/download/0.12.1/baikal-0.12.1.zip
sudo unzip -q baikal-0.12.1.zip -d /srv
sudo chown -R www-data:www-data /srv/baikal/Specific /srv/baikal/config

Hai thư mục đó là những nơi duy nhất mà web server cần quyền ghi, vì vậy không có gì khác cần phải ở trạng thái writable. Bên trong block server nginx của bạn, các phần dành riêng cho Baikal như sau:

root /srv/baikal/html;
index index.php;

location ~ /(\.ht|Core|Specific|config) { deny all; }

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

location = /.well-known/caldav  { return 308 /dav.php; }
location = /.well-known/carddav { return 308 /dav.php; }

Reload nginx, mở trang web trên trình duyệt, và trình hướng dẫn thiết lập sẽ tạo tài khoản admin cùng database SQLite. Việc thiết lập client tương tự như với Radicale, sử dụng https://cal.example.com/ làm địa chỉ máy chủ, vì quy tắc well-known sẽ gửi yêu cầu discovery đến /dav.php.

Nextcloud chỉ thực sự đáng dùng nếu bạn muốn đồng bộ file và sử dụng app điện thoại với cùng một tài khoản đăng nhập. DAV root của nó là /remote.php/dav/, và các quy tắc discovery tương tự cũng được áp dụng. Đối với bất kỳ dịch vụ nào trong số này, việc chạy trong container sẽ giúp tách biệt các phiên bản PHP khỏi host của bạn: Docker Compose trên VPS hướng dẫn về file compose và reverse proxy phía trước nó, còn những gì đáng để tự host trong năm 2026 là nơi phù hợp để bạn quyết định xem mình muốn đi xa đến đâu trên con đường này.

Các kiểu lỗi và thông báo bạn sẽ gặp

Mọi thao tác sync đều trả về 401. Hoặc file mật khẩu đã bị mất các tài khoản do một htpasswd -c khác, hoặc người dùng radicale không có quyền đọc file đó. Hãy kiểm tra bằng sudo -u radicale cat /etc/radicale/users; nếu nhận được thông báo permission denied thì đó chính là nguyên nhân, cách khắc phục là đặt group thành radicale với mode 640. Radicale cũng mặc định chờ một giây sau mỗi lần đăng nhập thất bại, vì vậy client dùng mật khẩu cũ sẽ có cảm giác phản hồi chậm thay vì bị từ chối ngay lập tức.

nginx trả về 405 với phương thức PROPFIND. URL đang được phục vụ như một file tĩnh, nên phương thức WebDAV không bao giờ đến được Radicale. Hãy kiểm tra endpoint trực tiếp:

curl -u you -X PROPFIND -H "Depth: 0" -i https://cal.example.com/you/

Một collection DAV hoạt động bình thường sẽ trả về 207 Multi-Status. Bất kỳ kết quả nào khác nghĩa là yêu cầu đã bị chặn lại ở web server.

Điện thoại không xác thực được tài khoản, trong khi trình duyệt vẫn hoạt động bình thường. Có hai nguyên nhân phổ biến. Redirect well-known bị thiếu, có thể kiểm tra bằng lệnh curl ở trên. Hoặc chuỗi chứng chỉ không đầy đủ, trình duyệt thường tự xử lý bằng cách tải về các chứng chỉ trung gian còn thiếu trong khi iOS thì không. Hãy kiểm tra từ shell:

openssl s_client -connect cal.example.com:443 -servername cal.example.com </dev/null

Tìm kiếm Verify return code: 0 (ok). Nếu thất bại, cấu hình nginx đang trỏ đến cert.pem thay vì trỏ đến fullchain.pem.

Sự kiện bị trùng lặp sau khi import. Mỗi sự kiện mang một UID, và các client coi đó là định danh duy nhất. Nếu import cùng một file hai lần thông qua một công cụ tự tạo lại định danh, bạn sẽ có hai sự kiện mà không hệ thống nào có thể tự gộp lại được. Hãy xóa các bản sao thừa trên một thiết bị và để lệnh xóa đó đồng bộ ra các thiết bị khác.

Mọi thứ ngừng hoạt động sau khi reboot. Service đã được khởi động thủ công. sudo systemctl is-enabled radicale sẽ in ra disabled, và sudo systemctl enable --now radicale sẽ khắc phục vấn đề này vĩnh viễn.

FAQ

Tôi có thực sự cần TLS cho server CalDAV tự host không?

Có. CalDAV xác thực bằng HTTP Basic, nên mật khẩu được truyền dưới dạng base64 trong mỗi request, và base64 rất dễ bị giải mã. Các client cũng bắt buộc điều này: macOS Calendar.app có thể âm thầm từ chối gửi thông tin xác thực qua HTTP không bảo mật, và iOS cũng hành xử tương tự, khiến tài khoản trông như đã lưu nhưng không bao giờ đồng bộ. sudo certbot --nginx -d cal.example.com là toàn bộ công việc cần làm.

Tại sao điện thoại không thêm được tài khoản trong khi Thunderbird lại hoạt động?

Thunderbird sử dụng toàn bộ URL bạn đã nhập. Điện thoại chỉ cung cấp một trường server, nên nó tuân theo cơ chế khám phá RFC 6764: nó yêu cầu https://cal.example.com/.well-known/caldav và mong đợi một lệnh chuyển hướng (redirect) đến root của DAV. Nếu không có lệnh chuyển hướng đó, điện thoại sẽ nhận lỗi 404 và báo rằng không thể xác minh tài khoản. Hãy thêm location = /.well-known/caldav { return 301 https://$host/; } vào nginx, sau đó xác nhận bằng curl -sI https://cal.example.com/.well-known/caldav rằng bạn nhận được mã 301 và header location.

Hai người có thể dùng chung một lịch không?

Có, và cách đáng tin cậy nhất là dùng chung một tài khoản đăng nhập. Hãy tạo tài khoản thứ ba bằng htpasswd, đặt lịch dùng chung dưới tài khoản đó, và thêm nó như một tài khoản CalDAV thứ hai trên mỗi thiết bị. File quyền của Radicale có thể cấp quyền đọc và ghi cho một user cụ thể trên một collection thuộc đường dẫn của user khác, nhưng client chỉ đọc calendar home set của chính nó sẽ không bao giờ hiển thị lịch đó, vì vậy cách này phù hợp với Thunderbird và DAVx⁵ hơn là iOS.

Chuyện gì xảy ra với các sự kiện nếu VPS bị hỏng?

Với Radicale, dữ liệu được lưu dưới dạng văn bản thuần: mỗi sự kiện là một file .ics nằm trong /var/lib/radicale/collections/collection-root/, bạn có thể sao lưu bằng tar và đọc bằng less. Việc khôi phục chỉ là giải nén, chown -R radicale:radicale, và khởi động lại service. Mọi client đã đồng bộ cũng giữ một bản sao cục bộ, nên một chiếc laptop đã cập nhật trước khi xảy ra sự cố sẽ chứa một bản sao đầy đủ thứ hai cho lịch của bạn.

Server CalDAV có đồng bộ cả danh bạ của tôi không?

Danh bạ sử dụng CardDAV, một giao thức anh em được định nghĩa trong RFC 6352, lưu trữ các file vCard thay vì sự kiện. Radicale, Baikal và Nextcloud đều phục vụ giao thức này từ cùng một tài khoản và cùng một hostname. Trên Android, DAVx⁵ đồng bộ lịch và danh bạ từ một tài khoản. Trên iOS, bạn thêm một tài khoản thứ hai loại CardDAV với cùng thông tin xác thực, đó là lý do tại sao lệnh chuyển hướng /.well-known/carddav cần nằm trong cấu hình nginx của bạn bên cạnh cấu hình CalDAV.

#caldav#calendar#radicale#tự lưu trữ#sync