Apache HTTP Serverはもう古い!
ということで、彗星の如く現れた、近い将来Apacheサーバーを追い越すであろうWebサーバー「nginx」(エンジンエックス)をさわっておきましょう。
ちなみに記事の内容は、ConoHa VPSにSSHで接続するでDebianサーバーを立てた状態を前提にしています。
設定の煩雑さもかなり改善されていて、これから先Apache2ではなくnginxを使わない理由が見当たらないのです
注意
この記事の内容は、nginxを理解することを最優先にするために、全てroot権限で実行しています。
内容をトレースしながら本番環境を作るのは避けてください。
nginxについて理解ができたら、自分の力でもう一度サーバーを作り直しましょう。
ユーザーのアクセス権を厳格に設定し、nginxの設定ファイルもセキュリティを厳しい内容に書き換えたうえで、です。
一度勉強をして理解し、その上で本番に臨む。
ウェブ開発はそれくらい慎重でないといけません。
nginxのインストール
公式ドキュメントを見よう
nginxは、ググって出てきた情報を元にインストールをしてみたもののうまく動かない可能性が高いです。
Linuxディストリビューションごとに別パッケージで管理されており、別の手順が必要になるからです。
nginxの公式ドキュメントではディストリビューションごとにインストールの手順を公開しているので、そちら見るのがオススメです。
(英語ですがコマンドだけ見れば大体理解できるはず。)
公式インストールガイドはこちら。
ちょっと公式見てもわからんわって人は、ConoHa VPSにSSHで接続するで紹介している内容通りにVPSを構築した環境であれば、この後説明する内容をそのままトレースしてもうまくいくはずです。
インストールしていく
公式ではsudoコマンドを使っての説明になっていますが、今回はnginxの理解と説明が目的なためrootユーザーで済ませました。
(非公式な環境でnginxについて勉強し、それが済んだら本番環境はまた別に作成する、くらいの心持ちで勉強するべし)
まずは依存パッケージをインストール
> apt install curl gnupg2 ca-certificates lsb-release
aptにnginxのdebian用パッケージのurlを登録
> echo "deb http://nginx.org/packages/debian `lsb_release -cs` nginx" \
| tee /etc/apt/sources.list.d/nginx.list
apt-keyにnginx_signing.keyを書き込み
> url -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -
apt-keyに追加した内容を確認
> apt-key fingerprint ABF5BD827BD9BF62
結果が次のようになっていればOK
573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62
追加したdebian用パッケージのurlからnginxファイルを取得
> apt update
nginxをインストール
> apt install nginxt
それぞれコマンドがエラーなく実行できればインストール完了です。
起動しているか確認してみる
インストールすると自動的にnginxのプロセスが立ち上がっているかもしれませんが、念のため起動コマンドを実行しておきましょう。
> nginx
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
(すでに起動していても、上記のようなメッセージが出るだけですので。)
http://xxx.xxx.xxx.xxx/(xxxは自分のVPSサーバーのIPアドレス)にブラウザから接続してみると、
あっけなく表示されました。
こういうのは初めはもっとエラーが出たり設定しないと動かなかったりするものだとばかり。
起動・停止・再設定
- nginx …起動(引数をつけない)
- nginx -s stop …強制終了
- nginx -s quit …終了
- nginx -s reopen …設定再読み込み
nginx -hで確認することができます。
# nginx -h
nginx version: nginx/1.18.0
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /etc/nginx/)
-c filename : set configuration file (default: /etc/nginx/nginx.conf)
-g directives : set global directives out of configuration file
デフォルトのページを差し替えてみる
せっかくHTTPサーバーを入れたら、何か自分のオリジナルのページを表示させてみたいですよね?
ということで、まずはデフォルトで表示されたページを自分オリジナルのページに書き換えてみましょう。
先ほどブラウザからアクセスして表示された「Welcome to nginx!」のページは /usr/share/nginx/html/index.htmlファイルです。
(インストールのしかたによって変わる可能性高いです。ファイルが見つからなかったらこの章を飛ばしても問題なしです。)
このファイルを書き換えて、内容が反映されるか確認してみましょう。
> nano /usr/share/nginx/html/index.html
内容を次のように書き換え
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ようこそエンジンエックスへ!</title>
</head>
<body>
<h1>ようこそエンジンエックスへ!</h1>
<p>エンジンエックス、サイコーのWebサーバーです!ヒャハー!</p>
</body>
</html>
そしてhttp://xxx.xxx.xxx.xxx/(xxxは自分のVPSサーバーのIPアドレス)にブラウザから接続してみると
オリジナルの内容が表示されました。
静的なファイルを提供するだけなら、既に十分運用できる状態ですね。
設定ファイルを読んでいこう
Apache HTTP Serverの設定ファイルはXML形式でしたが、nginxはもっとシンプルな形式で簡潔になっています。
nginxの設定ファイルは、/etc/nginx/nginx.confです。
開いて中を見てみると
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
こんな感じになっています。
ぱっと見、ごちゃごちゃして見えるかもしれませんが、この設定ファイルの文法はシンプルな2つのルールで成り立っています。
単純命令(simple directive)
文法その1はsimple directive(直訳すると「単純命令」)は、命令と値だけで構成されます。
命令 値;
先ほどの設定ファイル(nginx.conf)の最初の2行なんかがそうですね。
user nginx;
worker_processes 1;
コンテキスト(context)
文法その2はcontext(コンテキスト)です。
IT用語的に直訳すると制御情報というのが妥当ですが、イメージしづらいのでコンテキストとそのまま呼ぶことにしてしまいましょう。
コンテキストはコンテキスト名と波カッコ{bracket}で構成されます。
context-name {
}
nginx.confの8行目と10行目がコンテキストの記述です。
events {
worker_connections 1024;
}
events {} の中にあるのはworker_connectionsという単純命令で、ワーカーコネクションは1024に設定する、という内容になっています。
このようにコンテキストは単純命令とコンテキストを複数内包することができます。
シャープ(#)から行末はコメント扱い
シャープ(#)から行末まではコメントとみなされます。
# このようにシャープの後はコメントです
ここはコメントではありません
コメントも文法ルールとしてカウントすると3つあるということになる
nginx.confにコメントをつけてみた
と、いうことで、nginx.confの内容を、1行ずつ全てコメントをつけてみました。
# ワーカープロセスはnginxユーザーで実行される
user nginx;
# ワーカープロセスは1つのみ
worker_processes 1;
# エラーログは/var/log/nginx/error.logに記録される
# ログレベルはwarn
error_log /var/log/nginx/error.log warn;
# プロセスIDは/var/run/nginx.pidに書き込む
pid /var/run/nginx.pid;
# イベント(≒アクセス)に対する設定のコンテキスト
# パフォーマンスチューニングの時しか触らなくてOK
events {
worker_connections 1024;
}
# HTTPサーバー命令コンテキスト
http {
# /etc/nginx/mime.typesファイルを設定ファイルとして読み込む
include /etc/nginx/mime.types;
# レスポンスタイプは特に指定されない設定
# (application/octed-streamは指定しない的な意味になる)
default_type application/octet-stream;
# ログの書式を設定 設定名はmainとする
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# アクセスログは/var/log/nginx/access.logに書き込む
# 書式はmainで設定されたものを適用
access_log /var/log/nginx/access.log main;
# システムコールsendfile()を利用する(offが安定)
sendfile on;
#tcp_nopush on;
# HTTP KeepAliveがタイムアウトする時間は65秒
keepalive_timeout 65;
# 通信をgzip圧縮する
# (デフォルトではコメントアウトしてあるのでoff)
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
nginx.conf内で登場する命令の公式説明をリンクしておきました。
- user
- worker_process
- error_log
- pid
- events { } (Understanding the Nginx Configuration File Structure and Configuration Contextsで詳しく書いてありました。2014年の記事ですが。)
- worker_connections命令
- http {}
- include
- default_type
- log_format
- access_log
- sendfile
- keepalive_timeout
- gzip
conf.d/defaults.confの内容にコメントをつけてみた
続いて、nginx.confの最後に読み込んでいる/etc/nginx/conf.d/*.confの内容も見てみましょうかね。
conf.dの中には、default.confの1ファイルしかありません。
ファイルが沢山あったらページ閉じようかと思ってた人、いると思います。
安心して下さい。ホントにコレで終わりです。
default.confの内容にコメントを加えたものを紹介します。
さらっと読めば、イメージが伝わるかなと思います。
英語のコメントが最初から書いてあったもの、日本語のコメントがケンヂまるが付け足したコメントです。
# サーバー設定
# (複数のserver {}を運用することができる)
server {
# ポート80をリッスン
listen 80;
# httpリクエストヘッダのHostフィールドが
# localhostの時はサーバーで処理する
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# ルートへのアクセスは/usr/share/nginx/htmlディレクトリ内の
# ファイルで対応する
# http://example.com/のようにファイルを指定しないで
# アクセスされた場合はindex.htmlかindex.htmを表示する。
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# 404エラー用ページを設定
# デフォルトでは404.htmlは用意されていない。
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
# 500エラー、502エラー、503エラー、504エラーは、
# /usr/share/nginx/html/50x.htmlを表示する
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
# コメントアウトを解除すると.phpファイルへのアクセスは
# ローカルで動いているAapcheサーバーに渡す
# (CGIはApacheサーバーに処理させる場合の設定)
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
# コメントアウトを解除すると、.phpファイルねのアクセスは
# ローカルのポート9000で待機しているFastCGIサーバーに渡す
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#location ~ /\.ht {
# deny all;
#}
}
default.confで内で登場する命令の公式説明をリンクしておきました。
ほとんどがlocationコンテキストでの設定になっていますが、locationで指定したuriをマッチした部分はこう処理しますよという宣言をもれなく書いていくことで、phpファイルはこう処理する、pythonファイルはこう処理する、cssファイルはこう処理する、といったような制御ができるようになるわけです。
今さらですが注目していただきたいのが、20〜23行目です。
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
デフォルトのページを差し替えてみるで/usr/share/nginx/html/index.htmlを書き換えるとブラウザから表示されるページが変わりましたが、その理由はここでインデックスページが設定されていたからだったのでした。
CGIとか動かせるの?nginx単体ではCGIを動かすことはできません。が、しかし。
default.confを見てもらえるとわかるように、phpファイルなどのCGIとして実行させたいファイルに対してのアクセスは、Apacheや他のCGIサーバーにリダイレクトする設定しか示されていません。
つまり、nginx単体ではCGIを動かすことはできません。しかし、他のCGIサービスに処理を丸投げすることで、安全性を提供しつつ動的ページも提供できる、という設計になっています。
ここ、Apacheサーバーと大きく異なる部分です。
あとがき
僕はPythomプログラマなのですが、作ったプログラムを公開する手段としてnginx+uWSGI+Djangoの環境を構築中です。
Apacheサーバーとnginxのどちらを選択しようか迷っていたのですが、実際に使ってみてnginx一択だなと思ったので、「お、Apacheより簡単じゃん」と思っておらえたらと思って今回の記事を書いた次第です。