SSHトンネルを使用した3層Railsアプリケーションでの通信の保護

前書き

Webアプリケーションは、多くの場合、3つの異なる層で設計されています。

  • 最初の層はpresentation layerで、これはユーザーに表示されます。

  • 次はapplication layerで、これはアプリケーションのbusiness logicを提供します。

  • 最後に、data layerは、アプリケーションに必要なデータを格納します。

Ruby on Railsアプリケーションでは、これはプレゼンテーション層のWebサーバー、アプリケーション層のRailsサーバー、およびデータ層のデータベースに大まかにマップされます。 この設定では、アプリケーション層はデータ層と通信してアプリケーションのデータを取得し、プレゼンテーション層を介してユーザーに表示します。

これらすべてのアプリケーションを単一のサーバーにインストールすることは可能ですが、各レイヤーを独自のサーバーに配置すると、アプリケーションのスケーリングが容易になります。 たとえば、Railsサーバーがボトルネックになる場合、他の2つのレイヤーに影響を与えずにアプリケーションサーバーを追加できます。

このチュートリアルでは、3つの個別のサーバーに一意のソフトウェアセットをインストールし、各サーバーとそのコンポーネントを一緒に通信および機能するように設定し、SSHトンネルでそれらの間の接続を保護することにより、3層構成でRailsアプリをデプロイします。 ソフトウェアスタックの場合、プレゼンテーション層のWebサーバーとしてNginx、アプリケーション層のRailsアプリケーションサーバーとしてPuma、データ層のデータベースとしてPostgreSQLを使用します。 。

前提条件

このチュートリアルを完了するには、3つのUbuntu 16.04サーバーを起動する必要があります。 これらにweb-serverapp-server、およびdatabase-serverという名前を付け、それぞれでプライベートネットワークを有効にする必要があります。

3つのサーバーのそれぞれには、sudo特権を持つroot以外のユーザーと、SSH接続を許可するように構成されたファイアウォール(Initial Server Setup guideを使用して構成できます)が必要です。 このチュートリアルのコンテキストでは、各サーバーのsudoユーザーの名前はsammyです。

さらに、3つのサーバーにはそれぞれ固有の構成要件があります。

  • web-serverについて:

    • Nginx Webサーバーをインストールして構成します。 これを行うには、How to Install Nginx on Ubuntu 16.04に関するチュートリアルに従ってください。

  • app-serverについて:

    • How To Install Node.js on Ubuntu 16.04で説明されているように、公式PPAを使用してNode.jsをインストールします。 Asset PipelineなどのいくつかのRails機能はJavaScriptランタイムに依存しており、Node.jsはこの機能を提供します。

    • Ruby on Railsフレームワークをインストールします。 これを行うには、How to Install Ruby on Rails with rbenv on Ubuntu 16.04に関するガイドに従ってください。 このチュートリアルを進める際には、Rubyの最新バージョンをインストールしてください。これは、この記事の執筆時点ではRuby 2.5.1です。

    • チュートリアルHow To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 14.04の最初のセクションに示されているように、PostgreSQLをインストールします。 このセクションでは、この3層セットアップに必要な別のパッケージであるlibpq-devをインストールする方法についても説明します。

    • Pumaを使用してRailsアプリをデプロイします。 デプロイする独自のアプリがない場合は、How To Deploy a Rails App with Puma and Nginxに関するガイドに従ってサンプルアプリをデプロイしてください。 この前提条件の「インストールrbenv-varsプラグイン」セクションでは、database-serverにPostgreSQLをインストールするときに使用する値を反映するようにデータベースのユーザーとパスワードを設定する必要があることに注意してください。 また、「本番データベースの作成」セクションが機能するには、ファイアウォールを通過するポート3000を許可する必要があります。 最後に、この前提条件チュートリアルの最後の2つの手順「Puma Upstartスクリプトの作成」と「Nginxのインストールと構成」を完了する必要はありません。

  • database-serverについて:

    • PostgreSQLデータベースソフトウェアをインストールして構成します。 これを行う方法については、How To Install and Use PostgreSQL on Ubuntu 16.04に関するガイドに従ってください。 この前提条件のチュートリアルに従うときに、superuser権限を持つRailsアプリのPostgreSQLロールと、PostgreSQLロールと同じ名前のデータベースを作成します。 このチュートリアル全体を通して、PostgreSQLの役割とデータベースは両方ともsammyと呼ばれます。

    • 新しく作成されたPostgreSQLロールのパスワードを設定します。 「https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04#create」の最初のコマンドをスキップします-production-database-user [Create Production Database User]」セクション(これはapp-serverの設定にも使用しました)で、そのセクションの残りのコマンドに従ってデータベースユーザーのパスワードを変更します。 。 PostgreSQLの役割の名前とdatabase-serverに設定するパスワードは、app-serverのPostgreSQLインストールで設定したものと同じである必要があることに注意してください。

