The Jerusalem PostIsraeli extremist settlers use sheep farms, intimidation to expand West Bank control, CBS reportsESPNBills, Josh Allen outlast Rams in overtime on MNFESPN DeportesAllen, el héroe en un espectacular juego en Sofi StadiumBollywood HungamaSidharth Malhotra suffers leg injury, shares photo with a witty note!Daily MaverickSECOND CHANCE: Former Springbok coach Jake White will lead ‘best-prepared’ Fiji to RWC 2027RTP Desporto12h30 Ambiente difícil em Lens, Porto complicado diz PellegriniRTL BoulevardMan (27) stichtte bewust brand tijdens Pride en verheerlijkte ISAntara NewsIndonesia seeks land certainty to accelerate 3 million homes programVariety‘Death in Paradise’ Gets Its First International Adaptation in Croatia, Promises ‘Murder Mystery, Humor, Warmth and a Strong Sense of Place’ (EXCLUSIVE)ZDF heuteEntdecken Sie das ZDF-Nachrichtenstudio
The Daily Newsstand · Free, Always
Tuesday, October 13, 2026

[Перевод] Современное веб-приложение на C: CGI, SQLite и один бинарник

Translate

Если в 1994 году вам нужен был динамический сайт, вы писали программу на C, клали её в каталог cgi-bin и позволяли Apache форкать её на каждый запрос. Тридцать два года спустя я выпустил коммерческий веб-продукт на, по сути, той же технологии.

Всё в marketyour.games современное. Это веб-продукт с пользовательскими аккаунтами, дашбордом поиска для контент-мейкеров, папками для их организации, оплатой через Stripe и транзакционными письмами через Postmark. Он сделан по принципу прогрессивного улучшения и вообще не требует JavaScript. Современно всё, кроме способа, которым он написан и которым раздаётся.

Здесь мои мысли о том, каково писать настоящий продукт на C и отдавать его через CGI в 2026 году.

Коротко

Закат CGI в 2004 году был оправдан, но в 2026-м он уже не выдерживает критики. Современное веб-приложение на C написать можно. Я выпустил одно. Один бинарник, один файл SQLite, три зависимости, и всё приложение помещается в голове.

Как это сделано

Стек называется BCHS: OpenBSD, C, httpd и SQLite.

Фреймворка нет. Вы пишете программу на C, которая читает переменные окружения CGI и формирует ответ.

Шаблонизатора нет. Вы пишете на C код, который выводит HTML напрямую.

Отдельного сервера БД нет. Файл базы открывается через C API SQLite.

Контейнера нет. Вы собираете статически слинкованный бинарник и кладёте его в каталог.

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

OpenBSD из коробки даёт разумные настройки по умолчанию и инструменты, чтобы по-настоящему защитить программу на C, например pledge и unveil. Httpd по умолчанию работает в chroot, так что CGI-бинарник сидит в песочнице в своём уголке файловой системы.

Я использую ещё три библиотеки:

  • libcurl делает все исходящие запросы к Stripe и Postmark.

  • libsodium отвечает за генерацию случайных идентификаторов, хеширование паролей и проверку HMAC для вебхуков Stripe.

  • libcjson разбирает JSON от Stripe и Postmark.

Реальных зависимостей сборки из них только две: libcurl и libsodium. libcjson — один C-файл без внешних зависимостей. SQLite поставляется в виде официальной «амальгамы» (один C-файл). Обе эти библиотеки вендорятся и собираются вместе с проектом.

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

Статику я не раздаю традиционным способом. Весь трафик httpd направляет в CGI-бинарник, а каждый ассет вкомпилирован в исполняемый файл и отдаётся из памяти.

Что мне понравилось

Основы вместо фреймворков. CGI не фреймворк, его не нужно учить. Спецификация 1.1 опубликована в 2004 году и с тех пор не менялась. Никакого API запоминать не надо. Весь интерфейс — это горстка базовых понятий HTTP: заголовки запроса, методы, строка запроса, тело. Если вы понимаете HTTP, вы уже понимаете CGI. Он не привязан ни к языку, ни к платформе. Выучил один раз — и знание годится навсегда.

Чёткое разделение ответственности. Современное веб-приложение обычно ставит впереди веб-сервер вроде nginx и проксирует запросы на сервер приложения на Ruby, Python, Go или Rust. Мне это всегда казалось странным: по сути у вас два веб-сервера, и один из них ещё и отвечает за бизнес-логику. CGI даёт один веб-сервер, который напрямую вызывает вашу бизнес-логику. Понятно, кто за что отвечает.

