
2026/10/13 1:13
C で構築されたモダンな Web アプリ
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
本テキストは、2026 年に C と CGI を OpenBSD 上で構築された独自の商用 Web アプリケーション「marketyour.games」について説明しています。このプロジェクトは現代のフレームワークよりも極度な簡潔性とセキュリティを優先しており、「BCHS」スタック(OpenBSD、C、httpd、SQLite)を採用し、外部のフレームワークや独立したデータベースサーバーは一切使用しません。核心的な革新点は、アプリケーション全体が静的にリンクされた単一のバイナリとして動作し、ランタイム依存関係がゼロであるというアーキテクチャにあります。デプロイはファイルを 1 つだけフォルダに配置するだけであり、古いバージョンを置き換えるだけで済みます。再起動やダウンタイムも不要です。
セキュリティは OpenBSD のデフォルト設定を通じて強制されており、httpd に対して
chroot を適用し、C プログラムに対して pledge および unveil などのツールを使用して制約を課します。アーキテクチャは、すべての HTTP リクエストごとに新しいプロセスをフォークし、コードから直接アセットを提供することでメモリ内に完全に収まり、すべてのトラフィックを httpd を介して CGI バイナリにルーティングするという方式に基づいています。このアプローチでは JavaScript テンプレート言語を使用しない(プログレッシブ改善に従う)とともに、安定した CGI 1.1 規格に準拠しますが、使いやすさを犠牲にして制御性を追求します。
主な利点としては、サプライチェーンリスクが著しく低減すること—依存するのは C コンパイラーと 3 つのライブラリ(
libcurl、libsodium、組み込み済みの libcjson)のみ—、そして GDB のような標準ツールによるデバッグが容易であることです。アプリケーションは通常の実行ファイルだからです。しかしながら、この手法では開発者がデータを解析するためのロジック(クッキー、クエリ、フォーム)やカスタムヘッダーの管理を自ら実装する必要があり、複雑な依存関係グラフではなく、基本的な HTTP 概念と Vim のような古典的なツール(プラグインなし)を活用する姿勢を選択します。本文
コーリー・プロフィット:C 言語による現代型 Web アプリケーション
イントロダクション
1994 年に動的な Web サイトを実現するには、C プログラムを作成し
ディレクトリに配置し、Apache が各リクエストごとにフォークさせて実行させる方式でした。32 年たった現在も、本質的に同一の技術を用いて商用の Web 製品をリリースすることに成功しました。cgi-bin
- サービス名:
marketyour.games - 機能: ユーザーアカウント機能、コンテンツクリエイター向け検索ダッシュボード、整理用フォルダ搭載。
- 決済・通知: Stripe を介した支払い処理、Postmark を通じたトランザクションメール対応。
- アーキテクチャ: プログレッシブ・エンハンスメントの原則に従い、JavaScript の依存は全くありません。
現代ではないのは実装方法と提供方法のみです。2026 年において、C 言語で本格的な製品を開発し、CGI 方式にて提供することの是非について述べています。
タイムライン(TLR)
CGI の衰退は 2004 年時点で正当化されたものでありましたが、2026 年においては通用しません。C 言語で現代型の Web アプリケーションを作成することが可能です。私がリリースした製品の特徴は以下の通りです。
- 単一の実行ファイル
- 一つの SQLite ファイル
- 三つの依存関係のみ
- 全体が頭の中で把握できるほどシンプル
実装方法
スタックには BCHS という略称を使用します:OpenBSD、C 言語、httpd、および SQLite です。
フレームワークや外部ツールの不使用
- フレームワーク: 一切使用せず。CGI 環境変数を直接読み込み、レスポンスを返す C プログラムを記述します。
- テンプレートエンジン: 使用せず。HTML を直接出力する C コードを記述します。
- 独立したデータベースサーバー: 使用せず。SQLite の C API を通じてデータベースファイルを開きます。
- コンテナ: 採用せず。静的にリンクされたバイナリを作成し、単なるフォルダ内へ配置します。
デプロイと起動特性
- 各リクエストごとに新しいプロセスが起動します。
- 新バージョンのデプロイは、単一のファイル置換を意味します。
- サーバーの再起動やダウンタイムは一切生じません。
- 新しいリクエストは単に新たなバイナリを読み込んで実行すればよいです。
セキュリティ環境(OpenBSD と httpd)
- OpenBSD: 健全なデフォルト設定を搭載。
やpledge
といったツールを提供し、C プログラムを実際にセキュア化することを可能にします。unveil - httpd: デフォルトで chroot 環境から動作するため、CGI バイナリはファイルシステムの一角に限定的にサンドボックス化して実行されます。
活用するライブラリ(3 つ)
- libcurl: Stripe および Postmark へのすべてのアウトバウンドリクエスト処理。
- libsodium: ランダム識別子の生成、パスワードハッシュ化、Stripe ウェブフック用 HMAC 検証。
- libcjson: Stripe および Postmark 向けの JSON パース担当。
ビルド依存関係の最適化
- 実際のビルド依存関係:
とlibcurl
の 2 つのみです。libsodium - libcjson: 単一の C ファイルであり、外部依存関係は一切ありません(ベンダー化済み)。
- SQLite: 公式の統合ビルド(単一 C ファイル形式)を提供しており、プロジェクト内でベンダー化されます。
- 結果: ほぼ移動部品がゼロに近い構造です。クリーンなビルドは数秒で完了し、再ビルドは半秒未満で行われます。
アセットの提供方法
従来の静的アセットの提供ではなく、httpd からすべてのトラフィックを CGI バイナリへルーティングするアプローチを採用しました。各アセットは実行ファイル内にコンパイルされ、メモリから直接提供されます。
気に入りポイント
1. フレームワークよりも基本原則
CGI は学ぶためのフレームワークではなく、1994 年に公開された仕様書(現在も改訂なし)に基づいています。内部化すべき API も存在せず、インターフェース全体はごく基本的な HTTP の概念だけで構成されています:
- リクエストヘッダー
- リクエストメソッド
- クエリ文字列
- ボディデータ
HTTP が理解できれば、CGI も既に理解しています。 言語もプラットフォームも超えており、一度習得すれば生涯有効な知識です。
2. 懸念領域の明確な分離
現代の Web アプリケーションでは、通常 nginx などの Web サーバーを前面に置き、Ruby、Python、Go、Rust などで記述されたアプリケーションサーバーへリバースプロキシする構成となります。しかし CGI は以下の利点を持ちます:
- 単一の Web サーバー: ビジネスロジックを直接呼び出す方式です。
- 責任の所在が明確: 誰が何を担当しているかがわかり、デバッグも容易になります。
- プロセスとしての実行: アプリケーションはシェルから実行できる普通のプロセスです。リクエストをパイプして送り出し、stderr を監視し、
でステップ実行可能です。gdb - サーバーレスとの類似性: スーパーバイザーが各リクエストに対してコードを実行させ、環境変数の袋を渡し、結果を集約する仕組みです(ベンダーを除く)。
3. 最小限のサプライチェーンリスク
自律エージェントの台頭とパッケージリポジトリに対する攻撃が続く現在、依存関係が極めて少ないことは安心感を与えます。
- 現代技術スタック: パッケージマネージャーとエコシステムを備えているが、依存関係グラフは膨張しやすいです。
- C コンパイル環境: C コンパイラーと三つのライブラリだけです。
- 安全性:
を侵害するにはインターネット全体が監視するプロジェクトの脆弱性を突く必要があります。所有者も信頼性も異なります。libcurl
4. シンプルで使い勝手の良いツール環境
ミニマリスト志向のエディタ(プラグインを一つも使わないクラシックな Vim)を使用しています。
- 不要な機能: LSP、自動補完、コードフォーマッター、AI は一切ありません。
- スタックの構造: アプリケーション全体が C ファイルのディレクトリと Makefile です。
- 可読性: ファイルを開いて読むだけで、その動作がわかります。
- 既存ツールの活用: サンタイザーズ、
、valgrind
、gdb
、ctags
などは成熟したツールで、パッケージインストール一つで利用可能です(Vim などにはネイティブサポートあり)。cscope
5. C 言語で HTML と CSS を書くのも悪くない
フロントエンド全体を C 言語で書くことに最初は躊躇しましたが、想像していたほど苦痛ではありませんでした。以下の状況に遭遇した際、C の方が快適だと感じました:
- Vim で Go の
構文のハイライトと戦うこと。html/template - Helix エディタで Jinja テンプレート検出を壊さずに Go テンプレートを検出させるために戦うこと。
- Rustrover で Askama プロジェクト用の Jinja テンプレート認識のために戦うこと。
C を使うということは、エディタが半端に検出しようとする第二の言語がなく、混合構象によるハイライト崩れもなく、プラグインダンシングも不要です。新鮮さを再発覚しました(Tailwind も美しいとは限りませんが)。
6. SQLite は清涼剤
常に Web アプリケーション向けに Postgres をデフォルトとして選びましたが、運用負担が伴います:
- 管理すべきサーバープロセスがあること。
- 頻繁なアップデートが必要であること。
これに対して SQLite は以下の通りです:
- プロセス、設定、依存関係は一切不要です。
- アプリケーションはデータベースファイルを直接開きます。
- 運用負担は最小限です。
改善点
CGI は Web サーバーとアプリケーションの間のインターフェースです。フレームワークやライブラリが存在しないため、ボックスアウト(標準機能)では非常に限定的です。以下の処理を行うために独自の実用ユーティリティを開発する必要があります:
- クッキーのパースと生成
- クエリパラメータのパースと検証
- フォームデータのパースと検証
- 表示用への入力エスケープ
現在の対応策としては、単一のヘッダーファイル(
cgi.h)を自作しています。しかし、kcgi といった既存ライブラリも存在します。開発者がドロップインできる共有ユーティリティのセット(stb ライブラリのようなもの)が見られたいです。もしかしたら cgi.h を公開して始めるかもしれません。
結論
CGI は古くなっていますが、忘れ去られたわけではありません。2000 年代初頭に見送られた主な理由は今日では通用しません:
- プロセスフォークのコスト: かつてほど高価ではありません;現代のカーネルが大幅に最適化しています。
- 代替手段: フォークのコストが問題になる場合でも、FastCGI は非常にシンプルなアップグレードオプションです。
C 言語で現代型の Web アプリケーションを書くことは十分に可能であり、
marketyour.games は単一の実行ファイル上で動作する商用製品です。これは私が過去にリリースした何よりも移動部品が少なくシンプルです。私はこのスタックを再度選択することになるでしょう。