CentOS 8 & Nginx で JATOS 環境を作って,lab.js でオンライン実験を組むときに嵌まりそうなポイント #2 設定編

前回に引き続き,ここではインストールしたサービスの設定をしていきます。

ここからの作業は,root 権限がないと都合が悪いものが多いので,予め 

$ sudo su -

をしておくのを忘れないようにしてください(しなくても毎回 sudo command すればいいんですが,ちょっとメンドい)。

PHP の設定

まずは,PHP からいきましょうか。PHP 周りの設定は,/etc にあります。まず,PHP 全体の設定を書く /etc/php.ini の設定を編集します。

# vim /etc/php.ini

以下の辺りを設定しておけば良いでしょう。

date.timezone = "Asia/Tokyo"
mbstring.language = "Japanese"
mhstring.internal_encoding = "UTF-8"

多分,ですが,timezone の設定以外はデフォルトで設定されているように思います。なお,下の php-fpm.d/www.conf も含めて,PHP の設定ファイルで,行の先頭が ; になっている行は無視(コメントアウト)されます。

次に,PHP の FastCGI モジュールである php-fpm についてですが,この設定ファイルは,/etc/php-fpm.conf と /etc/php-fpm.d/ 以下のファイルに分かれています。/etc/php-fpm.d/www.conf を書き換えます。

# vim /etc/php-fpm.d/www.conf

書き換える内容は,以下の設定箇所です。

user = nginx
group = nginx

また,同じ www.conf にある listen という行が

listen = /run/php-fpm/www.sock;

となっているか,はたまた

listen = 127.0.0.1:9000

となっているか,どちらであるかを確認してください。上の方は,www.sock という通信用のソケット (UNIX ドメインソケット) を,下の方は 9000番ポート (tcp) を使う設定になっています。どちらでも構いませんが,どちらになっているかを確認しておきましょう。

JATOS の設定

まずは,JATOS の起動設定を作成します。CentOS 8 の場合,起動時の各種サービスは systemd というプログラムによってコントロールされています。systemd 経由で JATOS を起動する場合,JATOS 用の起動設定を作り,systemd に JATOS を認識させて,起動のための登録を行う,という手順を踏みます。まず,JATOS の起動設定ですが,JATOS の Documantation 

に従って /etc/systemd/system というディレクトリに jatos.service という名前で作成します。

# vim /etc/systemd/system/jatos.service

ファイルは以下の内容で作成します。

[Unit]
Description=JATOS
After=network-online.target

# If you use JATOS with an MySQL database use

# After=network-online.target mysql.service

[Service]
PIDFile=/usr/share/nginx/jatos/RUNNING_PID
User=nginx
ExecStart=/usr/share/nginx/jatos/loader.sh start
ExecStop=/bin/kill $MAINPID
ExecStopPost=/bin/rm -f /usr/share/nginx/jatos/RUNNING_PID
ExecRestart=/bin/kill $MAINPID
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

なお,/usr/share/nginx/jatos の部分は,実際に JATOS をインストールしたディレクトリ名と読み替えてください。また,# でコメントアウトされた箇所に書いてある通り,JATOS を  MySQL と一緒に使う場合は,After=network-online.target mysql.service と書かれている行の #  を消す必要があります。

次に,jatos のサービス登録ですが,

# systemctl daemon-reload
# systemctl enable jatos.service

とします。これで,サービスが登録されます(次にサーバを起動した時は,自動で JATOS が起動します)。ただ,まだ起動はしていないので,以下のコマンドを実行して,起動させます。

# systemctl start jatos.service

さて,この段階で,JATOS に接続できるかどうか確認しましょう。ブラウザで,my-ip-address:9000 という感じでアドレスを入力してください。my-ip-address には,実際にはサーバの IP アドレスが入ります(そのアドレスの 9000 番ポートに接続するという意味です)。JATOS のコンソール画面が出て,admin(パスワードも admin)でログインできれば成功です。

ログインが出来ない場合,理由はいくつか考えられますが,まず疑うべきなのは,サーバのファイアウォールの設定です。もし,9000番ポートの通信がブロックされていたら,それを一旦解放してください。それでもダメならば,先ほどの php-fpm の設定を見てください。もし,/etc/php-fpm.d/www.conf で,

