サイトロゴ

nginxの設定 いろいろ

著者画像
Toshihiko Arai
nginxの設定
いろいろ

nginx のインストール(Ubuntu)

アプリケーションインストール前のおまじない

初回実行時は時間がかかる場合があります。
以下のコマンドでパッケージ情報を更新・アップグレードします。

sudo apt-get update
sudo apt-get upgrade

nginx のインストール

次のコマンドで nginx をインストールします。

sudo apt install nginx

インストール確認

以下のコマンドで nginx のバージョンが表示されれば、インストールは成功です。

nginx -v

nginx の起動と自動起動設定

起動確認

nginx のインストールと同時にウェブサーバーは自動起動されます。
起動状況は以下のコマンドで確認できます。

sudo systemctl status nginx

出力例:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-10-20 15:15:44 JST; 53s ago
       Docs: man:nginx(8)
    Process: 36839 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 36840 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 36934 (nginx)
      Tasks: 3 (limit: 1033)
     Memory: 7.0M
        CPU: 40ms
     CGroup: /system.slice/nginx.service
             ├─36934 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             ├─36937 nginx: worker process
             └─36938 nginx: worker process

自動起動設定

起動・有効化:

sudo systemctl start nginx
sudo systemctl enable nginx

自動起動の解除:

sudo systemctl stop nginx
sudo systemctl disable nginx

ウェブサーバーへのアクセス確認

レンタルサーバーでパケットフィルターを利用している場合は、Web に使用する 80/443 ポートへのアクセスを許可してください。
設定完了後、ブラウザからサーバーの IP アドレスにアクセスし、以下のような nginx のスタート画面が表示されることを確認します。


nginx のドキュメントルート変更

nginx のドキュメントルートを変更するには、/etc/nginx/sites-enabled/default ファイルを編集します。

ドキュメントルートの変更手順

sudo vi /etc/nginx/sites-enabled/default

ファイル内の以下の行を修正します。

- # root /var/www/html;
+ root /home/ubuntu/example.com/output;

設定反映

設定変更後、nginx を再起動して変更内容を反映させます。

sudo systemctl restart nginx

注意: Web ドキュメントを ubuntu のホームディレクトリ配下に配置する場合、/home/ubuntu ディレクトリの権限が 755 になっていることを確認してください。


www あり・なしの統一

DNS 設定

まず、利用中のネームサーバー(DNS)で www のサブドメインを追加してください。

nginx の設定変更

/etc/nginx/sites-enabled/default に以下の設定を追加します。
これにより、www でアクセスされた場合、www なしのドメインへ 301 リダイレクトされます。

server {
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

Let’s Encryptをnginxへ導入するまで

cerbotのインストール

無料のSSL証明書を発行してhttps通信できるようにするため、Let’s Encryptをnginxへ導入します。まずは、Let’s Encryptを簡単に導入してくれるアプリケーション「cerbot」をインストールします。

sudo apt install certbot python3-certbot-nginx

インストールされたバージョンは次のとおり。

$ certbot --version
certbot 1.21.0

443ポートの開放

ファイアーウォールやパケットフィルターなどを使っている場合は、443ポートを開放します。

certbotでSSL証明書を発行

それではcertbotを使って、SSL証明書を発行しましょう。

sudo certbot --nginx -d example.com

example.com はnginxですでに設定してあるドメインになります。

certbotでSSL証明書の自動更新

SSL証明書は3か月のみ有効なので、期限が迫ってきたら自動で更新できるようにしておきましょう。

$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for example.com.fun

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

--dry-run(テストモード)を実行して success が表示されていればOKです。

nginxの設定ファイルにSSL証明書のパスが追加されていることを確認します

sudo vi /etc/nginx/sites-enabled/default

次の画像の通り、ssl_certificate(SSL証明書)、ssl_certificate_key(秘密鍵)のパスが追加されていればOKです。

nginxの構文チェック

次のコマンドでnginxの構文チェックをし、問題がないか確かめておきましょう。

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

ブラウザからドメインへhttpsでアクセスできるか確認

ブラウザでドメインへhttpsアクセスして、証明書が確認できればLet’s Encryptの設定完了です。

www・httpアクセスをhttps・wwwなしへリダイレクト

wwwありとなしを統一することで、SEO効果が見込める可能性があるようです。wwwありとなしのドメインの両方でアクセスできてしまうと、Google検索エンジンが二つのページが存在すると勘違いしてしまう可能性があり、評価が分散されてしまう恐れがあるからです。

さて、先述でwwwありをwwwなしに統一する設定をnginxで行いました。httpの場合はスムーズにできるのですが、Let’s Encryptを使ったhttpsの場合はちょっと工夫が必要です。

前回の設定だけですと、http://www へのアクセスはリダイレクトできても https://www のアクセスは次のようにエラーになってしまいます。

実はこの記事の前半で設定した証明書は、www付きのドメインアクセスでは使用できません。つまりは、www付きドメイン用のSSL証明書も別途用意しなければならないということです。 といっても解説した手順でやればとても簡単ですので、めんどくさがらずに進めてみましょう。次のコマンドで、www付きドメインのSSL証明書を発行、自動更新します。

sudo certbot --nginx -d www.example.com

証明書がインストールできたら /etc/nginx/sites-enabled/default を以下のように修正します。

server {
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;

}

server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}


