Эксплуатация Odoo Community: бэкапы, обновления, безопасность и мониторинг — регламент, по которому мы обслуживаем клиентов

Сервер Odoo под защитным щитом с орбитами бэкапов, замка и графика мониторинга

Чем грозит «поставили и забыли»: три отказа из нашей практики

Меня зовут Евгений Семёнов, я техдиректор ITfresh. В предыдущих статьях серии мы разобрали, что умеет Odoo Community как ERP, развернули её на сервере и прикрутили российскую локализацию. Сегодня — про то, о чём интеграторы обычно молчат: что происходит с инсталляцией через полгода-год после запуска, если её никто не обслуживает.

Когда в Odoo живут только контакты и сделки — потеря данных неприятна. Когда там склад, закупки, производственные заказы и вся цепочка «заказ клиента → резерв → отгрузка → счёт» — простой ERP на день останавливает отгрузки физически: кладовщик не знает, что собирать. Три реальных отказа, с которыми к нам приходили на сопровождение:

  • Диск съел filestore. Оптовик, около 30 рабочих мест. К каждой приёмке сканируют накладную и УПД, к каждой карточке товара — 3–5 фотографий, плюс ЭДО-архив PDF. Каталог вложений вырос примерно с 5 до 70 ГБ за полтора года, диск на 100 ГБ кончился, PostgreSQL не смог записать WAL и остановился. ERP лежала полдня, отгрузки оформляли на бумаге.
  • База погибла, бэкапа не было. «Хостер же делает копии» — делал, снапшот раз в неделю, целостность которого никто не проверял. После сбоя диска восстановился снапшот шестидневной давности: минус шесть дней складских перемещений, приёмок и счетов. Пересобирали остатки инвентаризацией всего склада.
  • Открытый менеджер баз данных. Страница /web/database/manager доступна из интернета, мастер-пароль — дефолтный admin. Любой, кто дошёл до неё сканером, может скачать полный дамп базы со всеми ценами и контрагентами или просто удалить базу. Боты перебирают типовые пути Odoo постоянно — мы видим это в логах каждого клиентского сервера.

Вывод из всех трёх историй один: Odoo — надёжный софт, но это продакшен-сервис уровня почты или 1С. Ему нужен регламент: что делаем каждый день, что раз в неделю, что раз в месяц и что при выходе нового релиза. Ниже — регламент, по которому мы в ITfresh сопровождаем клиентские инсталляции. Забирайте и пользуйтесь.

Бэкапы правильно: три слоя вместо одного

Слой 1–3: база, filestore, снапшот VM

Главная особенность Odoo, о которую спотыкаются, — вложения не лежат в базе данных. PDF накладных, фото товаров, отчёты о приёмке хранятся файлами в каталоге filestore (обычно /var/lib/odoo/.local/share/Odoo/filestore/имя_базы или /var/lib/odoo/filestore в Docker-томе). Дамп PostgreSQL без filestore — это ERP, в которой документы открываются, а приложенные к ним файлы дают 404.

Грабля номер один: pg_dump не содержит вложений. Проверьте прямо сейчас, попадает ли каталог filestore в вашу схему резервного копирования. В ERP-инсталляции со складом он растёт быстрее базы в разы — именно он в итоге занимает десятки гигабайт.

Поэтому слоёв три, и каждый закрывает свой класс аварий:

  • pg_dump ежедневно, ночью, в custom-формате (-Fc — сжатие и выборочное восстановление). Ротация: 14 суточных копий на самом сервере, 30 суток на внешнем хранилище. Закрывает логические аварии: кривой модуль, ошибочное массовое удаление, неудачная миграция.
  • rsync каталога filestore той же ночью. Мы гоним его инкрементально с жёсткими ссылками (--link-dest): каждая ночная копия выглядит полной, а места ест только на новые файлы — для 70-гигабайтного filestore это минуты, а не часы.
  • Снапшот виртуальной машины еженедельно плюс обязательно перед каждым обновлением. Закрывает аварии уровня системы: погибшая ОС, неудачный апгрейд пакетов, шифровальщик. Снапшот — не замена дампам: он один, он на той же площадке и его нельзя открыть выборочно.
