Firefly III на сервере: частые ошибки и решения
Firefly III — один из самых зрелых self-hosted менеджеров личных финансов: бюджеты, правила, отчёты, поддержка нескольких валют и импорт выписок. Но это полноценное Laravel-приложение с базой данных, очередями и cron-задачами, и на голом VPS оно спотыкается в предсказуемых местах — APP_KEY, подключение к БД, обратный прокси, импортёр. Ниже — конкретные ошибки и что с ними делать, без пересказа официальной документации построчно.
Содержание
- Установка через Docker Compose: минимальный рабочий конфиг
- «No application encryption key has been specified» и 500-я после установки
- Firefly III не может подключиться к базе данных
- Не работают автоматические задачи: курсы валют, правила, повторяющиеся транзакции
- Firefly III за Nginx: TRUSTED_PROXIES, APP_URL и петли редиректов
- Data Importer: CSRF и «Firefly III returned an error» при импорте выписок
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Установка через Docker Compose: минимальный рабочий конфиг
Firefly III официально распространяется как Docker-образ, и почти все проблемы ниже — следствие того, что в .env не хватает одной строки или переменная указывает не туда. Базовый набор сервисов — сам Firefly III и база данных:
services:
db:
image: mariadb:11
restart: unless-stopped
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: firefly
MYSQL_USER: firefly
MYSQL_PASSWORD: change_me
volumes:
- firefly_db:/var/lib/mysql
app:
image: fireflyiii/core:latest
restart: unless-stopped
depends_on:
- db
env_file: .env
ports:
- "127.0.0.1:8080:8080"
volumes:
- firefly_upload:/var/www/html/storage/upload
volumes:
firefly_db:
firefly_upload:
Порт нарочно выведен только на 127.0.0.1 — наружу приложение отдаёт Nginx с TLS, об этом ниже. Перед первым запуском создайте .env из .env.example, который лежит в репозитории проекта на GitHub, и сразу задайте DB_CONNECTION=mysql, DB_HOST=db, DB_DATABASE=firefly, DB_USERNAME=firefly, DB_PASSWORD — тот же пароль, что и в сервисе db. Имя хоста db — это имя сервиса в compose-файле, а не адрес, его нельзя заменить на localhost, иначе приложение будет стучаться само в себя.
«No application encryption key has been specified» и 500-я после установки
Самая частая первая ошибка — белый экран или JSON с текстом про APP_KEY. Firefly III на Laravel, и без ключа шифрования сессий он попросту не откроется. Генерируется он одной командой внутри уже запущенного контейнера:
docker compose exec app php artisan key:generate --show
Полученную строку вида base64:xxxxxxxx... вписывают в .env как APP_KEY= и перезапускают контейнер (docker compose restart app), потому что переменные окружения читаются один раз при старте. Если ключ уже стоит, а 500-я всё равно вылезает — смотрите логи:
docker compose logs -f app
docker compose exec app tail -n 100 storage/logs/laravel.log
Частая находка в логе — Permission denied на storage/ или bootstrap/cache. Это случается, если каталоги монтируются с хоста и владелец не совпадает с пользователем внутри контейнера (www-data, UID 33). Быстрое решение:
docker compose exec app chown -R www-data:www-data storage bootstrap/cache
Ещё одна причина 500-й после обновления образа — не докатились миграции. Firefly III обычно прогоняет их автоматически при старте, но если процесс был прерван (например, контейнер убили посреди запуска), база остаётся в промежуточном состоянии. Тогда миграции запускают вручную:
docker compose exec app php artisan migrate --force
docker compose exec app php artisan cache:clear
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверFirefly III не может подключиться к базе данных
Ошибка SQLSTATE[HY000] [2002] Connection refused или SQLSTATE[HY000] [1045] Access denied почти всегда означает рассинхрон между .env приложения и переменными контейнера с базой. Проверьте по шагам:
DB_HOSTдолжен совпадать с именем сервиса базы вdocker-compose.yml(db,mysql,mariadb— как назвали), а не сlocalhostили127.0.0.1— это разные сетевые пространства между контейнерами.DB_DATABASE,DB_USERNAME,DB_PASSWORDв.envприложения должны буква в букву совпадать сMYSQL_DATABASE,MYSQL_USER,MYSQL_PASSWORDконтейнера базы. Если база уже была создана один раз с другим паролем, повторное изменение переменныхMYSQL_*ничего не даст — образ MariaDB/MySQL применяет их только при первой инициализации пустого volume.- Проверьте, что оба контейнера реально в одной docker-сети:
docker network inspect <имя_сети>покажет оба контейнера в списке.
Если пароль в базе действительно поменялся, а volume уже проинициализирован, проще всего зайти в контейнер базы и обновить пароль пользователю напрямую, не пересоздавая volume с данными:
docker compose exec db mariadb -u root -p
ALTER USER 'firefly'@'%' IDENTIFIED BY 'новый_пароль';
FLUSH PRIVILEGES;
Firefly III одинаково хорошо работает и с MariaDB/MySQL, и с PostgreSQL (DB_CONNECTION=pgsql) — выбор чаще определяется тем, что уже крутится на сервере под другие проекты. Если у вас уже поднят MariaDB для сайтов, есть смысл посмотреть отдельный разбор MariaDB на сервере: частые ошибки и решения — там разобраны типовые проблемы с доступом и лимитами соединений, актуальные и для базы Firefly.
Не работают автоматические задачи: курсы валют, правила, повторяющиеся транзакции
Если приложение открывается, но курсы валют не обновляются, повторяющиеся транзакции не создаются, а правила не применяются автоматически — это не баг, а отсутствующий cron. Firefly III не запускает фоновые задачи сам по себе: он ждёт внешнего триггера по расписанию. В актуальных версиях это HTTP-запрос к внутреннему cron-эндпоинту с токеном, который задаётся переменной STATIC_CRON_TOKEN в .env (32 символа, латиница и цифры — сгенерировать можно openssl rand -hex 16). Задача в crontab хоста выглядит так:
0 3 * * * curl -fsS http://127.0.0.1:8080/api/v1/cron/ВАШ_STATIC_CRON_TOKEN >/dev/null 2>&1
Точное имя эндпоинта и переменной может отличаться между релизами — Firefly III их несколько раз менял, поэтому перед настройкой сверьтесь с блоком «Cron jobs» в документации именно вашей версии образа (тег latest тянет актуальную на день установки). Если после настройки задача всё равно молчит, проверьте вручную, что curl вообще достучался — при обратном прокси с базовой авторизацией или закрытым портом запрос извне контейнера может просто не проходить, тогда curl стоит слать изнутри контейнера app, а не с хоста. За планировщик задач на хосте отвечает обычный системный cron — если с ним раньше не сталкивались, пригодится Cron-задачи на сервере: частые ошибки и решения.
Firefly III за Nginx: TRUSTED_PROXIES, APP_URL и петли редиректов
Когда приложение стоит за Nginx с TLS-терминацией, вылезают две типовые проблемы: бесконечный редирект на HTTPS и «страница просрочена» (CSRF token mismatch) при входе. Причина обеих — Laravel не знает, что запрос пришёл по HTTPS, потому что видит его уже расшифрованным от Nginx по HTTP. Решение — две переменные в .env:
APP_URL=https://finance.example.com
TRUSTED_PROXIES=**
APP_URL обязан быть именно тем адресом, по которому реально открывают сайт — со схемой и без завершающего слэша. Если он не совпадает с тем, что вводит браузер, форма логина будет валиться по CSRF. TRUSTED_PROXIES=** говорит Laravel доверять заголовкам X-Forwarded-* от любого прокси перед собой — это безопасно, потому что порт приложения и так закрыт наружу и виден только Nginx на том же хосте. Сам Nginx должен эти заголовки прокидывать:
server {
listen 443 ssl http2;
server_name finance.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Если настраиваете обратный прокси впервые, общая механика (upstream, заголовки, таймауты) подробно разобрана в Nginx как реверс-прокси на сервере: частые ошибки и решения, а сертификат для домена проще всего выпустить и продлевать через certbot — сравнение с acme.sh есть в статье Certbot или acme.sh: что выбрать для сервера.
Data Importer: CSRF и «Firefly III returned an error» при импорте выписок
Импорт CSV и банковских выписок в Firefly III делает не сам основной контейнер, а отдельное приложение — Firefly III Data Importer (fireflyiii/data-importer), которое подключается к основному инстансу как отдельный OAuth-клиент. Типичная ошибка новичков — поднять импортёр, но не создать для него Personal Access Token или OAuth Client в основном Firefly III (раздел Options → Profile → OAuth), и указать в .env импортёра неверный FIREFLY_III_URL — например, внешний домен вместо внутреннего Docker-адреса контейнера app, если оба сервиса живут в одной docker-сети:
FIREFLY_III_URL=http://app:8080
VANITY_URL=https://finance.example.com
FIREFLY_III_URL — это адрес, по которому импортёр достучится до API изнутри сети, VANITY_URL — тот, что видит браузер пользователя; их разделяют специально, и путаница между ними — источник половины ошибок подключения. Сообщение «Firefly III returned an error, no further information available» почти всегда означает именно неверный FIREFLY_III_URL или то, что токен доступа истёк и его нужно перевыпустить в профиле основного приложения. CSRF-ошибки в самом импортёре лечатся тем же способом, что и в основном контейнере — сверить VANITY_URL со схемой, по которой реально заходят, и не забыть TRUSTED_PROXIES, если импортёр тоже стоит за тем же Nginx.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Firefly III и Data Importer — обязательно два разных контейнера?
Да, это архитектурное решение проекта: основное приложение хранит данные и отдаёт API, импортёр — отдельный сервис-клиент для конкретного банка или CSV-формата. Их можно развернуть на одном сервере в одной docker-сети без проблем.
Как сделать бэкап данных Firefly III?
Бэкапить нужно и базу, и каталог с загрузками. Дамп базы — обычный mysqldump из контейнера базы по расписанию, каталог storage/upload (или именованный volume под него) — обычным архивированием. Если процесс бэкапов на сервере ещё не настроен в принципе, стоит сразу заложить проверку восстановления, а не только создание архивов.
Можно ли использовать SQLite вместо MariaDB/PostgreSQL?
Официально поддерживается, и для одного пользователя это рабочий вариант — меньше движущихся частей. Но при росте истории операций и при параллельном доступе (например, вместе с Data Importer) полноценная СУБД ведёт себя стабильнее под нагрузкой и проще бэкапится инкрементально.
После обновления образа приложение не открывается — что делать в первую очередь?
Смотрите storage/logs/laravel.log внутри контейнера. Чаще всего это недокатившиеся миграции (php artisan migrate --force) или сброс кэша конфигурации, который нужен после смены переменных окружения (php artisan config:clear).
Сколько ресурсов нужно серверу под Firefly III?
Для личного использования хватает скромного VPS — приложение не тяжёлое, основной расход памяти уходит на саму СУБД. Совмещать с другими сайтами на одном сервере вполне нормально, если это уже входит в ваши планы.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →