世界を動かす技術を、日本語で。

Cによるモダンウェブアプリ

2026年10月13日原文(prophitt.me)

概要

  • CGI と C言語 によるWebアプリ開発の現代的実践例
  • BCHSスタック (OpenBSD, C, httpd, SQLite)のシンプルさと強み
  • 依存関係を最小限に抑えた 堅牢な開発環境 の紹介
  • CGIの古さ が現代では必ずしもデメリットでない理由
  • 実装時の課題と改善案、今後の展望

2026年にCとCGIで商用Webサービスを作った話

  • 1994年 のCGI技術を2026年でも活用した事例
  • marketyour.games という商用Webプロダクトの開発・運用
  • 最新の機能 (ユーザーアカウント、検索ダッシュボード、Stripe決済、Postmarkメール)を備えた現代的Webサービス
  • JavaScript不要 のプログレッシブエンハンスメント設計
  • 開発・配信方法のみが「古典的」な点

CGIの再評価:2004年の常識は2026年に通用しない

  • CGIの衰退理由 (2004年時点)は現代では妥当でない
  • C言語 でモダンなWebアプリの実現
  • 単一バイナリ、SQLiteファイル、3つの依存ライブラリのみで完結
  • 開発者が全体像を把握できるシンプル構成

BCHSスタック:実装の全容

  • BCHS :OpenBSD, C, httpd, SQLiteによる構成
  • フレームワーク不使用、CGI環境変数を直接読み書き
  • テンプレート言語不使用、CでHTMLを直接出力
  • データベースサーバ不要、SQLiteのC APIで直接ファイル操作
  • コンテナ不要、静的リンクバイナリをディレクトリに配置
  • 全リクエストごとに新規プロセス生成、デプロイはバイナリ差し替えのみ
  • OpenBSDのセキュリティ機能 (pledge, unveil, chroot)活用
  • 追加ライブラリは libcurl (外部リクエスト)、 libsodium (乱数・パスワード・HMAC)、 libcjson (JSON解析)
    • libcurl, libsodium のみビルド依存、libcjsonとSQLiteはプロジェクト内でビルド
  • 静的アセット も全てバイナリに埋め込み、httpdから全リクエストをCGIバイナリへルーティング

この方式の長所

  • フレームワーク不要、学習コストが低い
    • CGI仕様 は2004年から不変、HTTPの基本のみ理解すれば十分
    • 言語・プラットフォーム非依存、知識が長期間有効
  • 責務分離の明確化
    • Webサーバ が直接ビジネスロジックを呼び出す
    • デバッグ容易、シェルから直接実行・gdbでステップ実行可能
    • サーバーレスに近い構造、ベンダーロックや予想外の請求なし
  • サプライチェーンリスク最小化
    • 依存は Cコンパイラと3ライブラリ のみ
    • 複雑なエコシステムや不明なメンテナによる間接依存が発生しない
  • シンプルなツール環境
    • Vim等の軽量エディタ で十分対応可能
    • Sanitizer, valgrind, gdb, ctags, cscope など成熟したツールが利用可能
    • 多くのエディタに 統合サポート あり
  • CでのHTML/CSS生成も意外と悪くない
    • テンプレート言語の混在によるエディタ設定の煩雑さがない
    • Cだけで完結、ハイライト崩れやプラグイン問題も発生しない
  • SQLiteの運用負荷の低さ
    • Postgres に比べてプロセス管理やアップグレード不要
    • アプリから直接ファイルオープン、設定不要

改善したい点・課題

  • CGIはインターフェースのみ で、便利機能は自作が必要
    • Cookie処理、 クエリパラメータ解析・バリデーション、 フォームデータ処理、 エスケープ 等を自作
    • cgi.h (自作ヘッダ)で実装したが、最適解かは疑問
    • kcgi 等のライブラリも存在するが、APIやセキュリティモデルへの依存が発生
    • stbライブラリ のような、ドロップイン可能な共通ユーティリティの必要性
    • 今後 cgi.h を公開予定

結論:CGIの現在地と今後

  • CGIは古いが、現代でも十分実用的
  • プロセスフォークのコスト は現代カーネルで大幅に低減
  • 必要なら FastCGI への移行も容易
  • CでのWebアプリ開発は現実的かつ堅牢
    • marketyour.games は単一バイナリで商用運用中
    • これまでで最も「動く部品」が少ない堅実なスタック
  • 今後もこの構成を積極的に活用予定

Hackerたちの意見

なんで著者が最初にCを選んだのか、ちょっとよくわからないな。でも、経験をシェアしてくれてありがとう。

└

俺は、OKCupidの人たちがC++で自分たちのウェブサーバーを書いてた頃を覚えてるよ!リクエストの「スロット」の概念はそこから取ったんだ。https://github.com/okws/okws

└

昨日かその前にZigを使うっていう投稿があったよね。それを読んだとき、Cを使っても同じようにうまくいくんじゃないかと思った。

└

なんで全てがCじゃないのか、全然わからない。 :|

└

Cじゃなくて「X」って言うのは避けたかったんだ。コメントが言語戦争に発展しちゃうからね。

CGIは素晴らしいね。残念ながら、nginxはlighttpdとは違ってネイティブでサポートしてないんだ。このプロジェクトはnginxにCGIを追加するためのもので、気に入ってるよ。https://github.com/pjincz/nginx-cgi それに、nginxからpassengerを使ってRackアプリケーションを直接起動する方法もあるよ。RackはRubyのウェブアプリ用のCGIみたいなインターフェースだね。https://github.com/rack/rack Rubyの数行でアプリやミドルウェアを書くのが簡単にできるよ。

└

fastcgiラップ。

└

俺はlighttpd使ってるよ。

└

でも本当の疑問は、Caddyはそれをサポートしてるの?答えは、サポートしてるけどコミュニティプラグインを通じてって感じ。

別のデータベースサーバーはないよ。SQLiteのC APIを通じてデータベースファイルを開くんだ。 > すべてのリクエストが新しいプロセスを生成する。複数の同時リクエストが可能な場合、どうやって動くの?SQLiteは複数のプロセスからの同時書き込みアクセスを許可するの?

└

SQLiteはWALモードに設定すれば、複数の同時リクエストを処理できるよ。読み込みはすべてノンブロッキング/同時だけど、書き込みはまだ同期的なんだ。「ビジータイムアウト」も設定した方がいいよ、そうしないとブロックされた書き込みがすぐにタイムアウトしちゃうから。

└

同時リクエストを送るユーザーは即座にバンされて、そのデータは削除されるよ。それが確実な方法だからね。

Hacker Newsで議論の続きを見る