← vladburba.ru

Как устроен мой сервер

Один небольшой сервер, на котором уживаются сайт, личные инструменты, два телеграм-бота и VPN для семьи. Разбираю, что там внутри, как ходит трафик и что ломалось по дороге.

Влад Бурба · ИИнфра-Инженер · vladburba.ru

Это не витрина «смотрите, как у меня всё идеально». Наоборот: ниже честный разбор с ошибками, тупиковыми гипотезами и списком того, что до сих пор не сделано. Мне кажется, так полезнее — по вылизанным схемам не видно, как принимаются решения.

Железо

2 ядра

виртуальный сервер

Память

1.9 ГБ

занято около четверти

Диск

28 ГБ

занято 39 %

Система

Ubuntu

обновления автоматом

Сервисов

12

+ 3 контейнера

Портов наружу

3

было 7 неделю назад

Что там живёт

Четыре разные истории на одной машине. Всё внешнее общение идёт через один-единственный веб-сервер — он привратник, больше наружу не смотрит никто.

🖥️ Сервер · Ubuntu · 2 ядра · 1.9 ГБ · 28 ГБ

🌍 Снаружи

Боты и задачи

VPN

Веб

управление

Посетители сайта

Семья · телефоны

Владелец · управление

🚪 nginx
единственная дверь наружу

📄 Лендинг

🧰 Личные инструменты

🪝 Автодеплой сайта

⚙️ Панель управления

🔀 Маршрутизатор трафика

🤖 Телеграм-бот

🤖 Второй бот

📰 Новостной дайджест
по расписанию

🔌 Внутренний прокси
через него боты ходят наружу

🌐 Интернет

🛡️ Зарубежные выходы
по подписке

Схема 1 — кто есть на сервере и как связан с внешним миром

Принцип: одна дверь

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

Только внутри — недоступно снаружи

Открыто наружу — 3 входа

только владелец

🌐 Интернет

HTTP
перенаправляет на защищённый

HTTPS
сайт + инструменты + VPN

Управление
только с адресов владельца

Прокси для программ сервера

Вход VPN

Контейнер сайта

Приёмник автодеплоя

Панель управления VPN

Сервер подписок
про запас

Локальный DNS

Схема 2 — периметр. Жёлтое доступно из интернета, зелёное — только изнутри

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

VPN: вход дома, выход за границей

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

8 ячеек — зарубежные выходы

Сервер в России

РФ

заграница, семья

заграница, программы

если основные легли

если основные легли

проверяет

📱 Телефоны семьи

⚙️ Программы сервера
боты, обновления, API

Вход VPN

Внутренний прокси

Куда пакет?

🇷🇺 Российские сайты
идут напрямую, без VPN

Балансир «семья»

Балансир «программы»

🇪🇪 Страна А · 2 шт
для семьи

🇺🇸 Страна Б · 3 шт
для программ

🇸🇪 Запасной выход · 1 шт

🇩🇪 🇪🇸 Запас · 2 шт

🔄 Автопилот · каждую ночь
проверяет ячейки и чинит мёртвые

Схема 3 — путь трафика. Российское идёт коротким путём, заграничное — через выходы

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

Восемь «ячеек» — это восемь адресов зарубежных серверов, разбитых на группы: своя для семьи, своя для программ самого сервера, плюс запасной выход на случай, если основные лягут. Раньше выход был один, и когда провайдер удалил его адрес, всё встало разом. Теперь смерть одного адреса переживается автоматически.

Веб: путь запроса до страницы

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

nginx · разбирает, кто куда

👤 Посетитель

DNS ведёт прямо на сервер
без посредников

Основной сайт

Служебный поддомен

Скрытый поддомен
имя не угадать

Чужие имена
обрыв связи

📦 Лендинг

🧰 Инструменты
под паролем

🪝 Приём автодеплоя

⚙️ Панель VPN

🔐 Вход VPN

Схема 4 — как разбирается входящий запрос

История одной аварии

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

Симптом. Несколько дней подряд мои личные страницы не открывались. Браузер бесконечно крутил загрузку. При этом главная страница сайта открывалась нормально, а VPN на телефоне качал на десять мегабит. Разберитесь, называется.

