使用SSH隧道保护三层Rails应用程序中的通信

来自菜鸟教程
跳转至:导航、​搜索

介绍

Web 应用程序通常由三个不同的层构成:

  • 第一层是表示层,也就是用户看到的。
  • 接下来是【X15X】应用层【X36X】,提供应用的【X62X】业务逻辑【X80X】。
  • 最后,数据层存储应用程序需要的数据。

Ruby on Rails 应用程序中,这松散地映射到表示层的 Web 服务器、应用程序层的 Rails 服务器和数据层的数据库。 在此设置中,应用程序层与数据层通信以检索应用程序的数据,然后通过表示层将其显示给用户。

虽然可以将所有这些应用程序安装在单个服务器上,但将每一层放在自己的服务器上可以更轻松地扩展应用程序。 例如,如果 Rails 服务器成为瓶颈,您可以添加更多应用程序服务器而不影响其他两层。

在本教程中,您将在三层配置中部署 Rails 应用程序,方法是在三个独立的服务器上安装一组独特的软件,配置每个服务器及其组件以一起通信和运行,并使用 SSH 隧道保护它们之间的连接。 对于软件堆栈,您将使用 Nginx 作为表示层的 Web 服务器,Puma 作为应用层的 Rails 应用服务器,PostgreSQL 作为数据层上的数据库。

先决条件

为了完成本教程,您需要启动三台 Ubuntu 16.04 服务器。 将这些命名为 web-serverapp-serverdatabase-server,并且每个都应该启用专用网络。

三台服务器中的每台都应该有一个具有 sudo 权限的非 root 用户以及配置为允许 SSH 连接的防火墙(您可以使用我们的 初始服务器设置指南 进行配置)。 在本教程的上下文中,每个服务器上的 sudo 用户被命名为 sammy

此外,三台服务器中的每台都有自己独特的配置要求:

  • 网络服务器 上:
    • 安装和配置 Nginx Web 服务器。 为此,请按照我们关于 如何在 Ubuntu 16.04 上安装 Nginx 的教程进行操作。
  • 应用服务器 上:
    • 使用官方 PPA 安装 Node.js,如 如何在 Ubuntu 16.04 上安装 Node.js 中所述。 一些 Rails 功能,例如资产管道,依赖于 JavaScript 运行时,而 Node.js 提供了这个功能。
    • 安装 Ruby on Rails 框架。 为此,请按照我们关于 如何在 Ubuntu 16.04 上使用 rbenv 安装 Ruby on Rails 的指南进行操作。 在您学习本教程时,请务必安装最新版本的 Ruby,在撰写本文时,它是 Ruby 2.5.1。
    • 安装 PostgreSQL,如我们教程 How To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 14.04 的第一部分所示。 本节还介绍了如何安装 libpq-dev,这是此三层设置所需的另一个软件包。
    • 使用 Puma 部署 Rails 应用程序。 如果您没有自己的应用程序要部署,请按照我们的指南如何使用 Puma 和 Nginx 部署 Rails 应用程序来部署示例应用程序。 请注意,在此先决条件的“安装 rbenv-vars 插件”部分中,您必须设置数据库用户和密码以反映您在 数据库服务器 上安装 PostgreSQL 时使用的值。 此外,您必须允许端口 3000 通过防火墙,“创建生产数据库”部分才能正常工作。 最后,您不需要完成本必备教程的最后两个步骤,“创建 Puma Upstart 脚本”和“安装和配置 Nginx”。
  • 数据库服务器 上:
    • 安装和配置 PostgreSQL 数据库软件。 请按照我们关于 如何在 Ubuntu 16.04 上安装和使用 PostgreSQL 的指南获取有关如何执行此操作的说明。 当您按照此先决条件教程进行操作时,为您的 Rails 应用程序创建一个具有 superuser 权限的 PostgreSQL 角色,以及一个与 PostgreSQL 角色同名的数据库。 在本教程中,PostgreSQL 角色和数据库都称为 sammy
    • 为新创建的 PostgreSQL 角色设置密码。 跳过 Puma 教程的“Create Production Database User”部分中的第一个命令(您也使用它来设置 app-server),然后按照其中的其余命令进行操作部分更改数据库用户的密码。 请注意,您为 database-server 设置的 PostgreSQL 角色名称和密码应与您在 app-server 的 PostgreSQL 安装中设置的相同。

第 1 步 — 为 SSH 隧道创建用户

