序章

Redisは、オープンソースのKey-Valueキャッシュおよびストレージシステムであり、ハッシュ、リスト、セット、ビットマップなどのいくつかのデータ型を高度にサポートしているため、データ構造サーバーとも呼ばれます。 また、クラスタリングをサポートしているため、可用性が高くスケーラブルな環境で役立ちます。

このチュートリアルでは、Ubuntu16.04で実行されているPHPアプリケーションのセッションハンドラーとして使用される外部Redisサーバーをインストールして構成する方法を説明します。

セッションハンドラーは、セッションに保存されたデータの保存と取得を担当します。 デフォルトでは、PHPはこれにファイルを使用します。 これは単一のサーバーでは十分に機能しますが、セッション情報が単一のサーバーに関連付けられているため、パフォーマンスとスケーラビリティに大きな制限があります。

外部セッションハンドラーは、複数のアプリケーションサーバーで使用できる共有セッションデータの中央の場所を提供します。 これは、ロードバランサーの背後にスケーラブルなPHP環境を作成する場合に重要です。これは、どのアプリケーションサーバーが個々のリクエストを処理するかに関係なく、同じセッションデータが利用できるためです。

前提条件

このチュートリアルでは、2台のサーバーを使用してセッション処理を構成します。 フォローするには、次のものが必要です。

  • Ubuntu16.04でLAMPまたはLEMPを実行しているPHPWebサーバー。 このサーバーをwebと呼びます。
  • 2番目のクリーンなUbuntu16.04サーバー。Redisがインストールされます。 このサーバーをredisと呼びます。

これらの各サーバーでsudo権限が設定されたroot以外のユーザーが必要です。 また、各サーバーで基本的なファイアウォールが実行されていると想定します。 両方のサーバーでUbuntu16.04初期サーバーセットアップガイドに従って、これらの要件の両方をセットアップできます。

ステップ1:Redisサーバーとクライアントソフトウェアをインストールする

最初のステップは、両方のマシンに必要なソフトウェアをインストールすることです。 redisマシンにはRedisサーバーが必要です。 web マシンに、セッション処理用のRedis PHP拡張機能と、テスト用のRedisコマンドラインクライアントをインストールします。

Redisサーバーのインストール

最初に行う必要があるのは、redisマシンでRedisサーバーを実行することです。

ChrisLeaが提供する信頼できるPPAリポジトリを備えた通常のUbuntuパッケージマネージャーを使用します。 これは、Redisの最新の安定バージョンを確実に入手するために必要です。

注:一般的なセキュリティアドバイスとして、信頼できるソースからのPPAのみを使用する必要があります。

まず、以下を実行してPPAリポジトリを追加します。

  1. sudo apt-add-repository ppa:chris-lea/redis-server

ENTERを押して確認します。

次に、パッケージインデックスを更新し、次のように入力してRedisサーバーをインストールします。

  1. sudo apt-get update
  2. sudo apt-get install redis-server

これで、Redisがサーバーにインストールされて実行されているはずです。 次のように入力して、サービスが実行され、接続を受け入れていることをテストします。

  1. redis-cli ping
Redis server output
PONG

これにより、ポート6379localhostで実行されているRedisインスタンスに接続されます。 応答としてPONGを取得する必要があります。

RedisクライアントとPHP拡張機能のインストール

次に、RedisコマンドラインクライアントとRedisPHP拡張機能をwebサーバーにインストールします。 コマンドラインクライアントを使用して、接続と認証を簡単にテストします。 PHP拡張機能を使用して、セッションデータを保存します。

ローカルパッケージインデックスを更新し、次のように入力してwebサーバーにソフトウェアをインストールします。

  1. sudo apt-get update
  2. sudo apt-get install redis-tools php-redis

これで、redis-cliツールにアクセスできるようになりますが、テストするサーバーにはまだアクセスできません。

ステップ2:外部接続を受け入れるようにRedisを構成する

デフォルトでは、Redisはlocalhostからの接続のみを許可します。つまり、基本的には、Redisがインストールされているサーバー内からのみアクセスできます。 他のサーバーからの接続を許可するには、この構成を変更する必要があります。

Redisはネイティブ暗号化オプションを提供せず、信頼できるピアの分離されたネットワークにデプロイされていることを前提としています。 つまり、外部接続を安全に許可するには、両方のサーバーが分離されたネットワーク上にあるか、別の方法でサーバー間のトラフィックを保護する必要があります。

Redisが分離されたネットワークにデプロイされている場合…

サーバーが分離されたネットワークで動作している場合は、おそらく、分離されたネットワークのIPアドレスにバインドするようにRedisの構成ファイルを調整するだけで済みます。

redis サーバーで、Redis構成ファイルをバックアップして開きます。

  1. sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
  2. sudo nano /etc/redis/redis.conf

bind行を見つけて、Redisサーバーの分離されたネットワークIPアドレスを追加します。

/etc/redis/redis.conf
bind 127.0.0.1 isolated_IP_address

ファイルを保存して閉じます。 次のように入力して、サービスを再起動します。

  1. sudo systemctl restart redis-server.service

Redisポートへのアクセスを開きます。

  1. sudo ufw allow 6379

これで、Redisは分離されたネットワークからの接続を受け入れることができます。

Redisが分離されたネットワークにデプロイされていない場合…

分離されていない、または制御していないネットワークの場合、トラフィックを他の手段で保護することが不可欠です。 Redisサーバーへのトラフィックを保護するには、次のような多くのオプションがあります。

  • stunnel を使用したトンネリング: redis サーバーに着信トンネルを設定し、webサーバーに発信トンネルを設定する必要があります。 Webサーバーはローカルポートに接続して、リモートのRedisサービスと通信します。
  • spiped を使用したトンネリング:webサーバーはspipedクライアントマシンとして機能する必要があります。 各サーバーにsystemdユニットファイルを作成する必要があります。 Webサーバーはローカルポートに接続して、リモートのRedisサービスと通信します。
  • PeerVPNを使用したVPNのセットアップ:VPN上で両方のサーバーにアクセスできる必要があります。 web サーバーは、VPNIPアドレスを使用してredisサーバーにアクセスできるようになります。

上記のいずれかの方法を使用して、webサーバーからredisサーバーへの安全なアクセスを構成します。 webマシンがリモートマシンのRedisサービスに接続するために使用するIPアドレスとポートを知っている必要があります。

この時点で、WebサーバーからRedisサーバーに安全にアクセスできるはずです。

ステップ3:Redisサーバーのパスワードを設定する

Redisインストールにセキュリティの層を追加するには、サーバーデータにアクセスするためのパスワードを設定することをお勧めします。 /etc/redis/redis.confでRedis構成ファイルを編集します。

  1. sudo nano /etc/redis/redis.conf

requirepassディレクティブを見つけて、強力なパスフレーズに設定します。 Redisトラフィックは外部から保護されている必要がありますが、これによりRedis自体に認証が提供されます。 Redisは高速で、パスワードの試行をレート制限しないため、ブルートフォース攻撃から保護するために強力で複雑なパスフレーズを選択してください。

/etc/redis/redis.conf
requirepass yourverycomplexpasswordhere

終了したら、ファイルを保存して閉じます。

Redisサービスを再起動して、変更を実装します。

  1. sudo systemctl restart redis-server.service

これで、Redisサーバーは認証されていないリクエストを拒否するはずです。

ステップ4:Redisの接続と認証をテストする

変更が期待どおりに機能するかどうかをテストするには、webマシンからRedisサービスに接続します。

デフォルトでは、Redisサーバーはローカルインターフェイスで6379をリッスンしますが、上記で説明した各ネットワークセキュリティオプションは、外部の関係者に対して何らかの方法でデフォルトを変更します。 redis-cliクライアントと-hオプションを使用してIPアドレスを指定し、-pオプションを使用してリモートサービスへの接続に必要なポートを指定できます。 デフォルトのオプション(それぞれ127.0.0.1と6379)を使用している場合は、これらのいずれかを省略できます。

使用する値は、ネットワークトラフィックを保護するために使用した方法によって異なります。

  • 分離ネットワーク:Redisサーバーの分離ネットワークIPアドレスを使用します。 デフォルトのRedisポート(6379)が使用されているため、言及する必要はありません:redis-cli -h redis_isolated_IP
  • stunnelまたはspiped:リモートRedisサービスにトンネリングするローカルポートを使用します:redis-cli -p 8000
  • PeerVPN :RedisサーバーのVPN IPアドレスを使用します:redis-cli -h 10.8.0.1

一般的な形式は次のとおりです。

  1. redis-cli -h ip_to_contact_redis -p port_to_contact_redis

webサーバーからリモートRedisインスタンスに接続できるはずです。

パスワードを定義してデータにアクセスしようとすると、AUTHエラーが発生するはずです。

  1. keys *
Web server output
(error) NOAUTH Authentication required.

認証するには、AUTHコマンドを実行し、/etc/redis/redis.confファイルで定義したものと同じパスワードを入力する必要があります。

  1. AUTH yourverycomplexpasswordhere

クレデンシャルが受け入れられたことを示す応答としてOKが表示されます。

Web server output
OK

次に、Redis内で設定されているキーを一覧表示します。

  1. keys *

これが新しいRedisサーバーの場合、出力は次のようになります。

Web server output
(empty list or set)

この出力は、Redisサーバーが空であることを意味します。これはまさに私たちが期待していることです。 web サーバーは、このRedisサーバーをセッションハンドラーとして使用するようにまだ構成されていません。

次のように入力して、コマンドシェルに戻ります。

  1. exit

認証で正常に接続できることを確認したので、Redisをデフォルトのセッションハンドラーにすることができます。

手順5:RedisをWebサーバーのデフォルトのセッションハンドラーとして設定する

次に、 webサーバー上のphp.iniファイルを編集して、PHPのデフォルトのセッションハンドラーを変更する必要があります。 このファイルの場所は、現在のスタックによって異なります。

デフォルトのリポジトリからインストールされたUbuntu16.04のLAMPスタックの場合、これは通常/etc/php/7.0/apache2/php.iniです。 Ubuntu16.04のLEMPスタックの場合、パスは通常/etc/php/7.0/fpm/php.iniです。 これらの場所のいずれかが正しいことを確認した場合は、次のセクションをスキップしてください。

(オプション)正しいphp.iniファイルを見つける

メインのphp.iniファイルの場所がわからない場合は、phpinfo()機能を使用して確認できます。 webサーバーでドキュメントルートのinfo.phpというファイルを開きます。デフォルトでは、LAMPとLEMPの両方で/var/www/htmlになります。

  1. sudo nano /var/www/html/info.php

次のコードをファイルに配置します。

/var/www/html/info.php
<?php
phpinfo();

ブラウザでwebサーバーのドメイン名またはIPアドレスにアクセスし、続いて/info.phpにアクセスします。

http://web_server_domain_or_IP/info.php

「ロードされた構成ファイル」を含む行を探します。ロードされたメインのphp.iniの正確な場所を見つける必要があります。

終了したら、環境に関する機密情報が表示されるため、ファイルを削除します。

  1. sudo rm /var/www/html/info.php

ファイルの場所がわかったので、編集に進むことができます。

構成の変更

php.iniファイルを開いて編集します。

デフォルト構成でLAMPスタックを使用している場合、必要なコマンドは次のとおりです。

  1. sudo nano /etc/php/7.0/apache2/php.ini

デフォルト構成でLEMPスタックを使用している場合、必要なコマンドは次のとおりです。

  1. sudo nano /etc/php/7.0/fpm/php.ini

上記のphpinfo()メソッドを使用して別のパスを発見した場合は、代わりにそのパスをここに置き換えてください。

php.iniファイル内で、session.save_handlerを含む行を検索します。 デフォルト値はfilesです。 これをredisに変更して、RedisPHP拡張機能を使用します。

[label php.ini] 
session.save_handler = redis

次に、session.save_pathを含む行を見つけます。 コメントを外して値を変更し、Redis接続文字列が含まれるようにする必要があります。

接続文字列は、次の形式を使用して、すべて1行で作成できます。

tcp://IP_address:port?auth=redis_password

繰り返しますが、適切な値は、選択した安全なネットワーク戦略によって異なります。 前にredis-cliコマンドに指定したのと同じ値を使用します。 たとえば、stunnelまたはspipedを使用している場合、session.save_pathは次のようになります。

[label php.ini] 
session.save_path = "tcp://127.0.0.1:8000?auth=yourverycomplexpasswordhere"

終了したら、ファイルを保存して閉じます。 次に、PHPサービスを再起動して、変更を実装します。

LAMP 環境では、次のように入力します。

  1. sudo systemctl restart apache2

LEMP 環境では、次のように入力します。

  1. sudo systemctl restart php7.0-fpm

これで、セッションハンドラーとしてRedisを使用するようにPHPを構成する必要があります。

ステップ6:Redisセッション処理をテストする

セッションがRedisによって処理されるようにするには、セッションに情報を格納するPHPスクリプトまたはアプリケーションが必要になります。 カウンターを実装する簡単なスクリプトを使用します。 ページをリロードするたびに、印刷された番号が増加します。

ドキュメントルートフォルダ内のwebサーバーにtest.phpという名前のファイルを作成します。

  1. sudo nano /var/www/html/test.php

内部に、次のコードを貼り付けます。

[label /var/www/html/test.php] 
<?php
//simple counter to test sessions. should increment on each page reload.
session_start();
$count = isset($_SESSION['count']) ? $_SESSION['count'] : 1;

echo $count;

$_SESSION['count'] = ++$count;

ファイルを保存して閉じます。

スクリプトにアクセスするには、ブラウザでwebサーバーのパブリックIPアドレスに続けて/test.phpを指定します。

http://web_server_public_IP/test.php

ページをリロードするたびに表示される数が増えるはずです。

次に、 redis マシンで、redis-cliを使用してセッションを開きます。 ローカルインスタンスに接続しているため、IPアドレスやポートを指定する必要はありません。

  1. redis-cli

Redisパスワードを使用して認証します。

  1. AUTH yourverycomplexpasswordhere
Redis server output
OK

次に、既存のキーを確認します。

  1. keys *

PHPセッションの新しいエントリが表示されます。

Redis server output
1) "PHPREDIS_SESSION:2ofnvhhr6gdvp88u0c4e7kb800"

キーの値を尋ねると、現在のカウンター値を確認できるはずです。

  1. get PHPREDIS_SESSION:2ofnvhhr6gdvp88u0c4e7kb800
Redis server output
"count|i:6;"

これは、セッション情報がRedisサーバーに保存されていることを示しています。 追加のWebサーバーをRedisサーバーに接続して、セッションを一元管理できます。

結論

Redisは、PHPのセッションハンドラーとしても使用できる強力で高速なKey-Valueストレージサービスであり、セッションストレージ用の分散システムを提供することでスケーラブルなPHP環境を実現します。 PHPアプリケーションのスケーリングの詳細については、次の記事を確認してください:PHPアプリケーションの水平方向のスケーリング