[[step-1 -—- creating-a-user-for-the-ssh-tunnels]] ==ステップ1—SSHトンネルのユーザーの作成

SSH tunnelsは暗号化された接続であり、あるサーバーのポートから別のサーバーのポートにデータを送信できるため、2番目のサーバーのリスニングプログラムが最初のサーバーで実行されているように見えます。 SSHトンネル専用のユーザーがいると、セットアップのセキュリティが向上します。侵入者がサーバーの1つでsammyユーザーにアクセスした場合、侵入者は3つのサーバーの他のサーバーにアクセスできなくなります。層のセットアップ。 同様に、侵入者がtunnelユーザーにアクセスした場合、侵入者はRailsアプリディレクトリ内のファイルを編集することも、sudoコマンドを使用することもできません。

各サーバーで、tunnelという名前の追加ユーザーを作成します。 tunnelユーザーの唯一の機能は、サーバー間の通信を容易にするSSHトンネルを作成することです。したがって、sammyとは異なり、tunnelsudo特権を付与しないでください。 また、tunnelユーザーは、Railsアプリディレクトリへの書き込みアクセス権を持ってはなりません。 各サーバーで次のコマンドを実行して、tunnelユーザーを追加します。

sudo adduser tunnel

web-serverマシンで、tunnelユーザーに切り替えます。

sudo su tunnel

tunnelユーザーとして、SSHキーペアを生成します。

ssh-keygen

デフォルトの場所にキーを保存し、キーのパスフレーズを作成しないでください。パスフレーズを作成すると、後でサーバー間にSSHトンネルを作成するときに認証が複雑になる可能性があります。

キーペアを作成したら、sammyユーザーに戻ります。

exit

ここで、app-serverに切り替えて、同じコマンドを再度実行します。

sudo su tunnel
ssh-keygen
exit

これで、残りのチュートリアルに必要なすべてのユーザーを構成できました。 ネットでは、SSHトンネルの作成プロセスを合理化するために、各tunnelユーザーの/etc/hostsファイルにいくつかの変更を加えます。

[[step-2 -—- configuring-the-hosts-file]] ==ステップ2—Hostsファイルの構成

このチュートリアル全体を通して、コマンドでapp-serverまたはdatabase-serverのいずれかのIPアドレスを参照する必要がある場合がよくあります。 毎回これらのIPアドレスを覚えて入力する必要はなく、app-serverdatabase-serverのプライベートIPを各サーバーの/etc/hostsファイルに追加できます。 これにより、アドレスの代わりに後続のコマンドで名前を使用できるようになり、SSHトンネルのセットアッププロセスがはるかにスムーズになります。

簡単にするために、このチュートリアルでは、3つのサーバーのそれぞれの/etc/hostsファイルにapp-serverdatabase-serverの両方のプライベートIPアドレスを追加するように指示していることに注意してください。 技術的には、app-serverまたはdatabase-serverのプライベートIPアドレスを独自のhostsファイルに追加する必要はありませんが、追加しても問題は発生しません。 ここで説明する方法は、単に速度と利便性のために選択されたものです。

まず、app-serverdatabase-serverのプライベートIPアドレスを見つけます。 DigitalOcean Dropletsを使用している場合は、コントロールパネルに移動して、これらのドロップレットの名前をクリックします。 ドロップレット固有のページでは、ページの上部近くにパブリックIPアドレスとプライベートIPアドレスの両方が表示されます。

次に、各サーバーで、お気に入りのテキストエディターで/etc/hostsファイルを開き、次の行を追加します。

sudo nano /etc/hosts

/etc/hosts

. . .
app-server_private_ip app-server
database-server_private_ip database-server

これらの行を各サーバーのこのファイルに追加することで、通常これらのサーバーのIPアドレスを使用する必要があるコマンドでapp-serverおよびdatabase-serverという名前を使用できます。 この機能を使用してSSHキーを設定し、各tunnelユーザーが他のサーバーに接続できるようにします。

[[step-3 -—- setting-up-ssh-logins]] ==ステップ3—SSHログインの設定

3つのサーバーすべてにtunnelユーザーと更新された/etc/hostsファイルができたので、サーバー間のSSH接続の作成を開始する準備が整いました。

この手順を実行するときは、ピラミッドのような3つの層について考えてください。下部にdatabase-serverがあり、中央にapp-serverがあり、上部にweb-serverがあります。 Railsアプリに必要なデータにアクセスするには、app-serverdatabase-serverに接続できる必要があり、web-serverapp-serverに接続できる必要があります。ユーザーに提示するものがあります。

したがって、各tunnelユーザーのSSH公開鍵をその「下」のサーバーに追加するだけで済みます。つまり、web-servertunnelユーザーの公開鍵をapp-serverに追加する必要があります。 sを実行し、app-servertunnelユーザーの公開鍵をdatabase-serverに追加します。 これにより、階層間に暗号化されたSSHトンネルを確立し、ネットワーク上の盗聴者がそれらの間を通過するトラフィックを読み取れないようにすることができます。

このプロセスを開始するには、/home/tunnel/.ssh/id_rsa.pubにあるweb-servertunnelユーザーの公開鍵をapp-server/home/tunnel/.ssh/authorized_keysファイルにコピーします。

web-serverで、次のコマンドを使用して、ターミナルにtunnelユーザーの公開鍵を表示します。

sudo cat /home/tunnel/.ssh/id_rsa.pub

テキスト出力を選択し、システムのクリップボードにコピーします。

別のターミナルセッションでapp-serverにSSHで接続し、トンネルユーザーに切り替えます。

sudo su tunnel

システムのクリップボードのキーをapp-serverauthorized_keysファイルに追加します。 次のコマンドを使用して、1ステップでこれを行うことができます。 システムのクリップボードで、tunnel_ssh_publickey_copied_from_web_serverを公開鍵に置き換えることを忘れないでください。

echo "tunnel_ssh_publickey_copied_from_web-server" >> /home/tunnel/.ssh/authorized_keys

その後、authorized_keysファイルのアクセス許可を変更して、不正アクセスを防止します。

chmod 600 /home/tunnel/.ssh/authorized_keys

次に、sammyユーザーに戻ります。

exit

次に、/home/tunnel/.ssh/id_rsa.pubにあるapp-servertunnelユーザーの公開鍵を表示し、database-server/home/tunnel/.ssh/authorized_keysファイルに貼り付けます。

sudo cat /home/tunnel/.ssh/id_rsa.pub
sudo su tunnel

database-serverでSSHキーペアを生成しなかったため、/home/tunnel/.sshフォルダーを作成し、そのアクセス許可を調整する必要があります。

mkdir /home/tunnel/.ssh
chmod 700 /home/tunnel/.ssh

次に、app-serverの公開鍵をauthorized_keysファイルに追加し、そのアクセス許可を調整します。

echo "tunnel_ssh_publickey_copied_from_app-server" >> /home/tunnel/.ssh/authorized_keys
chmod 600 /home/tunnel/.ssh/authorized_keys

次に、sammyユーザーに戻ります。

exit

次に、SSHを使用して最初の接続をテストし、web-serverからtunnelユーザーとしてapp-serverに接続します。

sudo su tunnel

web-serverからapp-serverに初めて接続すると、接続先のマシンが信頼できることを確認するように求めるメッセージが表示されます。 「yes」と入力して、app-serverの信頼性を受け入れます。

