Все посты

Публичный шаблон, приватная инфра: где живёт деплой OSS-продукта

25 мая 2026 г.5 мин чтенияKB Labs
Share

Open-source продукт. README обещает «деплой за 10 минут». Человек клонирует, запускает — 502. Потому что мейнтейнеры держат nginx с хардкоженым proxy_pass и забыли написать об этом.

Или хуже: в публичный коммит однажды улетел API-ключ, потому что prod-конфиг жил в том же репо.

Это один и тот же баг — одно репо пытается делать две разные работы.

Папка examples/ не спасает

Первая реакция всегда одинаковая: «разделим — вот пример, вот настоящее». Появляются examples/, docs/deployment-example/, заметки в README.

Не работает. Через месяц пример расходится с реальностью. Никто не идёт обновлять examples/nginx.conf, когда ночью фиксит настоящий конфиг. Через год пример сломан — новые пользователи снова получают 502.

Дело не в лени. Просто у этих двух вещей разный жизненный цикл, и жить вместе они не умеют.

Это две разные вещи

Шаблон деплоя, который копирует пользователь — это часть продукта. Он generic, с {{ DOMAIN }} и ${PORT} вместо реальных значений. Обновляется когда меняется сам продукт. Его видят контрибьюторы, его проверяет CI. Это публичное.

Твой реальный деплой — это твоё. Конкретные домены, сертификаты, IP, секреты. Обновляется когда надо. Никто, кроме тебя, знать это не должен. Это приватное.

Смешать их в один репо — как в одной схеме держать production-базу и учебный SQL-туториал. Сломаешь или одно, или другое.

Три варианта, которые не работают

.gitignore на приватные файлы. Одна опечатка — и секрет в публичной истории навсегда. git clean -fdx снесёт всю инфру. Мина под собой.

Submodule на приватный репо. Факт его существования торчит из .gitmodules. Контрибьюторы не склонируются. И submodule — это отдельная боль: pinning, рассинхрон.

«Просто напишем в доках». Расходится с реальностью за 2–3 деплоя. В 3 часа ночи никто не открывает PR в docs.

Что работает

Два отдельных репо. Без связей в коде.

Публичный — монорепо продукта. Там templates/nginx/, templates/deploy/ с плейсхолдерами и README. Видят все, проходит ревью, версионируется с продуктом.

Приватный — твоя реальная инфра. Реальные домены, сертификаты, секреты, CI/CD для деплоя на VPS. Ссылок из публичного нет — пользователям не нужно знать, что он вообще существует.

Единственная связь — в доках приватного: «деплоит github.com/<org>/<product>, основан на templates/nginx/». Публичный про приватный ничего не знает.

Когда это окупается

На старте схема дороже: два места для коммитов, два workflow. Окупается в трёх случаях.

Открытый исходник. Если код видит мир — это не «если утечёт», а «когда».

Первый клиент. Когда кто-то начинает деплоить твой продукт у себя, ему нужен чистый шаблон без твоих конкретных доменов. Иначе он копирует твой kblabs.ru.conf и потом разбирается, почему упало.

Команда растёт. Джуну нельзя давать SSH к проду, но PR в templates/nginx/ — можно. Разделение позволяет делегировать без страха.


Когда я настраивал nginx для kblabs.ru, был соблазн положить всё в infra/ в монорепо. Не стал. Теперь у нас templates/nginx/ (публичный, generic) и kb-labs-infra (приватный, с реальными секретами). Когда первый клиент попробует самохостить — у него будет что копировать, не нужно расшифровывать мой конкретный конфиг.

Один репо не должен делать две работы.

Публичный шаблон, приватная инфра: где живёт деплой OSS-продукта