listen = 127.0.0.1:9000

となっていた場合,9000番ポートは php-fpm に使われていることになります。その場合は,JATOS の動作ポートを変更する必要があります。JATOS のポートを変更するには,インストールディレクトリの conf にある production.conf を編集します。

# vim /usr/share/nginx/jatos/conf/production.conf

ファイル中の play.server.http.port を以下のように書き換えます。

 #play .server.http.port = 80
play.server.http.port = 9030

番号は適当に 9030 としてありますが,空いているポートであれば他の番号で構いません。production.conf を修正したら,jatos.service を再起動します。

$ systemctl restart jatos.service
php-fpm の方の設定を書き換えるという方法もありますが,多分,こっちの方が影響する範囲が大きいので,JATOS のポート番号を変える方が面倒が少ないような気がします。

うまくログインできたら,admin ユーザのパスワードを変更し,実際に実験を動かす時に使う一般ユーザも作成しておきましょう。

SSL証明書の取得と certbot の設定

ここの設定は,後でやって,設定書き換えてもいいのですが,Nginx の設定の説明の都合上,とりあえずこの段階で,ドメイン名を決めて取得→SSL 証明書の取得をやってしまいましょう。もちろん,先に Nginx の設定を行って挙動を確かめてから,ここの作業を行っても問題ありません。ただ,SSL 証明書の取得は,ドメイン名を取らないと意味がありませんので,ドメイン名取得→ドメイン名関係の設定→ SSL 証明書取得,という順序は間違えないでください。

ドメインの取得は,色々な業者がありますので,適当に取得してください。ただ,検索トップで出てくる,○名前.com の場合,WHOIS 情報公開代行(ドメインの持ち主の連絡先を業者の連絡先で代行してくれるサービス)を,最初に申し込んでおかないで後から追加すると,毎年費用が請求されるというトラップがあるようなので,お気を付けください(私は,別業者にしましたが)。

また,ここから先は,多少好みの問題も出てきますが,今回ドメインを取得するにあたって,ホストの別名 (CNAME レコード)として,実験用サーバの名前を別に設定しました(WordPress の動いているメインのWebサーバと,実験用のサーバを見かけ上分けるため)。ドメインを取得するとき,複数の物理または仮想サーバを動かす場合でなければ,一つのIPアドレスに対して,一つのホスト名を割り当てると思います(例えば,192.168.1.51 に対して,mydomain.com のような感じで,これは A レコード)。また,多くのドメイン登録代行業者のサービスだと,ここで設定したホスト名の別名として "www.mydomain.com" という別名が設定されることが多いと思います。ここではホストの別名 (CNAME) として,"exp.mydomain.com" というものを追加登録しました。exp は "www.mydomain.com" や "mydomain.com" と同じ IP アドレス 192.168.50.1 を共有していますが,見かけ上は別々のホスト名になっています。

SSL 証明書の取得は,インストールした certbot のディレクトリに移動して,certbot-auto というコマンドを実行するだけです。

# cd /usr/local/certbot
# ./certbot-auto certonly

あとは,基本的に質問に答えて行けば OK です。certbot による SSL 証明書の取得の方法は,ググれば山のように出てくるので,適当に参照願います。

/etc/letsencrypt/live/domain.name 以下に証明書がインストールされます(使うのは fullchain.pem と privkey.pem の2つ)。domain.name は自分の取得したドメイン名になります。また,SSL 証明書は期限がありますので,期限を自動更新するための設定を cron(コマンドを定期実行するサービス)に登録します。自動更新の設定の仕方は,公式サイトを参考にして,

 /etc/cron.d に,certbot というファイルを作って実行することにしました。

# vim /etc/cron.d/certbot

中身は

# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/certbot/certbot-auto renew && systemctl restart nginx | sudo tee -a /etc/crontab > /dev/null

という感じです。これは毎日0時と12時に,(実際はそこから,ランダムに sleep time を挟んで),certbot-auto renew コマンドを実行します。ただし,このコマンドでは,必ずしも更新が行われるわけでは無く,更新を試みて,更新の必要がある場合のみ証明書を更新します。また,更新を行った後で nginx を再起動する必要があるので,それを systemctl restart nginx で実行しています。

