Свой сервер для нескольких сайтов на Docker и nginx
собственный продукт студии: изоляция сайтов, HTTPS, своя почта и бэкапы
Отдельный сервер для сайтов студии: входной nginx, каждый сайт в своей docker-сети, сертификаты с автопродлением, своя почта домена и ночные бэкапы. Сайты и VPN больше не делят память и nginx.
Задача
До 18.09.2026 сайты студии были разбросаны по машинам VPN: визитка, открытки и демонстрационный сайт на российском релее, стенды заказчиков на второй российской ноде, сервис открыток в Молдове. Каждая правка сайта рисковала уронить VPN у всех клиентов. Релей имеет 1,9 ГБ памяти и однажды уже лёг от соседнего сервиса. Сертификаты для второй ноды выпустить было нельзя, поэтому один из сайтов работал без HTTPS.
Нужен был отдельный сервер, где сайты не делят с VPN ни память, ни nginx, ни сертификаты, а каждый сайт защищён от соседних.
Решение
Отдельный сервер сайтов студии в Москве, конфигурация которого хранится в репозитории lab-server. Что сделано:
- Один входной nginx принимает HTTP и HTTPS, завершает TLS и разводит запросы по сайтам.
- Каждый сайт живёт в своём контейнере и в своей docker-сети
edge-<сайт>; сайты друг друга не видят. - Все сайты открываются по HTTPS, HTTP переадресуется. Голый IP-адрес ничего не отдаёт: рукопожатие отклоняется, соединение закрывается.
- Сертификаты Let's Encrypt продлеваются сами, после продления nginx перечитывает конфигурацию.
- Журналы входного nginx пишутся в файл и ротируются, логи docker ограничены по размеру. Сервер и контейнеры работают в часовом поясе Europe/Moscow.
- Своя почта домена студии: приём, отправка и веб-интерфейс.
- Ночные слепки почты и данных размещённых сайтов, сторож цепочки VPN и забор копии базы VPN.
- Туннели к сервисам за границей, чтобы сайты ходили к ботам и API без прямого соединения.
Как это устроено
Один входной nginx на все сайты
nginx — веб-сервер, который здесь работает как единственная точка входа. Он принимает запрос, смотрит на имя сайта и передаёт запрос контейнеру нужного сайта. Конфигурация входного nginx лежит в каталоге, который примонтирован в контейнер целиком, поэтому правка применяется командой reload без пересоздания контейнера. Незнакомые имена отклоняются.
Изоляция сайтов по docker-сетям
Docker-сеть — виртуальная сеть, внутри которой контейнеры видят только друг друга. Для каждого сайта создаётся своя сеть edge-<сайт>, и в неё входят только контейнер сайта и входной nginx. Порты сайтов наружу не публикуются. Базы данных подключены лишь к внутренним сетям своих проектов, поэтому взлом или сбой одного сайта не даёт пути к базе соседнего. Новый сайт добавляется по одной схеме: сеть, контейнер, имя в конфигурации, сертификат, файл сайта в conf.d.
Сертификаты HTTPS: автопродление и перечитывание nginx
Сертификаты выпускает certbot, проверка владения идёт через каталог webroot, поэтому nginx не останавливается. Продлением управляет таймер certbot.timer. Отдельный хук после каждого продления заставляет nginx перечитать сертификат: без хука nginx продолжал бы отдавать старый до срока его окончания. Скрипт проверки обходит все сайты и показывает срок каждого сертификата.
Своя почта на домене: docker-mailserver
Один контейнер mailserver содержит Postfix (отправка и приём), Dovecot (доступ по IMAP), Rspamd (фильтр спама) и fail2ban. Веб-интерфейс — Roundcube. Антивирус выключен: база сигнатур ClamAV занимает больше гигабайта из четырёх. Спам не отбрасывается, а кладётся в папку «Junk»: на маленьком потоке потерять письмо заказчика хуже, чем разобрать папку вручную. Письмо на несуществующий адрес отклоняется. Отдельный контейнер присылает каждое новое письмо в служебный Telegram-чат: тема, отправитель, текст, вложения файлами; спам приходит одной строкой без звука.
Туннели к сервисам за границей
Часть сервисов, включая Telegram-боты, остаётся за границей: из России новые TCP-соединения до них нередко не проходят фильтр. Поэтому соединения открываются заранее и из-за границы: десять независимых клиентов frp в одной группе балансировки везут запросы сайтов к сервису. Если сессия одного порвалась, новые соединения уходят в остальные девять. Лидбот студии (заявки с сайта в Telegram) ходит в Telegram и к API нейросети через отдельный egress-туннель.
Результат
- Сайты и VPN разведены: правка сайта больше не может уронить VPN.
- Каждый сайт изолирован в своей docker-сети, а голый IP-адрес не отдаёт содержимого.
- Сертификаты продлеваются автоматически, и nginx подхватывает их без перезапуска.
- Почта домена принимается на собственном сервере; письма приходят и в Telegram.
- Ночные слепки почты хранятся две недели.
Технологии: что и зачем
- nginx — входная точка: TLS, маршрутизация запросов по сайтам, журналы.
- Docker Compose — контейнер и docker-сеть на каждый сайт.
- certbot (Let's Encrypt) — бесплатные сертификаты с автопродлением через webroot.
- docker-mailserver, Roundcube — своя почта домена и веб-интерфейс.
- frp — туннели, по которым сайты достают до сервисов за границей.
- Python — лидбот студии и сервис пересылки писем в Telegram.
- logrotate, cron — ротация журналов и ночные слепки.
Статус
Версия 1.16.0 от 29.09.2026. Сервер работает в продакшене с 18.09.2026, когда сайты переехали с серверов VPN. С 29.09.2026 на нём же работает основной сайт студии на Nuxt, рядом — визитка инженера Валерия Афанасьева. Из-за нехватки памяти на сервере образ Nuxt собирается на рабочей машине и загружается командой docker load.
Что не закрыто по README: исходящая почта заблокирована хостером и копится в очереди; у части WordPress-стендов нет резервных копий по расписанию; сервер стоит у того же хостера, что и узлы VPN, поэтому от проблем провайдера сайты не отвязаны; Telegram-боты пока остаются за границей, и связь с ними идёт через туннели.
Вопросы по проекту
Как разместить несколько сайтов на одном сервере, чтобы они не мешали друг другу?
Зачем отдельный сервер для сайтов, если уже есть серверы под VPN?
Как продлеваются сертификаты HTTPS без ручной работы и простоя?
Можно ли держать почту на своём домене, а не у хостера?
Сохраняются ли резервные копии?
Что пока не работает так, как хотелось бы?
Ещё по этому направлению
Переговорка (ToshaStream): стрим-сервер и голосовая для команды
собственный продукт в продакшене, версия 1.50.0: голос, чаты и закрытый эфир
OshaVPN Router: своя прошивка для MikroTik — VPN на весь офис
прошили заказчику MikroTik с Авито: весь офис за VPN, российское напрямую, зарубежное через туннель, на устройствах ничего не нужно ставить
VPN-инфраструктура: входной узел в России, выход в Европе
собственный продукт: релей в России, постоянный туннель и узел в Нидерландах
Нужно похожее?
Расскажите о задаче — покажем, как решали такое, и прикинем объём работ.