server {
        root /home/ubuntu/somewhere;

        index index.html;

        server_name example.com;
        ....

最初のserverディレクティブでは、 http://www.example.com へのアクセスを https://example.com へリダイレクトさせてます。 2番目のserverディレクティブでは、 https://www.example.com へのアクセスを https://example.com へリダイレクトさせてます。この2番目のserverディレクティブを有効にするために、ww付きドメインのSSL証明書が必要だったわけですね。 最後のserverディレクティブは、すでに設定してきたメインの記述ですので変更は加えません。

設定ファイルの変更をおこなったら、文法チェックをし、nginxを再起動させましょう。

sudo nginx -t
sudo systemctl restart nginx

これでwwwあり・httpアクセスを、https・wwwなしにリダイレクト、統一できました。


登録したドメインをCertbotから削除する

Certbotに登録したドメインを削除するには、以下の手順を実行してください。

登録された証明書を確認

まず、現在登録されている証明書を確認します。

sudo certbot certificates

出力例:

Found the following certs:
  Certificate Name: www.example.com
  ...

削除したいドメイン名(Certificate Name)をメモしてください。

ドメインを削除

以下のコマンドを使用して、指定した証明書を削除します。

sudo certbot delete --cert-name www.example.com

削除確認

再度、証明書リストを確認して削除が完了したことを確認します。

sudo certbot certificates

削除したドメインが表示されなければ、削除成功です。

必要に応じて、Nginx の設定から該当ドメインに関する記述も削除してください。その後、Nginx を再読み込みします。

sudo systemctl reload nginx

nginxでVirtualHostを設定する

nginxで複数のドメインを管理するためのVirtualHost設定は非常に簡単です。既存のサーバー設定と同じ内容を元に、ドメイン部分だけ変更することで新たなサーバー設定を作成できます。

Ubuntuでは、nginxのサーバー設定は/etc/nginx/sites-availableおよび/etc/nginx/sites-enabledディレクトリに格納されています。既定ではdefaultというファイルが用意されていますが、複数のドメインを管理する際は、各ドメイン毎にファイルを分けると管理が容易になります。

既存の設定ファイルについて

/etc/nginx/sites-enabled/defaultはシンボリックリンクになっており、実際の設定ファイルは/etc/nginx/sites-available/defaultに存在します。このファイルを元に、各サーバー毎の設定ファイルを作成していきます。

defaultファイルをコピーする

まずは、既存のdefaultファイルを元に新しいサーバー設定ファイルを作成します。ここでは例としてドメイン名「101010.fun」で設定する場合を示します。

cd /etc/nginx/sites-available
sudo cp default 101010.fun

この時点で、/etc/nginx/sites-availableディレクトリ内に新しいファイル「101010.fun」が作成されます。

シンボリックリンクの作成

次に、/etc/nginx/sites-enabledディレクトリに新しい設定ファイルへのシンボリックリンクを作成します。

cd /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/101010.fun 101010.fun

これで、nginxは新しい設定ファイルも読み込むようになります。現在のディレクトリ内の一覧は以下のようになります。

ls -l
total 8
lrwxrwxrwx 1 root root   37 Dec  6 11:52 101010.fun -> /etc/nginx/sites-available/101010.fun
lrwxrwxrwx 1 root root   34 Oct 20 15:15 default -> /etc/nginx/sites-available/default

設定ファイルの編集

あとは、新規作成した「101010.fun」ファイル内の内容を、該当ドメインや必要な設定内容に合わせて編集します。
例えば、ドメイン名の設定やSSL証明書の設定(Let’s Encryptなど)を行います。
古いサーバーから新しいサーバーに移行する場合は、ドメインのDNS設定をあらかじめ新しいサーバーのIPに変更しておくことを忘れないでください。DNS設定が正しくないと、Let’s EncryptによるSSL証明書の発行に失敗する可能性があります。


nginxでPHPを動かす

Apacheの場合、PHPはモジュールとして組み込まれているため、Apacheを起動するだけでPHPが利用可能な状態になります。しかし、nginxの場合は、自前でPHP用のプロセスを立ち上げ、FastCGI経由で接続する設定が必要です。調べたところ、PHPを動かすには FastCGI Process Manager (FPM) に対応した php-fpm を使用するのが望ましいようです。

php-fpmのインストール

以下のコマンドで php-fpm をインストールします。

sudo apt install -y php-fpm

PHPのインストール確認

PHPがインストールされているかどうかを以下のコマンドで確認します。

$ which php
/usr/bin/php

$ which php-fpm8.1 
/usr/sbin/php-fpm8.1

$ php -v
PHP 8.1.2-1ubuntu2.9 (cli) (built: Oct 19 2022 14:58:09) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2-1ubuntu2.9, Copyright (c), by Zend Technologies

$ php-fpm8.1 -v
PHP 8.1.2-1ubuntu2.9 (fpm-fcgi) (built: Oct 19 2022 14:58:09)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2-1ubuntu2.9, Copyright (c), by Zend Technologies

nginxとphp-fpmの接続

nginxとphp-fpmの接続は、TCPまたはUNIXドメインソケットを使用して行います。ここではUNIXドメインソケットを使用します。

php-fpm.conf には、以下のように include=/etc/php/8.1/fpm/pool.d/*.conf と記述されており、/etc/php/8.1/fpm/pool.d/ ディレクトリ以下の .conf ファイル(実際には www.conf の設定)が読み込まれます。www.conf の内容を確認してみます。

vi /etc/php/8.1/fpm/pool.d/www.conf 

このファイル内の listen に、UNIXドメインソケットの接続先 が記述されています。後ほどこのアドレスをメモしておきます。

listen = /run/php/php8.1-fpm.sock

PHPプロセスの確認

php-fpm をインストールすると、自動的にPHP関連のデーモンプロセスが起動されるため、php-fpm の起動設定は特に必要ありません。

systemctl list-unit-files --type=service | grep php
php8.1-fpm.service                         enabled         enabled
phpsessionclean.service                    static          -
ls /run/php | grep php
php-fpm.sock
php8.1-fpm.pid
php8.1-fpm.sock

nginxの設定

次に、nginxからPHPを利用できるように、php-fpm への接続設定を行います。以下のコマンドで対象となるサーバー設定ファイルを編集します。

sudo vi /etc/nginx/sites-enabled/default

編集内容は以下の通りです。.php のURLがリクエストされた場合、UNIXドメインソケット経由でphp-fpmへ処理を渡す設定となっています。

server {
        root /somewehere;

        index index.html index.php;

        server_name xxxxxxxx;
        
        ...

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

過去に設定した リバースプロキシ の設定と非常に似ています。

設定内容に誤りがないか確認後、nginxを再起動します。

sudo nginx -t
sudo systemctl restart nginx

test.php ファイルを新規作成し、以下の内容を記述してサーバー上に配置します。ブラウザでアクセスし、PHP情報が表示されれば設定が正しく反映されたことになります。

<?php phpinfo(); ?>

なお、UNIXドメインソケットで通信しているかどうかは、以下のように netstat コマンドで確認できます。

sudo apt install net-tools
netstat -a --unix | grep php
unix  2      [ ACC ]     STREAM     LISTENING     15992968 /run/php/php8.1-fpm.sock

デフォルトの404エラーページを変更する

バージョン情報を非表示にする

nginxのデフォルトの404エラーページには、nginxのバージョン情報やOSの情報が表示されます。セキュリティ上望ましくないため、これらの情報を非表示にする方法を解説します。

まず、nginx.confの設定ファイルを開きます。

$ sudo vi /etc/nginx/nginx.conf 

設定ファイル内で「server_tokens off」という行がコメントアウトされている場合は、コメントアウトを解除して有効にします。

設定変更後、nginxを再起動します。

sudo systemctl restart nginx

これで、404エラー発生時にバージョン情報やOS情報が非表示になります。

オリジナルの404エラーページを表示する

サイトのデザインに合わせてオリジナルの404エラーページを表示させたい場合は、以下の手順で設定を行います。

まず、defaultファイルを編集します。

sudo vi /etc/nginx/sites-enabled/default

次に、オリジナルの404.htmlを用意し、serverディレクティブ内に以下のように記述して、404ページのファイルパスを指定します。
rootディレクティブには404.htmlが存在するディレクトリを指定してください。

server {
    :
    error_page 404 /404.html;
    location = /404.html {
        root /somewhere_dir;
    }
    :
    :
}

最後に、nginxを再起動します。

sudo systemctl restart nginx

アクセスログとエラーログの確認方法

nginxのログファイルがある場所

デフォルト設定では、ログファイルは以下の場所に保存されます(ubuntu)。

項目 場所
アクセスログ /var/log/nginx/access.log
エラーログ /var/log/nginx/error.log

access.logの例

220.213.212.146 - - [23/Oct/2022:21:42:52 +0900] "GET /images_small/niku-udon/eyecatch.jpg HTTP/2.0" 200 23571 "https://k.araisun.com/noodles/teuchi-udon.html" "Mozilla/5.0 (Linux; Android 4.4.2; LaVieTab PC-TE510S1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
...

error.logの例

2022/10/23 07:33:12 [crit] 52949#52949: *2381 SSL_do_handshake() failed (SSL: error:0A00006C:SSL routines::bad key share) while SSL handshaking, client: 154.89.5.78, server: 0.0.0.0:443

error.log には 404 エラーなども記録されます。

エラーログの整形出力

以下のコマンドは、open() を含むログ行から対象ファイルを抜き出し、重複件数をカウントして、件数の多い順にソートして出力するものです。

grep 'open()' error.log | awk -F'"' '{print $2}' | sort | uniq -c | sort -nr

この方法により、404エラーが多発しているページを一目で確認でき、アクセスの傾向把握に役立ちます。

「SSL_do_handshake() failed」とは?

エラーログを確認していると、SSL_do_handshake() failed というエラーが見受けられます。
こちらの記事 によると、サイバー攻撃に起因してログが失敗したもののようです。エラーが発生しているため、セキュリティ的には問題ないと考えられます。また、SSLプロトコルの SSLv2、SSLv3、TLSv1 は古く脆弱性があるため、使用せず、TLSv1.2 以降を利用することが望ましいとされています。

「.well-known/traffic-advice」とは?

.well-known/traffic-advice は、Google Chrome の先読み機能によるアクセスです。先読み機能を使用していない場合、アクセスを禁止するため、.well-known/traffic-advice ファイルを作成し、以下の内容を記述しておきます。

[
    {"user_agent": "prefetch-proxy", "disallow": true}
]

これにより、エラーログに該当の記録が出力されなくなるはずです。

ちなみに、well-known 関連のエラーログ抽出方法は以下の通りです。

grep ".well-known" /var/log/nginx/error.log.1 | sed -E 's/.* open\(\) "([^"]+)".*/\1/g' | uniq

不正なアクセス対処(PHP編)

PHPを使用していない環境では、.php 拡張子へのリクエストが大量に来るのは不要なアクセスとなり、ログに無駄なエントリが残ります。そこで、Nginxの設定でPHPファイルへのアクセスを拒否する方法が有効です。以下の設定を追加することで、.php リクエストに対してレスポンスを返さず、接続を切断(444エラーを返す)できます。

location ~ \.php$ {
    return 444;
}

「444」は、Nginx独自のステータスコードで、クライアントに何も返さずに接続を強制的に切断することを意味します。この方法により、PHPを使用していない場合の不要なアクセスを効果的にブロックし、ログの無駄な記録を防ぐことができます。


リダイレクトを行う rewrite の使い方

nginx を使ったサーバー構築では、基本的に Apache のような .htaccess は機能しません。nginx で 301 リダイレクトなどを行いたい場合は、nginx の設定ファイルに rewrite でルールを記述する必要があります。ここでは rewrite の使い方をまとめておきます。

rewrite の概要

nginx でリダイレクトを行うためには、rewrite ディレクティブを使用します。このディレクティブは、指定した条件に一致するリクエスト URI を別の URI に書き換えたり、外部の URL へリダイレクトさせたりすることができます。rewrite ディレクティブは、サーバーやロケーションコンテキスト内で使用することができます。

基本的な構文は以下の通りです:

rewrite regex replacement [flag];

パラメータ

パラメータ 説明
regex リダイレクトを適用するための正規表現パターン
replacement リダイレクト先の URI または外部 URL
flag リダイレクトの動作を制御するオプション

flag オプション

パラメータ 説明
last 現在のリライト処理を終了し、改めてリライト処理を開始
break 現在のリライト処理を終了し、さらなる処理を行わない
redirect 一時的なリダイレクト (302) を行う
permanent 永続的なリダイレクト (301) を行う

単純なリダイレクト

以下の設定例では、/old-page へのアクセスを /new-page に 301 リダイレクトします。

rewrite ^/old-page$ /new-page permanent;

複雑なリダイレクト

複数のサブディレクトリに対してリダイレクトを適用する場合、正規表現を使用します。

rewrite ^/old-site/(.*)$ /new-site/$1 permanent;

この例では、/old-site 以下の任意のパスへのアクセスを、同じサブパスを保持しつつ /new-site へリダイレクトします。

便利な機能: return ディレクティブ

リダイレクトを行う別の方法として、return ディレクティブがあります。これは、条件に応じてリダイレクトやエラーページの表示をよりシンプルに設定することができます。

location /old-page {
    return 301 /new-page;
}

この方法では、特定のリクエスト URI に対して簡潔にリダイレクトを設定でき、rewrite ディレクティブを使用するよりも読みやすく、パフォーマンスの面でも効率的です。また、HTTP ステータスコードを直接指定できるため、リダイレクトの種類を容易に制御できます。

nginx のリダイレクト設定は非常に柔軟であり、サイトの構造変更や URL スキームの更新、外部サイトへのリダイレクトなど、さまざまなシナリオに対応できます。適切なディレクティブや正規表現を使用することで、必要なリダイレクトルールを効率的に実装できます。

nginx の設定を変更した後は、 sudo nginx -t でテストし、 sudo systemctl reload nginx で設定を反映させます。


rewrite ディレクティブを別ファイルで管理する

これらの rewrite ディレクティブを server ディレクティブへ直接記述しても良いのですが、rewrite ルールが多すぎると管理が大変になります。そこで、rewrite ルールを別ファイルで管理する方法を紹介します。これには include ディレクティブを使用します。include ディレクティブを使用することで、外部の設定ファイルを読み込み、メインの nginx 設定ファイルをすっきりと保つことができます。

手順

  1. リダイレクトルールを含む新しいファイルを作成します。例えば、/etc/nginx/sites-available/redirects.conf といったパスに保存します。
  2. この新しいファイルに、すべての rewrite ルールを記述します。
  3. メインの nginx 設定ファイル(または適切なサーバーブロック設定ファイル)にて、次のように include ディレクティブを使用して、作成したリダイレクトルールファイルを読み込みます。
server {
    # その他の設定 ...

    # リダイレクトルールを含む外部ファイルを読み込む
    include /etc/nginx/sites-available/redirects.conf;

    # その他の設定 ...
}

この手順により、nginx 設定のメンテナンスが容易になり、特定の種類の設定を集中管理できるようになります。また、将来的にリダイレクトルールを追加または変更する際に、メインの設定ファイルを直接編集する必要がなくなり、エラーのリスクを減らすことができます。

include ディレクティブは非常に強力で、サーバー設定の柔軟性と再利用性を高めます。ただし、複数の include ファイルを使用する場合は、それらのファイル間での設定の競合に注意する必要があります。また、nginx の設定を変更した後は、設定のテストと nginx の再起動またはリロードが必要です。

nginx の設定を変更した後は、 sudo nginx -t でテストし、 sudo systemctl reload nginx で設定を反映させます。


関連記事