Invoice Ninja в Docker Compose: готовый файл
Freshbooks и QuickBooks считают в долларах и требуют карту, которую из России привязать всё сложнее, а зарубежные SaaS для инвойсинга периодически блокируют аккаунты по геопризнаку. Invoice Ninja закрывает эту проблему полностью: open-source система выставления счетов, приёма платежей, учёта клиентов и расходов, которая живёт на вашем сервере и не зависит от чужой политики. Ниже — рабочий docker-compose.yml, который поднимает Invoice Ninja с MySQL и Redis за один docker compose up, плюс нюансы, которые обычно всплывают уже после установки.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое Invoice Ninja и когда он оправдан
Invoice Ninja — PHP-приложение (Laravel) с открытым кодом, которое закрывает типовой набор задач фрилансера или небольшой компании: выставление счетов и смет, повторяющиеся инвойсы по подписке, учёт клиентов и проектов, трекинг времени, приём онлайн-оплат через интеграции с платёжными шлюзами, генерация PDF на кастомных шаблонах. Есть бесплатная self-hosted версия (Community Edition) и платная облачная — нас интересует первая, она без ограничений по числу клиентов и счетов.
Смысл self-host появляется, когда:
- вы выставляете счета клиентам за пределами РФ и не хотите зависеть от блокировки зарубежного сервиса;
- нужно хранить финансовые данные клиентов на своей инфраструктуре, а не в чужом облаке;
- есть 5-10 постоянных клиентов с повторяющимися счетами, и ручная возня в Excel/Google Docs уже надоела;
- важна кастомизация PDF-шаблонов под фирменный стиль — в Invoice Ninja это делается через Blade-шаблоны, а не через ограниченный конструктор SaaS.
Если у вас один клиент и три счёта в год — оверинжиниринг, проще выставлять вручную. Если счетов десятки в месяц — контейнер окупается за первую же неделю сэкономленного времени.
Требования к серверу
Invoice Ninja v5 (Laravel-версия, актуальная на конец августа 2026) вместе с MySQL и Redis в контейнерах требует немного:
| Ресурс | Минимум | Комфортно |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2 GB |
| Диск | 10 GB SSD | 20+ GB (растёт база + вложения) |
| ОС | Ubuntu 24.04 / Debian 12 | тот же |
Для теста хватит младшего VPS. Если параллельно планируете держать почтовый релей для отправки счетов и напоминаний об оплате — берите план с запасом по RAM, MySQL под нагрузкой любит память для буферного пула.
Docker и Docker Compose должны быть установлены заранее — если ставите с нуля, у нас есть отдельный разбор для Ubuntu 24.04 и для Debian 12.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверГотовый docker-compose.yml
Структура: контейнер приложения invoiceninja/invoiceninja, MySQL 8 для данных, Redis для очередей и кэша. Создайте директорию проекта и файл .env рядом с compose-файлом.
mkdir -p ~/invoiceninja/{data,mysql}
cd ~/invoiceninja
Файл .env:
# База
DB_DATABASE=ninja
DB_USERNAME=ninja
DB_PASSWORD=замените_на_сложный_пароль
MYSQL_ROOT_PASSWORD=замените_на_другой_сложный_пароль
# Приложение
APP_URL=https://invoice.your-domain.tld
APP_KEY=
REQUIRE_HTTPS=true
# Почта (пример для внешнего SMTP)
MAIL_MAILER=smtp
MAIL_HOST=smtp.your-provider.tld
MAIL_PORT=587
MAIL_USERNAME=invoice@your-domain.tld
MAIL_PASSWORD=пароль_почты
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=invoice@your-domain.tld
MAIL_FROM_NAME="Ваша компания"
Сам docker-compose.yml:
version: "3.8"
services:
app:
image: invoiceninja/invoiceninja:5
restart: unless-stopped
depends_on:
- db
- redis
ports:
- "127.0.0.1:8080:80"
environment:
APP_URL: ${APP_URL}
APP_KEY: ${APP_KEY}
APP_DEBUG: "false"
REQUIRE_HTTPS: ${REQUIRE_HTTPS}
DB_HOST: db
DB_DATABASE: ${DB_DATABASE}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
CACHE_DRIVER: redis
QUEUE_CONNECTION: redis
SESSION_DRIVER: redis
MAIL_MAILER: ${MAIL_MAILER}
MAIL_HOST: ${MAIL_HOST}
MAIL_PORT: ${MAIL_PORT}
MAIL_USERNAME: ${MAIL_USERNAME}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_ENCRYPTION: ${MAIL_ENCRYPTION}
MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
MAIL_FROM_NAME: ${MAIL_FROM_NAME}
volumes:
- ./data/public:/var/www/app/public/storage
- ./data/storage:/var/www/app/storage
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
command: --default-authentication-plugin=mysql_native_password
volumes:
- ./mysql:/var/lib/mysql
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
volumes:
redis-data:
Ключевой момент: порт приложения проброшен только на 127.0.0.1:8080, наружу контейнер не торчит напрямую — HTTPS и приём внешних подключений отдаём reverse-proxy (об этом ниже). Так безопаснее и удобнее, если на сервере уже крутятся другие сайты.
Сгенерируйте APP_KEY до первого запуска — без него Laravel не стартует корректно:
docker run --rm invoiceninja/invoiceninja:5 php artisan key:generate --show
Вставьте полученную строку вида base64:... в .env как значение APP_KEY, затем поднимайте стек:
docker compose up -d
docker compose logs -f app
Первый старт создаёт таблицы миграциями — это может занять минуту-полторы, дождитесь строчки о завершении миграций в логах, прежде чем открывать приложение в браузере.
HTTPS и подключение к домену
Invoice Ninja работает с финансовыми данными клиентов — HTTP без шифрования тут не вариант даже для теста. Проще всего поставить перед контейнером Caddy или Traefik с автоматическим Let's Encrypt.
Минимальный Caddyfile, если Caddy уже стоит на сервере как общий reverse-proxy:
invoice.your-domain.tld {
reverse_proxy 127.0.0.1:8080
}
Caddy сам выпустит и обновит сертификат. Если вы ещё не настраивали автоматический HTTPS на сервере, у нас есть разбор с частыми граблями — Caddy с авто-SSL: типичные ошибки и решения. Кто предпочитает Traefik с его провайдером Docker — смотрите Traefik как reverse proxy для Docker.
Не забудьте прописать A-запись домена invoice.your-domain.tld на IP сервера до попытки выпустить сертификат — иначе ACME-проверка не пройдёт.
Почта: без неё Invoice Ninja бесполезен наполовину
Половина смысла системы — автоматическая отправка счетов и напоминаний об оплате клиентам на почту. Если письма не уходят или падают в спам, вы теряете главное преимущество перед ручным выставлением в PDF.
Варианты:
- Внешний SMTP-релей (Mailgun, SendGrid, Postmark, Yandex почта для домена) — проще всего, репутация IP не ваша забота, настраивается через переменные
MAIL_*из примера выше. - Собственный почтовый сервер на том же или соседнем сервере — если у вас уже развёрнут Mailcow или похожее решение, можно использовать его как SMTP-relay для Invoice Ninja.
- Прямая отправка с VPS — рабочий, но рискованный путь: у многих хостеров IP новых VPS не имеют репутации, и письма с высокой вероятностью улетают в спам без настроенных SPF/DKIM/DMARC.
Практический совет: для B2B-инвойсинга внешний транзакционный SMTP почти всегда надёжнее самостоятельного почтового сервера — доставляемость там уже выстроена провайдером, вам остаётся только подтвердить домен через DNS-записи.
Бэкапы: что теряете при сбое и как не потерять
В контейнерах два места, где живут ваши данные: база MySQL (клиенты, счета, платежи) и volume data/storage (вложения, сгенерированные PDF, логотипы). Потеря любого из них — это потеря истории выставленных счетов, что для бухгалтерии критично.
Скрипт бэкапа базы и вложений одним архивом:
#!/bin/bash
set -e
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/root/backups/invoiceninja
mkdir -p "$BACKUP_DIR"
cd ~/invoiceninja
docker compose exec -T db mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" ninja > "$BACKUP_DIR/db_$DATE.sql"
tar czf "$BACKUP_DIR/storage_$DATE.tar.gz" ./data
# храним последние 14 бэкапов
ls -1t "$BACKUP_DIR"/db_*.sql | tail -n +15 | xargs -r rm
ls -1t "$BACKUP_DIR"/storage_*.tar.gz | tail -n +15 | xargs -r rm
Положите в cron на ежедневный запуск (crontab -e):
0 3 * * * /root/backup-invoiceninja.sh >> /var/log/invoiceninja-backup.log 2>&1
Локальный бэкап на том же диске не защищает от отказа самого сервера — копируйте архивы на отдельное хранилище (S3-совместимое, другой сервер, rsync). Если хотите более системный подход с дедупликацией и шифрованием, посмотрите BorgBackup в Docker Compose — годится и для этого стека. Общие грабли с бэкапом Docker-томов разобраны отдельно — бэкап Docker volume: частые ошибки и решения.
Обновление версии без потери данных
Invoice Ninja выпускает обновления регулярно, в том числе с закрытием уязвимостей — финансовое приложение, смотрящее в интернет, обновлять нужно оперативно, а не по остаточному принципу.
Порядок безопасного обновления:
cd ~/invoiceninja
# 1. Бэкап перед любым обновлением — обязательно
./backup-invoiceninja.sh
# 2. Тянем новый образ (тег :5 подхватывает минорные обновления автоматически,
# для контроля версий лучше зафиксировать конкретный тег, например :5.10)
docker compose pull app
# 3. Пересоздаём контейнер приложения
docker compose up -d app
# 4. Смотрим логи — миграции применяются автоматически при старте
docker compose logs -f app
Если после обновления что-то пошло не так — откат до предыдущего образа и восстановление базы из свежего бэкапа занимает пару минут, поэтому шаг 1 пропускать нельзя никогда.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Invoice Ninja поддерживает приём онлайн-оплат от клиентов?
Да, через интеграции с платёжными шлюзами (Stripe, PayPal и другие) — настраивается в разделе Settings → Online Payments. Учтите, что доступность конкретного шлюза зависит от юрисдикции и валюты, часть западных провайдеров ограничивает работу с российскими юрлицами — уточняйте это до интеграции.
Можно ли перенести данные из облачной версии Invoice Ninja в self-hosted?
Да, через встроенный экспорт компании (Settings → Account Management → Export/Import) — экспортируется JSON-архив со всеми клиентами, счетами и настройками, который импортируется в свежую self-hosted установку.
Нужен ли отдельный домен под Invoice Ninja или можно на поддомене основного сайта?
Поддомен (invoice.your-domain.tld) — обычная и рекомендуемая практика, никаких технических ограничений нет, сертификат Let's Encrypt выпускается на поддомен так же просто.
Что делать, если после docker compose up приложение отдаёт 500 ошибку?
В 90% случаев причина — не сгенерированный или неверно вставленный APP_KEY, либо MySQL ещё не успел подняться к моменту первого обращения приложения. Проверьте docker compose logs app и docker compose logs db, при необходимости перезапустите app после того как база полностью стартовала.
Сколько ресурсов реально ест Invoice Ninja при 20-30 активных клиентах?
Ориентировочно укладывается в 1-1.5 GB RAM для всего стека (приложение + MySQL + Redis) при умеренной нагрузке — точные цифры зависят от объёма вложений и частоты генерации PDF, поэтому закладывайте запас, а не работайте впритык к лимиту.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →