Snipe-IT в Docker за один день: наш пошаговый регламент внедрения

Изометрическая схема развёртывания Snipe-IT: сервер с контейнерами приложения, MariaDB и Redis за щитом nginx с TLS, рядом ноутбук админа и смартфон со сканером QR

Что понадобится: требования и выбор площадки

В обзорной статье серии я рассказывал, почему мы в ITfresh перевели учёт техники клиентов с Excel на Snipe-IT. Сегодня — практика: наш внутренний регламент развёртывания, по которому инженер поднимает систему с нуля за один рабочий день. Не «за 15 минут», как обещают ролики на YouTube, — за день, но зато с HTTPS, русским интерфейсом, заполненными справочниками, наклейками и первым подписанным актом выдачи. Разница примерно как между «машина завелась» и «машина поставлена на учёт и застрахована».

Начнём с железа, и здесь хорошая новость: Snipe-IT — одно из самых нетребовательных приложений в нашем стеке. Это PHP-приложение на Laravel, которое бо́льшую часть времени просто ждёт запросов. Для компании до 50 рабочих мест — а это сотни две-три активов с лицензиями и расходниками — за глаза хватает виртуалки с 2 vCPU и 2–4 ГБ RAM. Диска считайте 20–30 ГБ: сама система с базой занимает копейки, место со временем съедают фотографии активов и сканы документов, которые сотрудники прикладывают к карточкам. У нас есть инсталляции, которые третий год живут на минимальном тарифе VPS и ни разу не упирались в ресурсы.

Где размещать — вопрос политики, а не техники. Мы предлагаем клиентам два варианта. Первый — виртуалка на наших серверах в дата-центре МТС: мы отвечаем за гипервизор, бэкапы и мониторинг, клиент получает готовый сервис. Второй — VPS или виртуалка самого клиента, если у него есть принципиальная позиция «все данные у нас». Snipe-IT одинаково хорошо живёт в обоих сценариях; важно лишь, чтобы площадка была под чьим-то присмотром, потому что реестр всей техники компании — не тот сервис, который бросают без бэкапов.

До начала работ готовим три вещи, из-за которых чаще всего теряется время посреди внедрения:

  • DNS-запись. Заранее заводим A-запись вида assets.company.ru на IP будущего сервера. Пока TTL истекает и запись разъезжается по резолверам, мы спокойно ставим Docker — к моменту выпуска сертификата всё уже работает.
  • Почтовый ящик для уведомлений. Snipe-IT шлёт письма при выдаче техники, о истекающих гарантиях и лицензиях. Нужен SMTP-доступ: отдельный ящик вида assets@company.ru на корпоративной почте. Просить у клиента пароль от общего ящика «в последний момент» — верный способ потерять полдня.
  • ОС на сервере. Мы ставим Ubuntu 24.04 LTS или Debian 12 — без разницы, Docker уравнивает всё. Из пакетов нужны только docker с плагином compose, nginx и certbot.
Версии на момент написания (август 2026): актуальный релиз Snipe-IT — v8.6.3 от 15 июня 2026 года, ветка v8 живёт на Laravel 12 и требует PHP не ниже 8.2. Прелесть Docker-варианта в том, что версии PHP и всех расширений вас не касаются: они запечены в официальный образ snipe/snipe-it, и это единственный образ, который поддерживают сами разработчики. Сторонние сборки с Docker Hub мы в боевых внедрениях не используем принципиально.

Docker Compose: разбираем стек по контейнерам

Наш типовой стек — три контейнера: само приложение, MariaDB и Redis. База — понятно зачем; Redis держит кэш и сессии, чтобы не гонять их через файлы. Вот docker-compose.yml, с которого мы начинаем каждое внедрение (лежит в /opt/snipeit вместе с .env):

services:
  snipeit:
    image: snipe/snipe-it:v8.6.3
    restart: unless-stopped
    ports:
      - "127.0.0.1:8000:80"
    env_file: .env
    volumes:
      - snipe-data:/var/lib/snipeit
    depends_on:
      - db
      - redis

  db:
    image: mariadb:11.4
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "смените-меня-тоже"
      MYSQL_DATABASE: snipeit
      MYSQL_USER: snipeit
      MYSQL_PASSWORD: "смените-меня"
    volumes:
      - snipe-db:/var/lib/mysql

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  snipe-data:
  snipe-db:

Три решения в этом файле — не случайность, а выводы из наших граблей:

  • Версия образа прибита гвоздями (v8.6.3, а не latest). Релизы у проекта выходят каждые несколько недель, и «плавающий» тег означает, что случайный docker compose pull посреди рабочего дня обновит вам систему без спроса. Обновляемся мы только осознанно — об этом будет отдельная статья про эксплуатацию.
  • Порт слушает только 127.0.0.1. Наружу смотрит nginx с TLS, а голый HTTP приложения из интернета недоступен. Забытая публикация порта на 0.0.0.0 — классика, из-за которой «внутренние» панели находятся поисковиками Shodan.
  • Именованные тома вместо bind-mount. В snipe-data живут загруженные файлы и ключи, в snipe-db — база. Это ровно то, что попадает в бэкап.

Теперь .env — файл, в котором сосредоточены все настройки приложения. Полный шаблон есть в документации, я покажу критичные строки:

APP_ENV=production
APP_DEBUG=false
APP_URL=https://assets.company.ru
APP_TIMEZONE=Europe/Moscow
APP_KEY=base64:...   # см. ниже

MYSQL_PORT_3306_TCP_ADDR=db
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_DATABASE=snipeit
MYSQL_USER=snipeit
MYSQL_PASSWORD=смените-меня

REDIS_HOST=redis
REDIS_PORT=6379
CACHE_DRIVER=redis
SESSION_DRIVER=redis

Про APP_KEY скажу отдельно и громко, потому что это грабля номер один всех самостоятельных внедрений. Этим ключом Laravel шифрует чувствительные данные в базе — в том числе значения зашифрованных кастомных полей и остатки сессий. Генерируется он один раз, перед первым запуском:

docker compose run --rm snipeit php artisan key:generate --show

Команда печатает строку вида base64:xxxx... — её вписываем в .env и тут же кладём копию в парольный менеджер. У нас это Vaultwarden, запись заводится в момент генерации, а не «потом». Потеряете ключ — база останется при вас, но всё зашифрованное в ней превратится в тыкву, и никакой бэкап не спасёт: бэкап без APP_KEY для шифрованных полей бесполезен.

Вторая грабля — правки .env. Docker передаёт переменные окружения в момент создания контейнера, поэтому после любого изменения .env нужен именно docker compose up -d (пересоздание), а не docker compose restart. Рестарт перечитывать файл не будет — вы поменяли пароль SMTP, перезапустили контейнер, а письма всё равно не идут, и полчаса жизни уходят на «почему».

Запускаем: docker compose up -d. Через минуту-полторы (первый старт накатывает миграции базы) по адресу http://127.0.0.1:8000 на сервере уже отвечает приложение. Наружу его пока не видно — и это правильно, сначала TLS.

TLS и reverse-proxy: nginx впереди контейнера

Вариант «опубликовать порт 8000 наружу и жить так» мы не рассматриваем: реестр техники со всеми серийниками, локациями и фамилиями — это карта вашей инфраструктуры, и гулять по интернету в открытом виде она не должна. Впереди контейнера встаёт nginx, сертификат — бесплатный Let's Encrypt. Конфиг тривиальный:

server {
    server_name assets.company.ru;
    listen 80;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
        client_max_body_size 20m;
    }
}

Дальше certbot --nginx -d assets.company.ru — и certbot сам дописывает секцию с TLS и редиректом с 80-го порта. Обратите внимание на client_max_body_size: по умолчанию nginx режет загрузки крупнее мегабайта, а сотрудники будут прикладывать к карточкам фотографии техники с телефона по 5–8 МБ.

Чтобы приложение корректно жило за прокси, в .env добавляем две строки и пересоздаём контейнер:

APP_TRUSTED_PROXIES=REMOTE_ADDR
SECURE_COOKIES=true

И главная грабля этого этапа, на которую мы наступили в одном из первых внедрений: APP_URL обязан до буквы совпадать с внешним адресом, включая схему https. Laravel строит все абсолютные ссылки от этой переменной. Если в APP_URL остался http:// или внутренний адрес, симптомы будут странные и разрозненные: ссылки в письмах ведут «не туда», после логина выбрасывает на голый IP, браузер ругается на смешанный контент. Мы тогда минут сорок искали «проблему с nginx», а проблема была в одной букве s.

Правило из нашего регламента: кто занял порт 80 — тот и продлевает сертификаты. История такая: на одном сервере рядом со Snipe-IT жил другой сервис, который тоже слушал :80 через свой контейнер. Certbot в standalone-режиме не смог поднять свой временный сервер, продление тихо падало три месяца подряд, и однажды утром клиент встретил браузерную страницу «соединение не защищено». С тех пор в регламенте жёстко: на сервере ровно один владелец 80-го порта (у нас — системный nginx), все сертификаты продлеваются только через него, а после установки мы руками прогоняем certbot renew --dry-run и убеждаемся, что продление отработает.

