はじめに (対象読者・この記事でわかること)

本記事は、Webサーバーの内部構造に興味がある初心者から中級者のエンジニアを対象としています。Apache や Nginx といった代表的な HTTP サーバーがどのプログラミング言語で実装されているのか、なぜその言語が選ばれたのかを理解したい方に最適です。この記事を読むことで、各サーバーの実装言語と歴史的背景、実際のビルド手順や拡張モジュールの作り方、そして開発・運用時に直面しやすいトラブルと対処法が分かります。サーバー選定や自前のモジュール開発を検討している方は、ぜひ参考にしてください。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。
- 基本的な Linux 操作(シェル、パッケージ管理)
- C 言語の基礎(変数宣言、関数定義、コンパイル概念)
- HTTP の基礎概念(リクエスト・レスポンスの流れ)

Apache と Nginx の実装言語と歴史的背景

Apache HTTP Server(通称 Apache)は、1995 年に最初のバージョンがリリースされた当時、C 言語で書かれたモジュラーな設計が採用されました。C 言語は当時の UNIX 系 OS の標準的な開発言語であり、パフォーマンスと移植性を兼ね備えていたため、広範なプラットフォームで動作させやすいという利点がありました。Apache は「モジュール」方式を採用し、必要な機能を「LoadModule」ディレクティブで動的にロードできる点が大きな特徴です。この設計は、当時のハードウェアリソースが限られていた環境でも、必要最低限の機能だけを組み込んで軽量化できるように配慮されています。

一方、Nginx(エンジンエックス)は、2002 年にロシアのプログラマー Igor Sysoev が開発を開始し、2004 年にオープンソース化されました。Nginx も C 言語で実装されていますが、設計思想は「イベント駆動型非ブロッキング I/O」に重点を置いています。これにより、同時接続数が多数に達してもメモリ使用量を抑え、高いスループットを実現できる点が特徴です。C 言語の低レベル制御と、Unix 系 OS が提供する epoll/kqueue といった高性能 I/O 機構を直接呼び出すことが可能だったため、Nginx のスケーラビリティは当初から高く評価されました。

近年では、パフォーマンス・安全性への関心から、Rust で書かれた Web サーバー(例:Actix‑Web、Warp)や、Go 言語で実装された Caddy Server なども登場していますが、Apache と Nginx のコアは依然として C 言語が主流です。C 言語はコンパイル時に最適化が可能で、CPU アーキテクチャごとの差異を細かく調整できる点が、まだまだ根強い支持を受けている理由です。

実装言語の詳細と設計思想

以下では、Apache と Nginx の実装言語に焦点を当て、実際に C 言語でビルド・モジュール開発を行う手順を紹介します。コード例やビルドコマンドを交えて、初心者でも手を動かしやすい形で解説します。

ステップ1:ソースコードの取得とビルド

Apache のビルド手順

  1. 必要な開発ツールと依存ライブラリをインストール
    bash sudo apt-get update sudo apt-get install -y build-essential libpcre3-dev libssl-dev

  2. Apache HTTP Server の公式サイトから最新版ソースを取得
    bash wget https://downloads.apache.org/httpd/httpd-2.4.59.tar.gz tar xf httpd-2.4.59.tar.gz cd httpd-2.4.59

  3. configure スクリプトでビルドオプションを指定(例:MPM を event に設定)
    bash ./configure --with-included-apr --enable-mods-shared=all --with-mpm=event

  4. コンパイルとインストール
    bash make -j$(nproc) sudo make install

Nginx のビルド手順

  1. 必要な開発ツールと依存ライブラリをインストール
    bash sudo apt-get install -y build-essential libpcre3-dev zlib1g-dev libssl-dev

  2. Nginx の公式サイトから最新版ソースを取得
    bash wget https://nginx.org/download/nginx-1.27.0.tar.gz tar xf nginx-1.27.0.tar.gz cd nginx-1.27.0

  3. configure オプションでモジュールを組み込む(例:HTTP/2, SSL)
    bash ./configure --with-http_ssl_module --with-http_v2_module --with-cc-opt="-O2"

  4. コンパイルとインストール
    bash make -j$(nproc) sudo make install

ステップ2:C 言語でモジュール(拡張)を作成

Apache モジュール例(簡単なハンドラ)