SSH 隧道 是加密连接,可以将数据从一台服务器上的端口发送到另一台服务器上的端口,看起来好像第二台服务器上的侦听程序正在第一台服务器上运行。 拥有 SSH 隧道的专用用户有助于提高设置的安全性:如果入侵者在您的一台服务器上获得了对 sammy 用户的访问权限,他们将无法访问该服务器中的其他服务器三层设置。 同样,如果入侵者要访问 tunnel 用户,他们将无法编辑 Rails 应用程序目录中的文件,也无法使用 sudo 命令。

在每台服务器上,创建一个名为 tunnel 的附加用户。 tunnel用户唯一的作用是创建SSH隧道,方便服务器之间的通信,所以,不像sammy,不要给tunnel sudo特权。 此外,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

您现在已经配置了本教程其余部分所需的所有用户。 Net,您将对每个 tunnel 用户的 /etc/hosts 文件进行一些更改,以简化创建 SSH 隧道的过程。

第 2 步 — 配置主机文件

在本教程中,很多时候您必须在命令中引用 app-serverdatabase-server 的 IP 地址。 不必每次都记住并输入这些 IP 地址,您可以将 app-serverdatabase-server 的私有 IP 添加到每个服务器的 /etc/hosts文件。 这将允许您在后续命令中使用它们的名称来代替它们的地址,并使设置 SSH 隧道的过程更加顺畅。

请注意,为了简单起见,本教程指导您将 app-serverdatabase-server 的私有 IP 地址添加到 [X177X ] 文件分别在三台服务器上。 虽然技术上没有必要将 app-serverdatabase-server 的私有 IP 地址添加到它们自己的 hosts 文件中,但这样做不会不会引起任何问题。 选择这里描述的方法只是为了速度和方便。

首先,找到您的 app-serverdatabase-server 的私有 IP 地址。 如果您使用的是 DigitalOcean Droplets,请导航到您的控制面板并单击这些 Droplets 的名称。 在其任何特定于 Droplet 的页面上,公共和私有 IP 地址都显示在页面顶部附近。

然后在每台服务器上,使用您喜欢的文本编辑器打开 /etc/hosts 文件并附加以下行:

sudo nano /etc/hosts

/etc/hosts

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

通过将这些行添加到每个服务器上的此文件中,您可以在通常需要您使用这些服务器的 IP 地址的命令中使用名称 app-serverdatabase-server。 您将使用此功能设置 SSH 密钥,以便您的每个 tunnel 用户都可以连接到您的其他服务器。

第 3 步 — 设置 SSH 登录

现在您在所有三台服务器上都有一个 tunnel 用户和一个更新的 /etc/hosts 文件,您可以开始在它们之间创建 SSH 连接了。

当你完成这一步时,把三层想象成一个金字塔,底部是 database-server,中间是 app-server,而 web-server 在顶部。 app-server 必须能够连接到 database-server 才能访问 Rails 应用程序所需的数据,并且 web-server 必须能够连接到 app-server 以便向用户展示一些内容。

因此,您只需将每个 tunnel 用户的 SSH 公钥添加到它“下方”的服务器,这意味着您必须添加 web-server tunnel 用户的公钥到 app-server 并将 app-server tunnel 用户的公钥添加到 database-server。 这将允许您在层之间建立加密的 SSH 隧道,并防止网络上的任何窃听者读取它们之间传递的流量。

要开始此过程,请将位于 /home/tunnel/.ssh/id_rsa.pubweb-server 上的 tunnel 用户的公钥复制到 /home/tunnel/.ssh/authorized_keys 文件中 应用服务器

web-server 上,使用以下命令在终端中显示 tunnel 用户的公钥:

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

选择文本输出并将其复制到系统的剪贴板。

在单独的终端会话中 SSH 到 app-server,并切换到隧道用户:

sudo su tunnel

将系统剪贴板中的密钥附加到 app-server 上的 authorized_keys 文件中。 您可以使用以下命令一步完成。 请记住将 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

接下来,在 app-server(位于 /home/tunnel/.ssh/id_rsa.pub)上显示 tunnel 用户的公钥,并将其粘贴到 /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 以 tunnel 用户身份从 web-server 连接到 app-server 来测试第一个连接:

sudo su tunnel
ssh tunnel@app-server

第一次从 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-serverapp-server 的 SSH 连接运行正常。

退出SSH连接到app-server,然后退出tunnel用户回到你web-server的sammy[ X150X] 用户:

exit
exit

接下来,按照相同的步骤测试从 app-serverdatabase-server 的 SSH 连接:

sudo su tunnel
ssh tunnel@database-server

也接受 database-server 的真实性。 当您从 database-server 看到欢迎横幅和命令提示符时,您将知道从 app-serverdatabase-server 的 SSH 连接正在按预期工作。

退出与 database-server 的 SSH 连接,然后退出 tunnel 用户:

