Nginxでまず静的ファイルのみ表示してみる(Nginxその2)

VPSサーバーのDjangoにNginx、gunicornを適用する予定ですが、一度に設定するとエラーが生じたときに何がおかしいのか分からなくなります。そこで、まずNginxで静的なファイルを表示するところから始めたいと思います。

1.Nginxで静的ファイルを表示するとは

下図はクライアントの要求に対する処理の流れです。Nginxは静的なページの要求については、gunicornやDjangoに頼らずにNginxだけで静的ページを表示することが可能です。(下図の赤矢印)

この記事では、Nginxの設定を行い、実際に静的ページを表示します。

03_Nginx_gunicorn_Django

2.Nginxのインストールと初期画面の表示

まず、静的ページを表示する準備としてファイアウォールでポートを閉じているときには、Nginxが使用する80番(http)、あるいは443番(https)を開放しましょう。

$ sudo ufw status  #登録されているルールの一覧を表示
$ sudo ufw allow 80  #httpのポートを有効にする。
$ sudo ufw allow 443  #httpsの場合は443。

参照記事:ConoHa VPSにUbuntu。ufwでファイアウォール。

次にNginxをインストールします。

$ sudo apt install nginx  #Nginxのインストール

インストール時はNginxが起動した状態になっているので、ブラウザでVPSサーバーのIPアドレス(あるいはドメイン)にアクセスすると「Welcom to nginx!」が表示されます。

http://●●●.●●●.●●●.●●●/
01_Welcome_to_nginx

これで、VPSサーバーが公開されました。簡単です。しかし、自分が作ったhtmlのページを表示するには、もう少し設定が必要です。

3.Nginxの主なコマンド

Nginxで使用される主なコマンドは以下の通りです。特に設定ファイルを変更したときには、reloadによる設定ファイルの再読込みを忘れないようにしましょう。

$ sudo systemctl start nginx.service  #起動
$ systemctl status nginx.service  #状態確認
$ sudo systemctl stop nginx.service  #停止
$ sudo systemctl reload nginx.service  #設定ファイルの再読込み
$ sudo systemctl enable nginx.service #自動起動を設定
$ sudo systemctl disable nginx.service  #自動起動の解除

4.Nginxのルートディレクトリの確認

ところで、先ほどの表示された「Welcome to nginx!」のhtmlファイルはどこにあるのでしょうか。Nginxではブラウザから静的ページのリクエストがあったときに、静的ファイルを検索するディレクトリを設定できます。そして、このディレクトリをNginxの「ドキュメントルート」と呼びます。

そして、ドキュメントルートを設定したファイルの場所は以下のコマンドで確認できます。「grep」は「キーワードが記述された行」を表示するコマンドです。ディレクトリ「/etc/nginx/」の中のテキストファイルからキーワード「"root /"」を検索し、キーワードを見つけたファイルのパスと行を表示します。

なお、rオプションがあるので、「/etc/nginx/」だけではなく、それより下の階層のディレクトリも検索します。

grep "root /" -r /etc/nginx/

検索結果は以下の通りです。ディレクトリ「/etc/nginx/sites-available」の中のテキストファイル「default」の中に、キーワード「"root /"」が存在する行が2か所発見されました。

2行目は行頭に「#」があるのでコメント文です。したがって、デフォルトのドキュメントルートは「/var/www/html」であることがわかります。そして、「/etc/nginx/sites-available/default」が設定ファイルです。

/etc/nginx/sites-available/default:     root /var/www/html;
/etc/nginx/sites-available/default:#    root /var/www/example.com;

ディレクトリ「/var/www/html」をのぞいてみると、index.nginxdebian.htmlというファイルがあります。これが、「Welcome to nginx!」のhtmlファイルです。viエディタなどで表示を変えると面白いと思います。

