2026年8月23日

2026年8月23日

Nginxでバーチャルホスト(server block)を設定する方法(複数サイトの運用とWordPress向けの書き方)

Nginxでは、1台のサーバーで複数のサイトを動かすときに、サイトごとに server { ... } のブロック(server block)を書き、server_name でドメインを振り分けます。Apacheのバーチャルホストにあたる仕組みです。この記事では、Nginxがリクエストをどのserver blockに渡すかの規則、WordPressサイト用のserver blockの書き方、DNSを切り替える前の動作確認、そして別のサイトが表示されるといったよくあるつまずきの直し方を説明します。

Nginxがserver blockを選ぶ規則

server blockの設定で混乱しやすいのは、「どのブロックが応答するか」の決まり方です。Nginxは次の順番で選びます。

  1. **listen で絞り込む**: まず、リクエストを受けたIPアドレスとポートに一致する listen を持つブロックだけが候補になります。
  2. **server_name で選ぶ**: 候補の中から、リクエストの Host ヘッダーに一致する server_name を探します。優先順位は、文字どおり一致する名前、先頭がワイルドカードの名前(*.example.com)のうち最も長いもの、末尾がワイルドカードの名前のうち最も長いもの、正規表現(設定ファイルに書かれた順で最初に一致したもの)の順です。
  3. 見つからなければ既定のサイト: どれにも一致しない場合は、そのポートで default_server を指定したブロックが応答します。指定がなければ、そのポートで最初に読み込まれたブロックが使われます。

3番目の規則が、「IPアドレスでアクセスしたら別のサイトが出た」「設定していないドメインで自分のサイトが表示された」という現象の原因です。サイトを追加する前に、どれにも一致しないリクエストを受け止める既定のブロックを用意しておくと、意図しないサイトが表示されることを防げます。

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 444;
}

return 444 は、応答を返さずに接続を閉じるNginx独自の指定です。

ディレクトリの構成

設定ファイルの置き場所は、ディストリビューションによって異なります。

  • Ubuntu・Debian: /etc/nginx/sites-available/ にサイトごとのファイルを作り、/etc/nginx/sites-enabled/ にシンボリックリンクを張って有効にします。
  • RHEL系・nginx.orgのパッケージ: /etc/nginx/conf.d/ に example.com.conf のように .conf で終わる名前でファイルを置けば読み込まれます。

どちらの場合も、1サイトにつき1ファイルにしておくと、サイトの停止や削除がファイル単位で行え、設定の見通しもよくなります。ファイル名にはドメイン名を使うのが分かりやすい方法です。

サイトの公開ディレクトリとログも、サイトごとに分けておきます。

sudo mkdir -p /var/www/example.com/public
sudo chown -R www-data:www-data /var/www/example.com   # RHEL系は nginx:nginx(PHP-FPMの実行ユーザーに合わせる)

WordPressサイト用のserver block

PHP-FPMと連携してWordPressを動かす、HTTPの段階のserver blockの例です。Ubuntuで、PHP-FPMがUnixソケットで待ち受けている前提にしています。

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.php index.html;

    access_log /var/log/nginx/example.com.access.log;
    error_log  /var/log/nginx/example.com.error.log;

    client_max_body_size 64m;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    # .htaccess などドットで始まるファイルを拒否(Let's Encryptの認証用ディレクトリは除く)
    location ~ /\.(?!well-known) {
        deny all;
    }
}

それぞれの行の意味と、つまずきやすい点は次のとおりです。

  • **server_name**: このブロックが受け持つドメインを空白区切りで並べます。www ありとなしの両方で受ける場合は、両方を書きます。どちらかに統一するリダイレクトは、別のserver blockを作って return 301 で行うのが一般的です。
  • **try_files**: 要求されたファイルやディレクトリが実在すればそれを返し、なければ index.php に渡します。WordPressのパーマリンク(投稿名などのURL)は、この行で動きます。Apacheと違ってNginxは .htaccess を読まないため、この行がないとトップページ以外が 404 になります。
  • **fastcgi_pass**: PHP-FPMの待ち受け先です。ソケットのパスはPHPのバージョンやディストリビューションによって異なります。ls /run/php/ などで実際のパスを確かめて書き換えてください(2026年10月現在の例として8.3を記載しています)。snippets/fastcgi-php.conf はDebian系のパッケージに含まれるファイルで、RHEL系にはないため、その場合は include fastcgi_params; と fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; を書きます。
  • ドットファイルの拒否: WordPressから移行してきたサイトでは、.htaccess や .git が公開ディレクトリに残っていることがあります。Nginxは何も設定しないとこれらをそのまま返すため、拒否しておきます。

サイトごとにPHP-FPMのプールを分け、別のユーザーで実行するようにすると、1つのサイトが改ざんされたときにほかのサイトへ被害が広がりにくくなります。複数の顧客や用途のサイトを同じサーバーに載せる場合は検討する価値があります。

有効にして反映する

Ubuntu・Debianでは、シンボリックリンクを張ってから、文法を確認して再読み込みします。

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

nginx -t で syntax is ok と test is successful が表示されたときだけ再読み込みされます。サイトを止めるときは、sites-enabled のリンクだけを削除して再読み込みすれば、元のファイルは残ります。

DNSを切り替える前に確認する

サーバー移転などでは、DNSを新しいサーバーに向ける前に、新しいserver blockが正しく応答するかを確かめておきたいところです。Nginxは Host ヘッダーでサイトを選ぶので、ヘッダーを指定してアクセスすれば、DNSを変えずに確認できます。

# サーバー内から
curl -I -H "Host: example.com" http://127.0.0.1/

# 手元のPCから(203.0.113.10 は新サーバーのIPに置き換え)
curl -I --resolve example.com:80:203.0.113.10 http://example.com/

ブラウザで確認したい場合は、手元のPCの hosts ファイルに新サーバーのIPとドメインを一時的に書く方法もあります。確認が終わったら、書いた行を忘れずに消してください。

HTTPSを追加する

HTTPで応答することを確認したら、証明書を取得してHTTPSに対応させます。CertbotのNginxプラグインを使うと、listen 443 ssl と証明書のパスを含む設定がserver blockに追加されます。手で書く場合、HTTPSのserver blockは次のような形になります。

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 以下、root・location などはHTTPのブロックと同じ
}

http2 on; はNginx 1.25.1以降の書き方で、それより古い版では listen 443 ssl http2; と書きます。新しい版で古い書き方を使うと、非推奨の警告が出ます。

HTTPSにも、どれにも一致しないリクエストを受け止める既定のブロックが必要です。証明書がなくても、Nginx 1.19.4以降では ssl_reject_handshake on; を使ってTLSの接続そのものを断れます。

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    ssl_reject_handshake on;
}

よくあるつまずき

  • 別のサイトが表示される: server_name の綴りの誤りか、listen の不一致(片方だけ [::] がない、IPアドレス付きの listen が混ざっているなど)で、既定のブロックに流れています。sudo nginx -T で全体の設定を表示し、同じポートのブロックを並べて比べます。
  • **conflicting server name "example.com" on 0.0.0.0:80, ignored**: 同じ名前を持つブロックが2つあります。古い設定ファイルや、sites-available ではなく sites-enabled に直接置いたコピーが残っていないかを確認します。後から読み込まれた側は無視されます。
  • **could not build server_names_hash, you should increase server_names_hash_bucket_size**: 長いドメイン名や多数のドメインを登録したときに出ます。http ブロックに server_names_hash_bucket_size 64; のように、メッセージに従って値を大きくして書きます。
  • パーマリンクが 404 になる: try_files の行がないか、location / が別の設定で上書きされています。

設定を大きく変える前は、sudo cp -a /etc/nginx /root/nginx-backup-$(date +%Y%m%d) のように設定一式を保存しておくと、問題が起きたときにすぐ戻せます。

まとめ

  • server blockは、listen で受けたポートの中から、Host ヘッダーに一致する server_name のブロックが選ばれます。一致しなければ default_server か、最初に読み込まれたブロックが応答します。
  • どれにも一致しないリクエスト用に、HTTPは return 444、HTTPSは ssl_reject_handshake on の既定のブロックを用意します。
  • WordPress用のブロックでは、try_files $uri $uri/ /index.php?$args; とPHP-FPMへの転送が要になります。ソケットのパスは環境に合わせます。
  • 反映は nginx -t を通してから reload し、DNSの切り替え前は curl --resolve で新しいブロックの応答を確かめます。
  • 別のサイトが表示されるときは、nginx -T で同じポートのブロックを並べて比べます。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