OutputThe authenticity of host '111.111.11.111 (111.111.11.111)' can't be established.
ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
Are you sure you want to continue connecting (yes/no)? yes

app-serverからウェルカムバナーが表示され、コマンドプロンプトにapp-serverにログインしていることが示されます。 これにより、web-serverからapp-serverへのSSH接続が正しく機能していることが確認されます。

app-serverへのSSH接続を終了してから、tunnelユーザーを終了して、web-serversammyユーザーに戻ります。

exit
exit

次に、次の同じ手順に従って、app-serverからdatabase-serverへのSSH接続をテストします。

sudo su tunnel

database-serverの信頼性も受け入れます。 database-serverからウェルカムバナーとコマンドプロンプトが表示されると、app-serverからdatabase-serverへのSSH接続が期待どおりに機能していることがわかります。

database-serverへのSSH接続を終了してから、tunnelユーザーを終了します。

exit
exit

このステップで設定したSSH接続は、3つのサーバー層の間で安全な通信を可能にするSSHトンネルの基礎を形成します。 ただし、現在の形式では、これらの接続はクラッシュに対して脆弱であるため、信頼性はそれほど高くありません。 ただし、追加のソフトウェアをいくつかインストールし、トンネルをサービスとして機能するように構成することにより、これらの脆弱性を軽減できます。

[[step-4 -—- setting-up-a-persistent-ssh-tunnel-to-the-database-server]] ==ステップ4—データベースサーバーへの永続的なSSHトンネルの設定

最後の手順では、ローカルサーバーからリモートサーバーのコマンドプロンプトにアクセスしました。 SSHトンネルを使用すると、ローカルホストのポートからリモートホストのポートにトラフィックをトンネリングすることにより、これ以上のことができます。 ここでは、SSHトンネルを使用して、app-serverdatabase-serverの間の接続を暗号化します。

このチュートリアルのすべての前提条件を順守すると、app-serverdatabase-serverの両方にPostgreSQLがインストールされます。 ポート番号の衝突を防ぐには、これらのサーバー間のSSHトンネルを構成して、app-serverのポート5433からdatabase-serverのポート5432に接続を転送する必要があります。 後で、database-serverで実行されているPostgreSQLのインスタンスを使用するように、Railsアプリケーション(app-serverでホストされている)を再構成します。

app-serversammyユーザーとして開始し、ステップ1で作成したtunnelユーザーに切り替えます。

sudo su tunnel

次のフラグとオプションを指定してsshコマンドを実行し、app-serverdatabase-serverの間にトンネルを作成します。

ssh -f -N -L 5433:localhost:5432 [email protected]
  • -fオプションは、sshをバックグラウンドに送信します。 これにより、トンネルがバックグラウンドプロセスとして実行を継続している間に、既存のプロンプトで新しいコマンドを実行できます。

  • -Nオプションは、sshにリモートコマンドを実行しないように指示します。 ポートのみを転送するため、ここで使用されます。

  • -Lオプションの後に、構成値5433:localhost:5432が続きます。 これは、ローカル側のポート5433app-server)からのトラフィックがリモートサーバーのlocalhostのポート5432database-server)に転送されることを指定します。 ここでのlocalhostは、リモートサーバーの観点からのものであることに注意してください。

  • コマンドの最後の部分である[email protected]は、接続するユーザーとリモートサーバーを指定します。

SSHトンネルを確立した後、sammyユーザーに戻ります。

exit

この時点で、トンネルは実行されていますが、トンネルが立ち上がっていることを確認するためにトンネルを監視するものはありません。 プロセスがクラッシュすると、トンネルがダウンし、Railsアプリはデータベースと通信できなくなり、エラーが表示されるようになります。

より信頼性の高いセットアップを行うため、今作成したトンネルを削除します。 接続はバックグラウンドにあるため、接続を強制終了するにはプロセスIDを見つける必要があります。 すべてのトンネルはtunnelユーザーによって作成されるため、現在のプロセスを一覧表示し、キーワード「tunnel」の出力をフィルタリングすることで、そのプロセスIDを見つけることができます。

ps axu | grep tunnel

これにより、以下の出力のようなものが返されます。

Outputtunnel   21814  0.0  0.1  44920   692 ?        Ss   14:12   0:00 ssh -f -N -L 5433:localhost:5432 [email protected]
sammy    21816  0.0  0.2  12916  1092 pts/0    S+   14:12   0:00 grep --color=auto tunnel

killコマンドに続けてプロセスIDを実行して、プロセスを停止します。

sudo kill 21814

アプリケーションサーバーとデータベース間の永続的なSSH接続を維持するには、autosshをインストールします。 autosshは、SSH接続を開始および監視し、接続が停止するかトラフィックの通過を停止した場合に再起動するプログラムです。

sudo apt-get install autossh

systemd is the default init system on Ubuntuは、システムの起動後にプロセスを管理することを意味します。 systemdを使用して、サーバーの再起動時にSSHトンネルを管理して自動的に開始するサービスを作成できます。 これを行うには、systemdユニットファイルが保存される標準の場所である/lib/systemd/system/ディレクトリ内にdb-tunnel.serviceというファイルを作成します。

sudo nano /lib/systemd/system/db-tunnel.service

次のコンテンツを新しいファイルに追加して、systemdが管理するサービスを構成します。

/lib/systemd/system/db-tunnel.service

[Unit]
Wants=network-online.target
After=network-online.target

[Service]
User=tunnel
WorkingDirectory=/home/tunnel
ExecStart=/bin/bash -lc 'autossh -N -L 5433:localhost:5432 [email protected]'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process

[Install]
WantedBy=multi-user.target

ここでの重要な行はExecStartです。 これは、コマンドへのフルパスと、プロセスを開始するために実行する必要がある引数を指定します。 ここでは、新しいbashシェルを開始してから、autosshプログラムを実行します。

ファイルを保存して閉じてから、systemd構成を再ロードして、新しいサービスファイルが確実に取得されるようにします。

sudo systemctl daemon-reload

db-tunnelサービスを有効にして、サーバーが起動するたびにdatabase-serverへのトンネルが自動的に開始されるようにします。

sudo systemctl enable db-tunnel.service

次に、サービスを開始します。

sudo systemctl start db-tunnel.service

次のコマンドを再度実行して、トンネルが起動しているかどうかを確認します。

ps axu | grep tunnel

出力では、autosshがトンネルを監視しているため、今回はさらに多くのプロセスが実行されていることがわかります。

Outputtunnel   25925  0.0  0.1   4376   704 ?        Ss   14:45   0:00 /usr/lib/autossh/autossh -N -L 5432:localhost:5432 [email protected]
tunnel   25939  0.2  1.0  44920  5332 ?        S    14:45   0:00 /usr/bin/ssh -L 61371:127.0.0.1:61371 -R 61371:127.0.0.1:61372 -N -L 5432:localhost:5432 [email protected]
sammy    25941  0.0  0.2  12916  1020 pts/0    S+   14:45   0:00 grep --color=auto tunnel

トンネルが稼働しているので、psqlを使用してdatabase-serverへの接続をテストし、正しく機能していることを確認できます。

psqlクライアントを起動し、localhostに接続するように指示します。 また、SSHトンネルを介してdatabase-server上のPostgreSQLインスタンスに接続するには、ポート5433を指定する必要があります。 前に作成したデータベース名を指定し、プロンプトが表示されたらデータベースユーザー用に作成したパスワードを入力します。

psql -hlocalhost -p5433 sammy

次の出力のようなものが表示される場合、データベース接続は正しくセットアップされています。

Outputpsql (9.5.10)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

sammy=#

PostgreSQLプロンプトを閉じるには、\qと入力し、ENTERを押します。

最後に、app-serverdatabase-serverの間のトラフィックを暗号化する永続的で信頼性の高いSSHトンネルができました。 app-serverのRailsアプリがdatabase-serverのPostgreSQLインスタンスと通信するのはこのトンネルを経由するため、トンネルのセキュリティ機能が重要です。

[[step-5 -—- configuring-rails-to-use-a-remote-database]] ==ステップ5—リモートデータベースを使用するためのRailsの構成

app-serverからdatabase-serverへのトンネルが設定されたので、Railsアプリがトンネルを介してdatabase-server上のPostgreSQLインスタンスに接続するための安全なチャネルとして使用できます。 。

アプリケーションのデータベース構成ファイルを開きます。

nano /home/sammy/appname/config/database.yml

ポート番号が環境変数として指定されるように、productionセクションを更新します。 それは今このように見えるはずです:

/home/sammy/appname/config/database.yml

. . .
production:
  <<: *default
  host: localhost
  adapter: postgresql
  encoding: utf8
  database: appname_production
  pool: 5
  username: <%= ENV['APPNAME_DATABASE_USER'] %>
  password: <%= ENV['APPNAME_DATABASE_PASSWORD'] %>
  port: <%= ENV['APPNAME_DATABASE_PORT'] %>

このファイルを保存して閉じてから、アプリケーションディレクトリの.rbenv-varsファイルを開き、環境変数を編集します。

nano /home/sammy/appname/.rbenv-vars

database-serverのPostgreSQLロールに別の名前とパスワードを設定した場合は、ここでそれらを置き換えます(以下の例では、PostgreSQLロールの名前はsammyです)。 また、データベースのポートを指定する新しい行を追加します。 これらの変更を行うと、.rbenv-varsファイルは次のようになります。

/home/sammy/appname/.rbenv-vars

SECRET_KEY_BASE=secret_key_base
APPNAME_DATABASE_USER=sammy
APPNAME_DATABASE_PASSWORD=database_password
APPNAME_DATABASE_PORT=5433

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

Railsアプリをデプロイしたapp-serverではなくdatabase-serverでPostgreSQLインスタンスを使用しているため、データベースを再度セットアップする必要があります。

app-serverで、アプリのディレクトリに移動し、rakeコマンドを実行してデータベースを設定します。

[.note]#Note:このコマンドは、すべてのデータを既存のデータベースから新しいデータベースにnot移行します。 データベースに重要なデータがすでにある場合は、それをバックアップしてから後で復元する必要があります。

cd /home/sammy/appname
rake db:setup

このコマンドが完了すると、Railsアプリは暗号化されたSSHトンネルを介してdatabase-server上のPostgreSQLインスタンスとの通信を開始します。 次に行うことは、管理を容易にするためにPumaをsystemdサービスとして構成することです。

[[step-6 -—- configuring-and-starting-puma]] ==ステップ6—Pumaの構成と開始

手順4でdb-tunnelサービスを設定する方法と同様に、Puma(前提条件の一部としてapp-serverにインストールしたサーバーソフトウェア)をサービスとして実行するようにsystemdを構成します。 。 Pumaをサービスとして実行すると、サーバーの起動時に自動的に起動したり、クラッシュした場合に自動的に再起動したりできるため、展開の堅牢性が向上します。

/lib/systemd/system/ディレクトリ内にpuma.serviceという名前の新しいファイルを作成します。

sudo nano /lib/systemd/system/puma.service

Puma’s systemd documentationから適応した次のコンテンツを新しいファイルに追加します。 UserWorkingDirectory、およびExecStartディレクティブで強調表示されている値を更新して、独自の構成を反映させてください。

/lib/systemd/system/puma.service

[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
# Foreground process (do not use --daemon in ExecStart or config.rb)
Type=simple

# Preferably configure a non-privileged user
User=sammy

# The path to the puma application root
# Also replace the "" place holders below with this path.
WorkingDirectory=/home/sammy/appname

# Helpful for debugging socket activation, etc.
# Environment=PUMA_DEBUG=1

Environment=RAILS_ENV=production

# The command to start Puma.
ExecStart=/home/sammy/.rbenv/bin/rbenv exec bundle exec puma -b tcp://127.0.0.1:9292

Restart=always

[Install]
WantedBy=multi-user.target

ファイルを保存して閉じます。 次に、systemdをリロードし、Pumaサービスを有効にして、Pumaを起動します。

sudo systemctl daemon-reload
sudo systemctl enable puma.service
sudo systemctl start puma.service

この後、サービスのステータスを確認して、Pumaが実行されていることを確認します。

sudo systemctl status puma.service

実行中の場合、次のような出力が表示されます。

Outputpuma.service - Puma HTTP Server
   Loaded: loaded (/lib/systemd/system/puma.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2017-12-26 05:35:50 UTC; 1s ago
 Main PID: 15051 (bundle)
    Tasks: 2
   Memory: 31.4M
      CPU: 1.685s
   CGroup: /system.slice/puma.service
           └─15051 puma 3.11.0 (tcp://127.0.0.1:9292) [appname]

Dec 26 05:35:50 app systemd[1]: Stopped Puma HTTP Server.
Dec 26 05:35:50 app systemd[1]: Started Puma HTTP Server.
Dec 26 05:35:51 app rbenv[15051]: Puma starting in single mode...
Dec 26 05:35:51 app rbenv[15051]: * Version 3.11.0 (ruby 2.4.3-p205), codename: Love Song
Dec 26 05:35:51 app rbenv[15051]: * Min threads: 5, max threads: 5
Dec 26 05:35:51 app rbenv[15051]: * Environment: production

次に、curlを使用してWebページのコンテンツにアクセスして印刷し、正しく提供されていることを確認します。 次のコマンドは、ポート9292app-serverで起動したばかりのPumaサーバーにアクセスするようにcurlに指示します。

curl localhost:9292/tasks

以下のコードのようなものが表示された場合、Pumaとデータベース接続の両方が正しく機能していることを確認します。

Output...

Tasks

Title Note
...

RailsアプリがPumaによって提供されており、database-serverでリモートPostgreSQLインスタンスを使用するように正しく構成されていることを確認したら、web-serverとの間のSSHトンネルの設定に進むことができます。 app-server

[[step-7 -—- setting-up-and-persisting-the-ssh-tunnel-to-the-app-server]] ==ステップ7—AppServerへのSSHトンネルの設定と永続化

app-serverが稼働しているので、web-serverに接続できます。 手順4で行ったプロセスと同様に、別のSSHトンネルを設定してこれを行います。 このトンネルにより、web-serverのNginxは、暗号化された接続を介してapp-serverのPumaに安全に接続できます。

web-serverautosshをインストールすることから始めます。

sudo apt-get install autossh

/lib/systemd/system/ディレクトリにapp-tunnel.serviceという名前の新しいファイルを作成します。

sudo nano /lib/systemd/system/app-tunnel.service

このファイルに次のコンテンツを追加します。 繰り返しますが、キーラインはExecStartで始まるものです。 ここで、この行は、web-serverのポート9292を、Pumaがリッスンしているapp-serverのポート9292に転送します。

/lib/systemd/system/app-tunnel.service

[Unit]
StopWhenUnneeded=true
Wants=network-online.target
After=network-online.target

[Service]
User=tunnel
WorkingDirectory=/home/tunnel
ExecStart=/bin/bash -lc 'autossh -N -L 9292:localhost:9292 [email protected]'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process

[Install]
WantedBy=multi-user.target

[.note]#Note:ExecStart行のポート番号は、前の手順でPuma用に構成されたものと同じです。

systemdをリロードして、新しいサービスファイルを読み取り、app-tunnelサービスを有効にして開始します。

sudo systemctl daemon-reload
sudo systemctl enable app-tunnel.service
sudo systemctl start app-tunnel.service

トンネルが稼働していることを確認します。

ps axu | grep tunnel

以下の出力に似たものが表示されるはずです。

Outputtunnel   19469  0.0  0.1   4376   752 ?        Ss   05:45   0:00 /usr/lib/autossh/autossh -N -L 9292:localhost:9292 [email protected]
tunnel   19482  0.5  1.1  44920  5568 ?        S    05:45   0:00 /usr/bin/ssh -L 54907:127.0.0.1:54907 -R 54907:127.0.0.1:54908 -N -L 9292:localhost:9292 [email protected]
sammy    19484  0.0  0.1  12916   932 pts/0    S+   05:45   0:00 grep --color=auto tunnel

このフィルタリングされたプロセスリストは、autosshが実行中であり、web-serverapp-serverの間に実際の暗号化トンネルを作成する別のsshプロセスを開始したことを示しています。

これで、2番目のトンネルが稼働し、web-serverapp-serverの間の通信が暗号化されます。 3層のRailsアプリを起動して実行するために行うべきことは、リクエストをPumaに渡すようにNginxを設定することだけです。

[[step-8 -—- configuring-nginx]] ==ステップ8—Nginxの構成

この時点で、必要なすべてのSSH接続とトンネルがセットアップされ、3つのサーバー層のそれぞれが互いに通信できるようになりました。 このパズルの最後のピースは、Pumaにリクエストを送信してセットアップを完全に機能させるようにNginxを構成することです。

web-serverで、/etc/nginx/sites-available/appnameに新しいNginx構成ファイルを作成します。

sudo nano /etc/nginx/sites-available/appname

次のコンテンツをファイルに追加します。 このNginx構成ファイルは、How To Deploy a Rails App with Puma and Nginxに関するガイドに従った場合に使用したものと似ています。 主な違いは、アップストリームアプリの場所です。ローカルソケットファイルを使用する代わりに、この構成はNginxがポート9292でリッスンしているSSHトンネルを指すようにします。

/etc/nginx/sites-available/appname

upstream app {
    server 127.0.0.1:9292;
}

server {
    listen 80;
    server_name localhost;

    root /home/sammy/appname/public;

    try_files $uri/index.html $uri @app;

    location @app {
        proxy_pass http://app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;
}

このファイルを保存して閉じ、サイトを有効にして、変更をアクティブにします。

最初に、デフォルトのサイトを削除します。

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

Nginxsites-enabledディレクトリに移動します。

cd /etc/nginx/sites-enabled

sites-enabledディレクトリにsymbolic linkを作成し、sites-availableディレクトリに今作成したファイルを作成します。

sudo ln -s /etc/nginx/sites-available/appname appname

Nginx構成の構文エラーをテストします。

sudo nginx -t

エラーが報告された場合は、先に戻ってファイルを確認してから続行してください。

準備ができたら、Nginxを再起動して新しい設定を読み取ります。

sudo systemctl restart nginx

前提条件でPumaチュートリアルに従った場合、app-serverにNginxとPostgreSQLがインストールされているはずです。 両方とも、他の2つのサーバーで実行される個別のインスタンスに置き換えられたため、これらのプログラムは冗長です。 したがって、これらのパッケージをapp-serverから削除する必要があります。

sudo apt remove nginx
sudo apt remove postgresql

これらのパッケージを削除した後、ファイアウォールルールを更新して、不要なトラフィックがこれらのポートにアクセスしないようにしてください。

これで、Railsアプリが実稼働しています。 Webブラウザでweb-serverのパブリックIPにアクセスして、実際の動作を確認してください。

http://web-server_public_IP/tasks

結論

このチュートリアルに従うことで、Railsアプリケーションを3層アーキテクチャにデプロイし、web-serverからapp-serverへ、およびapp-serverからdatabase-serverへの接続を保護しました。 ■暗号化されたSSHトンネルを使用します。

アプリケーションのさまざまなコンポーネントを別々のサーバーに配置すると、サイトが受信するトラフィックの量に基づいて、各サーバーに最適な仕様を選択できます。 これを行う最初のステップは、サーバーが消費しているリソースを監視することです。 サーバーのCPU使用率を監視する方法については、our guide on CPU monitoringを参照してください。 1つの層でのCPUまたはメモリの使用量が非常に高い場合、その層のみでサーバーのサイズを変更できます。 サーバーサイズの選択に関するその他のアドバイスについては、Choosing the Right Droplet for Your Applicationに関するガイドを参照してください。

次のステップとして、web-serverにSSL証明書をインストールして、ユーザーからweb-serverへの接続を保護する必要があります。 手順については、Nginx Let’s Encrypt tutorialを確認してください。 また、SSHトンネルの使用について詳しく知りたい場合は、this guideを確認してください。

Related