別のディレクトリにある以下のnginx.confも設定ファイルであり、本来はこちらがメインの設定ファイルなのですが、ポート番号やサーバーの名称などの設定はnginx.confではなく、ディレクトリ「/etc/nginx/sites-available/」の中で設定することが勧められています。

/etc/nginx/nginx.conf

なお、設定ファイルの保存場所としては、他にもディレクトリconf.dやdefault.dが紹介されている書籍やサイトがありますが、私のNginx 1.18.0のインストール時の構成ではconf.dはありましたが、default.dというフォルダは存在しませんでした。環境やバージョンの違いによって、設定ファイルのディレクトリ構成が違う可能性があるので注意してください。

5.基本的な仮想サーバーの構成

設定ファイルの位置と名前がわかったので、まず最初に、基本的な仮想サーバーの構成を説明したいと思います。

以下の設定は、「仮想サーバー0」「仮想サーバー1」「仮想サーバー2」の3台の仮想サーバーを構成した例です。それぞれserver_nameにより、仮想サーバー1にはドメイン1、仮想サーバー2にはドメイン2が関係付けられています。

例えば「http://ドメイン1/」のようにリクエストされると、仮想サーバー1の設定が適用されます。

また、仮想サーバー0の設定ように「server_name _;」とすると、全ての名前に対応することができます。ただし、ドメイン1、ドメイン2は、仮想サーバー1、仮想サーバー2の設定が優先されるため仮想サーバー0の設定の影響は受けません。

ところで、設定例ではserver_nameは全てIPアドレスではなくドメイン名で指定されています。もし、このような設定でIPアドレスでリクエストされた場合は、どのサーバーの設定が適用されるのでしょうか。

server_nameで指定のないドメイン名やIPアドレスのリクエストに対しては、「listenでdefault_serverが指定されたサーバー」の設定が適用されます。また、いずれもdefault_serverの指定がない場合には「一番最初に記述されたサーバー」が対応します。

以下の例では、仮想サーバー0は「server_name _;」によってすべての名前に対応し、さらにlistenでdefault_serverであることが明記されているので、このような想定外のリクエストには仮想サーバー0が対応します。

仮想サーバー0の存在は、想定しないページの表示を防いだり、IPアドレスを使った不正アクセスから防御することができます。

以下の例では、サーバー0はステータスコード444を返す設定になっています。

ステータスコード444はレスポンスヘッダを返さずにコネクションを切断します。したがって、ステータスコードである444という番号自体もクライアントには送信されません。444番はginx独自のステータスコードです。

#仮想サーバー0
server {
    listen 80 default_server;
    server_name _;
    #すべてのリクエストに対応する。
    retrun 444;  #ステータスコード444を返す。
}


#仮想サーバー1
server {
    listen 80;
    server_name ドメイン1;
    #以下ドメイン1の設定を記述
}


#仮想サーバー2
server {
    listen 80;
    server_name ドメイン2;
    #以下ドメイン2の設定を記述
}

なお、上記の設定の仮想サーバー0、仮想サーバー1、仮想サーバー2の設定を同じファイルに記述することも出来ますが、それぞれの設定を別のファイルに記述することによって、例えば仮想サーバー1だけを停止するといった対応が容易になります。

さて、説明の最後になりましたが、listenの後の80はサーバーがどのポートでリクエストを待機するかを指定します。httpは80番、httpsは443番です。

6.設定ファイルの有効・無効の切り替え

以下、設定ファイルの構成例です。

そして、ディレクトリ「/etc/nginx/sites-available」の「server0」「server1」「server2」が新し作成した設定ファイルです。

設定ファイルの名称は、例えばドメイン名にするなど、もっと分かりやすい名称にするとよいです。

/etc/nginx
 │
 ├sites-available
 │ ├default
 │ ├server0
 │ ├server1
 │ └server2
 ├sites-enabled
 │ ├server0
 │ ├server1
 │ └server2
 └nginx.conf