certbot のインストールディレクトリに応じて,/usr/local/certbot のパスは書き換えてください。

Nginx の設定

最後に Web サーバの設定をします。ここが一番嵌まるポイントかもしれません。まず,ここで考えている JATOS を含めた Nginx の構成は

画像1

上のような感じです。まず,*.mydomain.com 宛てに来た http または https リクエストを,一旦 Nginx で受け取り,それが exp.mydomain.com 宛てならば TCP ソケットで待機している JATOS へ処理を渡し,www.mydomain.com,さらには mydomain.com 全般の場合はそのまま Nginx で処理をする(PHP の場合は,php-fpm へ渡す)ようにします。また,80番ポートの http で来たリクエストは,SSL 化された 443番ポートの https へとリダイレクトします。

Nginx の設定ファイルは,基本的には /etc/nginx/nginx.conf となります。ここに全てを書いても良いのですが,設定ファイルが長くなると色々とトラブルの元なので,設定をいくつかのファイルに分け,nginx.conf から随時呼び出す形にします。そのため,デフォルトのインストール状態の設定から,多少変更をしてあります。まず,/etc/nginx に,global, sites というディレクトリを作成し,それぞれサイトに共通の設定,サイト毎の設定ファイルを置くようにしました。

# mkdir /etc/nginx/global
# mkdir /etc/nginx/sites

また,デフォルトでは,上のディレクトリの他に /etc/nginx/conf.d というディレクトリの中のファイルも参照するようになっています(多分,php-fpm 関係の設定はここにあると思います)。

では,まずメインとなる /etc/nginx/nginx.conf ですが,こんな内容になっています。

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
   worker_connections 1024;
}