На этом инфраструктурная часть закончена: https://assets.company.ru открывается, замочек зелёный. По времени — часа полтора-два от чистого сервера, включая кофе. Дальше начинается настройка самого приложения.

Первый вход и включение русского интерфейса

При первом заходе Snipe-IT встречает страницей Pre-Flight check — самопроверкой окружения: версия PHP, расширения, права на каталоги, доступность базы. В Docker-варианте она проходит зелёной практически всегда, потому что образ собран правильно; если что-то красное — вы что-то поменяли в томах или правах руками. Затем мастер просит создать первого администратора и назвать сайт. Логин админа мы заводим по нашему стандарту именования, пароль генерируем в парольный менеджер сразу — тот же принцип, что с APP_KEY: секрет рождается одновременно с записью в хранилище.

Следующие пять минут — то, ради чего многие наши клиенты вообще выбирали Snipe-IT: русский интерфейс. Включается он в два счёта: Admin → Settings → Localization, в поле языка выбираем «Russian / Русский», сохраняем — и весь интерфейс, включая меню, формы и статусы, переключается на русский. Здесь же ставим формат дат и валюту (рубль в списке есть). Часовой пояс приложение уже взяло из APP_TIMEZONE.

Важная деталь для смешанных команд: язык в Snipe-IT — настройка не только глобальная, но и персональная. Глобальный параметр задаёт язык по умолчанию для всех и для писем-уведомлений, но каждый пользователь может выбрать свой в профиле. У нас есть клиент, где бухгалтерия и офис работают в русском интерфейсе, а два инженера-экспата — в английском, и все довольны. Проверьте после включения: профиль пользователя → Language.

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