ここで注意しなければならないのは、「/etc/nginx/sites-available」には設定ファイルが入っており、「/etc/nginx/sites-enabled」には設定ファイルに対するショートカットのようなファイルが入っているということです。このショートカットのようなファイルはシンボリックリンクと呼ばれています。

設定ファイル「default.old」「server0」「server1」「server2」の有効・無効はこのシンボリックリンクの有無で設定します。「/etc/nginx/sites-enabled」に「default」がないのは、「default」を無効にしたかったからです。

#設定ファイル名:server0
#仮想サーバー0
server {
    listen 80 default_server;
    server_name _;
    #すべてのリクエストに対応する。
    retrun 444;  #ステータスコード444を返す。
}
#設定ファイル名:server1
#仮想サーバー1
server {
    listen 80;
    server_name ドメイン1;
    #以下ドメイン1の設定を記述
}
#設定ファイル名:server2
#仮想サーバー2
server {
    listen 80;
    server_name ドメイン2;
    #以下ドメイン2の設定を記述
}

さて、メインの設定ファイル「/etc/nginx/nginx.conf」には、以下の記述があります。これは、「/etc/nginx/sites-enabled」にあるシンボリックリンクを読み込んでいます。つまり、「/etc/nginx/sites-enabled」のシンボリックリンクを介して「/etc/nginx/sites-available」の設定ファイルが読み込まれているのです。

