目次
- はじめに:Webアクセスの大まかな流れ(旅の始まり)
-
URL:Web上の住所を読み解く
- スキーム (http, https)
- ホスト名 (ドメイン名)
- ポート番号 (省略されることが多い)
- パス (サーバー上のどこ?)
- クエリパラメータ (追加情報)
- フラグメント (ページ内の特定箇所)
-
DNS:名前から住所(IPアドレス)を調べる
- DNSサーバーの役割
- 名前解決の流れ
-
TCP/IP:通信路の確立(電話をかける)
- IPアドレス:インターネット上の住所
- TCP:信頼性の高い通信の約束(3ウェイハンドシェイク)
-
HTTP/HTTPS:会話のルール(何を・どう伝えるか)
- HTTPリクエスト:ブラウザからサーバーへのお願い
- リクエストライン (GET /index.html HTTP/1.1)
- ヘッダー (Host, User-Agent, Accept など)
- ボディ (POSTデータなど)
- HTTPS:安全な会話のための暗号化 (SSL/TLS)
- HTTPリクエスト:ブラウザからサーバーへのお願い
-
Webサーバーソフトウェア:リクエストを受け取る門番 (Apache, Nginx)
- 役割:リクエストの受付、処理の振り分け
- 代表的なソフトウェア:Apache, Nginx
-
【重要】ホストとパスの切り替え:正しい宛先へ案内する
-
仮想ホスト (Virtual Host):1台のサーバーで複数のWebサイトを運営する技術
- なぜ必要か? (IPアドレスの節約、管理の容易さ)
- 仕組み:
Host
ヘッダーの利用 - Apacheでの設定例 (
<VirtualHost>
ディレクティブ) - Nginxでの設定例 (
server
ブロック) - 設定のポイント:
ServerName
,DocumentRoot
-
パスに基づいた処理の振り分け:URLのパスを見て、どこにあるファイルやプログラムを動かすか決める
- ドキュメントルート (Document Root):Web公開の起点
- URLパスとファイルシステムパスのマッピング
- ディレクトリインデックス (
index.html
,index.php
など) - URL書き換え (Rewrite):綺麗なURL、処理の集約 (Apache
mod_rewrite
, Nginxrewrite
,location
) - フレームワークにおけるルーティング (より高度なパス制御)
-
仮想ホスト (Virtual Host):1台のサーバーで複数のWebサイトを運営する技術
-
【重要】サーバー上のディレクトリ・ファイル構成:コンテンツを整理整頓する
- 基本原則:公開するもの、しないものを分ける
- ドキュメントルート (Document Root) の役割再訪
-
実践的なディレクトリ構成例
- 例1:シンプルな静的サイト
- 例2:一般的なCMS (WordPressなど) の構成
-
例3:Webアプリケーションフレームワーク (MVCなど) の構成
-
public
(公開ディレクトリ): エントリーポイント、アセットファイル -
app
/src
(アプリケーションコード): ロジック、コントローラー、モデルなど -
vendor
(ライブラリ): 外部依存パッケージ -
config
(設定ファイル) -
storage
/var
(一時ファイル、ログ)
-
- なぜこのように分けるのか? (セキュリティ、保守性、共同開発)
- ファイル・ディレクトリのパーミッション (権限):誰が何をして良いか
-
コンテンツの処理:静的ファイルと動的ファイル
-
静的コンテンツ (Static Content):そのまま返すファイル
- HTML, CSS, JavaScript, 画像ファイルなど
- Webサーバーが直接ファイルを読み込んで送信
-
動的コンテンツ (Dynamic Content):プログラムが生成するコンテンツ
- PHP, Python, Ruby, Node.js, Javaなどで書かれたプログラム
- Webサーバーからアプリケーションサーバー/インタプリタへ処理依頼 (CGI, FastCGI, WSGI, Rack, Node.jsプロセスなど)
- データベースとの連携
- テンプレートエンジンによるHTML生成
- なぜ動的コンテンツが必要か? (パーソナライズ、インタラクション、最新情報)
-
静的コンテンツ (Static Content):そのまま返すファイル
-
HTTPレスポンス:サーバーからブラウザへの返事
- ステータスライン (HTTP/1.1 200 OK)
- ヘッダー (Content-Type, Content-Length, Set-Cookie, Cache-Control など)
- ボディ (HTMLデータ、画像データなど)
-
ブラウザによるレンダリング:受け取った情報を画面に描画
- HTML解析 → DOMツリー構築
- CSS解析 → CSSOMツリー構築
- DOM + CSSOM → レンダーツリー構築
- レイアウト (要素の配置計算)
- ペイント (描画)
- JavaScriptの実行 (DOM操作、イベント処理など)
- 追加リソースの取得 (CSS, JS, 画像ファイルなど - ここでも1〜10の処理が繰り返される)
-
さらに知っておきたい技術要素(実践レベルの補足)
- ロードバランサ:アクセス負荷分散
- CDN (Content Delivery Network):静的ファイルの高速配信
- キャッシュ (ブラウザ、サーバー、CDN):表示速度の向上
- データベースサーバー:データの永続的な保管場所
- ファイアウォール / WAF:セキュリティ対策
- デプロイ:開発したコードをサーバーに配置する方法 (FTP, Git, CI/CD)
- まとめ:一連の流れを振り返る
1. はじめに:Webアクセスの大まかな流れ(旅の始まり)
あなたがブラウザのアドレスバーに https://www.example.com/products/
と入力してEnterキーを押した瞬間、インターネットの世界を巡る小さな旅が始まります。
この旅の目的は、www.example.com
という名前のサーバーに「/products/
という場所にある情報(コンテンツ)を見せてください」とお願いし、その結果を受け取って画面に表示することです。
この一連の流れは、大まかに以下のステップで進みます。
-
行き先(サーバー)の特定:
www.example.com
がインターネット上のどこにあるのかを探します (DNS)。 - 通信路の確保: あなたのPCとサーバー間で、安全で確実な情報の通り道を確立します (TCP/IP, HTTPS)。
- お願いの伝達: ブラウザがサーバーに「このページのデータください!」と具体的にリクエストを送ります (HTTPリクエスト)。
- サーバーでの処理: サーバーがリクエストを受け取り、どの情報(ファイルやプログラム)を渡すべきか判断し、準備します (Webサーバー, ホスト/パス解決, ファイル構成, 動的処理)。
- 返事の送信: サーバーが準備したデータをブラウザに送り返します (HTTPレスポンス)。
- 画面への表示: ブラウザが受け取ったデータを解釈し、画面に表示します (レンダリング)。
これから、これらのステップを一つずつ詳しく見ていきましょう。特に、ステップ4のサーバー内部での動き、つまり「どのようにして目的のファイルやプログラムにたどり着くのか」「ファイルはどのように整理されているのか」に焦点を当てて解説します。
2. URL:Web上の住所を読み解く
旅の始まりはURL (Uniform Resource Locator) です。これはインターネット上のリソース(情報)の場所を一意に示すための「住所」のようなものです。
例: https://www.example.co.jp:8080/service/item?id=123#section1
このURLは、いくつかの部分に分解できます。
-
スキーム (Scheme):
https
- リソースにアクセスするための方法(プロトコル)を指定します。
-
http
: HyperText Transfer Protocol。情報を平文(暗号化なし)でやり取りします。 -
https
: HTTP Secure。SSL/TLSという技術で通信を暗号化し、安全性を高めたものです。現代のWebサイトではhttps
が標準です。 - 他にも
ftp
,mailto
,file
などがあります。
-
ホスト名 (Host Name):
www.example.co.jp
- リソースが存在するサーバーの名前(ドメイン名)です。人間が覚えやすいように付けられています。
- この名前は、後述するDNSによって、コンピューターが理解できるIPアドレスに変換されます。
-
ポート番号 (Port Number):
:8080
- サーバー内のどの「窓口」に接続するかを指定します。コンピューターには多くの通信口(ポート)があり、サービスごとに番号が割り当てられています。
-
http
のデフォルトポートは80
、https://
のデフォルトポートは443
です。これらのデフォルトポートを使う場合は、URL内で省略可能です。例の:8080
はデフォルトではないため明記されています。
-
パス (Path):
/service/item
- サーバー内のリソースがどこにあるかを示す「経路」です。通常、サーバー内の特定のディレクトリやファイルに対応します。
-
/
は最上位(ルート)を表します。この例では、「service」ディレクトリの中の「item」というリソースを指しています。これがどのようにサーバー上のファイル構成と結びつくかは、後ほど詳しく解説します。
-
クエリパラメータ (Query Parameter):
?id=123
-
?
の後に続くキー=値
の形式の文字列で、リソースに渡す追加情報です。&
で複数繋げることができます (例:?id=123&type=A
)。 - 動的なWebページで、表示する内容を絞り込んだり、検索条件を指定したりするのによく使われます。
-
-
フラグメント (Fragment):
#section1
-
#
の後に続く文字列で、ページ内の特定の場所(アンカー)を示します。 - この情報はサーバーには送信されず、ブラウザがページ表示後に該当箇所へスクロールするために使われます。
-
3. DNS:名前から住所(IPアドレス)を調べる
人間は www.example.com
のような名前(ホスト名)でWebサイトを覚えますが、コンピューターは 192.0.2.1
のような数字の羅列(IPアドレス)で通信相手を特定します。
ここで登場するのが DNS (Domain Name System) です。DNSは、インターネット上の「電話帳」のようなシステムで、ホスト名をIPアドレスに変換(名前解決)する役割を担います。
名前解決の流れ(概要):
- ブラウザはまず、PCのOSに「
www.example.com
のIPアドレス教えて」と依頼します。 - OSは、まず自身のキャッシュ(一時的な記憶)や
hosts
ファイル(手動設定)を確認します。 - 見つからなければ、ネットワーク設定で指定された DNSリゾルバ(キャッシュDNSサーバー)(通常はプロバイダや社内ネットワークが提供)に問い合わせます。
- DNSリゾルバもキャッシュになければ、ルートDNSサーバー → トップレベルドメイン(TLD)DNSサーバー (
.com
,.jp
などを管理) → 権威DNSサーバー (example.com
の情報を管理しているサーバー) へと、順々に問い合わせてIPアドレスを探し出します。 - 最終的に見つかったIPアドレス
192.0.2.1
をOS経由でブラウザに返します。
このDNSの仕組みがあるおかげで、私たちは覚えにくいIPアドレスを意識することなく、分かりやすいドメイン名でWebサイトにアクセスできるのです。
4. TCP/IP:通信路の確立(電話をかける)
IPアドレスが分かったら、次はサーバーとの間で実際にデータをやり取りするための通信路を確立します。ここで使われるのが TCP/IP というプロトコル群です。
- IP (Internet Protocol): データをパケットという小さな単位に分割し、それぞれに宛先IPアドレスと送信元IPアドレスを付けて、インターネット網に送り出す役割を担います。「荷物に宛先ラベルを貼って送り出す」イメージです。ただし、IPだけではデータが相手に届く保証や、届く順番の保証はありません。
-
TCP (Transmission Control Protocol): IPの上位層で動作し、信頼性の高い通信を実現します。「確実に荷物を届け、順番通りに組み立てる」役割です。
- コネクション確立(3ウェイハンドシェイク): 通信を始める前に、送信側と受信側で「今から通信を始めます」「OKです」「了解しました」という3段階の確認応答(SYN, SYN/ACK, ACK)を行い、仮想的な通信路(コネクション)を確立します。電話をかける前に相手が出て、双方で話せる状態を確認するようなものです。
- データ分割と順序制御: 送信するデータを適切なサイズのセグメントに分割し、それぞれにシーケンス番号を付けて送ります。受信側はシーケンス番号を元にデータを正しい順序に並べ替えます。
- 到達確認と再送制御: データを受け取ったら「受け取りました」(ACK)という確認応答を送り返します。一定時間内にACKが返ってこない場合、データが消失したと判断して再送します。
HTTPSの場合は、このTCPコネクションが確立した後、さらに SSL/TLSハンドシェイク という暗号化通信路を確立するためのやり取りが行われます(後述)。
5. HTTP/HTTPS:会話のルール(何を・どう伝えるか)
通信路が確保されたら、いよいよブラウザとWebサーバーの間で「会話」が始まります。この会話のルールが HTTP (HyperText Transfer Protocol) です。
HTTPリクエスト:ブラウザからサーバーへのお願い
ブラウザは、サーバーに対して「何をしてほしいか」「どんな情報がほしいか」を伝えるために、HTTPリクエストメッセージを送信します。これは主に3つの部分から構成されます。
-
リクエストライン (Request Line): リクエストの最も重要な情報。
-
メソッド (Method): サーバーに何をしてほしいかを示す動詞。
-
GET
: 指定したリソース(Webページや画像など)を取得したい。URLにパラメータを含めることが多い。最も一般的なメソッド。 -
POST
: データをサーバーに送信したい(フォーム入力内容の送信、ファイルのアップロードなど)。データはリクエストボディに含まれる。 - 他にも
PUT
(リソースの更新/作成),DELETE
(リソースの削除),HEAD
(ヘッダーのみ取得),OPTIONS
(利用可能なメソッドの問い合わせ) などがあります。
-
-
リクエストURI (Request-URI): どのリソースに対するリクエストかを示すパスとクエリパラメータ (
/service/item?id=123
など)。 -
HTTPバージョン (HTTP Version): 使用するHTTPのバージョン (
HTTP/1.1
やHTTP/2
など)。
例:
GET /service/item?id=123 HTTP/1.1
-
メソッド (Method): サーバーに何をしてほしいかを示す動詞。
-
ヘッダー (Headers): リクエストに関する追加情報。
ヘッダー名: 値
の形式で複数記述されます。-
Host: www.example.co.jp
: 【重要】 アクセス先のホスト名を指定します。後述する仮想ホストで、どのWebサイト宛のリクエストかをサーバーが判断するために必須のヘッダーです。 -
User-Agent: Mozilla/5.0 (...) Chrome/100.0
: ブラウザの種類やバージョン情報。サーバーはこれを見て、ブラウザごとに最適な表示を返すことがあります。 -
Accept: text/html,application/xhtml+xml,...
: ブラウザが受け入れ可能なコンテンツの種類(MIMEタイプ)。 -
Accept-Language: ja,en-US;q=0.9,en;q=0.8
: ブラウザが希望する言語。 -
Cookie: session_id=abcdef12345
: 以前サーバーから受け取ったCookie情報。ログイン状態の維持などに使われます。 -
Referer: https://search.example.com/
: どのページからリンクを辿ってきたか。 - など、多数のヘッダーがあります。
-
-
ボディ (Body):
POST
メソッドなどで、サーバーに送信するデータ本体(フォームの入力内容、アップロードファイルなど)。GET
リクエストの場合は通常ボディはありません。
HTTPS:安全な会話のための暗号化 (SSL/TLS)
URLのスキームが https
の場合、HTTP通信は SSL (Secure Sockets Layer) またはその後継である TLS (Transport Layer Security) というプロトコルによって暗号化されます。
TCPコネクション確立後、HTTPリクエスト/レスポンスを送信する前に、SSL/TLSハンドシェイクと呼ばれる手順で以下のことを行います。
- サーバー認証: ブラウザはサーバーから送られてきた「SSLサーバー証明書」を検証し、アクセス先のサーバーが本物であることを確認します。証明書には、サーバーのドメイン名、発行者(認証局)、有効期限などが含まれます。
- 暗号化方式の決定: ブラウザとサーバーで、どの暗号化アルゴリズムを使うかを取り決めます。
- 共通鍵の生成と共有: 安全な方法(公開鍵暗号など)を使って、実際の通信データを暗号化するための「共通鍵」をブラウザとサーバーの間で共有します。
これにより、以降のHTTP通信(リクエストとレスポンス)の内容はすべて暗号化され、途中で盗聴されたり改ざんされたりするのを防ぐことができます。個人情報や決済情報を扱うサイトでは必須の技術です。
6. Webサーバーソフトウェア:リクエストを受け取る門番 (Apache, Nginx)
ブラウザからのHTTP(S)リクエストは、インターネット網を経由して、目的のIPアドレスを持つサーバーマシンに到達します。サーバーマシン上では、Webサーバーソフトウェア(HTTPデーモンとも呼ばれる)が常に待ち構えており、やってきたリクエストを受け取ります。
Webサーバーソフトウェアの主な役割:
- リクエストの受信: 指定されたポート(通常は80番 or 443番)でHTTP(S)リクエストを待ち受け、受信します。
- リクエストの解析: 受信したリクエストの内容(メソッド、パス、ヘッダーなど)を解析します。
-
処理の振り分け: 解析結果に基づいて、どのコンテンツを返すか、どのプログラムを実行するかを決定します。
- 静的なファイル(HTML, CSS, 画像など)であれば、ファイルシステムから読み込んでそのまま返します。
- 動的な処理が必要な場合(PHP, Python スクリプトなど)は、対応するアプリケーションサーバーやインタプリタに処理を依頼します。
- 仮想ホストやURL書き換えの設定に基づき、適切な処理先にリクエストをルーティングします。(←ここが重要ポイント!後述)
- レスポンスの生成・送信: 処理結果(ファイルの内容やプログラムの実行結果)を元に、HTTPレスポンスメッセージを組み立ててブラウザに返送します。
- アクセスログの記録: どのようなリクエストがいつ来たかなどをログファイルに記録します。
- 同時接続の管理: 多数のクライアントからの同時アクセスを効率的に処理します。
代表的なWebサーバーソフトウェア:
-
Apache HTTP Server (Apache): 歴史が長く、非常に高機能で柔軟な設定が可能です。
.htaccess
ファイルによるディレクトリ単位での設定変更が特徴的です。多くのレンタルサーバーで採用されています。 - Nginx (エンジンエックス): 後発ながら、高いパフォーマンス(特に同時接続処理能力)とメモリ効率の良さで人気を集めています。静的ファイルの配信やリバースプロキシ(後述)としての利用も得意です。
他にも Microsoft IIS (Windows Server向け) や LiteSpeed などがあります。会社やサービスの種類によって、これらのソフトウェアが単独で、あるいは組み合わせて使われています。(例:静的ファイルはNginx、動的処理はApacheへ、など)
7. 【重要】ホストとパスの切り替え:正しい宛先へ案内する
Webサーバーはリクエストを受け取った後、「どのWebサイトの」「どのファイルやプログラム」に対するリクエストなのかを正確に判断し、適切な処理を行わなければなりません。特に、1台のサーバーで複数のWebサイトを運用したり、URLの見た目と実際のファイル構成を分離したりする場合、この「切り替え」の仕組みが非常に重要になります。
仮想ホスト (Virtual Host):1台のサーバーで複数のWebサイトを運営する技術
なぜ仮想ホストが必要か?
- IPアドレスの節約: 本来、1つのグローバルIPアドレスは1台のサーバーマシンを指します。もしWebサイトごとにサーバーマシンとIPアドレスを用意していたら、コストも管理の手間も膨大になります。仮想ホストを使えば、1つのIPアドレスを持つ1台のサーバーで、あたかも複数のサーバーが存在するかのように、複数の異なるドメイン名(ホスト名)のWebサイトを運用できます。
- 管理の容易さ: 関連する設定(ドキュメントルート、ログファイル、アクセス制御など)をドメインごとにまとめて管理できます。
仕組み:Host
ヘッダーの利用
仮想ホストの実現に不可欠なのが、HTTPリクエストヘッダーに含まれる Host
ヘッダーです。
- ブラウザは、アクセスしたいWebサイトのホスト名(例:
www.example.com
やshop.example.org
)をHost
ヘッダーに含めてリクエストを送信します。 - Webサーバー(ApacheやNginx)は、リクエストを受け取ると、まず
Host
ヘッダーの値を見ます。 - Webサーバーの設定ファイルには、各ホスト名(ドメイン名)に対応する設定ブロック(仮想ホスト設定)が記述されています。
- サーバーは
Host
ヘッダーの値と、設定ファイル内の仮想ホスト設定で指定されたホスト名(ServerName
など)を照合します。 - 一致する仮想ホスト設定が見つかれば、その設定ブロック内で定義された指示(特に ドキュメントルート やログファイルの場所など)に従って処理を進めます。
- もし一致するものがなければ、デフォルトの仮想ホスト設定(最初に定義されたものや、明示的にデフォルト指定されたもの)が適用されます。
Apacheでの設定例 (httpd.conf
や sites-available/
内のファイル)
# この設定ファイルを読み込むことを httpd.conf で指定しておく
# NameVirtualHost *:80 (Apache 2.4より前では必要だった)
# example.com 用の仮想ホスト設定
<VirtualHost *:80>
# この仮想ホストが処理するドメイン名
ServerName www.example.com
ServerAlias example.com *.example.com # 別名も指定可能
# このドメインにアクセスが来た時に公開するファイルの起点となるディレクトリ
DocumentRoot "/var/www/example.com/public_html"
# ログファイルの場所
ErrorLog "/var/log/httpd/example.com-error.log"
CustomLog "/var/log/httpd/example.com-access.log" combined
# ディレクトリごとの設定 (後述の .htaccess の内容などもここに書ける)
<Directory "/var/www/example.com/public_html">
Options Indexes FollowSymLinks
AllowOverride All # .htaccess ファイルによる設定上書きを許可
Require all granted
</Directory>
</VirtualHost>
# shop.example.org 用の仮想ホスト設定
<VirtualHost *:80>
ServerName shop.example.org
# こちらは別のディレクトリを公開起点にする
DocumentRoot "/var/www/shop.example.org/htdocs"
ErrorLog "/var/log/httpd/shop.example.org-error.log"
CustomLog "/var/log/httpd/shop.example.org-access.log" combined
<Directory "/var/www/shop.example.org/htdocs">
Options FollowSymLinks
AllowOverride None # .htaccess は使わせない
Require all granted
</Directory>
</VirtualHost>
-
*:80
: どのIPアドレスの80番ポートに来たリクエストかを指定(*
は全て)。HTTPSなら*:443
。 -
ServerName
: この仮想ホストが担当する主要なホスト名。Host
ヘッダーと照合される。 -
ServerAlias
:ServerName
以外の別名。ワイルドカード (*
) も使える。 -
DocumentRoot
: 【超重要】 この仮想ホストにおける、Web公開ファイルのルートディレクトリ。URLのパス/
が、このディレクトリに対応する。 -
ErrorLog
,CustomLog
: エラーログ、アクセスログの出力先ファイル。仮想ホストごとに分けるのが一般的。 -
<Directory>
: 特定のディレクトリに対する詳細設定(アクセス権、機能の有効/無効など)。
Nginxでの設定例 (nginx.conf
や sites-available/
内のファイル)
# http ブロック内に server ブロックを記述する
http {
# ... (全体設定)
# example.com 用のサーバーブロック (仮想ホスト)
server {
listen 80; # 待ち受けるポート
# listen [::]:80; # IPv6 も待ち受ける場合
# このサーバーブロックが処理するドメイン名 (Hostヘッダーと照合)
server_name www.example.com example.com *.example.com;
# Web公開ファイルの起点となるディレクトリ
root /var/www/example.com/public_html;
# デフォルトで表示するファイル名 (後述)
index index.html index.htm;
# ログファイルの場所
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# 特定のパスへのリクエストに対する設定
location / {
try_files $uri $uri/ =404; # ファイル -> ディレクトリ -> 404 の順で探す
}
# 特定の拡張子を持つファイルへのリクエスト (例: PHPの処理)
location ~ \.php$ {
# FastCGI (PHP-FPMなど) への処理の委譲設定 (後述)
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
}
# shop.example.org 用のサーバーブロック
server {
listen 80;
server_name shop.example.org;
root /var/www/shop.example.org/htdocs;
index index.php index.html;
access_log /var/log/nginx/shop.example.org.access.log;
error_log /var/log/nginx/shop.example.org.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string; # ファイル -> ディレクトリ -> index.php へ
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock; # PHPのバージョンが違う場合など
}
}
}
-
listen
: 待ち受けるポート番号。 -
server_name
: このサーバーブロックが担当するホスト名。ApacheのServerName
とServerAlias
を合わせたようなもの。 -
root
: 【超重要】 このサーバーブロックにおけるドキュメントルート。 -
index
: ディレクトリ名だけでアクセスされた場合に、そのディレクトリ内で探すファイル名(後述)。 -
access_log
,error_log
: ログファイルのパス。 -
location
: 特定のURLパスパターンに対する設定ブロック。Nginxではlocation
を使って細かな制御を行うのが一般的。
このように、仮想ホスト設定を使うことで、Webサーバーは Host
ヘッダーを見て、「ああ、www.example.com
へのアクセスだから、/var/www/example.com/public_html
を起点にファイルを探そう」「shop.example.org
へのアクセスだから、/var/www/shop.example.org/htdocs
を起点にしよう」と判断できるわけです。
パスに基づいた処理の振り分け:URLのパスを見て、どこにあるファイルやプログラムを動かすか決める
仮想ホストによって「どのWebサイトか」が決まったら、次はURLの パス部分 (/service/item
など) を見て、具体的にどのファイルやプログラムを処理するかを決定します。
ドキュメントルート (Document Root):Web公開の起点
前述の仮想ホスト設定で最も重要なのが DocumentRoot
(Apache) や root
(Nginx) です。これは、そのWebサイトにおいて、Webブラウザからアクセス可能なファイルが置かれているファイルシステムの最上位ディレクトリ(起点) を指定します。
- もし
DocumentRoot
が/var/www/example.com/public_html
に設定されていて、 - ブラウザから
https://www.example.com/css/style.css
というURLでアクセスがあった場合、 - Webサーバーは、ファイルシステム上の
/var/www/example.com/public_html/css/style.css
というファイルを探しに行きます。
URLパスとファイルシステムパスのマッピング:
原則として、URLのパスはドキュメントルート以下のディレクトリ構造にマッピングされます。
URL | DocumentRoot | サーバーが探すファイル/ディレクトリ |
---|---|---|
https://www.example.com/ |
/var/www/html |
/var/www/html/ (ディレクトリ) |
https://www.example.com/about.html |
/var/www/html |
/var/www/html/about.html (ファイル) |
https://www.example.com/products/ |
/var/www/html |
/var/www/html/products/ (ディレクトリ) |
https://www.example.com/img/logo.png |
/var/www/html |
/var/www/html/img/logo.png (ファイル) |
https://shop.example.org/user/login |
/var/www/shop.example.org/htdocs |
/var/www/shop.example.org/htdocs/user/login |
ディレクトリインデックス (index.html
, index.php
など)
URLのパスがファイル名ではなく、ディレクトリ名で終わっている場合(例: https://www.example.com/products/
や https://www.example.com/
)、Webサーバーはそのままではどのファイルを返せばよいか分かりません。
そこで、ディレクトリインデックス という仕組みがあります。これは、「ディレクトリへのアクセスがあった場合に、そのディレクトリ内で自動的に探して表示するファイル名」を定義するものです。
- Apacheでは
DirectoryIndex
ディレクティブで指定します。この設定の場合、DirectoryIndex index.html index.php index.cgi
/products/
ディレクトリにアクセスがあると、サーバーはまず/products/index.html
を探し、なければ/products/index.php
を探し、それでもなければ/products/index.cgi
を探します。最初に見つかったものを表示します。 - Nginxでは
index
ディレクティブで指定します。意味はApacheと同様です。index index.html index.htm index.php;
この機能により、ユーザーは index.html
を省略して https://www.example.com/
のようにアクセスできます。
URL書き換え (Rewrite):綺麗なURL、処理の集約
Webサイトやアプリケーションを開発していると、以下のような要望が出てきます。
-
https://www.example.com/product.php?id=123
のようなURLではなく、https://www.example.com/products/123
のような「綺麗な」URL(Clean URL, Friendly URL)を使いたい。 - 特定のディレクトリへのアクセスを、実際には別のファイルやスクリプトで処理させたい(例:全てのアクセスを一旦
index.php
に集約する「フロントコントローラーパターン」)。 -
http://
へのアクセスをhttps://
へ強制的にリダイレクトしたい。 -
example.com
へのアクセスをwww.example.com
へ統一したい。
これらを実現するのが URL書き換え (URL Rewriting) の機能です。Webサーバーは、受け取ったURLを、内部的なルールに基づいて別のURLやファイルパスに変換してから処理を進めることができます。
-
Apache:
mod_rewrite
モジュールを使用します。設定は主に.htaccess
ファイル(ディレクトリごとに置ける設定ファイル)や仮想ホスト設定内の<Directory>
ディレクティブにRewriteEngine On
で機能を有効にし、RewriteRule
やRewriteCond
で書き換えルールを記述します。# .htaccess の例 RewriteEngine On # ファイルやディレクトリが存在しない場合のみ適用 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # 全てのリクエストを index.php に渡す (フロントコントローラー) RewriteRule ^(.*)$ index.php?path=$1 [QSA,L] # products/数字 の形式を product.php に渡す RewriteRule ^products/(\d+)$ product.php?id=$1 [L]
-
RewriteRule パターン 置換文字列 [フラグ]
が基本。正規表現が使えます。 -
[L]
は「このルールが適用されたら以降のルールは処理しない」、[QSA]
は「元のクエリパラメータを引き継ぐ」という意味です。 -
.htaccess
は手軽ですが、サーバーに負荷がかかるため、可能ならサーバー設定ファイル (httpd.conf
など) に書くことが推奨されます。
-
-
Nginx:
rewrite
ディレクティブやlocation
ブロック内のtry_files
を使って実現します。Nginxには.htaccess
に相当する機能はなく、全てサーバー設定ファイルに記述します。# nginx.conf や sites-available/ 内の server ブロック内 location / { # ファイル -> ディレクトリ -> それでもなければ index.php に渡す try_files $uri $uri/ /index.php?$query_string; } location /products/ { # /products/123 を /product.php?id=123 として内部処理 (URLは変わらない) rewrite ^/products/(\d+)$ /product.php?id=$1 last; } # http から https へのリダイレクト server { listen 80; server_name www.example.com example.com; # 恒久的なリダイレクト (301) を返す return 301 https://$host$request_uri; }
-
try_files
は指定された順にファイルやディレクトリを探し、見つからなければ最後の引数(内部リダイレクト先やステータスコード)を使います。フロントコントローラーパターンで多用されます。 -
rewrite
は Apache のRewriteRule
に似ていますが、フラグ(last
,break
,redirect
,permanent
)の意味合いが少し異なります。 -
return
は指定したステータスコードとURLでリダイレクトを返すのに便利です。
-
URL書き換えを使いこなすことで、ユーザーにとって分かりやすく、検索エンジンにも優しいURL構造を実現しつつ、サーバー内部では効率的なファイル配置や処理の集約が可能になります。
フレームワークにおけるルーティング
PHPのLaravel, Symfony、PythonのDjango, Flask、RubyのRailsなどのWebアプリケーションフレームワークを使用する場合、多くはフレームワーク自体が高度な ルーティング (Routing) 機能を提供します。
これは、URLのパスと、それを処理するプログラムの関数やメソッド(コントローラーのアクションなど)を対応付ける仕組みです。WebサーバーのURL書き換え(多くは全てのアクセスを index.php
等の単一ファイルに集約する設定)と連携し、アプリケーションコード内でより柔軟かつ表現力豊かにURLと処理を結びつけます。
例 (Laravel風のルーティング定義):
// routes/web.php
use App\Http\Controllers\ProductController;
Route::get('/products/{id}', [ProductController::class, 'show']);
// URL /products/123 へのGETリクエストは、ProductController の show メソッドが処理する
// {id} の部分は可変で、メソッドに引数として渡される
この場合、Webサーバーは /products/123
というリクエストをまずフロントコントローラー (public/index.php
) に渡し、フレームワークがルーティング定義に基づいて ProductController
の show
メソッドを呼び出し、引数として 123
を渡す、という流れになります。
8. 【重要】サーバー上のディレクトリ・ファイル構成:コンテンツを整理整頓する
Webサーバーがリクエストを正しく処理するためには、サーバー上にファイルやディレクトリが適切に配置・構成されている必要があります。特に、Webブラウザから直接アクセスされて良いもの(公開ファイル) と、サーバー内部でのみ使われるべきもの(非公開ファイル、プログラムコード、設定ファイルなど) を明確に分離することが、セキュリティと保守性の観点から非常に重要です。
基本原則:公開するもの、しないものを分ける
-
公開ディレクトリ (Public Directory):
- Webサーバーの ドキュメントルート (
DocumentRoot
,root
) に設定されるディレクトリ。 - このディレクトリ以下にあるファイルは、基本的にURLを通してWebブラウザから直接アクセスされる可能性があります。
- ここに置くべきもの:
- HTMLファイル
- CSSファイル
- JavaScriptファイル (クライアントサイド)
- 画像、動画、音声ファイルなどのメディアファイル
- Webフォントファイル
- Webアプリケーションの エントリーポイント となるファイル(例:
index.php
)。フロントコントローラーパターンを採用する場合、基本的に公開ディレクトリにはこのファイルとアセットファイル(CSS, JS, 画像)しか置かないことが多いです。
- Webサーバーの ドキュメントルート (
-
非公開ディレクトリ (Non-Public Directory):
- ドキュメントルートの 外 に配置されるディレクトリ。
- ここに置かれたファイルは、Webサーバーの設定を意図的に変更しない限り、URLを通して直接アクセスすることはできません。
- ここに置くべきもの:
- サーバーサイドのプログラムコード(PHPクラス、Pythonモジュール、ビジネスロジックなど)
- 設定ファイル(データベース接続情報、APIキーなど、機密情報を含むことが多い)
- テンプレートファイル(HTMLの雛形)
- ライブラリ、フレームワークのコアファイル
- ログファイル
- 一時ファイル、キャッシュファイル
- アップロードされたファイル(直接アクセスさせたくない場合)
ドキュメントルート (Document Root) の役割再訪
仮想ホスト設定で指定した DocumentRoot
(Apache) や root
(Nginx) は、公開ディレクトリの最上位 を指します。この設定が、公開/非公開の分離の基点となります。
悪い例:
/var/www/my_project/ <-- ここを DocumentRoot に設定
├── index.php (公開OK - エントリーポイント)
├── style.css (公開OK - アセット)
├── images/
│ └── logo.png (公開OK - アセット)
├── config.php (非公開にしたい - DB接続情報など) ← ダメ!URLでアクセスされる危険性
├── src/ (非公開にしたい - アプリケーションコード) ← ダメ!
│ ├── Controller/
│ └── Model/
└── templates/ (非公開にしたい - HTMLテンプレート) ← ダメ!
この構成では、もしWebサーバーの設定ミスや脆弱性があった場合に、https://www.example.com/config.php
のように機密情報ファイルにアクセスされたり、ソースコードが閲覧されたりするリスクがあります。
良い例(公開/非公開の分離):
/var/www/my_project/ <-- プロジェクト全体のルート (非公開)
├── public/ <-- ここを DocumentRoot に設定
│ ├── index.php (公開 - エントリーポイント)
│ ├── css/
│ │ └── style.css (公開 - アセット)
│ └── images/
│ └── logo.png (公開 - アセット)
├── config/
│ └── database.php (非公開 - 設定)
├── src/ (非公開 - アプリケーションコード)
│ ├── Controller/
│ └── Model/
├── templates/ (非公開 - HTMLテンプレート)
├── vendor/ (非公開 - ライブラリ)
└── logs/ (非公開 - ログ)
この構成では、DocumentRoot
が /var/www/my_project/public
に設定されているため、ブラウザからURLでアクセスできるのは public
ディレクトリ以下のファイルのみです。config
, src
, templates
などはドキュメントルートの外にあるため、直接アクセスされることはありません。public/index.php
内のプログラムコードからは、相対パス (../src/Controller/SomeController.php
のように) や絶対パスでこれらの非公開ファイルにアクセスして利用します。
実践的なディレクトリ構成例
実際のプロジェクトでは、使用する技術(静的サイトか、CMSか、フレームワークか)によって標準的な構成が変わってきます。
-
例1:シンプルな静的サイト
- 構成が単純なため、ドキュメントルート直下にHTML, CSS, JS, 画像を置くことも多いです。
/var/www/html/ <-- DocumentRoot ├── index.html ├── about.html ├── css/ │ └── style.css ├── js/ │ └── script.js └── images/ └── logo.png
-
例2:一般的なCMS (WordPressなど) の構成
- CMSは独自のディレクトリ構造を持っています。WordPressを例にとると、以下のような構成が典型的です(簡略化)。
/var/www/wordpress/ <-- DocumentRoot ├── index.php (公開 - エントリーポイント) ├── wp-admin/ (公開 - 管理画面ファイル。アクセス制御はPHP側で行う) ├── wp-content/ (公開 - ユーザーが追加するコンテンツ) │ ├── themes/ (公開 - テーマファイル) │ ├── plugins/ (公開 - プラグインファイル) │ └── uploads/ (公開 - アップロードされたメディアファイル) ├── wp-includes/ (公開 - WordPressコアファイル。直接アクセスは想定されない) ├── .htaccess (Apache用設定ファイル) └── wp-config.php (非公開にしたいが、歴史的経緯でここに置かれる。パーミッション設定が重要)
- WordPressの場合、
wp-config.php
(DB接続情報など) がドキュメントルート直下に置かれるのが標準ですが、設定によりドキュメントルート外に移動することも可能です(セキュリティ上推奨)。コアファイル (wp-includes
,wp-admin
) もドキュメントルート内にありますが、PHPスクリプトであり、直接アクセスされても問題ないように作られています(多くは定数チェックなどで直接実行を防止)。
-
例3:Webアプリケーションフレームワーク (MVCなど) の構成 (前述の良い例)
- Laravel, Symfony, CakePHP, Django, Ruby on Rails など、多くの現代的なフレームワークは、前述した「公開ディレクトリ (
public
,web
,public_html
など) と非公開ディレクトリを明確に分離する構成」を標準として採用しています。
/var/www/my_laravel_app/ <-- プロジェクトルート (非公開) ├── public/ <-- DocumentRoot │ ├── index.php # フロントコントローラー │ ├── .htaccess # Apache用書き換えルール (index.phpへ集約) │ ├── robots.txt │ └── css/ js/ images/ # アセット ├── app/ # アプリケーションコード (Controllers, Models, etc.) ├── bootstrap/ # フレームワーク起動処理 ├── config/ # 設定ファイル ├── database/ # DBマイグレーション、シーダー ├── resources/ # ビュー(テンプレート), 言語ファイル, 未コンパイルアセット ├── routes/ # ルーティング定義 ├── storage/ # キャッシュ, ログ, アップロードファイル(非公開運用時) ├── tests/ # テストコード └── vendor/ # Composerで管理されるライブラリ
- この構成は、セキュリティを高めるだけでなく、コードの役割分担が明確になり、整理され、保守や共同開発がしやすくなるというメリットがあります。
- Laravel, Symfony, CakePHP, Django, Ruby on Rails など、多くの現代的なフレームワークは、前述した「公開ディレクトリ (
なぜこのように分けるのか?(まとめ)
- セキュリティ: 機密情報(設定ファイル、ソースコード)がWebから直接アクセスされるのを防ぐため。
- 保守性: ファイルの役割(公開アセット、ビジネスロジック、設定など)が明確になり、どこに何があるか分かりやすくなるため。修正や機能追加が容易になる。
-
共同開発: 担当者が自身の担当領域(例:フロントエンドは
public
やresources/assets
、バックエンドはapp
やsrc
)に集中しやすくなるため。
ファイル・ディレクトリのパーミッション (権限):誰が何をして良いか
サーバー上のファイルやディレクトリには、パーミッション(権限) が設定されています。これは、「誰(所有者、グループ、その他)が」「何(読み取り、書き込み、実行)をして良いか」を制御する仕組みです。
- 読み取り (Read): ファイルの内容を読む、ディレクトリ内の一覧を見る権限。
- 書き込み (Write): ファイルの内容を変更する、ディレクトリ内にファイルを作成/削除する権限。
-
実行 (Execute): ファイルをプログラムとして実行する、ディレクトリ内に入る(
cd
する)権限。
Webサーバーがファイルをブラウザに送信するには、そのファイルに対する読み取り権限が必要です。PHPなどのスクリプトを実行するには、そのスクリプトファイルに対する読み取り権限と、場合によっては実行権限(CGIの場合など。FastCGIでは通常不要)が必要です。また、Webサーバープロセス(例: apache
, nginx
, www-data
ユーザー)がログファイルやキャッシュファイル、アップロードディレクトリに書き込みを行うには、対象ディレクトリに対する書き込み権限が必要です。
不適切なパーミッション設定は、セキュリティリスク(例:誰でも設定ファイルを書き換えられる)や、アプリケーションのエラー(例:Webサーバーがファイルを読めない、書き込めない)の原因となります。
一般的に、以下のような設定が基本となります(数値はLinux/Unix系のパーミッション表記)。
-
ディレクトリ:
755
(所有者: rwx, グループ: r-x, その他: r-x)- 所有者は全て可能。他は読み取りとディレクトリへの進入のみ可能。
-
ファイル (HTML, CSS, JS, 画像など):
644
(所有者: rw-, グループ: r--, その他: r--)- 所有者は読み書き可能。他は読み取りのみ可能。
-
ファイル (PHPなどスクリプト):
644
(FastCGIなどでWebサーバー経由で実行する場合) または755
(CGIとして直接実行する場合など状況による)。機密情報を含む設定ファイルは600
(所有者: rw-, 他: ---) のように、より厳しくすることも。 -
書き込みが必要なディレクトリ (キャッシュ、ログ、アップロード): Webサーバーの実行ユーザーが書き込めるように
755
または775
(グループも書き込み可にする場合)、場合によっては777
(全員書き込み可、セキュリティリスク高いため限定的に)。所有者やグループをWebサーバーの実行ユーザーに設定することも重要です。
パーミッション設定は、サーバー環境や運用ポリシーによって異なりますが、「最小権限の原則」(必要な権限だけを与える)を意識することが大切です。
9. コンテンツの処理:静的ファイルと動的ファイル
Webサーバーは、URLパスとファイルシステムのマッピングが完了した後、要求されたリソースが静的コンテンツなのか動的コンテンツなのかによって、処理を分岐します。
-
静的コンテンツ (Static Content):そのまま返すファイル
- 対象: HTMLファイル、CSSファイル、JavaScriptファイル、画像ファイル (JPEG, PNG, GIF, SVG)、動画ファイル、PDFファイルなど。
-
処理:
- Webサーバー (Apache, Nginx) は、ファイルシステムから該当するファイルを直接読み込みます。
- ファイルの内容をHTTPレスポンスのボディに設定します。
- 適切な
Content-Type
ヘッダー(例:text/html
,text/css
,image/jpeg
)を付与します。これはファイル拡張子などから判断されます。 - 必要に応じて
Content-Length
ヘッダー(ファイルサイズ)なども付与します。 - 組み立てたHTTPレスポンスをブラウザに送信します。
- 特徴: サーバー側での特別な計算や処理が不要なため、高速にレスポンスを返すことができます。Nginxは特に静的ファイルの配信性能が高いと言われています。
-
動的コンテンツ (Dynamic Content):プログラムが生成するコンテンツ
- 対象: ユーザーごとに内容が変わるページ、データベースから取得した情報を表示するページ、フォーム送信を受け付けるページ、APIエンドポイントなど。
-
処理:
- Webサーバーは、リクエストが動的コンテンツであると判断します(例: ファイル拡張子が
.php
、特定のURLパスパターンに一致する、など)。 - Webサーバー自身がプログラムを実行するのではなく、外部のプログラム(サーバーサイド言語のインタプリタやアプリケーションサーバー) に処理を依頼します。この連携方法はいくつかあります。
- CGI (Common Gateway Interface): 古典的な方法。リクエストごとにプログラムのプロセスを起動するため効率が悪い。現在ではあまり使われない。
- FastCGI: CGIの欠点を改良し、プロセスを起動したままリクエストを処理できる。PHP (PHP-FPM) でよく使われる。Nginx + PHP-FPM は定番の組み合わせ。
-
各種言語固有のインターフェース:
- Python: WSGI (Web Server Gateway Interface)。 Gunicorn や uWSGI といったアプリケーションサーバーと連携。
- Ruby: Rack。 Puma や Unicorn といったアプリケーションサーバーと連携。
- Java: Servlet/JSP。 Tomcat や Jetty といったServletコンテナ(アプリケーションサーバー)と連携。
- Node.js: Node.js自体がサーバー機能を持つため、直接リクエストを処理することも、Nginxなどを前段に置く(リバースプロキシ)構成も多い。
- リバースプロキシ: Webサーバー (Nginxなど) が一旦リクエストを受け、バックエンドで動作しているアプリケーションサーバー (Node.js, Python/WSGI, Ruby/Rack, Java/Tomcatなど) にリクエストを転送し、結果を受け取ってブラウザに返す方式。負荷分散、SSL終端、静的ファイル配信の分離などのメリットがある。
- 依頼を受けたアプリケーションサーバー/インタプリタは、指定されたプログラム(例:
index.php
, Pythonの関数, Rubyのコントローラーアクション)を実行します。 - プログラムは、必要に応じて データベースサーバー に接続してデータを取得・更新したり、外部APIを呼び出したり、複雑な計算を行ったりします。
- 多くの場合、テンプレートエンジン (Blade(Laravel), Twig(Symfony), ERB(Rails), Jinja2(Flask/Django), EJS(Node.js) など) を使用して、取得したデータとHTMLの雛形(テンプレートファイル)を組み合わせて、最終的なHTMLコンテンツを生成します。APIの場合はJSONやXMLを生成します。
- 生成されたコンテンツ(HTML, JSONなど)と、設定すべきHTTPヘッダー(
Content-Type
,Set-Cookie
など)をWebサーバーに返します。 - Webサーバーは、受け取った内容を元にHTTPレスポンスを組み立ててブラウザに送信します。
- Webサーバーは、リクエストが動的コンテンツであると判断します(例: ファイル拡張子が
-
なぜ動的コンテンツが必要か?
- パーソナライズ: ログインユーザーの名前を表示するなど、ユーザーごとに異なる内容を表示できる。
- インタラクション: フォーム送信、コメント投稿など、ユーザーのアクションに応じて結果を返すことができる。
- 最新情報の表示: データベースの内容をリアルタイムに反映した情報を表示できる(ニュースサイト、ECサイトの商品一覧など)。
- 複雑な処理: 単なるファイル表示以上の、複雑なビジネスロジックを実行できる。
多くのWebサイトは、静的コンテンツ(CSS, JS, 画像)と動的コンテンツ(HTML本体、APIレスポンス)を組み合わせて構成されています。
10. HTTPレスポンス:サーバーからブラウザへの返事
Webサーバーは、静的ファイルを取得するか、動的処理の結果を受け取ると、ブラウザに対して HTTPレスポンス メッセージを返します。これもHTTPリクエストと同様に、いくつかの部分から構成されます。
-
ステータスライン (Status Line): レスポンスの結果を示す最も重要な情報。
-
HTTPバージョン (HTTP Version): 使用されたHTTPのバージョン (
HTTP/1.1
,HTTP/2
など)。 -
ステータスコード (Status Code): リクエストが成功したか、失敗したか、どういう状態かを示す3桁の数字。
-
2xx
(成功):-
200 OK
: リクエスト成功。最も一般的。 -
201 Created
: リソースの作成成功 (POST, PUT)。 -
204 No Content
: 成功したが返すコンテンツはない。
-
-
3xx
(リダイレクション): 他のURLへ転送する必要がある。-
301 Moved Permanently
: 恒久的に移動した。ブラウザは新しいURLを記憶する。 -
302 Found
/307 Temporary Redirect
: 一時的なリダイレクト。 -
304 Not Modified
: 要求されたリソースは更新されていない(キャッシュ利用を促す)。
-
-
4xx
(クライアントエラー): リクエスト側に問題がある。-
400 Bad Request
: リクエストの構文がおかしい。 -
401 Unauthorized
: 認証が必要。 -
403 Forbidden
: アクセス権限がない。 -
404 Not Found
: 要求されたリソースが見つからない。
-
-
5xx
(サーバーエラー): サーバー側に問題が発生した。-
500 Internal Server Error
: サーバー内部で予期せぬエラーが発生(プログラムのエラーなど)。 -
502 Bad Gateway
: ゲートウェイ(プロキシなど)が不正なレスポンスを受け取った。 -
503 Service Unavailable
: サーバーが一時的に過負荷またはメンテナンス中。
-
-
-
理由フレーズ (Reason Phrase): ステータスコードの簡単な説明 (
OK
,Not Found
など)。
例:
HTTP/1.1 200 OK
例:HTTP/1.1 404 Not Found
-
HTTPバージョン (HTTP Version): 使用されたHTTPのバージョン (
-
ヘッダー (Headers): レスポンスに関する追加情報。
ヘッダー名: 値
の形式。-
Content-Type: text/html; charset=UTF-8
: レスポンスボディの内容の種類(MIMEタイプ)と文字エンコーディング。ブラウザが正しく表示するために重要。(text/css
,image/jpeg
,application/json
など多数) -
Content-Length: 12345
: レスポンスボディのバイト数。 -
Date: Tue, 15 May 2024 10:00:00 GMT
: レスポンスが生成された日時。 -
Server: Apache/2.4.52 (Ubuntu)
またはServer: nginx/1.18.0
: 応答したWebサーバーソフトウェアの情報。 -
Set-Cookie: session_id=abcdef12345; Path=/; HttpOnly
: ブラウザにCookieを保存させる指示。ログイン状態の維持などに使われる。 -
Cache-Control: max-age=3600, public
: キャッシュの制御方法(例: 3600秒間キャッシュして良い)。 -
Location: https://www.example.com/new-page
(301
や302
の時にリダイレクト先URLを示す)。 - など、多数のヘッダーがあります。
-
-
ボディ (Body): 実際のコンテンツデータ。
-
Content-Type
がtext/html
ならHTMLソースコード。 -
image/jpeg
ならJPEG画像のバイナリデータ。 -
application/json
ならJSON形式のデータ。 -
204 No Content
や304 Not Modified
など、ステータスコードによってはボディがない場合もあります。
-
11. ブラウザによるレンダリング:受け取った情報を画面に描画
ブラウザは、WebサーバーからHTTPレスポンスを受け取ると、その内容を解釈してユーザーが見ることのできる画面を描画(レンダリング)します。このプロセスも非常に複雑ですが、主なステップは以下の通りです。
-
HTML解析とDOM構築:
- レスポンスボディのHTMLコードを上から順に解析します。
- HTMLタグを解釈し、文書の構造を表現するツリー構造のデータ、DOM (Document Object Model) をメモリ上に構築します。DOMはJavaScriptからHTML要素を操作するためのインターフェースにもなります。
-
CSS解析とCSSOM構築:
- HTML内で
<link rel="stylesheet">
や<style>
タグが見つかると、CSSコードを解析します。 - CSSのスタイルルールを解釈し、どのDOM要素にどのスタイルを適用するかを示すツリー構造、CSSOM (CSS Object Model) を構築します。
- HTML内で
-
レンダーツリー構築:
- DOMとCSSOMを組み合わせて、実際に画面に表示される要素とそのスタイル情報だけを含む レンダーツリー (Render Tree) を構築します。(
display: none;
が指定された要素などはレンダーツリーに含まれません)。
- DOMとCSSOMを組み合わせて、実際に画面に表示される要素とそのスタイル情報だけを含む レンダーツリー (Render Tree) を構築します。(
-
レイアウト (Layout / Reflow):
- レンダーツリーの情報に基づき、各要素が画面上のどこに、どのくらいの大きさで配置されるかを計算します。ビューポート(ブラウザの表示領域)のサイズなどが考慮されます。
-
ペイント (Paint / Painting):
- レイアウト計算結果に基づき、要素の見た目(色、背景、枠線など)を画面上のピクセルに実際に描画します。要素は複数のレイヤーに分けて描画され、後で合成されることもあります(Compositing)。
-
JavaScriptの実行:
- HTML解析中に
<script>
タグが見つかると、HTML解析を一時中断してJavaScriptコードをダウンロード・解析・実行します(非同期(async
)や遅延(defer
)属性で挙動を変えられます)。 - JavaScriptはDOMを動的に変更したり(例: 要素を追加・削除・変更)、CSSOMを変更したり(例: 要素のスタイルを変更)、イベント(クリックなど)に応じて処理を実行したりできます。
- JavaScriptによってDOMやCSSOMが変更されると、変更内容に応じて再度レイアウトやペイント(またはその一部)が実行されることがあります(リフロー、リペイント)。
- HTML解析中に
-
追加リソースの取得:
- HTMLを解析する過程で、
<link rel="stylesheet">
(CSS)、<script src="...">
(JS)、<img src="...">
(画像) などの外部リソースへの参照が見つかると、ブラウザはそれらのリソースを取得するために、それぞれについて再度、DNS解決から始まるHTTP(S)リクエストをサーバーに送信します。 - つまり、最初にHTMLを取得した後も、ページ表示に必要な多数のファイルを取得するために、ブラウザとサーバーの間で何度も通信が行われます。ブラウザはこれらの通信を並行して行うことで、表示速度を向上させようとします。
- HTMLを解析する過程で、
これらのステップを経て、最終的にWebページが私たちの目の前の画面に表示されるのです。
12. さらに知っておきたい技術要素(実践レベルの補足)
実際の企業のWebシステムでは、これまで説明した基本的な流れに加えて、パフォーマンス、スケーラビリティ(拡張性)、セキュリティ、可用性(止まらないこと)などを向上させるために、様々な技術要素が組み合わせて使われています。
-
ロードバランサ (Load Balancer):
- Webサーバーへのアクセスを複数のサーバーに振り分ける装置やソフトウェア。
- 1台のサーバーへの負荷集中を防ぎ、処理能力を向上させます(スケーラビリティ)。
- 1台のサーバーが故障しても、他のサーバーでサービスを継続できるようにします(可用性)。
- ユーザーからのアクセスはまずロードバランサが受け、そこから実際のWebサーバー(複数台)のいずれかに転送されます。
-
CDN (Content Delivery Network):
- CSS, JavaScript, 画像, 動画などの静的コンテンツを、世界中に分散配置されたキャッシュサーバー(エッジサーバー)にコピーしておき、ユーザーに最も近いサーバーから配信する仕組み。
- ユーザーは地理的に近いサーバーからコンテンツを取得できるため、表示速度が大幅に向上します。
- オリジンサーバー(本来のWebサーバー)の負荷を軽減できます。
-
キャッシュ (Cache):
- 一度取得したデータを一時的に保存しておき、次回同じリクエストがあった場合に、保存したデータを使って素早く応答する仕組み。様々なレベルで活用されます。
-
ブラウザキャッシュ: ブラウザがローカルにCSS, JS, 画像などを保存。
Cache-Control
やExpires
ヘッダーで制御。 - サーバーサイドキャッシュ: 動的コンテンツの生成結果(HTMLやデータ)をサーバー側で一時的に保存(Memcached, Redisなど)。DBアクセスなどを減らし高速化。
- CDNキャッシュ: 前述の通り。
- オペコードキャッシュ: PHPなどで、コンパイル済みコードをキャッシュし実行速度を向上。
-
データベースサーバー (Database Server):
- 商品情報、ユーザー情報、ブログ記事など、動的に変化する大量のデータを永続的に保存・管理するための専用サーバー(またはクラウドサービス)。
- MySQL, PostgreSQL, Oracle Database, SQL Server (リレーショナルデータベース) や、MongoDB, Redis (NoSQLデータベース) などがあります。
- Webサーバー(やアプリケーションサーバー)は、必要に応じてデータベースサーバーに接続し、データの検索、追加、更新、削除(CRUD操作)を行います。
-
ファイアウォール (Firewall) / WAF (Web Application Firewall):
- ファイアウォール: ネットワークレベルで不正な通信を遮断する壁。特定のIPアドレスやポートからのアクセスを制限するなど。
- WAF: Webアプリケーションの脆弱性を狙った攻撃(SQLインジェクション、クロスサイトスクリプティング(XSS)など)を検知・防御することに特化したファイアウォール。HTTP(S)リクエスト/レスポンスの内容を検査します。
-
デプロイ (Deploy):
- 開発環境で作ったWebサイトやアプリケーションのコード、ファイル一式を、本番のWebサーバーに配置して公開する作業のこと。
- 手動: FTP/SFTP/SCPでファイルをアップロード。単純だがミスが起きやすい。
-
バージョン管理システム連携: Gitなどのバージョン管理システムを使ってコードをサーバーに反映 (例:
git pull
)。 - 自動化 (CI/CD): Jenkins, GitLab CI/CD, GitHub Actionsなどのツールを使って、コードのテスト、ビルド、サーバーへの自動デプロイを行う。現代的な開発では主流。
これらの技術要素は、Webサイトやサービスの規模、要件に応じて適切に選択・組み合わせて利用されます。
13. まとめ:一連の流れを振り返る
最後に、ブラウザでURLを入力してからWebページが表示されるまでの旅を、もう一度簡単に振り返ってみましょう。
- URL解析: ブラウザはURLを分解し、ホスト名、パスなどを理解します。
- DNS名前解決: ブラウザはDNSに問い合わせて、ホスト名に対応するサーバーのIPアドレスを取得します。
- TCPコネクション確立: ブラウザはサーバーのIPアドレスとポート番号(通常80 or 443)を使って、TCPによる信頼性の高い通信路を確立します(HTTPSの場合は、ここでSSL/TLSによる暗号化も行われます)。
-
HTTPリクエスト送信: ブラウザは、取得したいリソースのパスや
Host
ヘッダーなどを含むHTTPリクエストをサーバーに送信します。 - Webサーバーによるリクエスト受信・解析: サーバー上のWebサーバーソフトウェア (Apache, Nginx) がリクエストを受け取り、内容を解析します。
-
ホスト解決: Webサーバーはリクエストの
Host
ヘッダーを見て、どの仮想ホスト(Webサイト)に対するリクエストかを判断し、対応する設定(ドキュメントルートなど)を適用します。 - パス解決・ルーティング: WebサーバーはURLのパス部分を見て、ドキュメントルートを起点として、ファイルシステムのどのファイルやディレクトリに対応するかを判断します。URL書き換えルールやディレクトリインデックスの設定もここで考慮されます。フレームワーク利用時は、フロントコントローラーを経由してアプリケーションのルーティング機能が呼び出されます。
-
コンテンツ処理:
- 静的ファイルの場合: Webサーバーは該当ファイルを読み込み、レスポンスを作成します。
- 動的ファイルの場合: WebサーバーはPHP-FPMや他のアプリケーションサーバーに処理を依頼します。アプリケーションはDBアクセスやロジック実行、テンプレートエンジンによるHTML生成などを行い、結果をWebサーバーに返します。
- HTTPレスポンス送信: Webサーバーは、処理結果(HTML, CSS, 画像データなど)とステータスコード、ヘッダーを含むHTTPレスポンスをブラウザに返送します。
- ブラウザによるレンダリング: ブラウザはレスポンスを受け取り、HTMLを解析してDOMを構築し、CSSを解析してCSSOMを構築し、これらを組み合わせてレンダーツリーを作成、レイアウト計算、ペイントを行い、画面に表示します。JavaScriptを実行し、必要に応じて追加リソース(CSS, JS, 画像など)をリクエストします(追加リソースについてもステップ2〜10が繰り返されます)。
この一連の流れは、多くの技術が階層的に連携することで実現されています。特に、仮想ホストによる複数サイトの管理、ドキュメントルートとパスによるファイル特定、そして公開/非公開を意識したディレクトリ構成は、実際のWebサーバー運用において非常に重要な概念です。