C
/* hello_module.c */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" static int hello_handler(request_rec *r) { if (!r->handler || strcmp(r->handler, "hello-handler")) return DECLINED; ap_set_content_type(r, "text/plain"); ap_rprintf(r, "Hello from custom Apache module!\n"); return OK; } static void hello_register_hooks(apr_pool_t *p) { ap_hook_handler(hello_handler, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA hello_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config */ NULL, /* merge per-dir config */ NULL, /* create per-server config */ NULL, /* merge per-server config */ NULL, /* commands */ hello_register_hooks };

ビルド手順(Apache の apxs ユーティリティを使用)

Bash
apxs -c -i hello_module.c

Nginx モジュール例(シンプルなコンテンツハンドラ)

C
/* ngx_http_hello_module.c */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) { ngx_str_t type = ngx_string("text/plain"); ngx_str_t response = ngx_string("Hello from custom Nginx module!\n"); r->headers_out.content_type = type; r->headers_out.content_length_n = response.len; ngx_int_t rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } ngx_buf_t *b = ngx_create_temp_buf(r->pool, response.len); ngx_memcpy(b->pos, response.data, response.len); b->last = b->pos + response.len; b->last_buf = 1; ngx_chain_t out = { .buf = b, .next = NULL }; return ngx_http_output_filter(r, &out); } static char *ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_cfg(cf, ngx_http_core_module); clcf->handler = ngx_http_hello_handler; return NGX_CONF_OK; } static ngx_command_t ngx_http_hello_commands[] = { { ngx_string("hello"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_http_hello, 0, 0, NULL }, ngx_null_command }; static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; ngx_module_t ngx_http_hello_module = { NGX_MODULE_V1, &ngx_http_hello_module_ctx, /* module context */ ngx_http_hello_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, NULL, NULL, NULL, NULL, NULL, NGX_MODULE_V1_PADDING };

ビルド手順(nginx ディレクトリに配置し、configure 時にモジュールを指定)

Bash
./configure --add-module=/path/to/ngx_http_hello_module make sudo make install

ハマった点やエラー解決

1. apxs が見つからない

  • 原因apache2-dev パッケージが未インストール。
  • 対処sudo apt-get install apache2-dev でインストール後、再度 apxs を実行。

2. Nginx のビルド時に ngx_http_v2_module が無効になる

  • 原因:OpenSSL が古く、HTTP/2 が有効化できない。
  • 対処:最新の OpenSSL (1.1.1以上) をインストールし、./configure --with-http_v2_module を再実行。

3. カスタムモジュールのシンボル未解決

  • 原因ngx_http_hello_module.c を単体でコンパイルしたため、必要なヘッダーやシンボルがリンクされていない。
  • 対処:Nginx のビルドプロセスにモジュールを組み込むか、-I オプションで正しいインクルードパスを指定。

4. メモリリークの検出

  • 原因:バッファを作成したまま解放し忘れた。
  • 対処ngx_pfree を使用してリクエストプールから確保したバッファを明示的に解放、もしくはプールの自動解放に任せる。

解決策のまとめ

  • 依存パッケージは事前に確認apt-cache search で必要な -dev 系パッケージをリストアップし、インストールしておく。
  • 公式ドキュメントのビルドオプション表を活用./configure --help で有効なフラグを把握し、必要な機能だけを有効化。
  • デバッグツールの活用gdbvalgrind を使ってセグメンテーションフォルトやメモリリークを早期に検出。
  • モジュール開発ガイドの参照:Apache の mod_so、Nginx の Dynamic Module ガイドは、モジュールのロード方式や API 変更点がまとめられているので必読。

まとめ

本記事では、Apache と Nginx がどちらも C 言語で実装されている理由と、歴史的・技術的な背景を解説しました。
- C 言語が選ばれた理由:高いパフォーマンス、低レベル制御、広範な OS への移植性。
- Apache のモジュラー設計:ロード可能モジュールで機能拡張が容易。
- Nginx のイベント駆動モデル:非ブロッキング I/O による高スループット実現。

読者は、実際にソースコードを取得しビルド・モジュール開発を行う手順を学び、ビルド時の典型的なエラーとその対処法を把握できました。今後は、Rust や Go で書かれた新世代サーバーの比較や、既存サーバーへのプラグイン化手法についても取り上げる予定です。

参考資料