include /etc/nginx/modules-enabled/*.conf;

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

「/etc/nginx/sites-enabled」のシンボリックリンクは以下のコマンドで作ることができます。「/etc/nginx/sites-available」の設定ファイルから、「/etc/nginx/sites-enabled」にシンボリックリンクを生成します。

$ sudo ln -s /etc/nginx/sites-available/server0 /etc/nginx/sites-enabled/server0

VS Codeなどでシンボリックリンクを開くと、ショートカット先を示すテキストが表示されるのではなく、元ファイルのコードが表示されます。したがって、ショートカットではなくファイルがコピーされたのではないかと感じるかもしれませんが、「ls -l」で調べるとシンボリックリンクの容量は元ファイルよりも小さく、ショートカットであることがわかります。

なお、シンボリックリンクの所有者を替えたい場合には、以下のようにhオプションを付けて下さい。hオプションがない場合は、リンク元のファイルの所有者が変更されます。

sudo chown -h user_name:user_name /etc/nginx/sites-enabled/server0

8.静的ファイル、メディアファイルの配置ディレクトリ

実際に設定ファイルを作成する前に、準備しておかなければならないことがあります。それは、静的ファイルとメディアファイルを保存する場所です。

静的ファイルとは、CSS、JavaScript、画像ファイルといった、どのクライアントからでも見ることができる中身が変わらないデータです。JavaScriptを使えばページの表示を変えることは可能ですが、サーバーに保存されている静的ファイル自体は変化しません。

一方、メディアファイルも静的ファイルの1つですが、Webアプリを通してアップロードされた静的ファイルです。メディアファイルも、どのクライアントからでも閲覧可能です。この記事では「静的ファイル」といえば、メディアファイルは含まないものとします。

なお、静的ファイル、メディアファイルを配置するディレクトリのルートであるドキュメントルートはデフォルトでは「/var/www/html/」となっていますが、Nginxでは/user/share/nginx/htmlをドキュメントルートに設定することが多いようです。

したがって、以下のフォルダ構成で静的ファイルを保存するようにしたいと思います。

/user/share/nginx/html  #ドキュメントルート
 ├static  #静的ファイル配置ディレクトリ
 └media  #メディアファイル配置ディレクトリ

ディレクトリは「mkdir」コマンドで作成します。mkdirはpオプションを指定すると、ディレクトリstaticだけではなく、ルートディレクトリからstaticに至るまでのディレクトリnginxやhtmlも作ってくれます。

なお、設定ファイルを一般ユーザーでも変更できるように、ディレクトリの所有者を一般ユーザーに変更しなければなりません。

$ sudo mkdir -p /user/share/nginx/html/static
$ cd /user/share/nginx/html
$ sudo mkdir media
$ sudo chown ユーザー名 static
$ sudo chown ユーザー名 media

9.Nginxの設定

では、実際に以下のような構成で設定ファイルを作成してみましょう。想定外のリクエスト対応用仮想サーバーの設定ファイルをserver0とし、サイトを表示する仮想サーバーの設定ファイルをdj_testとします。

また、sites-enabledにあるシンボリックリンクdefaultは削除し、設定ファイルdefaultを無効にします。

/etc/nginx
 │
 ├sites-available
 │ ├default
  #デフォルトの設定ファイル
 │ ├server0  #想定外の対応
 │ └dj_test  #仮想サーバー
 ├sites-enabled
 │ ├server0
 │ └dj_test
 └nginx.conf

念のため設定ファイル「/etc/nginx/nginx.conf」に以下のコードがあることを、確認してください。なければ追加する必要があります。nginx.confがメインの設定ファイルだからです。

include /etc/nginx/modules-enabled/*.conf;

server0の設定は、既に解説済みなのでコマンドの説明は省略します。

#設定ファイル名:server0
server {
    listen 80 default_server;
    server_name _;
    #すべてのリクエストに対応する。
    retrun 444;  #ステータスコード444を返す。
}

以下、「http://ドメイン名/static/」で始まるurlの設定は「location /static { }」、「http://ドメイン名/media/」で始まるurlの設定は「location /media{ }」それ以外の「http://ドメイン名/」で始まるurlの設定は「location / { }」に記述します。また、「location / { }」の部分にはdjangoに処理を引き継ぐ設定が書かれています。

つまり、「http://ドメイン名/static/」「http://ドメイン名/media/」で始まるurlでアクセスした場合にはNginxだけで静的ページを表示し、それ以外のurlの場合にはdjangoに処理を引き継ぐという設定です。

また、locationの外で「root /usr/share/nginx/html」が設定されているので、「location /static { }」、「location /media { }」のaliasは省略可能です。

#設定ファイル名:dj_test
server {
	listen 80;
  #ポート番号の指定 httpは80番
        server_name test.com   #VPSサーバーの
ドメインを指定
	#server_name ***.***.***.***;  #IPアドレスで指定するときの書式

        #ドキュメントルートの指定(静的ファイル、メディアファイルの保存先)
	root /usr/share/nginx/html;
  

	#http://ドメイン名/static/で始まるURLにアクセスする場合の設定
        location /static {
                #http://ドメイン名/static/に対応するディレクトリ
                #locationのstaticとaliasのstaticは同じ名前である必要はない
		alias /usr/share/nginx/html/static;
	}

	#http://ドメイン名/media/で始まるURLにアクセスする場合の設定
	location /media {
		alias /usr/share/nginx/html/media;
	}

        #http://ドメイン名/static/、http://ドメイン名/media/以外の
        #http://ドメイン名/で始まるURLにアクセスする場合の設定
        location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X_Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8000;
        }


}

なお、最初の目標は静的ページの表示なので、入力が面倒ならば、まずは「location / { }」の設定を空白にしてもかまいません。

つまり、djangoを使わず静的ファイルを表示する環境を試すだけであれば、以下のようにシンプルな設定になります。余計なコードがあるとエラー発見が難しくなるので、まず、以下の設定で検証してみましょう。

#設定ファイル名:dj_test
server {
	listen 80;
  #ポート番号の指定 httpは80番
        server_name test.com   #VPSサーバーの
ドメインを指定
	root /usr/share/nginx/html;
  
#ドキュメントルートの指定

        location /static {
	}

	location /media {
	}

}

設定ファイルができたら、「/etc/nginx/sites-enabled」にシンボリックリンクを作成することを忘れないようにしてください。

10.rootとalias

なお、rootやaliasの設定は、色々な書き方があります。以下、設定1~3は全て同じ内容です。rootで指定した場合は、「location /static」の起点となるディレクトリを指定します。内容の違うrootの設定がlocationの外側、内側の両方にある場合は内側が優先されます。

#設定1
server {
	root /usr/share/nginx/html;

        location /static {
	}
}
#設定2
server {
        location /static {
            root /usr/share/nginx/html; 
	}
}

aliasで指定する場合は、「location /static」の「/static」によって検索されるディレクトリ名をaliasで直接指定します。rootによる指定と異なり、aliasの最後に/staticがあるので注意して下さい。

#設定3
server {
        location /static {
            alias /usr/share/nginx/html/static;
	}
}

したがって、aliasでは以下のような記述も可能であり、「http://ドメイン名/aaa/ファイル名」とすれば、ディレクトリ「/usr/share/nginx/html/static」の中でファイルを検索します。

#設定4
server {
        location /aaa {
            alias /usr/share/nginx/html/static;
	}
}

以下の参考資料によれは、locationの外でrootによりドキュメントルートを指定し、このrootが利用できない場合はlocationの中で設定を上書きすることが推奨されています。

落とし穴とよくある間違い | NGINX 日本語訳 - FC2

11.静的ページの表示

いよいよ、自分で作った静的ページを表示します。test.htmlというファイルを作り、以下のコードをコピペし、VPSサーバーの「/usr/share/nginx/html/static」にコピーして下さい。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Nginxの練習</title>
  </head>
  <body>
    <h1>Welcome to nginx!</h1>
    <p>htmlの場所:/static</p>
  </body>
</html>

htmlファイルのコピーができたら、statusによってNginxが起動していることを確かめ、起動していない場合にはstartで起動します。

$ systemctl status nginx.service  #状態確認
$ sudo systemctl start nginx.service  #起動

すでにNginxが起動済みの場合でもreloadにより書き換えた設定ファイルを読み込みます。

$ sudo systemctl reload nginx.service  #設定ファイルの再読み込み

ブラウザにより「http://ドメイン名/static/test.html」にアクセスしてみましょう。なお、拡張子htmlの入力も必要ですので注意して下さい。

すると、下図のようにhtmlファイルが表示されたら成功です。

なお、htmlファイルだけではなく、画像データも「http://ドメイン名/test.png」のように直接指定し表示することができます。

02_test_html_02

このように、静的ページはstaticの下に静的ファイルを入れ、アクセスするurlを「http://ドメイン名/static/・・・」とすることにより、Nginxだけで表示することが可能です。

静的ページはdjangoを使わず、Nginxで表示する方が高速に処理することが可能ですし、VPSサーバ-のCPUの負担を軽減することができます。

なお、この例ではディレクトリstaticにhtmlファイルを直接入れましたが、DjangoとNginxの組み合わせでは、このような使い方はしません。「/usr/share/nginx/html/static」にはDjangoプロジェクトの中の静的ファイルを自動ツールを使って複写し、コードの記述としてはDjangoプロジェクト内にあるテンプレートから静的ファイルを呼び出します。

つまり、「/usr/share/nginx/html/static」はDjango用のディレクトリなので、例えばDjangoで作ったアプリとは別に、静的ページのブログ記事が複数あるといった場合には、staticではなく「/usr/share/nginx/html/blog」にブログ記事をまとめ、Nginxから直接読み取るといった運用になると思います。

12.デフォルトの設定ファイルdefault

設定ファイル「/etc/nginx/sites-available/default」の内容は以下の通りです。defaultは無効にするので、無効にされた設定の内容を確認しておきたいと思います。

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;  #シンボリックルート

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

}

以下の部分はIPv6構成用であり、[::]の部分はIPアドレスです。通常はIPv4を使用することになると思いますので不要です。

listen [::]:80 default_server;

以下、コメント文の英語は「PHPを使うならindex.phpも追加するように」と書かれています。PHPでNginxを使うのであればindex.phpを追加します。しかし、Djangoなので関係のない記述です。

indexコマンドの引数で指定したファイルは、urlでファイル名の指定しなくても読み込むことができます。「Welcome to nginx!」のhtmlファイルのファイル名がindex.nginx-debian.htmlだったことを思い出してください。

このindexの設定は残した方がよいと思います。

# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;

try_filesはファイルやディレクトリを検索する方法を指定できます。「$uri」という記号を使って検索する書式を指定します。例えば「http://ドメイン/abc」にアクセスしたとき、$uri 、$uri/の$uriの部分を "abc"に置き換えて、それを検索します。つまり、"abc"というファイルと"abc/"というディレクトリを探します。そして、"abc"も"abc/"もなければ404ステータスコードを返します。

location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
}

ちなみに、以下のように「$uri.html」を追加すると、abc.htmlも検索してくれるので拡張子なしでもhtmlファイルにアクセスできるようになります。

location / { }は、この後、djangoに処理を移す設定を記述するので、try_fileの設定は不要です。むしろ、location /static { }の中で必要に応じて設定すればよいと思います。

location / {
	try_files $uri $uri/ $uri.html =404;
}

13.最終的な設定ファイル

最終的な設定ファイルは、以下の通りです。好みや要求に応じて不必要なものは省いたり、追加してください。

#設定ファイル名:server0
server {
    listen 80 default_server;
    server_name _;
    #すべてのリクエストに対応する。
    retrun 444;  #ステータスコード444を返す。
}
#設定ファイル名:dj_test
server {
	listen 80;
  #ポート番号の指定http
	server_name ***.***.***.***;
  #IPアドレス(ドメイン)の指定
	root /usr/share/nginx/html;
  #ドキュメントルートの指定

	# index.html等はファイル名の指定なしで実行
	index index.html index.htm index.nginx-debian.html;
    
	location /static {
                #.htmlは省略できる
		try_files $uri $uri/ $uri.html =404;
	}

	location /media {

	}

    #以下、この記事では説明しませんが、djangoにデータを引き渡す設定です。
    location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X_Forwarded-Proto $scheme;

            proxy_pass http://127.0.0.1:8000;
        }
}

以上で、Nginxによる静的ページの表示の説明は終了です。複雑な設定では順番に設定を固めていくのが近道です。

次の記事では、いよいよDjangoのページを公開したいと思います。

私が実際にレンタルしたVPSサーバー

私が実際にレンタルしたVPSサーバーはConoHa VPSです。私は1GBのプランを申し込みました。VPSサーバーは一般のレンタルサーバーと異なりOSやアプリケーションを自由に設定できるので、Pythonで計算した結果をサイトに表示することもできます。

なお、ConoHa VPSの特長として、サーバーのディスクイメージを丸ごとバックアップできるイメージ保存機能を無料で使用することができます。コードを変更して元に戻せなくなった場合にも安心です。

また、ConoHa VPSは途中でプランをスケールアップできるだけでなく、スケールダウンすることもできます。つまり、2Gプランを1Gプランに変更することができます。ただし、512MBプランだけはスケールアップ・ダウン機能が使用できないので注意してください。

また、初期費用なしで3日だけ借り、3日分の費用だけ払うといったことも可能なので気軽に始められます。※時間課金(月の上限額は決まっています)



その他

Twitterへのリンクです。SNSもはじめました♪

以下、私が光回線を導入した時の記事一覧です。
 (1) 2020年「光回線は値段で選ぶ」では後悔する ←宅内工事の状況も説明しています。
 (2) NURO光の開通までWiFiルーターを格安レンタルできる
 (3) NURO光の屋外工事の状況をご紹介。その日に開通!
 (4) 光回線開通!実測するとNURO光はやっぱり速かった
 (5) ネット上のNURO光紹介特典は個人情報がもれないの?