Схема трёх слоёв резервного копирования Odoo: база, filestore и снапшот VM с выгрузкой на внешнее хранилище
Три слоя бэкапа: pg_dump + filestore каждую ночь уходят на внешнюю площадку, снапшот VM остаётся у гипервизора

Скрипт: ночной бэкап с выгрузкой на внешнюю площадку

Копия, лежащая рядом с сервером, погибнет вместе с ним. Поэтому финальный шаг скрипта — выгрузка на независимое хранилище: S3-совместимый бакет российского провайдера или FTP на площадке в другом ЦОД (у нас — собственные серверы в ЦОД МТС). Рабочий скелет, который мы кладём клиентам в cron:

#!/bin/bash
set -e
DB="erp_prod"
FS="/var/lib/odoo/.local/share/Odoo/filestore/$DB"
DST="/backup/odoo"
TODAY=$(date +%F)
YESTERDAY=$(date -d yesterday +%F)

# 1. Дамп базы в custom-формате
mkdir -p "$DST/$TODAY"
sudo -u postgres pg_dump -Fc "$DB" -f "$DST/$TODAY/$DB.dump"

# 2. Инкрементальная копия filestore (hardlink на вчерашнюю)
rsync -a --delete --link-dest="$DST/$YESTERDAY/filestore" \
      "$FS/" "$DST/$TODAY/filestore/"

# 3. Выгрузка наружу: rclone в S3-совместимый бакет
rclone sync "$DST/$TODAY" "s3-backup:erp-backup/$TODAY" \
      --transfers 8 --s3-chunk-size 64M

# 4. Ротация: 14 суток локально, 30 — в бакете
find "$DST" -maxdepth 1 -type d -mtime +14 -exec rm -rf {} \;
rclone delete "s3-backup:erp-backup" --min-age 30d --rmdirs

# 5. Отчёт в мониторинг (пустой файл-маркер с датой)
touch /var/run/odoo-backup-ok

Маркер из последней строки проверяет Zabbix: если файлу больше 26 часов — алерт «бэкап не отработал». Молча сломавшийся бэкап хуже отсутствующего: он даёт ложное чувство защищённости.

Бэкап не существует, пока не восстановлен

Раз в месяц мы разворачиваем последний дамп на стейджинг-машине и смотрим не «файл скачался», а «ERP работает»: база поднялась, остатки по складам совпадают с продом на момент дампа, вложения к последним приёмкам открываются, отчёт по закупкам строится. На стейджинге обязательно выполняем нейтрализацию базы (о команде — в разделе про аварии), чтобы копия не начала слать письма контрагентам и гонять планировщики закупок. Пятнадцать минут в месяц — и в день настоящей аварии вы восстанавливаетесь по отработанной процедуре, а не изобретаете её под крики из отдела продаж.

Обновления: минорные — рутина, мажорные — мини-проект

Минорные: окно 20 минут по чек-листу

Внутри мажорной версии Odoo регулярно выпускает исправления — багфиксы и заплатки безопасности без изменения схемы данных. Для установки из пакетов это apt update && apt upgrade odoo, для Docker — свежий образ тега своей версии. Порядок у нас жёсткий и всегда одинаковый:

  1. Снапшот VM (минута, но именно он превращает неудачное обновление в нестрашное).
  2. Внеочередной запуск бэкап-скрипта.
  3. docker compose pull && docker compose up -d — или apt-обновление с рестартом службы.
  4. Смоук-тест три минуты: вход, создать черновик заказа, открыть складские остатки, проверить лог на трейсбеки.

Окно — вечер буднего дня после отгрузок, простой две-три минуты на рестарт. Делаем раз в 3–4 недели; заплатки безопасности — вне очереди.

Мажорные (18 → 19): почему это отдельный проект