Отлаживать тоже проще. Ваше приложение — обычная программа, которую можно запустить из шелла: скормить ей запрос через пайп, посмотреть stderr, пройтись по ней в gdb. В каком-то смысле CGI похож на serverless: супервизор вызывает ваш код на каждый запрос, передаёт ему набор переменных окружения и забирает результат. CGI — это serverless минус вендор (и неожиданные счета).

Минимальный риск цепочки поставок. На фоне роста автономных агентов и еженедельных атак на репозитории пакетов приятно иметь очень мало зависимостей. К большинству современных стеков прилагаются менеджер пакетов и экосистема. Это удобно, но граф зависимостей раздувается: одна-две прямые зависимости тянут сотни косвенных, и каждую поддерживает кто-то, о ком вы никогда не слышали, а доступ к публикации у него защищён паролем, который он не менял с 2015 года. Моя цепочка поставок — это компилятор C и три библиотеки. Чтобы её скомпрометировать, нужно взломать libcurl, за которым следит весь интернет, а не пакет с одиннадцатью скачиваниями в неделю и владельцем, ушедшим в 2019 году.

Простой инструментарий. Я минималист по натуре. Я пользуюсь классическим Vim без единого плагина: ни LSP, ни автодополнения, ни форматтеров, ни ИИ. Сложные технологические стеки требуют сложных инструментов, например языкового сервера, чтобы продираться сквозь слои абстракции. Здесь стек настолько прост, что хватает обычного редактора. Всё приложение — каталог C-файлов и Makefile. Открываешь файл, читаешь — и знаешь, что он делает.

Хороший инструментарий под рукой. Если инструменты всё-таки нужны, они недалеко. Санитайзеры, valgrind, gdb, ctags, cscope — зрелые (ну, скорее, геронтологические) инструменты, которые десятилетиями шлифовались и ставятся одним пакетом в любой системе, где можно скомпилировать C. Зрелость не ограничивается самими инструментами: интеграция встроена во многие редакторы. В Vim есть нативная поддержка ctags и cscope и графический фронтенд для gdb (см. :h Termdebug).

Писать HTML и CSS на C не так уж плохо. Я сомневался, стоит ли писать весь фронтенд на C, но это оказалось далеко не так мучительно, как я себе представлял. Сколько раз я:

  • боролся с vim, чтобы он подсвечивал html/template из Go;

  • боролся с helix, чтобы он определял шаблоны Go и не ломал определение HTML;

  • боролся с RustRover, чтобы он распознавал шаблоны jinja в проекте на askama.

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

SQLite — глоток свежего воздуха. Для веб-приложений я всегда по умолчанию брал Postgres. Отличная база, но она приносит эксплуатационную нагрузку: серверный процесс, за которым надо присматривать, и частые релизы, на которые надо обновляться. У SQLite этого нет. Нет процесса, нет конфигурации, нет зависимостей. Приложение открывает файл базы напрямую. Эксплуатационная нагрузка минимальна.

Что бы я изменил

CGI — это интерфейс между веб-сервером и вашим приложением. Ни фреймворка, ни библиотеки тут нет, поэтому из коробки вы получаете очень мало. Придётся самому писать утилиты для:

  • разбора и создания cookie;

  • разбора и валидации параметров запроса;

  • разбора и валидации данных форм;

  • экранирования вводимых данных при выводе.

Я написал их сам в одном заголовочном файле (cgi.h), но не уверен, что это было правильное решение. Есть библиотеки вроде kcgi, но, взяв одну из них, вы покупаете её API и модель безопасности. Мне бы хотелось набор общих утилит, которые разработчики могли бы просто подключать (как библиотеки stb). Возможно, я опубликую cgi.h для начала.

Заключение

CGI стар, но не забыт. Большинство причин, по которым мы отказались от него в начале 2000-х, сегодня не работают. Форк процесса уже не так дорог: современные ядра сильно его оптимизируют. А если стоимость форка когда-нибудь станет проблемой, до FastCGI добраться достаточно просто.

Писать современное веб-приложение на C вполне реально: marketyour.games — коммерческий продукт, работающий на одном бинарнике по модели обслуживания, стандартизованной в 2004 году. В нём меньше подвижных частей, чем во всём, что я выпускал раньше. Я ещё вернусь к этому стеку.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.