Как искали причину

1

Первая версия — виновата тяжёлая библиотека. Страница подгружала три мегабайта постороннего кода. Убрали. Не помогло.

2

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

3

Перестали гадать и стали мерить. Запросили одну и ту же страницу с четырёх точек: мой компьютер, домашнее хранилище, сервер в другом дата-центре и точка за границей. Оказалось, что не открывается только у меня дома. Сервер и Cloudflare свою часть отрабатывали идеально.

4

Нашли странность. Обрыв всегда случался на одном и том же месте — 17 770 байт, с точностью до байта. Случайные помехи так себя не ведут: цифра бы плясала. Значит вмешивается что-то систематическое.

5

Решающий опыт. Обратились к одному и тому же адресу Cloudflare, поменяв только имя сайта в запросе. Чужое имя — 87 килобайт за треть секунды. Моё имя — обрыв на семнадцати. Один провод, один адрес, разница только в имени.

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

А маршрут был такой: мой запрос уходил за границу, там его принимал Cloudflare, возвращался в Москву за данными, и вёз их обратно. Граница пересекалась четыре раза ради страницы, лежащей в тридцати километрах от меня.

Ирония. Cloudflare ставился как раз для того, чтобы обойти ограничения. А он сам создал тот трансграничный переход, на котором всё и ломалось. Внутри страны никаких ограничений не было — мы их себе организовали добровольно.

Решение. Убрали Cloudflare из пути: имена стали вести прямо на сервер. Маршрут сократился до «Москва → Москва». Страница, которая не открывалась вовсе, стала приходить за девять сотых секунды.

через Cloudflareнапрямую
главная страница0.28 сек0.03 сек
картинка-превью 36 КБне доходила0.04 сек
словарь 558 КБне открывался0.09 сек
пересечений границы40

Что я забрал из этой истории. Во-первых, диагноз надо ставить сразу с нескольких точек — иначе неделю чинишь не то. Во-вторых, Cloudflare не спасает от отбора по имени: имя обязано быть видно, иначе шифрование не начнётся. В-третьих, две мои первые версии были неверны, и хорошо, что не остановился на обходном решении — оно бы работало, а причина осталась бы непонятой.

Автопилот, который чинит сам

После той аварии с VPN стало ясно: следить руками — плохая опора.

Теперь каждую ночь на сервере запускается скрипт. Он сверяет все восемь выходов со списком провайдера, проверяет каждый живым запросом и заменяет те, что отвалились. Если замена сама не отвечает — не трогает рабочий выход, а пишет мне. Если после замены что-то пошло не так — откатывается на резервную копию.

Сообщение приходит, только когда есть что сказать. Молчит — значит всё в порядке. За первую неделю четыре ночи подряд промолчал, а на пятую заменил два адреса, которые провайдер вывел из обращения, — я узнал об этом из отчёта утром.

Заодно он присылает сводку человеческим языком: не «upstream-de-1 недоступен», а «Германия, запасной выход: адрес перестал отвечать, заменил на рабочий». Разница кажется мелочью, ровно до момента, когда читаешь это спросонья.

Что ещё не сделано

Честный список. Он существует не для красоты: пока долг записан и виден, он рано или поздно закрывается. Когда не записан — живёт годами.

Резервных копий нет

Самое неприятное в списке. Пропадёт диск — пропадёт всё разом: настройки, боты, сайт. Первое в очереди на исправление.

Наблюдения за сервисами нет

О том, что что-то упало, узнаю, когда сам этим пользуюсь. Именно так вышло с VPN — сервер молчал двое суток. Автопилот закрыл только VPN, остальное пока нет.

✓ Контейнеры без ограничений по памяти — закрыто 3 сентября

Чтобы задать потолок, надо знать, сколько сервис ест на самом деле. Я замерил сразу после запуска и увидел 35 МБ — поставил бы 128 и получил бы бота, которого система убивает через час. Спасло сомнение: замер снят на непрогретом процессе, до того как поднялись библиотеки, кэши и планировщик. Через несколько минут те же боты вышли на 150–175 МБ.

Потолок поставлен от установившегося значения с тройным запасом, а не от первого показания. Сайту хватило 64 МБ — он отдаёт готовые файлы и почти ничего не держит в памяти.

Былобез ограничений: любой бот мог занять все 1.9 ГБ и выдавить остальных, включая VPN
Ошибкапервый замер снят до прогрева — 35 МБ вместо реальных 175
Стало512 МБ каждому боту (едят 150 и 174), 64 МБ сайту (ест 5.5)

✓ Системный журнал разросся — закрыто 3 сентября

Здесь важнее не потолок, а вопрос «почему вообще накопилось три гигабайта». Задать предел — десять минут, но тогда журнал просто вытеснял бы сам себя, и в нужный момент история за нужный день оказалась бы стёртой.

Считаю записи по часам: VPN-панель пишет 1834 строки в час, ровно и непрерывно. У неё оказался включён отладочный уровень логирования — записывалось каждое соединение каждого устройства семьи. Такой режим включают на время разбора и забывают выключить; так было и здесь.

Было2.7 ГБ, предела нет, 1834 записи в час — журнал рос бы до 10% диска
Причинаотладочный уровень логирования у VPN-панели, включённый и забытый
Сталоуровень «предупреждения», потолок 500 МБ. После правки — одна запись за два часа вместо 3668

✓ Вход по паролю был открыт четыре месяца — закрыто 3 сентября

Я был уверен, что пароль отключён: правило записано в отдельный файл настроек ещё в мае, файл на месте, содержимое верное. Но сервер отвечал, что вход по паролю разрешён.

Причина в том, как читаются такие настройки. Файлы применяются по алфавиту, и выигрывает первое встреченное значение параметра, а не последнее — в отличие от привычной логики «позже переопределяет раньше». Мой файл назывался 99-…, а рядом лежал 50-…, созданный системой первичной настройки на полтора часа позже моего. Он шёл раньше по алфавиту и молча побеждал.

Мало исправить — надо убедиться, что исправление держит удар. Я положил рядом подставной файл, снова разрешающий вход по паролю, и проверил: он больше ничего не перебивает. После этого удалил.

Быловход по паролю разрешён с мая, хотя правило запрета лежало на месте и выглядело рабочим
Причинапорядок чтения файлов: побеждает первый по алфавиту, а не последний
Сталозапрет читается первым, устойчивость проверена подставным конфликтом

✓ Выкатка у каждого сервиса своя — закрыто 3 сентября

Нашлось при разборе: один из ботов три недели работал на старом коде. Выкатка была списком команд в инструкции; шаг обновления кода падал с правами доступа, а следующий за ним шаг сборки отрабатывал успешно и рапортовал об успехе. Снаружи выкатка выглядела удачной.

Второй случай того же рода нашёлся тут же: скрипт третьего сервиса содержал комментарий «основное хранилище — резервное», но отправки туда не делал. Резервная копия истории отстала на два коммита, и заметить это было неоткуда.

Теперь у всех сервисов выкатка называется и работает одинаково — одна команда, один порядок шагов. Сервисы разные, порядок один: в этом и смысл. Главное не в удобстве, а в том, что каждый шаг проверяется отдельно, и об успехе не сообщается, пока шаг не выполнился.

Былоу каждого сервиса свои команды; неудачный шаг мог остаться незамеченным
Стоилотри недели работы на старом коде и отставшая резервная копия
Сталоодна команда на всех; проверяются журнал запуска, счётчик перезапусков и ответ сайта снаружи

✓ Закрыто на этой неделе

Перезагрузка с обновлением ядра (сервер работал 96 дней без неё), закрытие четырёх лишних портов, снос нерабочей схемы туннеля, удаление задачи, три месяца работавшей вхолостую, переезд бота в общую папку, уборка старых копий (было 16 снимков базы VPN-панели — остался один).

Зачем я это выкладываю

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

Здесь видно, как я работаю: сначала гипотеза, потом замер, при расхождении — отказ от гипотезы, а не подгонка фактов. И обходное решение только после того, как понята причина, а не вместо этого.

Если такой подход нужен вашей инфраструктуре — я открыт для найма и консалтинга.