MAATRIX / Блог / Radicale на сервере: частые ошибки и решения

Radicale на сервере: частые ошибки и решения

MAATRIX

Radicale — один из немногих CalDAV/CardDAV серверов, который реально поднимается за пять минут: один Python-пакет, один конфиг-файл, никакой базы данных. Но именно из-за этой простоты новички спотыкаются на мелочах — то клиент упорно спрашивает пароль по кругу, то после обновления пакета календари как будто исчезают, то сервер работает по HTTP, но телефон отказывается синхронизироваться без TLS. Разберём типичные проблемы Radicale по порядку — с конкретными командами и путями к файлам, актуально для версии 3.x на Ubuntu 24.04.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Установка и первый запуск

Radicale ставится через pip или из репозитория дистрибутива. Для продакшена лучше pip в отдельном venv — так проще следить за версией и обновлениями:

sudo apt install python3-pip python3-venv -y
sudo python3 -m venv /opt/radicale
sudo /opt/radicale/bin/pip install --upgrade pip
sudo /opt/radicale/bin/pip install radicale

Создайте системного пользователя и каталог для данных:

sudo useradd -r -s /usr/sbin/nologin -d /var/lib/radicale radicale
sudo mkdir -p /var/lib/radicale/collections
sudo mkdir -p /etc/radicale
sudo chown -R radicale:radicale /var/lib/radicale

Базовый конфиг /etc/radicale/config:

[server]
hosts = 127.0.0.1:5232

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

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

[logging]
level = info

Файл с пользователями создаётся отдельно (нужен модуль htpasswd для bcrypt):

sudo /opt/radicale/bin/pip install passlib bcrypt
sudo /opt/radicale/bin/python -m radicale --config /etc/radicale/config &
sudo htpasswd -B -c /etc/radicale/users ivan

Если системного htpasswd нет (пакет apache2-utils не стоит), поставьте его: sudo apt install apache2-utils. После первого запуска убедитесь, что процесс слушает порт: ss -tlnp | grep 5232. Если порта нет — смотрите раздел про systemd ниже, скорее всего сервис просто не стартовал.

Ошибка 401 Unauthorized при каждом подключении

Самая частая жалоба: клиент (Thunderbird, DAVx5, iOS Календарь) раз за разом просит логин-пароль, хотя они введены верно. Причины обычно три.

Во-первых, неверный формат хэша в htpasswd_filename. Если файл создавался без флага -B (bcrypt) или -m (MD5), а в конфиге указан htpasswd_encryption = bcrypt, Radicale не сможет проверить пароль и молча вернёт 401. Пересоздайте файл:

sudo htpasswd -B -c /etc/radicale/users ivan

Флаг -c пересоздаёт файл с нуля — используйте его только для первого пользователя, для остальных добавляйте без -c.

Во-вторых, права на сам файл. Radicale работает от пользователя radicale, и если /etc/radicale/users принадлежит root с правами 600, процесс просто не сможет его прочитать:

sudo chown radicale:radicale /etc/radicale/users
sudo chmod 640 /etc/radicale/users

В-третьих, обратный прокси (если он есть) может съедать заголовок Authorization при определённых конфигурациях nginx с proxy_pass без явного проброса заголовков. Проверьте, что в конфиге nginx стоит:

proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;

Без этой строки некоторые связки nginx + Radicale теряют заголовок авторизации, и клиент видит 401 даже при правильном пароле.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

403 Forbidden и права на коллекции

Если авторизация проходит, но при попытке создать календарь или контакт-книгу сервер отвечает 403, дело почти всегда в правах на файловую систему хранилища. Radicale по умолчанию создаёт коллекции при первом обращении клиента, и для этого процессу нужны права записи в filesystem_folder:

sudo chown -R radicale:radicale /var/lib/radicale/collections
sudo chmod -R 750 /var/lib/radicale/collections

Отдельная частая причина 403 — включённый rights-модуль с плагином прав доступа ([rights] type = from_file), где в файле /etc/radicale/rights неверно прописаны регулярные выражения на пути коллекций. Пример рабочей секции для модели «каждый пользователь видит только свои календари»:

[user]
user: .+
collection: {user}(/.*)?
permissions: RW

Если вы правили rights, проверяйте синтаксис построчно — одна лишняя точка в регулярке закрывает доступ ко всем вложенным коллекциям, и клиент получает 403 именно там, где раньше всё работало.

Календари «пропали» после обновления Radicale

После апгрейда с 2.x на 3.x структура хранения на диске не меняется драматично, но иногда путается указанный в конфиге путь filesystem_folder, либо новый systemd-юнит запускает Radicale от другого пользователя (например, от www-data вместо ранее использовавшегося radicale), и сервис просто не видит старые файлы, потому что не может их прочитать.

Проверка простая — зайдите в каталог хранения и посмотрите, на месте ли данные:

sudo ls -la /var/lib/radicale/collections/collection-root/

Если каталоги пользователей на месте, но клиент показывает пустой список — сверьте filesystem_folder в актуальном конфиге с реальным путём (после обновления пакета конфиг иногда откатывается к дефолтному /var/lib/radicale/collections, а ваши данные могли лежать в другом месте). Второй момент — Radicale кэширует список коллекций; после ручного вмешательства в файлы на диске (например, восстановления из бэкапа) перезапустите сервис:

sudo systemctl restart radicale

Резервные копии стоит делать банальным rsync или tar каталога collections — формат хранения Radicale текстовый (iCalendar/vCard-файлы на диске), поэтому бэкап такой же простой, как копирование папки, и восстанавливается без миграций.