exit
exit

您在该步骤中设置的 SSH 连接构成了 SSH 隧道的基础,可在您的三个服务器层之间实现安全通信。 然而,在它们目前的形式下,这些连接很容易崩溃,因此它们并不像它们应该的那样可靠。 但是,通过安装一些额外的软件并将隧道配置为服务,您可以缓解这些漏洞。

第 4 步 — 设置到数据库服务器的持久 SSH 隧道

在最后一步中,您从本地服务器访问了远程服务器上的命令提示符。 SSH 隧道允许您通过将流量从本地主机上的端口隧道传输到远程主机上的端口来做更多的事情。 在这里,您将使用 SSH 隧道来加密 app-serverdatabase-server 之间的连接。

如果您遵循本教程的所有先决条件,您将在 app-serverdatabase-server 上安装 PostgreSQL。 为了防止端口号冲突,您必须配置这些服务器之间的 SSH 隧道,以将 app-server 的端口 5433 的连接转发到 5432 端口。 X187X] 数据库服务器。 稍后,您将重新配置 Rails 应用程序(托管在 app-server 上)以使用在 database-server 上运行的 PostgreSQL 实例。

app-server 上的 sammy 用户开始,切换到您在步骤 1 中创建的 tunnel 用户:

sudo su tunnel

使用以下标志和选项运行 ssh 命令以在 app-serverdatabase-server 之间创建隧道:

ssh -f -N -L 5433:localhost:5432 tunnel@database-server
  • -f 选项将 ssh 发送到后台。 这允许您在现有提示符中运行新命令,同时隧道继续作为后台进程运行。
  • -N 选项告诉 ssh 不要执行远程命令。 此处使用它,因为您只想转发端口。
  • -L 选项后跟配置值 5433:localhost:5432。 这指定来自本地端口 5433app-server)的流量被转发到远程 localhost 的端口 5432服务器( 数据库服务器)。 注意这里的localhost是从远程服务器的角度来看的。
  • 命令的最后一部分 tunnel@database-server 指定要连接的用户和远程服务器。

建立SSH隧道后,返回sammy用户:

exit

此时,隧道正在运行,但没有任何东西在监视它以确保它保持畅通。 如果进程崩溃,隧道将关闭,Rails 应用程序将不再能够与其数据库通信,您将开始看到错误。

终止您现在创建的隧道,因为我们将进行更可靠的设置。 由于连接在后台,您必须找到它的进程 ID 才能将其终止。 因为每个隧道都是由 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 tunnel@database-server
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 连接,请安装 autosshautossh 是一个启动和监控 SSH 连接的程序,并在连接中断或停止通过流量时重新启动它:

sudo apt-get install autossh

systemd 是 Ubuntu 上默认的 init 系统,这意味着它在系统启动后管理进程。 您可以使用 systemd 创建一个服务,该服务将在服务器重新启动时管理并自动启动您的 SSH 隧道。 为此,请在 /lib/systemd/system/ 目录中创建一个名为 db-tunnel.service 的文件,该目录是存储 systemd 单元文件的标准位置:

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 tunnel@database-server'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process

[Install]
WantedBy=multi-user.target

这里的关键线是 ExecStart。 这指定了命令的完整路径以及启动进程所需执行的参数。 在这里,它启动一个新的 bash shell,然后运行 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 tunnel@database-server
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 tunnel@database-server
sammy    25941  0.0  0.2  12916  1020 pts/0    S+   14:45   0:00 grep --color=auto tunnel

现在隧道已启动并运行,您可以使用 psql 测试与 database-server 的连接,以确保它正常工作。

启动 psql 客户端并告诉它连接到 localhost。 您还必须指定端口 5433 以通过 SSH 隧道连接到 database-server 上的 PostgreSQL 实例。 指定您之前创建的数据库名称,并在出现提示时键入您为数据库用户创建的密码:

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

最后,你有一个持久、可靠的 SSH 隧道,它可以加密 app-serverdatabase-server 之间的流量。 隧道的安全特性是关键,因为您的 app-server 上的 Rails 应用程序将通过此隧道与您的 database-server 上的 PostgreSQL 实例通信。

第 5 步 — 配置 Rails 以使用远程数据库

现在从 app-serverdatabase-server 的隧道已经建立,您可以将它用作 Rails 应用程序通过隧道连接到 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

完成后保存并关闭此文件。

因为您现在使用的是 database-server 上的 PostgreSQL 实例,而不是部署 Rails 应用程序的 app-server 上的实例,因此您必须再次设置数据库.

app-server 上,导航到您的应用程序目录并运行 rake 命令来设置数据库:

