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は次の順番で選びます。
- **
listenで絞り込む**: まず、リクエストを受けたIPアドレスとポートに一致するlistenを持つブロックだけが候補になります。 - **
server_nameで選ぶ**: 候補の中から、リクエストのHostヘッダーに一致するserver_nameを探します。優先順位は、文字どおり一致する名前、先頭がワイルドカードの名前(*.example.com)のうち最も長いもの、末尾がワイルドカードの名前のうち最も長いもの、正規表現(設定ファイルに書かれた順で最初に一致したもの)の順です。 - 見つからなければ既定のサイト: どれにも一致しない場合は、そのポートで
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で同じポートのブロックを並べて比べます。