Мини-чек-лист после первого входа: русский язык включён глобально, формат даты — d.m.Y, валюта — RUB, часовой пояс — Europe/Moscow, у админа включена двухфакторка (Settings → Security → Two-Factor), демо-данные не загружали (галочку с сидированием примеров при установке мы всегда снимаем — вычищать потом «Тестовый ноутбук #4» из боевой базы неинтересно).

Скелет справочников — 80% успеха внедрения

Вот здесь решается, приживётся система или нет. Snipe-IT из коробки — пустой конструктор, и если начать заводить активы «как попало», через месяц внутри будет тот же Excel, только с веб-мордой: три написания одного производителя, категории «Ноутбуки», «Ноуты» и «Laptop» одновременно. Поэтому по нашему регламенту сначала строится скелет справочников — сверху вниз, от структуры компании к моделям техники, — и только потом появляется первый актив.

Таймлайн внедрения Snipe-IT за один рабочий день: от VPS утром через Docker, TLS и справочники к наклейкам и первому акту выдачи вечером

Companies, Locations, Departments — оргструктура

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

Categories и Manufacturers — типовой набор

Категории — то место, где самодеятельность плодит хаос, поэтому мы приносим готовый список из 12 категорий, отточенный на десятках внедрений: ноутбуки, системные блоки, мониторы, смартфоны, планшеты, принтеры и МФУ, сетевое оборудование, серверы, ИБП, телевизоры и панели, периферия (категория для аксессуаров), расходники. Этого хватает офису до 50 РМ с запасом; экзотику вроде «кассовые аппараты» добавляем по факту. Производителей заводим только тех, что реально есть у клиента — обычно 8–10: Lenovo, HP, Dell, Apple, Kyocera, MikroTik, D-Link, APC и пара местных. Ключевое правило: справочники пополняет админ, а не каждый пользователь на лету — это настройка прав, и мы её фиксируем сразу.

Status Labels — жизненный цикл техники

Статусы в Snipe-IT делятся на типы: deployable (можно выдавать), pending (в подвешенном состоянии), undeployable и archived. Наш типовой набор — «Готов к выдаче» (deployable), «Выдан» (метка присваивается автоматически при checkout), «В ремонте» (pending), «На диагностике» (pending), «Списан» (archived). Больше пяти-шести статусов заводить не советую: каждый лишний статус — это вопрос «а какой ставить?» у офис-менеджера и бардак в отчётах. Списанную технику, забегая вперёд, никогда не удаляем — только архивный статус: история выдач нужна бухгалтерии дольше, чем живёт сам ноутбук.

Models и Fieldsets — почему сначала модели

Частая ошибка новичков — лететь заводить активы, минуя модели. В Snipe-IT актив обязан ссылаться на модель («ThinkPad E14 Gen 5»), а модель — на категорию и производителя. Именно модель определяет, какие кастомные поля будут у актива, через привязанный Fieldset — набор полей. Наш стандартный fieldset для компьютерной техники: процессор, объём RAM, объём диска, MAC-адрес и — обязательное поле по опыту — инвентарный номер бухгалтерии. Это отдельная сущность, не совпадающая с asset tag системы: у бухгалтерии своя нумерация основных средств, и если её некуда записать, сверка при инвентаризации превращается в ад с распечатками. Одно текстовое поле решает проблему навсегда. Заведёте модели правильно — дальше каждый новый ноутбук добавляется за тридцать секунд: выбрал модель, вбил серийник, готово.

Asset Tags, QR-наклейки и печать

Инвентарная наклейка — это то, что превращает базу данных в работающий учёт. Пока на ноутбуке нет наклейки, связь «физический предмет — запись в системе» живёт в чьей-то голове; с наклейкой любой человек со смартфоном за две секунды открывает карточку актива.

Сначала формат тегов. В Settings → Asset Tags включаем автогенерацию: префикс + автоинкремент с ведущими нулями. Наш стандарт — ITF-0001, ITF-0002 (для клиентов — их аббревиатура). Четыре цифры с запасом хватает на любой офис; главное — включить автоинкремент до заведения первого актива, чтобы не было ручной нумерации «кто во что горазд». Тег — это идентификатор навсегда: он не переиспользуется после списания и не меняется при передаче техники.

Дальше наклейки. В Snipe-IT встроен генератор этикеток (Settings → Labels) с гибкой настройкой: размер листа и самой этикетки, поля, что печатать — QR-код, штрих-код, тег, название, серийник, логотип компании. QR-код кодирует прямую ссылку на карточку актива, поэтому сканируется обычной камерой смартфона без всяких приложений — навёл камеру, тапнул по ссылке, открылась карточка. Это и есть механика будущих инвентаризаций: обход офиса с телефоном вместо распечаток.

Практика печати, выстраданная на внедрениях:

  • Шаблон подгоняется под конкретный принтер и конкретные этикетки. Мы чаще всего печатаем на обычном офисном лазернике на листах самоклейки A4 (типовой раскрой 65×25 мм) либо на термопринтере этикеток, если он у клиента есть. Перед боевой печатью — тестовый лист на обычной бумаге, прикладываем к самоклейке на просвет: экономит и этикетки, и нервы.
  • Тест сканирования до массовой печати. Печатаем одну наклейку, клеим на ноутбук, сканируем тремя разными смартфонами. Если QR меньше сантиметра или принтер «замыливает» края — код читается через раз, и вся затея девальвируется.
  • Материал наклеек имеет значение. Бумажная самоклейка на ноутбуке разъездного менеджера превращается в грязный обмылок за полгода. Для техники, которая ездит, берём полиэстеровые (виниловые) этикетки для лазерной печати — они переживают три года в рюкзаке, не выцветая. Для стационарных мониторов и системников достаточно обычной бумажной.
  • Куда клеить — тоже стандарт: на ноутбуках — нижняя крышка у петли (не на съёмный аккумулятор), на мониторах — задняя панель у стойки, на системниках — правый бок сверху. Единое место наклейки экономит секунды тысячу раз в год.
QR-наклейка с инвентарным тегом на крышке ноутбука и смартфон, сканирующий код камерой

Почта, EULA и первый акт выдачи

Финальный технический блок дня — почта. Без неё Snipe-IT нем: не отправляет сотрудникам уведомления о выдаче и не присылает админу алерты об истекающих гарантиях. Настраивается всё в .env (помним: после правки — docker compose up -d, не restart):

MAIL_MAILER=smtp
MAIL_PORT_587_TCP_ADDR=mail.company.ru
MAIL_PORT_587_TCP_PORT=587
MAIL_ENV_ENCRYPTION=tls
MAIL_ENV_USERNAME=assets@company.ru
MAIL_ENV_PASSWORD=пароль-из-хранилища
MAIL_ENV_FROM_ADDR=assets@company.ru
MAIL_ENV_FROM_NAME="Учёт техники"

Проверяем кнопкой тестового письма в настройках уведомлений — и обязательно смотрим, что письмо пришло во «Входящие», а не в спам. Если корпоративная почта у клиента настроена по-взрослому (SPF/DKIM в порядке, а слать мы ходим через её же SMTP), проблем не бывает.

Теперь моя любимая часть — EULA и подпись при выдаче. В настройках категории (или глобально по умолчанию) заводится текст соглашения в Markdown — по-русски это обычно «Акт приёма-передачи оборудования»: сотрудник получает такую-то технику, обязуется вернуть при увольнении, о поломках сообщает в IT. Для категорий с EULA включаем два флажка: требовать принятия и требовать подпись. Дальше происходит магия, ради которой директора нам это внедрение и заказывают.

Делаем первый боевой checkout: берём реальный ноутбук, который сегодня же завели в систему и оклеили, и выдаём его реальному сотруднику. Сотруднику падает письмо: «вам выдан ноутбук ThinkPad, серийный номер такой-то, подтвердите получение». Он открывает ссылку, читает акт, расписывается пальцем или мышкой прямо в браузере — и подписанный документ с датой, временем и картинкой подписи навсегда прикрепляется к карточке актива. Через год, при увольнении, спор «я ничего не получал» заканчивается за десять секунд: открываем карточку, показываем акт с подписью.

Это и есть «вау-момент» внедрения. Мы сознательно заканчиваем день именно живой выдачей, при заказчике. Таблицы и Docker директора не впечатляют, а вот письмо сотруднику, подпись на экране телефона и PDF в карточке — впечатляют всегда. После этой демонстрации вопрос «зачем нам это всё» больше не звучит, а офис-менеджер сам просит показать, как делать checkout.

Чек-лист сдачи внедрения и типовые ошибки

Внедрение мы закрываем не «вроде работает», а прогоном по чек-листу из 15 пунктов. Вот он целиком — пользуйтесь:

  1. HTTPS работает, сертификат валиден, certbot renew --dry-run проходит.
  2. APP_URL совпадает с внешним адресом до буквы.
  3. APP_KEY сохранён в парольном менеджере (проверить, что запись реально открывается!).
  4. Пароли БД и админа — в парольном менеджере, не в чате и не на стикере.
  5. Порт приложения слушает только 127.0.0.1, наружу — только nginx.
  6. Русский язык включён, дата/валюта/часовой пояс — российские.
  7. 2FA включена у всех учёток с админскими правами.
  8. Справочники заполнены: компании, локации, отделы, 12 категорий, производители, статусы.
  9. Модели заведены с fieldset'ом, включая поле «инвентарный номер бухгалтерии».
  10. Автогенерация asset tag включена, формат согласован с клиентом.
  11. Шаблон этикеток подогнан, тестовая наклейка сканируется тремя телефонами.
  12. SMTP работает, тестовое письмо дошло во «Входящие».
  13. EULA заведена, тестовый checkout с подписью проведён на реальном сотруднике.
  14. Бэкап включён и хотя бы один архив реально создан и скачан.
  15. Права ролей настроены: справочники правит только админ, офис-менеджер — только выдачи.

И топ-5 ошибок самостоятельных внедрений — рейтинг составлен по инсталляциям, которые нам приносили «доделать после самих себя»:

#ОшибкаЧем оборачивается
1APP_KEY нигде не сохранёнПри переезде или восстановлении из бэкапа зашифрованные поля потеряны безвозвратно
2Тег latest в composeСлучайный pull обновляет систему в разгар рабочего дня, иногда — с сюрпризами мажорной версии
3Активы заведены до справочниковТри написания каждого производителя, категории-дубли; чистка занимает больше времени, чем внедрение
4Панель торчит в интернет по HTTP или с портом 8000 на 0.0.0.0Реестр всей техники компании индексируется сканерами; в лучшем случае — неприятный разговор про безопасность
5Бэкап «настроим потом»«Потом» наступает после первого сбоя диска; базу с двумя сотнями активов набивают заново руками

По времени весь регламент — действительно один рабочий день: утром чистый VPS, к обеду HTTPS и русский интерфейс, после обеда справочники и наклейки, вечером первый подписанный акт. В следующей статье серии займёмся тем, что превращает свежую систему в живую: синхронизация сотрудников из Active Directory, миграция исторического Excel-реестра через CSV-импорт и автоматизации через REST API. А если возиться самим не хочется — мы делаем это внедрение под ключ, со всеми граблями, уже собранными за вас.

Развернём Snipe-IT под ключ за один день

ITfresh — IT-аутсорсинг для компаний до 50 рабочих мест в Москве. Поднимем Snipe-IT в Docker с HTTPS и русским интерфейсом, настроим справочники, наклейки и акты выдачи — по регламенту из этой статьи. Собственные серверы в дата-центре МТС, 15+ лет опыта. Telegram: @ITfresh_Boss, телефон: +7 903 729-62-41

📞 Связаться с нами
#snipe-it #docker #установка #учёт ит-активов #инвентаризация #qr-коды #nginx #open source
Комментарии 0

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

загрузка...

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

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

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

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