🗄️

Свой сервер для нескольких сайтов на Docker и nginx

собственный продукт студии: изоляция сайтов, HTTPS, своя почта и бэкапы

Отдельный сервер для сайтов студии: входной nginx, каждый сайт в своей docker-сети, сертификаты с автопродлением, своя почта домена и ночные бэкапы. Сайты и VPN больше не делят память и nginx.

В продакшене · собственный продукт
1 вход
один nginx держит HTTP и HTTPS для всех сайтов, голый IP-адрес не отдаёт ничего
1 сайт — 1 сеть
каждый сайт в своей docker-сети, сайты друг друга не видят
2 недели
хранятся ночные слепки почты и ключа подписи писем

Задача

До 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-боты пока остаются за границей, и связь с ними идёт через туннели.

Вопросы по проекту

Как разместить несколько сайтов на одном сервере, чтобы они не мешали друг другу?
Один входной nginx принимает все запросы, завершает TLS и разводит их по сайтам. Каждый сайт живёт в своём контейнере и в своей docker-сети, поэтому сайты друг друга не видят. Базы данных подключены только к внутренним сетям своих проектов, входной nginx до них не достаёт.
Зачем отдельный сервер для сайтов, если уже есть серверы под VPN?
Раньше сайты жили на машинах VPN, и каждая правка сайта рисковала уронить VPN у всех клиентов: релей с 1,9 ГБ памяти однажды уже лёг от соседнего сервиса. Отдельный сервер разрывает эту связь: сайты и VPN больше не делят ни память, ни nginx, ни сертификаты.
Как продлеваются сертификаты HTTPS без ручной работы и простоя?
Сертификаты Let's Encrypt продлевает certbot по таймеру. После продления хук сообщает входному nginx, и он перечитывает конфигурацию без перезапуска контейнера. Скрипт проверки показывает срок каждого сертификата, порог тревоги — меньше 20 дней.
Можно ли держать почту на своём домене, а не у хостера?
Да. Приём и отправку берёт на себя docker-mailserver с Postfix, Dovecot, Rspamd и fail2ban, читать почту можно в веб-интерфейсе Roundcube или в любом почтовом клиенте. Для работы нужны записи DNS: адрес сервера, MX, SPF, DKIM, DMARC и обратная запись PTR у IP-адреса.
Сохраняются ли резервные копии?
Ночные слепки делаются для почты (хранятся две недели) и для базы с файлами части размещённых сайтов; отдельный скрипт забирает копию базы VPN. Расписания резервных копий у части WordPress-стендов пока нет, это записано в ограничениях.
Что пока не работает так, как хотелось бы?
Хостер блокирует исходящие соединения на почтовые порты: приём писем работает, а отправляемые копятся в очереди Postfix и уйдут сами, когда выход появится. Обходные пути: смена тарифа, отправка через внешний релей по HTTPS-API или туннель на зарубежный сервер.

Ещё по этому направлению

В продакшене · собственный продукт

Переговорка (ToshaStream): стрим-сервер и голосовая для команды

собственный продукт в продакшене, версия 1.50.0: голос, чаты и закрытый эфир

Тестирование у заказчикаNDA

OshaVPN Router: своя прошивка для MikroTik — VPN на весь офис

прошили заказчику MikroTik с Авито: весь офис за VPN, российское напрямую, зарубежное через туннель, на устройствах ничего не нужно ставить

OpenWrtucode
В продакшене · собственный продукт

VPN-инфраструктура: входной узел в России, выход в Европе

собственный продукт: релей в России, постоянный туннель и узел в Нидерландах

Нужно похожее?

Расскажите о задаче — покажем, как решали такое, и прикинем объём работ.