注意: 此命令不会而不是 将任何数据从现有数据库迁移到新数据库。 如果您的数据库中已经有重要数据,您应该备份它,然后再恢复它。


cd /home/sammy/appname
rake db:setup

此命令完成后,您的 Rails 应用程序将开始通过加密的 SSH 隧道与 database-server 上的 PostgreSQL 实例通信。 接下来要做的是将 Puma 配置为 systemd 服务,以使其更易于管理。

第 6 步 — 配置和启动 Puma

与您在步骤 4 中设置 db-tunnel 服务的方式类似,您将配置 systemd 以运行 Puma(您在 app-server 上安装的服务器软件作为先决条件)作为服务。 将 Puma 作为服务运行允许它在服务器启动时自动启动,或者在它崩溃时自动重新启动,有助于使您的部署更加健壮。

/lib/systemd/system/ 目录中创建一个名为 puma.service 的新文件:

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

将以下内容改编自 Puma 的 systemd 文档,添加到新文件中。 请务必更新 UserWorkingDirectoryExecStart 指令中突出显示的值以反映您自己的配置:

/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 "<WD>" 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 访问并打印网页的内容,以便您可以检查它是否被正确提供。 以下命令告诉 curl 访问你刚刚在 app-server 端口 9292 上启动的 Puma 服务器:

curl localhost:9292/tasks

如果你看到类似下面的代码,那么它确认 Puma 和数据库连接都正常工作:

Output...

<h1>Tasks</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Note</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
  </tbody>
</table>

...

一旦您确认您的 Rails 应用程序正在由 Puma 提供服务并且已正确配置为使用 数据库服务器 上的远程 PostgreSQL 实例,您可以继续设置 之间的 SSH 隧道web-serverapp-server

第 7 步 - 设置和持久化到应用服务器的 SSH 隧道

现在 app-server 已启动并运行,您可以将其连接到 web-server。 与您在第 4 步中经历的过程类似,您将通过设置另一个 SSH 隧道来完成此操作。 该隧道将允许 web-server 上的 Nginx 通过加密连接安全地连接到 app-server 上的 Puma。

首先在 web-server 上安装 autossh

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 tunnel@app-server'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=process

[Install]
WantedBy=multi-user.target

注: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 tunnel@app-server
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 tunnel@app-server
sammy    19484  0.0  0.1  12916   932 pts/0    S+   05:45   0:00 grep --color=auto tunnel

此过滤的进程列表显示 autossh 正在运行,并且它已启动另一个 ssh 进程,该进程在 web-server 和 app-server[ X195X]。

您的第二条隧道现已启动并加密您的 web-serverapp-server 之间的通信。 为了让您的三层 Rails 应用程序启动并运行,您剩下要做的就是配置 Nginx 以将请求传递给 Puma。

第 8 步 — 配置 Nginx

至此,所有必需的 SSH 连接和隧道都已设置完毕,并且您的三个服务器层中的每一层都能够相互通信。 这个难题的最后一块是让您配置 Nginx 以向 Puma 发送请求以使设置完全正常运行。

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

切换到 Nginx sites-enabled 目录:

cd /etc/nginx/sites-enabled

sites-enabled目录下创建一个符号链接到你刚才在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。 两者都被其他两台服务器上运行的单独实例所取代,因此这些程序是多余的。 因此,您应该从 app-server 中删除这些包:

sudo apt remove nginx
sudo apt remove postgresql

删除这些软件包后,请务必更新您的防火墙规则,以防止任何不需要的流量访问这些端口。

您的 Rails 应用程序现已投入生产。 在网络浏览器中访问您的 web-server 的公共 IP 以查看它的运行情况:

http://web-server_public_IP/tasks

结论

按照本教程,您已经在三层架构上部署了 Rails 应用程序,并保护了从 web-serverapp-server的连接app-serverdatabase-server 使用加密的 SSH 隧道。

将应用程序的各种组件放在不同的服务器上,您可以根据站点接收的流量为每台服务器选择最佳规格。 这样做的第一步是监视服务器正在消耗的资源。 请参阅 我们的 CPU 监控指南,了解如何监控服务器 CPU 使用率的说明。 如果您发现某一层上的 CPU 或内存使用率非常高,则可以单独调整该层上的服务器大小。 有关选择服务器大小的更多建议,请参阅我们关于 为您的应用程序选择正确的 Droplet 的指南。

作为紧接着的下一步,您还应该通过在 web-server 上安装 SSL 证书来保护从用户到 web-server 的连接。 查看 Nginx Let's Encrypt 教程 获取说明。 此外,如果您想了解有关使用 SSH 隧道的更多信息,请查看 本指南