Kimai на сервере: частые ошибки и решения
Kimai — удобный self-hosted тайм-трекер для фрилансеров и команд, но между «скачал образ» и «команда реально ведёт учёт времени» лежит десяток мест, где всё ломается: белый экран вместо интерфейса, обрыв связи с базой, неправильные ссылки за прокси, немые cron-задачи и падающий экспорт в PDF. Ниже — разбор самых частых ошибок Kimai на сервере по схеме «симптом → причина → решение», собранный на практике эксплуатации именно на выделенных VPS, а не в идеальном демо-окружении.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →С чего начинать диагностику
Прежде чем что-то чинить, соберите факты. У Kimai (это Symfony-приложение) есть встроенная диагностика, которая быстро находит половину проблем с окружением:
docker compose exec kimai php bin/console kimai:check
Если Kimai установлен без Docker — та же команда выполняется из корня приложения от имени пользователя веб-сервера:
sudo -u www-data php bin/console kimai:check
Дальше — три источника логов, которые покрывают почти все случаи:
docker compose logs -f kimai
tail -f var/log/prod.log
tail -f /var/log/nginx/kimai-error.log
Если контейнер вообще не поднимается, сначала смотрите docker compose ps и код выхода — это отличит проблему конфигурации от нехватки ресурсов на самом сервере. Держите эти команды под рукой: дальше почти каждая ошибка отлавливается через них.
Белый экран или ошибка 500 после установки
Классика: контейнер запущен, порт открыт, а вместо интерфейса — пустая страница или общий текст «Internal Server Error» без деталей. Причина почти всегда одна из двух: неверные права на каталоги var/cache и var/log, либо приложение работает в production-режиме, который прячет подробности ошибки.
Проверьте владельца каталогов — они должны принадлежать пользователю, от имени которого работает PHP-FPM (обычно www-data):
ls -la var/
chown -R www-data:www-data var/cache var/log var/data
chmod -R 775 var/cache var/log
Чтобы увидеть реальную причину падения, временно переключитесь в dev-режим и очистите кэш:
APP_ENV=dev php bin/console cache:clear
APP_ENV=dev php bin/console debug:config
После установки нового Kimai или обновления версии кэш почти всегда нужно очищать отдельно — Symfony агрессивно кэширует конфигурацию, и старый кэш прод-режима после обновления образа даёт именно такой белый экран. Не забудьте вернуть APP_ENV=prod после диагностики — dev-режим заметно медленнее и не предназначен для постоянной работы.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОшибки подключения к базе данных
Симптом: при заходе на страницу входа Kimai падает с ошибкой вида SQLSTATE[HY000] [2002] Connection refused или Unknown database. Причина в неверном DATABASE_URL — формат строки подключения у Kimai строгий и не прощает опечаток:
DATABASE_URL=mysql://kimai:pароль@mysql:3306/kimai?charset=utf8mb4&serverVersion=8.0
Три частые ошибки в этой строке: хост mysql указан как localhost (в Docker контейнер базы виден только по имени сервиса из compose-файла, не по localhost), пароль с спецсимволами не URL-экранирован, и не указана кодировка utf8mb4 — без неё эмодзи и часть юникода в описаниях задач ломают запись. Проверить, что база вообще доступна из контейнера Kimai:
docker compose exec kimai php bin/console doctrine:query:sql "SELECT 1"
Если ответ приходит, а страницы всё равно не открываются — не выполнены миграции после установки или обновления:
docker compose exec kimai php bin/console doctrine:migrations:migrate --no-interaction
Если база разворачивается на отдельном VPS, а не в том же compose-стеке, отдельная категория проблем — сама настройка MySQL: лимит подключений, права пользователя на конкретную базу, bind-address. Это разобрано подробнее в статье про частые ошибки MySQL на сервере.
Kimai в Docker: переменные окружения и права на volume
Официальный образ kimai/kimai2 удобен, но у него есть свои грабли. Первая — при первом запуске не создался администратор, потому что переменные ADMINUSER и ADMINPASS заданы неправильно или контейнер уже был проинициализирован раньше без них (повторный запуск init-скрипт не выполняет):
services:
kimai:
image: kimai/kimai2:apache
environment:
DATABASE_URL: "mysql://kimai:pass@mysql:3306/kimai?charset=utf8mb4&serverVersion=8.0"
ADMINMAIL: "admin@example.com"
ADMINPASS: "смените-сразу-после-установки"
TRUSTED_HOSTS: "^kimai\\.example\\.com$$"
volumes:
- kimai_data:/opt/kimai/var/data
- kimai_plugins:/opt/kimai/var/plugins
restart: unless-stopped
Если админ уже не создаётся автоматически, создайте его вручную командой внутри контейнера:
docker compose exec kimai php bin/console kimai:user:create admin admin@example.com ROLE_SUPER_ADMIN
Вторая грабля — не заданы volume под var/data и var/plugins. Без них при пересоздании контейнера (обновление образа, docker compose up -d --force-recreate) исчезают загруженные аватары, вложения к записям времени и установленные плагины — данные жили внутри слоя контейнера и не пережили его пересоздание. Общий принцип разобран в статье про Docker Compose для продакшена: всё, что должно пережить обновление образа, обязано лежать в именованном томе, а не в файловой системе контейнера.
Реверс-прокси, HTTPS и неправильные ссылки
Симптом: Kimai открывается по HTTPS через nginx, но сам генерирует ссылки на http://, форма логина зацикливается на редиректе, а браузер ругается на смешанный контент. Причина в том, что Kimai (как и любое Symfony-приложение) не знает, что перед ним стоит прокси, который терминирует SSL, и видит только внутренний HTTP-запрос от nginx.
Решение — сообщить приложению, каким доверенным прокси разрешено передавать заголовки X-Forwarded-*. В .env.local (или через переменную окружения контейнера):
TRUSTED_PROXIES=127.0.0.1,172.16.0.0/12
TRUSTED_HOSTS=^kimai\.example\.com$
В 172.16.0.0/12 попадает диапазон, который Docker обычно выдаёт мостовым сетям compose — уточните реальную подсеть через docker network inspect, если контейнеры не в дефолтной сети. На стороне nginx конфиг реверс-прокси должен прокидывать заголовки протокола и хоста, иначе никакой TRUSTED_PROXIES не поможет:
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Если после этого ссылки всё равно генерируются неправильно — почти всегда виноват именно недостающий proxy_set_header X-Forwarded-Proto $scheme. Общие принципы настройки такого прокси и типовые ошибки конфига разобраны в статье про nginx как реверс-прокси.
Не работают email и cron-задачи
Kimai не рассылает уведомления, напоминания о незаполненном времени и не создаёт запланированные счета — при этом никакой ошибки на экране нет, приложение просто молчит. Причина в двух независимых вещах: почта и cron у Kimai не настроены сами по себе, их нужно включить отдельно.
Почта настраивается через MAILER_DSN (в новых версиях Kimai это переменная в .env.local, не MAILER_URL из старой документации, которую иногда копируют по инерции):
MAILER_DSN=smtp://user:pass@smtp.example.com:587
Проверить отправку без похода в интерфейс:
docker compose exec kimai php bin/console kimai:reset-2fa admin@example.com
docker compose exec kimai php bin/console messenger:consume async -vv
Второе — фоновые задачи (пересчёт статистики, напоминания, автоматические счета) выполняются командой kimai:cron, которую нужно самим повесить на системный cron: сам Kimai её не планирует, он только выполняет то, что вызвали. Внутри контейнера или на хосте с установленным Kimai:
*/5 * * * * docker compose exec -T kimai php bin/console kimai:cron >> /var/log/kimai-cron.log 2>&1
Частая ошибка — команда прописана в crontab пользователя, у которого нет прав на docker compose exec, либо путь к compose-файлу не совпадает с рабочим каталогом cron-задачи (cron запускает команды без вашего .bashrc и без текущей директории терминала). Общие грабли с cron на сервере — не тот PATH, не та временная зона, отсутствие логов ошибок — разобраны в статье про cron-задачи на сервере.
Экспорт в PDF не работает
Кнопка «Экспорт в PDF» (счета, отчёты по времени) либо ничего не делает, либо возвращает пустой файл или ошибку 500. У Kimai для генерации PDF используется библиотека mPDF, и её самая частая проблема — нехватка памяти PHP на больших отчётах, а не сама генерация:
docker compose exec kimai php -i | grep memory_limit
Если стоит стандартные 128M, а отчёт содержит сотни записей времени за месяц по всей команде, процесс просто упирается в лимит и падает без внятного сообщения в интерфейсе — подробности видны только в var/log/prod.log. Поднимите лимит в конфиге PHP-FPM или переменной окружения контейнера:
php_admin_value[memory_limit] = 512M
Вторая частая причина — кастомный шаблон счёта или логотип компании ссылается на внешний ресурс (шрифт, изображение по внешнему URL), а исходящий трафик из контейнера заблокирован файрволом или у контейнера просто нет доступа в интернет. mPDF рендерит документ синхронно, и внешний ресурс, до которого не достучаться, роняет генерацию по таймауту. Проверить доступность:
docker compose exec kimai curl -I https://адрес-вашего-логотипа
Практичное решение — держать логотип и шрифты локально в var/data, а не тянуть их из интернета при каждой генерации отчёта: так экспорт не зависит от внешней сети вообще.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
После обновления образа Kimai пропали загруженные аватары и вложения — как вернуть?
Если данные не лежали в отдельном volume, они восстанавливаются только из бэкапа; на будущее вынесите var/data и var/plugins в именованные тома, чтобы пересоздание контейнера их не затрагивало.
Kimai пишет «Unknown database» при первом запуске — что не так?
База ещё не создана или создана с другим именем, чем указано в DATABASE_URL; создайте базу вручную через CREATE DATABASE kimai CHARACTER SET utf8mb4 и перезапустите контейнер.
Как понять, реально ли выполняется kimai:cron, а не просто стоит в crontab?
Добавьте вывод в лог-файл (>> /var/log/kimai-cron.log 2>&1) и проверьте время последнего изменения файла — если оно не обновляется, проблема в правах crontab или в неверном пути к compose-файлу.
Нужен ли для Kimai отдельный SSL-сертификат, если он уже стоит на реверс-прокси?
Нет, сертификат нужен только на уровне nginx или Caddy перед приложением; сам Kimai работает по HTTP внутри контейнера и о сертификате не знает — если сертификат периодически не обновляется, смотрите отдельно почему не обновился SSL-сертификат.
Сколько ресурсов реально нужно Kimai на команду из 20-30 человек?
Заметно зависит от нагрузки и количества плагинов, но как ориентир: 2 vCPU и 4 ГБ RAM обычно хватает с запасом на MySQL, PHP-FPM и периодические PDF-отчёты — точную цифру для вашей команды лучше проверить на практике под реальной нагрузкой.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →