NetBox: восстановили базу, а фото оборудования пропали
АйТи Фреш
Linux, Docker и DevOps

Восстановили базу NetBox, а фотографии оборудования не появились: что ещё должно быть в резервной копии

Автор: , директор ООО «АйТи-Фреш» · · ~15 мин чтения
Иллюстрация: восстановленный файл фотографии оборудования лежит отдельно от карточки устройства NetBox без связи в базе данных
Файл вернулся на диск, но связь с карточкой устройства хранится не в файле, а в базе — без неё фото не покажется

Если после восстановления NetBox карточки устройств стоят с битой иконкой вместо фото — это почти всегда не повреждённый файл, а рассинхрон между базой PostgreSQL и каталогом media, взятыми в разное время. Разбираю, как NetBox на самом деле связывает фото с оборудованием, что реально входит в резервную копию и как я настраиваю бэкап, чтобы это не повторялось.

Симптом: файл физически на месте, а в карточке устройства — сломанная иконка

Типичная жалоба после аварии: NetBox подняли из бэкапа, все стойки, устройства и IP-адреса на месте, но фотографии оборудования — таблички с серийниками, снимки патч-панелей, фото повреждённого блока питания — не отображаются. Если вы внедряли систему учёта инфраструктуры NetBox именно ради того, чтобы не листать 12 файлов в Excel и не звонить дежурному инженеру «а как там выглядит эта плата», пустые карточки в первый же день после аварии — неприятный сюрприз: вместо документации в момент, когда она особенно нужна, вы получаете список записей без визуального подтверждения.

Первая реакция администратора — проверить, распаковался ли архив с фотографиями. И тут обычно выясняется, что файл на месте: он лежит в каталоге media, его можно открыть напрямую по прямой ссылке на файл, размер совпадает с оригиналом, никакой порчи архива нет. Но в интерфейсе устройства, во вкладке с вложениями, — пусто или битая ссылка. Это сбивает с толку: раз файл цел, почему NetBox его не показывает? Ответ в том, что NetBox не сканирует каталог media в поисках картинок для конкретного устройства — он показывает то, что написано в базе данных, а файл на диске сам по себе для интерфейса ничего не значит.

Как NetBox на самом деле связывает фото с оборудованием

Вложение изображения в NetBox — это не просто файл, а отдельная запись модели ImageAttachment в базе PostgreSQL. У неё есть необязательное поле name (если его не заполнить, интерфейс показывает имя файла) и поле image — собственно файл. Но главное — связь с устройством или другим объектом сделана через generic-связь parent: она не хранит прямую ссылку на конкретную таблицу dcim_device, а опирается на два столбца, object_type и object_id, которые вместе говорят: «это вложение принадлежит объекту такого-то типа с таким-то ID». Файл при этом физически лежит в MEDIA_ROOT — по умолчанию это каталог netbox/media/ относительно корня установки NetBox, внутри него — в подкаталоге image-attachments/ с префиксом вида device_123_ в имени, а относительный путь к нему хранится в самой записи ImageAttachment.