http {
   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;
   error_log   /var/log/nginx/error.log;

   sendfile            on;
   tcp_nopush          on;
   tcp_nodelay         on;
   keepalive_timeout   65;
   keepalive_requests  100;
   types_hash_max_size 2048;
   index               index.php index.html index.htm;

   include             /etc/nginx/mime.types;
   default_type        application/octet-stream;

   # fastcgi
   fastcgi_buffers             8 64k;
   fastcgi_buffer_size         64k;
   fastcgi_connect_timeout     60;
   fastcgi_send_timeout        60;
   fastcgi_read_timeout        60;

   # proxy
   proxy_buffering             off;
   proxy_connect_timeout       60;
   proxy_send_timeout          60;
   proxy_read_timeout          120;
   proxy_http_version          1.1;
   proxy_cache_bypass          $http_upgrade;
   proxy_set_header            Upgrade         $http_upgrade;
   proxy_set_header            Connection      $connection_upgrade;
   proxy_set_header            Host            $host;
   proxy_set_header            X-Real-IP       $remote_addr;
   proxy_set_header            X-Forwarded-Host        $host;
   proxy_set_header            X-Forwarded-Server      $host;
   proxy_set_header            X-Forwarded-For         $proxy_add_x_forwarded_for;
   proxy_set_header            X-Forwarded-Proto       $scheme;
   proxy_set_header            X-Forwarded-Port        $server_port;
   map $http_upgrade $connection_upgrade {
       default upgrade;
       '' close;
   }
   
   # Load modular configuration files from the /etc/nginx/conf.d directory.
   # See http://nginx.org/en/docs/ngx_core_module.html#include
   # for more information.
   include /etc/nginx/conf.d/*.conf;

   # Load site configuration
   include /etc/nginx/sites/*.conf;
}

デフォルトの設定から変更を加えている点で大きなものは,FastCGI と proxy 関連の設定を追加したことと,サイト別の設定ファイルを /etc/nginx/sites/ の下に,.conf という拡張子が付いているファイルとして作成し,それを読み込むようにしてある点です。また,デフォルトの設定では,server {} という設定がこの後続いていると思いますが,それは全て削除してあります(この server の設定を,sites/ 以下のファイルに分けています)。Proxy の設定を忘れると,うまく動かないので注意しましょう。

次に,/etc/nginx/conf.d に jatos.conf という名前で,以下の内容を作成します(公式サイトのドキュメントも参照してください)。

   upstream jatos-backend {
               server 127.0.0.1:9000;
   }

これは jatos-backend という名前で,(nginx と)同じホスト上に 9000 番ポートで待機している JATOS へ向けた proxy を定義しています。

もし,JATOS の待機しているポート番号を変更した場合は,それに合わせてポート番号を書き換えてください。

同じく,/etc/nginx/conf.d に php-fpm.conf というファイルがあると思いますが,そちらの内容を見ると,

# PHP-FPM FastCGI server
# network or unix domain socket configuration

upstream php-fpm {
       server unix:/run/php-fpm/www.sock;
}

と書かれていると思います。こっちは,php-fpm 宛ての proxy で,unix ドメインソケット (www.sock) で待機している php-fpm へ処理を向けるわけです。なお,ここで書かれている待機ポートの設定(unix ドメインソケットか,その場合のファイルのパスは,また tcp ソケットか)を確認し,その設定が,↑の php-fpm の設定ファイル (/etc/php-fpm.d/www.conf) の listen 項目で設定されている内容と同じになっているかどうかを確認してください(私は,ここの設定を間違っていて嵌まりました)。

次に,サイトにまたがって共通に使用する設定を,/etc/nginx/global 以下に作成します。とりあえず,common.conf という名前にしておきましょうかね。

# vim /etc/nginx/global/common.conf

このファイルの中身は,以下のような感じです。

location ~ /\. {
       deny    all;
       access_log      off;
       log_not_found   off;
}
location ~ /(favicon.ico|apple-touch-icon-*) {
       log_not_found   off;
       access_log      off;
}
location = /robots.txt {
       allow   all;
       log_not_found   off;
       access_log      off;
}

最初の location の設定は,.(ピリオド)で始まるファイル(大体,重要な設定ファイルで読まれると困る)は,接続を拒否(ログも一々残さない)という設定です。まあ,こんな感じで全てのサイトで共通しそうなアクセス制御なんかを書いていきます(他にも共通する設定があれば,ここに書き込んでも良いでしょう)。

では,次にサイト別のサーバ設定を書いていきましょう。まずは,メインとなる JATOS の方です。とりあえず,ここではこのファイルを /etc/nginx/sites/server-exp.conf という名前で作ります(nginx.conf からは,このディレクトリにある拡張子が .conf であるファイルを全て読み込むように設定してあるので,拡張子さえ気をつければ,名前は何でも構いません)。

# vim /etc/nginx/sites/server-exp.conf

このファイルの中身は,以下のような感じです。

server {
       listen 80;
       server_name  exp.mydomain.com;
       return 301      https://$host$request_uri; # */
}
server {
       listen 443 ssl; 
       server_name  exp.mydomain.com;
       root         /usr/share/nginx/jatos;
       access_log      /var/log/nginx/access-exp.log;
       error_log       /var/log/nginx/error-exp.log;

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

       include /etc/nginx/default.d/*.conf; # load from default.d */
       include /etc/nginx/global/common.conf;

       location ~ "^/(jatos/testWebSocket|publix/[\d]+/(group/join|batch/open))" {
               proxy_pass              http://jatos-backend;
               proxy_connect_timeout   7d;
               proxy_send_timeout      7d;
               proxy_read_timeout      7d;
       }
       location / {
               proxy_pass              http://jatos-backend;
       }
}  
note.com のコードブロックの仕様で,表示がおかしくなるので,default.d/*.conf から include している行に */ が入っています。この文字は無くて構いません。また,http:// の後がコメントアウトされた状態になっていますが,実際は↑の内容の通りに入力してください。nginx の設定ファイルのコメントは # 以下 の内容になります。

設定ファイル中の mydomain.com はご自分のドメインに読み替えてください。まず,最初の server{} ブロックは,http,つまり SSL なしの部分の設定です。こちらは,全てのリクエストを https にリダイレクトします。

次の server{} ブロックは SSL の場合の設定です。ここで大事なのは,# SSL 以下の2行の設定(Let's Encrypt で取得した SSL 証明書の指定)と,location{} ブロックの設定です。location{} は,アクセスしてきた URL の exp.mydomain.com 以下のパスによって処理を切り分けています。基本的には JATOS の公式サイトのドキュメントに従った形での設定ですが,ミソは proxy_pass の行ですね。ここで,アクセスしてきたリクエストを,全て↑の jatos.conf で設定した jatos-backend のソケットに丸投げしているという点です。この設定をすることで,JATOS サーバの方に処理を(Proxy 経由で)渡すことができます。また,途中で,include しているのは,全サイトに共通の設定(default.d/ 以下のファイルと,アクセス制限を書いた general/common.conf)を読み込んでいます。また,access / errro の両ログは,この後説明するデフォルトのサーバと分けるために,それぞれホスト名 exp を付けたファイルにしてあります (access-exp.log / error-exp.log)。

次に,exp.mydomain.com 以外のアクセス,つまり通常の(デフォルト) Web サーバの方の設定ファイルを作成します。こちらは,server-default.con という名前で作成しましょうか。

# vim /etc/nginx/sites/server-default.conf

このファイルの中身は,以下のようになります。

server {
       server_name     mydomain.com;
       listen 80;
       return  301     https://$host$request_uri;
}

server {
       server_name     mydomain.com;
       listen 443 ssl;
       root    /usr/share/nginx/html;

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

       include /etc/nginx/default.d/*.conf; # Load from default.d */
       include /etc/nginx/global/common.conf;
       
       location / {
               try_files       $uri $uri/ /index.php?$args;
       }
}

こちらの方は,JATOS 周りの設定がない分簡単です。ちなみに root は,Apache で言うところの DocumentRoot,つまり HTML や PHP ファイルを置いてあるディレクトリになります(CentOS で dnf 経由で Nginx をインストールした場合のデフォルトのディレクトリのままです)。また,location{} ブロックにある try_files というのは,まずリクエストのあったページ  ($uri) をテストし,それが無かった場合は,$uri がディレクトリであると仮定して ($uri/) そのディレクトリにアクセスを試み,それでも無かった場合は,デフォルトの処理として,root にある index.php にパラメータを付けて処理させるという命令を行うものです。WordPress のように php で処理されているページの場合に使う設定となっています。

さて,ここで PHP でアクセスしてきた場合の php-fpm に飛ばす設定がないことに気づいた人がいるかもしれません。実は,この処理は default.d/ にある設定ファイルで定義されています。Nginx のインストール時に,このディレクトリに php.conf というファイルが作成されています。それを,

include /etc/nginx/default.d/*.conf;

の部分で読み込んでいます。ちなみに,php.conf では,

# pass the PHP scripts to FastCGI server
#
# See conf.d/php-fpm.conf for socket configuration
#
index index.php index.html index.htm;

location ~ \.(php|phar)(/.*)?$ {
   fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;

   fastcgi_intercept_errors on;
   fastcgi_index  index.php;
   include        fastcgi_params;
   fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
   fastcgi_param  PATH_INFO $fastcgi_path_info;
   fastcgi_pass   php-fpm;
}

このような定義がされていて,拡張子が .php になっている場合(上では .phar である場合や .php/hoge .phar/hoge のように,php / phar をパスに含む場合も同じく),fastcgi の設定を使ってパスを処理し,最終的には fastcgi_pass php-fpm; の行の設定によって,php-fpm に処理を渡すようになっています。他にも,/etc/nginx/fastcgi_params といったファイルも読み込まれていますが,この辺はデフォルトのままで問題ないので,省略します。

これで,Nginx をプロキシとして JATOS にアクセスする設定が完了しました。あとは,https://exp.mydomain.com にアクセスして JATOS のコンソールが表示されることを確認してください(www.mydomain.com の場合は別途設定したサイトにアクセスできることも)。

なお,JATOS で実験をホストする場合,実験を組むのに一番楽なのは,lab.js だと思います(もちろん,お好みで OSWeb/OpenSesame, jsPsych でも問題ありません)。なお,lab.js で実験を行う場合,1行に1反応分のデータが保存されますが,一つだけ厄介なのは,参加者を識別する番号のようなものが全ての行に出力されないということです。この点ついては,とてもすばらしい解決法が,以下のサイトで解説されています。

解説記事の中の,Tips・Q&A を見てください。

これで,いつでもマルチユーザーの実験管理ができますね。JATOS を使った実際の実験の管理方法については,また記事を改めて解説したいと思います。


この記事が気に入ったらサポートをしてみませんか?