Мажорный релиз меняет схему базы, и просто «подсунуть» базу 18-й версии коду 19-й нельзя. Для Community-редакции миграцию делают через OpenUpgrade — открытый инструмент сообщества OCA, который прогоняет базу через скрипты преобразования версия-в-версию. И тут ERP-инсталляция сложнее «голой» CRM на порядок:

  • каждый сторонний модуль OCA (склад, закупки, российская локализация, коннектор с 1С) должен существовать в ветке под новую версию — а порты модулей выходят через месяцы после релиза;
  • кастомные поля и правила пополнения запасов надо проверять руками: изменения в модели склада между версиями регулярно ломают доработки;
  • прогон на стейджинге обязателен: полная копия базы + filestore, миграция, неделя-две параллельной проверки ключевых сценариев людьми, которые в системе работают.

Бюджетируйте мажорный апгрейд как проект на 2–4 недели календарного времени, а не как «обновимся в субботу».

Наша политика версий

Odoo выпускает мажорный релиз раз в год осенью (19-я вышла осенью 2025-го) и поддерживает три последних мажора — сейчас это 17, 18 и 19. Наше правило: прод отстаёт от свежего мажора на 3–6 месяцев. За это время экосистема OCA догоняет релиз портами модулей, а первые минорные заплатки выгребают детские болезни. Обновляться реже, чем раз в три года, тоже нельзя: версия выпадает из поддержки, перестаёт получать заплатки безопасности, а прыжок через два-три мажора по цепочке OpenUpgrade мучительнее трёх плановых апгрейдов вместе взятых.

Безопасность инсталляции: закрываем то, что ломают ботами

ERP хранит закупочные цены, маржу, базу поставщиков и клиентов — то, за чем приходят целенаправленно. Минимальный обязательный набор, который мы применяем на каждом сервере:

  • list_db = False и сильный admin_passwd в odoo.conf. Первое прячет список баз и сам менеджер БД, второе — мастер-пароль на операции с базами: 24+ случайных символов из менеджера паролей, а не название компании.
  • Менеджер баз — только со своих IP. Даже со включённым list_db = False мы дополнительно режем /web/database/ на уровне nginx: allow для офисного IP и VPN, deny all для остальных. Двойной забор дешевле одного инцидента.
  • nginx + TLS с автопродлением. Odoo слушает 8069 только на 127.0.0.1, наружу — nginx с сертификатом Let's Encrypt. Грабля, на которую наступают постоянно: certbot в режиме standalone пытается сам занять порт 80, который уже занят nginx, — и продление молча падает. Используйте certbot --nginx (авторизация через работающий веб-сервер) и проверяйте certbot renew --dry-run.
  • fail2ban на страницу логина. Odoo пишет неудачные входы в свой лог — по этой строке fail2ban банит перебор паролей на уровне фаервола. Правило простое: 5 промахов за 10 минут — бан на час.
  • 2FA для пользователей. Встроенная TOTP-двухфакторка включается в настройках без сторонних модулей. Обязательна для админов и всех, кто ходит в ERP извне офиса.
  • Права по группам, а не «всем всё». Кладовщику — склад без закупочных цен, менеджеру — продажи без настроек, бухгалтеру — учёт. Раз в квартал сверяем список активных пользователей с кадрами: учётки уволенных — самый недооценённый вектор утечки.
# /etc/fail2ban/filter.d/odoo-login.conf
[Definition]
failregex = ^.*\sodoo\.addons\.base\.models\.res_users:\s+Login failed for db:.* login:.* from <HOST>

# /etc/fail2ban/jail.d/odoo.conf
[odoo-login]
enabled  = true
port     = http,https
filter   = odoo-login
logpath  = /var/log/odoo/odoo-server.log
maxretry = 5
findtime = 600
bantime  = 3600

Мониторинг и логи: узнать о проблеме раньше клиента

Цель мониторинга — чтобы о проблеме первым узнал инженер, а не кладовщик, у которого не открывается приёмка. Мы вешаем на каждую инсталляцию связку «Zabbix + Telegram-алерты» (подойдёт и любой uptime-сервис, если Zabbix для вас избыточен) и смотрим пять вещей:

  • Доступность и время ответа HTTP. Веб-сценарий дёргает /web/login раз в минуту. Алерт не только на «лежит», но и на деградацию: ответ дольше 3 секунд три проверки подряд — значит, база пухнет или воркеры захлебнулись, и через неделю это станет простоем.
  • Место на диске — с прогнозом. Не «осталось меньше 10%», а «при текущей скорости роста filestore диск кончится через N дней». Zabbix умеет предиктивные триггеры из коробки; история с оптовиком из первого раздела не случилась бы.
  • Длинные транзакции PostgreSQL. Зависшая транзакция блокирует autovacuum и коллег: складской отчёт, который держит транзакцию 20 минут, тормозит всю ERP. Запрос для агента мониторинга:
    SELECT pid, now() - xact_start AS dur, state, query
    FROM pg_stat_activity
    WHERE xact_start IS NOT NULL
      AND now() - xact_start > interval '5 minutes';
  • Ошибки cron-задач в логе Odoo. Самое коварное в ERP: планировщики падают беззвучно. Упавшее правило пополнения запасов (reordering rules) не создаёт черновики закупок — и об этом узнают через две недели, когда склад пуст, а поставка едет 30 дней. Грепаем лог на ERROR и Traceback рядом с odoo.addons.base.models.ir_cron — любое совпадение уходит алертом.
  • Маркер бэкапа — тот самый файл из скрипта выше: старше 26 часов — алерт.

Практика: алертов должно быть мало и все — по делу. Если канал в Telegram сыпет по 20 сообщений в день, его перестают читать за неделю, и настоящая авария тонет в шуме. Начните с пяти проверок выше — они закрывают 90% реальных инцидентов Odoo.

Производительность в бою: когда отчёт по остаткам строится 30 секунд

Деградация ERP наступает не скачком, а ползком: через год работы отчёт по остаткам, который открывался за 2 секунды, строится 30. Таблицы складских перемещений (stock_move, stock_move_line) — самые быстрорастущие в базе: каждая отгрузка и приёмка рождает десятки строк. Что мы делаем в порядке приоритета:

  • Настраиваем autovacuum агрессивнее дефолта для горячих таблиц. Стандартные пороги PostgreSQL рассчитаны на средние нагрузки; на таблице в несколько миллионов строк перемещений мёртвые кортежи копятся быстрее, чем дефолтный autovacuum их вычищает, — раздувается и таблица, и индексы. Снижаем autovacuum_vacuum_scale_factor до 0.02 точечно через ALTER TABLE, а после массовых чисток запускаем ручной VACUUM ANALYZE в ночное окно.
  • Индексы на кастомные поля. Каждое добавленное поле, по которому фильтруют список или строят отчёт («наш артикул поставщика», «зона склада»), должно иметь индекс — в Odoo это флаг index=True на поле. Ищем кандидатов по pg_stat_statements: медленные запросы с Seq Scan по большим таблицам.
  • Лимиты воркеров по формуле. Рабочая отправная точка — workers = CPU×2 + 1, при 4 ядрах это 9; плюс limit_memory_soft/limit_memory_hard, чтобы разжиревший от тяжёлого отчёта воркер перезапускался сам, а не утаскивал сервер в своп. Мало воркеров — очередь запросов, много — драка за память.

Когда пора переезжать с 4 на 8 GB RAM — не по ощущениям, а по метрикам-триггерам: своп используется постоянно (не пики, а фон), в логе появляются перезапуски воркеров по достижении limit_memory_hard чаще нескольких раз в день, PostgreSQL не может держать рабочий набор в кэше (shared_buffers упирается, попадание в кэш падает ниже ~95%). Для типовой инсталляции на 20–40 активных пользователей со складом 8 GB — комфортная норма, 4 GB — стартовый минимум, который заканчивается через год роста базы.

Регламент сопровождения ITfresh: таблица, которую можно забрать

Всё перечисленное складывается в один лист. Это наш внутренний шаблон регламента для клиентских Odoo — вычеркните лишнее, впишите свои имена серверов и пользуйтесь:

ПериодичностьОперацииКто/как
Ежедневноpg_dump + rsync filestore + выгрузка на внешнее хранилище; контроль маркера бэкапа; разбор алертов мониторинга; просмотр лога на новые ERROR/TracebackАвтоматика; инженер — только по алерту
ЕженедельноСнапшот VM; обновления безопасности ОС (unattended-upgrades + контроль); динамика диска и роста filestore; проверка успешности cron-задач Odoo (закупки, рассылки, курсы валют); certbot renew --dry-runИнженер, 20–30 минут
ЕжемесячноТестовое восстановление дампа на стейджинг с нейтрализацией; минорное обновление Odoo по чек-листу; VACUUM ANALYZE горячих таблиц и просмотр pg_stat_statements; аудит пользователей и прав (уволенные, лишние группы); просмотр банов fail2banИнженер, 2–3 часа
На мажорный релизРевизия совместимости OCA-модулей и кастомизаций; полный клон прод-базы на стейджинг; миграция OpenUpgrade; 1–2 недели параллельной проверки ключевыми пользователями; плановое окно переключения с точкой отката (снапшот + дамп)Проект 2–4 недели, через 3–6 мес после релиза
Инфографика регламента обслуживания Odoo в четыре колонки: ежедневно, еженедельно, ежемесячно, на релиз
Регламент одним взглядом: автоматика — каждый день, руки инженера — от 20 минут в неделю

Суммарно живого времени инженера — порядка 4–6 часов в месяц на инсталляцию. Это и есть цена того, чтобы ERP со складом «просто работала» годами.

Что делать при аварии: план восстановления с командами

Сценарий: сервер погиб (диск, гипервизор, шифровальщик — неважно). Целевой RTO для бизнеса до 50 рабочих мест — 2–4 часа, RPO — сутки (ночной бэкап). Порядок действий, отработанный на ежемесячных тест-ресторах:

  1. Оценка (10 минут). Если жив гипервизор — откат на снапшот и накат свежего дампа поверх быстрее всего. Если площадка потеряна целиком — поднимаем новую VM из шаблона (Odoo + PostgreSQL + nginx у нас в стандартном образе).
  2. Забираем последний бэкап с внешнего хранилища и восстанавливаем базу:
# забрать последний комплект из бакета
rclone copy "s3-backup:erp-backup/2026-07-29" /restore/

# пересоздать базу и накатить дамп
sudo -u postgres dropdb --if-exists erp_prod
sudo -u postgres createdb -O odoo erp_prod
sudo -u postgres pg_restore -d erp_prod --no-owner --role=odoo \
     -j 4 /restore/erp_prod.dump

# вернуть filestore на место и раздать права
mkdir -p /var/lib/odoo/.local/share/Odoo/filestore
cp -a /restore/filestore \
      /var/lib/odoo/.local/share/Odoo/filestore/erp_prod
chown -R odoo:odoo /var/lib/odoo

systemctl start odoo
  1. Проверка перед открытием доступа: вход админом, складские остатки на вчерашний вечер, вложения к последним приёмкам открываются, cron-задачи в статусе «готово к запуску».
  2. Переключение DNS/проброса на новый сервер, объявление пользователям: «работаем, данные на утро, документы за сегодня вносим повторно».

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

# отключить в копии почтовые серверы, планировщики и внешние вызовы
odoo-bin neutralize -d erp_staging

Запомните главное: RTO в 2–4 часа достижим только потому, что процедура прогонялась ежемесячно. Первое в жизни восстановление, выполняемое в панике по статье из интернета, занимает день-два — проверено чужими авариями, которые мы разгребали.

Если держать этот регламент самим некому — мы возьмём вашу Odoo на сопровождение: бэкапы с ежемесячным тест-рестором, обновления, мониторинг с реакцией и восстановление при авариях на наших серверах в ЦОД МТС. Напишите в Telegram @ITfresh_Boss или позвоните +7 903 729-62-41 — за 30 минут разговора скажем честно, что у вас уже хорошо, а что грозит историей из первого раздела.

Сопровождение Odoo и ERP под ключ

ITfresh — IT-аутсорсинг для компаний до 50 рабочих мест: 15+ лет практики, собственные серверы в ЦОД МТС. Возьмём вашу Odoo на регламент: бэкапы с тест-рестором, обновления, мониторинг 24/7 и восстановление при авариях

✈️ Telegram @ITfresh_Boss 📞 +7 903 729-62-41
#Odoo #OdooCommunity #бэкапы #ERP #PostgreSQL #мониторинг #безопасность #сопровождение

Читайте также на itfresh.ru:

Комментарии 0

Оставить комментарий

загрузка...

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.