Отсюда следует не самый очевидный вывод: карточка устройства в интерфейсе не «ищет свои фото» на диске, а выполняет запрос к базе — какие записи ImageAttachment ссылаются на эту пару object_type и object_id. Если такой записи нет, NetBox не покажет фото, даже если сам файл образцово лежит на своём законном месте в media и открывается напрямую по URL. И наоборот: если запись в базе есть, а файла по указанному в ней пути нет, вы получите битую иконку — NetBox честно попытается отдать несуществующий файл. Ровно это и произошло в разборе на GitHub (Discussion #1156, netbox-docker): пользователь сначала сделал бэкап каталога media, затем удалил вложение через интерфейс — это действие стирает и запись в базе, и файл, — а после восстановил только файлы из архива media. Файл вернулся на диск и открывался по прямому URL, но в карточке устройства и в разделе Image Attachments вложение так и не появилось: соответствующей записи в базе для него больше не существовало.

Схема связи ImageAttachment в NetBox: запись в PostgreSQL через parent_object_type и parent_object_id указывает на файл в media
Фото в NetBox — это запись в базе, которая указывает на файл, а не сам файл в папке

Что реально входит в резервную копию NetBox

Официальное руководство NetBox по репликации прямо перечисляет два обязательных элемента бэкапа: база данных PostgreSQL и каталог media с загруженными файлами (изображения и другие вложения). Для базы предлагается обычный pg_dump:

pg_dump --username netbox --password --host localhost netbox > netbox.sql

Документация показывает и вариант без данных журнала изменений — но оговаривает, что он предназначен для копии под разработку, где история правок не нужна. Для резервной копии боевого NetBox я его не использую: журнал изменений — это ровно то, по чему потом разбираются, кто и когда удалил или перезалил вложение:

pg_dump --username netbox --password --host localhost --exclude-table-data=core_objectchange netbox > netbox.sql

Для каталога media — обычный архив без специальных инструментов NetBox: tar -czf netbox_media.tar.gz netbox/media/. Восстановление симметрично: psql для базы и распаковка tar для media в тот же каталог, из которого брали бэкап. Одна важная деталь из той же документации: psql по умолчанию продолжает работу после ошибки и всё равно завершается с кодом 0, поэтому восстановление, оборванное на середине, выглядит успешным. Я всегда запускаю его как psql -v ON_ERROR_STOP=1 netbox < netbox.sql и смотрю код возврата. И помните, что дамп отдельной базы не содержит ролей PostgreSQL — пользователя netbox на новом сервере нужно создать заранее.

Ключевое условие, которое в документации подразумевается, но не проговаривается отдельными буквами: оба артефакта — дамп базы и архив media — должны относиться к одному и тому же моменту времени. Это тот же принцип, который я формулирую для баз 1С: бэкап — это не факт наличия файла, а согласованный набор объектов на одну точку времени, а не архив, который можно собирать по кускам, когда удобно. Если дамп базы снят в понедельник, а архив media — в среду, после того как кто-то удалил и заново загрузил пару фотографий, вы восстановите смесь из записей ImageAttachment, для части которых файлов в архиве попросту нет, и файлов в архиве, на которые в базе понедельника ещё не было ссылок (для фото, загруженных во вторник) или уже нет ссылок (для удалённых в тот же вторник).

Резервные копии базы PostgreSQL и каталога media, снятые в разное время или по разным расписаниям, — это не полноценный бэкап NetBox, а гарантированный источник рассинхрона: часть карточек останется без фото, часть файлов в архиве media окажется никому не нужным мусором.
Сравнение двух подходов к бэкапу NetBox: раздельные расписания базы и media против единого скрипта с общей меткой времени
Дамп базы и архив media должны сниматься одним скриптом на одну точку времени — иначе часть фото не восстановится

netbox-docker: точные команды бэкапа и восстановления

Если NetBox развёрнут через официальный netbox-docker, база и media живут в отдельных контейнерах и томах, и команды из общего руководства нужно адаптировать под docker compose. Каталог media в контейнере netbox примонтирован из именованного тома netbox-media-files по пути /opt/netbox/netbox/media — это видно прямо в docker-compose.yml репозитория. Бэкап базы вики netbox-docker рекомендует снимать через контейнер postgres:

docker compose exec -T postgres sh -c 'pg_dump -cU $POSTGRES_USER $POSTGRES_DB' | gzip > db_dump.sql.gz

а media — через контейнер netbox, тем же приёмом с tar в поток:

docker compose exec -T netbox tar c -zf - -C /opt/netbox/netbox/media ./ > media-backup.tar.gz

Флаг -T отключает выделение псевдо-TTY — без него вывод команды через pipe в файл легко ломается лишними управляющими символами.

Восстановление начинается с остановки сервисов, которые пишут в базу и в media, — иначе можно словить блокировки или наложить восстановленные данные поверх новых записей, созданных уже после аварии: docker compose stop netbox netbox-worker. Для установок на NetBox старше 4.4 в этой же команде раньше нужно было останавливать ещё и netbox-housekeeping — отдельный контейнер для фоновой очистки базы; начиная с NetBox 4.4 его функциональность перенесена внутрь самого NetBox как системная задача, и netbox-docker с релиза 3.4.0 этот контейнер из docker-compose.yml убрал. На сегодня (23.09.2026) актуальная стабильная версия — NetBox 4.7.1, так что для свежих установок отдельно останавливать housekeeping не нужно, а вот netbox и netbox-worker — обязательно. Дальше восстанавливаем базу: gunzip -c db_dump.sql.gz | docker compose exec -T postgres sh -c 'psql -U $POSTGRES_USER $POSTGRES_DB' (в вики команда приведена именно так; я добавляю после psql ключ -v ON_ERROR_STOP=1, чтобы ошибка не потерялась), и media: docker compose exec -T netbox tar x -zvf - -C /opt/netbox/netbox/media < media-backup.tar.gz. Учтите: восстановление media перезаписывает файлы, которые уже лежат в каталоге на момент запуска команды, так что запускать его на живой рабочей системе без предварительной остановки сервисов не стоит. После обеих команд — docker compose start netbox netbox-worker, и только тогда сверяем несколько карточек устройств с фото вручную, а не полагаемся, что раз команды отработали без ошибок, всё восстановилось верно.

Кейс «Личный рост Плюс»: разъехавшиеся расписания бэкапа

Клиент — коучинг-центр «Личный рост Плюс», 18 рабочих мест, небольшая серверная с парой коммутаторов, роутером и NAS для записей тренингов. NetBox завели, чтобы не держать в голове, какой патч-корд куда воткнут и как выглядит панель за шкафом, до которой без демонтажа полки не добраться, — в NetBox завели около 30 объектов — коммутаторы, роутер, NAS, патч-панели, ИБП, точки доступа и рабочие станции в серверной, — сфотографировали маркировку, серийные номера и разводку кабелей, в сумме около 70 фотографий на три десятка карточек. Дамп базы PostgreSQL снимался ежедневно по cron в 3:00, а вот бэкап каталога media настраивал другой человек по отдельному заданию — раз в неделю, по воскресеньям, «чтобы не грузить диск лишний раз в будни».

Через месяц эксплуатации сгорел блок питания на хост-сервере с NetBox, диск уцелел, но администратор решил не рисковать и поднять систему из бэкапов на новом железе — благо оба архива, дампа базы и media, регулярно улетали на NAS. Восстановили в четверг: дамп базы был свежий, за среду, а вот архив media — недельной давности, с прошлого воскресенья. За неделю между этими датами админ успел переснять 8 фотографий (заменил размытые снимки серийников на чёткие, той же процедурой — сначала удалить старое вложение через интерфейс, потом загрузить новое) и добавить фото для трёх новых устройств, поставленных на этой неделе. В восстановленной системе для этих 11 карточек либо не было файлов вовсе, либо были старые размытые версии, которые база уже не знала — они превратились в ссылки в никуда, как в примере из обсуждения на GitHub, о котором я писал выше.

Практических потерь оказалось немного — 11 фотографий из 70, — но именно эти 11 карточек описывали новое оборудование и проблемные места, которые чаще всего и спрашивают на удалённой поддержке. Пересъёмка заняла у их сисадмина около полутора часов вечером того же дня: он приехал в офис, обошёл стойку с телефоном и заново загрузил фото по каждой карточке из списка расхождений, который я составил, сверив дату последнего изменения записи ImageAttachment в базе с содержимым архива media. После этого случая расписания бэкапа базы и media объединили в один cron-джоб, который снимает оба архива подряд, без разрыва между ними, и складывает их в одну папку с общей меткой времени в имени — так расхождение по датам физически исключено.

Как я настраиваю бэкап NetBox, чтобы это не повторилось

Правило простое: дамп PostgreSQL и архив media должны сниматься одним скриптом, один за другим, без пауз на другие задачи между ними, и складываться в один каталог с одинаковой меткой времени в имени файла — тогда физически невозможно взять дамп базы за один день, а media за другой. Второе правило — оба архива хранить и переносить как единое целое: если ротация или перенос на внешнее хранилище чистит старые копии, чистить нужно синхронно оба файла с одной меткой времени, а не независимо по своим правилам хранения для базы и для media.

Третье и самое частое упущение — бэкап никогда не проверяли фактическим восстановлением, только фактом, что архив создался без ошибок. Работающий cron и файл нужного размера на NAS — это ещё не доказательство, что систему из этого архива реально можно поднять; я регулярно рекомендую клиентам делать тестовое восстановление бэкапа на отдельном стенде, а не полагаться на факт его наличия — для NetBox это буквально проверка, что после restore на тестовом контейнере фото открываются в интерфейсе, а не только физически лежат в каталоге. И это не специфика NetBox: та же логика ломает восстановление контроллеров домена, когда из двух связанных компонентов системы восстанавливают только один, а второй остаётся в старом состоянии — базу подняли, а с media (или с журналом SYSVOL, если говорить про AD) не сверились.

Чек-лист правильного порядка резервного копирования базы PostgreSQL и каталога media в NetBox
Бэкап без тестового восстановления — это файл на диске, а не гарантия, что фото вернутся

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

Почему фото устройства пропадает в NetBox, если файл физически есть в каталоге media?

Потому что NetBox показывает фото не по факту наличия файла на диске, а по записи модели ImageAttachment в базе PostgreSQL — она через generic-связь (object_type и object_id) указывает, какому устройству принадлежит вложение, и хранит путь к файлу. Если такой записи нет или база и media взяты из бэкапов за разные даты, файл остаётся «ничьим» для интерфейса, даже если открывается напрямую по прямой ссылке.

Что именно нужно бэкапить в NetBox, чтобы не терять фотографии оборудования?

Официальное руководство по репликации требует два элемента: дамп базы PostgreSQL (pg_dump) и каталог media (по умолчанию netbox/media/ относительно корня установки, MEDIA_ROOT). Оба нужно снимать в одном скрипте и хранить как единое целое — раздельные расписания для базы и для media почти гарантированно приведут к рассинхрону.

Как сделать бэкап базы и media в netbox-docker?

База — через контейнер postgres: docker compose exec -T postgres sh -c 'pg_dump -cU $POSTGRES_USER $POSTGRES_DB' | gzip > db_dump.sql.gz. Media — через контейнер netbox: docker compose exec -T netbox tar c -zf - -C /opt/netbox/netbox/media ./ > media-backup.tar.gz. Перед восстановлением остановите netbox и netbox-worker (docker compose stop netbox netbox-worker), восстановите оба архива и запустите сервисы заново.

Нужно ли останавливать контейнер netbox-housekeeping при восстановлении?

Только на установках NetBox старше версии 4.4 — там housekeeping был отдельным контейнером, который стоило остановить вместе с netbox и netbox-worker. Начиная с NetBox 4.4 эта функциональность перенесена внутрь самого NetBox как системная задача, и netbox-docker с релиза 3.4.0 отдельный контейнер housekeeping убрал из docker-compose.yml.

Можно ли восстановить только media без восстановления базы, если нужно вернуть конкретное фото?

Файл физически восстановится и будет открываться по прямой ссылке, но в интерфейсе устройства он не появится — без соответствующей записи ImageAttachment в базе NetBox не знает, какому объекту принадлежит этот файл. Если запись в базе для нужного вложения ещё существует (например, вы восстанавливаете свежее удаление, а не полную аварию), можно обойтись копированием файла по пути, указанному в записи; если записи нет — нужно либо восстановить дамп базы, либо загрузить фото заново через интерфейс.

Как проверить, что бэкап NetBox действительно восстанавливается вместе с фотографиями?

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

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи