Новости

[Перевод] Песочница для Nginx

Как-то я болтала с приятелем о том, как было бы здорово если бы был такой сайт-песочница, где бы можно было просто скопировать-вставить конфиг Nginx-а и протестировать его. И я поняла, что это не так уж сложно сделать, поэтому погрузилась в тему и сделала: nginx-playground.wizardzines.com.

Далее поговорим о том, как тут всё устроено, потому что в процессе я столкнулась с некоторыми любопытными нюансами и проблемами с неочевидными решениями.

Как пользоваться

Нужно задать конфигурацию Nginx, а также написать curl или http команду, которая отправит HTTP-запрос этому сконфигурированному вами веб-серверу.

Вы жмёте «Run» вверху-справа и получаете ответ:

  • результат выполненной команды (если Nginx запустился нормально), либо
  • лог ошибок Nginx-а (если что-то пошло не так).

Зачем нужна эта песочница?

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

А Nginx чрезвычайно привередлив в настройке, и поэтому, я думаю, что уж для него-то точно должен быть такой инструмент.

Вот три других похожих проекта, которые я сделала ранее:

  • SQL-песочница — позволяет выполнять произвольные SQL-запросы на небольших данных к SQLite (использует sql.js).
  • CSS примеры — используя CodePen демонстрируют некоторые поразительные примеры стилизации с помощью CSS, с которыми вы можете поиграться.
  • DNS lookup — позволяет выполнять любые DNS-запросы и видеть ответы.

И несколько других замечательных песочниц, разработанных другими людьми:

  • CodePen — для CSS/JS/HTML.
  • RegExr — для регулярных выражений.
  • DB Fiddle — для SQL (MySQL, PostgreSQL и SQLite).
  • Nginx location match tester — имитирует алгоритм перебора директив location конфига Nginx (написан на TypeScript).

Делаем быстро, без усложнений

Сайт состоит из:

  1. статичного фронтенда (и применением Vue.js и Tailwind, моего типичного фронтендового набора);
  2. написанного на Go бэкенда с единственным API-методом, который делает лишь одно — запускает Nginx с заданным конфигом.

План прост, потому красив: всего-то нужно написать один API-метод, ну и ещё фронт, который его вызывает. Так же просто выполнен инструмент DNS lookup. Уж очень нравится мне такой подход, думаю, я и остальные проекты буду делать так же.

Давайте расскажу о том, что делает код на бэкенде, когда к нему поступает запрос с фронта.

Что происходит при поступлении запроса

Вот что делает Go-бэкенд, когда вы жмёте «Run» (вот вам сразу заметка с кодом):

  1. записываем конфиг во временный файл;
  2. создаём новый сетевой неймспейс (ip netns add $RANDOM_NAMESPACE_NAME);
  3. запускаем go-httpbin на порту 7777, чтобы люди могли использовать его в качестве следующего узла в своих конфигурациях Nginx (для отладки обратного прокси);
  4. запускаем Nginx;
  5. ждём 100 миллисекунд — позволяем Nginx-у запуститься, а если он не заработал, то возвращаем клиенту лог с ошибками;
  6. выполняем заданную пользователем команду (предварительно убеждаемся, что команда начинается с curl или http);
  7. возвращаем результат выполнения команды;
  8. PROFIT!

Вопросы о безопасности

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

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

Подход к безопасности: немного изоляции и YOLO (!)

Вот, к чему я пришла по поводу безопасности после обсуждения с другом:

  1. Нужно разместить фронтенд отдельно от бэкенда — где-то в CDN (если бэкенд и будет взломан, то хотя бы на фронте никто не разместит какой-нибудь малварь).
  2. Не использовать базу данных, только localStorage браузера (невозможно взломать БД, если её нет).
  3. Изолировать Nginx в собственном сетевом неймспейсе, запретить выходить в глобальную сеть.
  4. Использовать бесплатный план на fly.io: слабые сервера, зато изолированные виртуальные машины, которые я при желании могу убивать и пересоздавать хоть каждый час.
  5. Попросить людей быть лапочками в разделе FAQ (это и есть «YOLO» 🙂 )

Самое плохое, что может случиться при всех этих ограничениях:

  • кто-то сможет получить доступ к чужому конфигу Nginx, если два человека пользуются сайтом одновременно;
  • подменит бэкенд так, что последующие клиенты будут получать всякие гадости в качестве ответа сервера вместо ожидаемого лога с ошибками или результата выполнения curl;
  • какой-нибудь хитрец попробует майнить биткоин на этом крошечном виртуальном сервере (1 shared CPU, 256 MB RAM).

Не думаю, что перечисленное выглядит так уж плохо в свете потенциальной пользы от сайта. Впрочем, возможно я упускаю что-то ещё более важное. Например, кто-то уже показал, что можно украсть содержимое файла /etc/passwd (было занятно, но в нём всё равно ничего важного не было).

Можно было бы запускать Nginx в контейнере (вместо изоляции только с помощью сетевого неймспейса), но это сильно ударит по производительности. И без этого работает не то чтобы очень быстро.

К слову о производительности.

Кое-что о производительности

Как упомянуто ранее, бэкенд работает на довольно слабом железе (1 shared CPU, 256 MB RAM). По этому поводу имею сказать следующее:

  1. Фронтенд расположен в CDN, поэтому нагрузка бэкенда начинается только тогда, когда пользователь нажимает кнопку «Run». Уже только это значительно облегчает серверу жизнь.
  2. Если верить логам, запросы занимают порядка 400 миллисекунд. Неплохо!
  3. Сейчас проект живёт на сервере, расположенном в Торонто. Полагаю, что для удалённых от Торонто пользователей всё происходит ещё медленнее. Так что можно развернуть больше таких маленьких серверов и в других уголках планеты.
  4. Я применила написанный на Go клон httpbin вместо оригинального (написанного на Python), потому что эта версия показалась более лёгкой и быстрой.
  5. Производительность на стороне фронтенда слегка хромает: стили и скрипты разделены на несколько файлов. Я не хотела собирать это всё командой npm build, потому что я не очень сильна в JavaScript, и поэтому переживала, что в случае возникновения проблем в скриптах это будет дополнительным препятствием перед исправлением ошибок и обновлениями — просто будет лень.
  6. Добавила маленькую гифку с летящей ракетой — её видит пользователь, пока выполняется запрос.

Самая глупая ошибка, связанная с производительностью, была вызвана тем, что для остановки Nginx я отправляла SIGKILL. Это останавливало только главный процесс, а воркер-процессы продолжали работать, и в какой-то момент в системе заканчивалась свободная память. Когда я переделала всё так, чтобы отправлялся сигнал SIGTERM, ситуация улучшилась.

Дизайн

Внешне повторяет дизайн JSFiddle и CodePen.

В частности, у JSFiddle есть кое-что занятное: они вычисляют высоту рабочей области как calc(100vh - 60px), а для заголовка установлена высота 60px. Я бы не догадалась сама, а работает это хорошо.

Я использую CodeMirror в качестве редактора с подсветкой синтаксиса, потому что именно его применяют JSFiddle и CodePen. Настроить его было достаточно просто. К тому же, там есть подсветка синтаксиса для конфигов Nginx и shell. Всё, о чём только можно мечтать 🙂

Была головная боль с этим CodeMirror только из-за того, что я собиралась использовать готовый пакет vue-codemirror, но были проблемы совместимости с Vue 3. Я решила, что в этом нет необходимости, и просто написала свою крошечную интеграцию, которая обновляет Vue при обновлении текстового поля.

Вы можете взглянуть на код в файле script.js, его там не много.

Что бы сделать ещё: больше примеров конфигов

Я до сих пор не понимаю, какими именно должны быть эти примеры конфигурации, но не лишним было бы добавить парочку разных типичных конфигов в качестве стартовых.

Это было легче, чем казалось

Сделать этот инструмент было гораздо проще, чем я думала. И этот успех побуждает делать ещё больше подобных песочниц для других программ, хотя я и не выбрала следующую. HAProxy кажется хорошим кандидатом.

Добавить комментарий

Кнопка «Наверх»