HTTPS: без него мобильные клиенты не подключатся

Radicale по умолчанию слушает HTTP на localhost, и это осознанное решение — TLS-терминацию отдают обратному прокси. iOS и Android CalDAV-клиенты в большинстве случаев требуют HTTPS для синхронизации по интернету (по локальной сети некоторые ещё стерпят HTTP, но полагаться на это не стоит). Схема — nginx перед Radicale плюс Let's Encrypt:

server {
    listen 443 ssl http2;
    server_name caldav.вашдомен.ru;

    ssl_certificate     /etc/letsencrypt/live/caldav.вашдомен.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/caldav.вашдомен.ru/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5232;
        proxy_set_header Host $host;
        proxy_set_header X-Script-Name /;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Authorization $http_authorization;
        proxy_pass_header Authorization;
    }
}

Заголовок X-Script-Name важен, если Radicale отвечает не из корня домена, а из подпапки — без него ссылки в ответах сервера (WebDAV href) будут собраны неправильно, и клиент не найдёт свои коллекции. Сертификат получите через certbot — если сомневаетесь между certbot и acme.sh, разница и плюсы каждого разобраны в статье про выбор ACME-клиента. Если сертификат уже был, но клиент вдруг перестал подключаться по HTTPS — вероятно, дело не в Radicale, а в истёкшем сертификате, это отдельная и тоже частая история, разобранная в статье про не обновившийся SSL-сертификат.

systemd: сервис не стартует или падает после reboot

Юнит-файл для systemd не всегда идёт в комплекте с pip-установкой, его нужно создать самостоятельно в /etc/systemd/system/radicale.service:

[Unit]
Description=A simple CalDAV/CardDAV server
After=network.target

[Service]
ExecStart=/opt/radicale/bin/python -m radicale --config /etc/radicale/config
Restart=on-failure
User=radicale
Group=radicale

[Install]
WantedBy=multi-user.target

После создания:

sudo systemctl daemon-reload
sudo systemctl enable --now radicale
sudo systemctl status radicale

Если сервис падает сразу после старта, первым делом смотрите журнал — там почти всегда точная причина:

sudo journalctl -u radicale -n 50 --no-pager

Типичные находки в логе: неверный путь к venv в ExecStart (проверьте which python внутри venv), отсутствие прав пользователя radicale на конфиг или хранилище, либо синтаксическая ошибка в /etc/radicale/config (лишний пробел вокруг = Radicale в некоторых версиях не прощает). После правки конфига обязательно daemon-reload не нужен — reload нужен только при изменении самого юнит-файла, а конфиг Radicale перечитывается при перезапуске сервиса.

Firewall и доступ снаружи

Если Radicale работает только через nginx на 443-м порту, порт 5232 должен быть закрыт снаружи и слушать исключительно 127.0.0.1 — так и указано в примере конфига выше. Проверьте, что порт 5232 не торчит наружу:

sudo ss -tlnp | grep 5232

Должно быть 127.0.0.1:5232, а не 0.0.0.0:5232 или *:5232. Если по ошибке указали hosts = 0.0.0.0:5232 в конфиге, любой в интернете сможет достучаться до сервера в обход nginx и TLS — это стоит закрыть либо правкой конфига, либо через firewall. Базовая настройка ufw для сервера с Radicale за nginx — открыть только 80/443/22, всё остальное закрыть:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Подробный разбор типичных проблем самого ufw — в статье про частые ошибки файрвола, если правила внезапно перестают применяться или блокируют не то, что ожидалось.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Нужна ли Radicale база данных типа PostgreSQL или MySQL?

Нет, штатное хранилище — файловая система: каждая коллекция и событие хранятся как обычные iCalendar/vCard-файлы в каталоге filesystem_folder. Это упрощает бэкапы и перенос, но при тысячах пользователей файловый backend становится узким местом — для таких масштабов стоит смотреть в сторону других серверов CalDAV.

Почему после смены пароля в htpasswd клиент всё равно логинится по старому паролю?

Обычно это кэш авторизации на стороне клиента (особенно у DAVx5 и Thunderbird) — удалите учётную запись в приложении и добавьте заново, либо просто перезайдите. На стороне сервера кэширования паролей нет, конфиг читается заново при каждом обращении.

Можно ли использовать Radicale вместо полноценного Nextcloud, если нужны только календарь и контакты?

Да, для одной этой задачи Radicale заметно легче: меньше зависимостей, меньше памяти, проще поддержка. Если позже понадобятся файлы, заметки и совместная работа — есть смысл посмотреть на настройку Nextcloud, но начинать с тяжёлого решения ради одного календаря обычно избыточно.

Как перенести Radicale на новый сервер?

Скопируйте содержимое filesystem_folder (обычно /var/lib/radicale/collections) и файл /etc/radicale/users через rsync -avz, установите тот же конфиг на новом сервере, проверьте права radicale:radicale на скопированные каталоги и перезапустите сервис — миграции данных не требуется, формат совместим между минорными версиями 3.x.

DAVx5 находит сервер, но не показывает ни одного календаря — в чём дело?

Чаще всего календарь просто не создан: Radicale не генерирует коллекции сама по себе, их нужно один раз создать через веб-интерфейс Radicale (откройте https://caldav.вашдомен.ru/ivan/ в браузере — там есть форма создания календаря/книги контактов) или через сам клиент, если он поддерживает создание коллекций на сервере.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →