前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用SSH隧道保护三层Rails应用程序中的通信

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

原创
作者头像
彼岸轮回
发布2018-08-13 14:46:37
5.6K0
发布2018-08-13 14:46:37
举报

介绍

Web应用程序通常采用三层不同的结构构建:

  • 第一层结构是表示层,是用户看到的那一层。
  • 接下来是应用程序层,它提供应用程序业务逻辑
  • 最后,数据层存储应用程序所需的数据。

Ruby on Rails应用程序中,它可以轻易地映射到表示层的Web服务器,应用程序层的Rails服务器和数据层的数据库。在此设置中,应用程序层与数据层通信来检索应用程序的数据,然后通过表示层向用户显示该数据。

虽然在单个服务器上安装所有这些应用程序也可以,但将每个层放在自己的服务器上可以更容易扩展应用程序。例如,如果Rails服务器到达了瓶颈,您可以添加更多应用程序服务器而不会影响其他两个层。

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

准备

为了完成本教程,您需要三个Ubuntu 16.04服务器。分别为Web服务器应用程序服务器数据库服务器命名,并且每个服务器都应启用专用网络。

三个服务器都应该具有具有sudo权限的非root用户以及配置为允许SSH连接的防火墙。在本教程的上下文中,每个服务器上的用户都被命名为 sammy 。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器

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

​ 在 Web服务器上

  • 安装和配置Nginx Web服务器。想要了解如何配置Nginx的同学,可以参考这篇教程《如何在Ubuntu 16.04中安装Linux,Nginx,MySQL,PHP(LNMP堆栈)》。 在 应用程序服务器上
  • 使用官方PPA安装Node.js。一些Rails功能(例如Asset Pipeline)依赖于JavaScript运行,Node.js提供此功能。
  • 安装Ruby on Rails框架。在您学习本教程时,请务必安装最新版本的Ruby,在撰写本文时,是Ruby 2.5.1。
  • 安装PostgreSQL。本节还介绍了如何安装此三层设置所需的另一个程序包libpq-dev。关于如何安装PostgreSQL,可以参考这篇文章《如何安装和使用PostgreSQL》
  • 使用Puma部署Rails应用程序。请注意,在安装rbenv-vars插件部分中,必须设置数据库用户和密码以反映在 数据库服务器 上安装PostgreSQL时使用的值。此外,您必须允许通过防火墙的端口3000才能使创建生产数据库部分顺利进行。最后,您不需要完成此教程的最后两个步骤,创建Puma Upstart脚本和安装和配置Nginx。
  • 建议您直接使用云关系型数据库,云关系型数据库让您在云中轻松部署、管理和扩展的关系型数据库,提供安全可靠、伸缩灵活的按需云数据库服务。腾讯云关系型数据库提供 MySQL、SQL Server、MariaDB、PostgreSQL 数据库引擎,并针对数据库引擎的性能进行了优化。云关系型数据库是一种高度可用的托管服务,提供容灾、备份、恢复、监控、迁移等数据库运维全套解决方案,可将您从耗时的数据库管理任务中解放出来,让您有更多时间专注于您的应用和业务。 在 数据库服务器上
  • 安装和配置PostgreSQL数据库软件。请为具有superuser权限的Rails应用程序创建PostgreSQL角色,以及与PostgreSQL角色同名的数据库。在本教程中,PostgreSQL角色和数据库都称为 sammy
  • 为新创建的PostgreSQL角色设置密码。请注意,PostgreSQL角色的名称和您为 数据库服务器 设置的密码应与您在应用程序服务器的PostgreSQL安装中设置的密码相同。因为数据库服务器是最容易被攻击的服务器,要想了解怎样保护Postgre免受恶意黑客的攻击,请点击这里

第一步 - 为SSH隧道创建用户

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

在每台服务器上,创建一个名为 tunnel 的其他用户。该 tunnel 用户的唯一功能是创建SSH隧道,以方便服务器之间的通信,因此,不要像 sammy 一样给 tunnel sudo特权。此外, tunnel 用户不应具有对Rails应用程序目录的写入权限。在每台服务器上运行以下命令以添加 tunnel 用户:

代码语言:javascript
复制
$ sudo adduser tunnel

Web服务器 计算机上,切换到 tunnel 用户。

代码语言:javascript
复制
sammy@web-server$ sudo su tunnel

作为 tunnel 用户,生成SSH密钥对:

代码语言:javascript
复制
tunnel@web-server$ ssh-keygen

将密钥保存在默认位置,不要为密钥创建密码,因为这样做可能会在以后在服务器之间创建SSH隧道时使身份验证复杂化。

创建密钥对后,返回 sammy 用户:

代码语言:javascript
复制
tunnel@web-server$ exit

现在切换到 app-server 并再次执行相同的命令:

代码语言:javascript
复制
$ sudo su tunnel
$ ssh-keygen
$ exit

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

第二步 - 配置主机文件

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

请注意,为了简单起见,本教程指示您将 app-server数据库服务器 的专用IP地址添加到三个服务器中的每个服务器上的/etc/hosts文件中。虽然技术上不需要将 app-server数据库服务器 的私有IP地址添加到自己的hosts文件中,但这样做不会导致任何问题。选择此处描述的方法仅仅是为了方便快捷。

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

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

代码语言:javascript
复制
$ sudo nano /etc/hosts
/ etc / hosts
...
app-server_private_ip app-server
database-server_private_ip database-server

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

第三步 - 设置SSH登录

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

在完成此步骤时,请考虑三层结构,如金字塔结构,底部是 数据库服务器 ,中间是 app-server ,顶部是 Web服务器 。该 应用程序服务器 必须能够连接到 数据库服务器 才能访问所需的Rails应用程序中的数据,和 web服务器 必须能够连接到 应用服务器 ,以便它有东西呈现给用户。

因此,你只需要每增加 tunnel 用户的SSH公共密钥服务器下了,这意味着你必须添加 Web服务器** tunnel 用户的公钥来对 应用程序服务器 和添加 应用程序服务器的 tunnel** 用户的公钥该 数据库服务器 。这将允许您在层之间建立加密的SSH隧道,并防止网络上的任何窃听者读取它们之间传递的流量。

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

Web服务器上 ,使用以下命令在终端中显示 tunnel 用户的公钥:

代码语言:javascript
复制
sammy@web-server$ sudo cat /home/tunnel/.ssh/id_rsa.pub

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

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

代码语言:javascript
复制
sammy@app-server$ sudo su tunnel

将系统剪贴板中的密钥附加到 app-server 上的authorized_keys文件中。您可以使用以下命令一步完成此操作。请记住使用系统剪贴板中的公钥替换tunnel_ssh_publickey_copied_from_web_server

代码语言:javascript
复制
tunnel@app-server$ echo "tunnel_ssh_publickey_copied_from_web-server" >> /home/tunnel/.ssh/authorized_keys

之后,修改authorized_keys文件的权限以防止未经授权的访问:

代码语言:javascript
复制
tunnel@app-server$ chmod 600/home/tunnel/.ssh/authorized_keys

然后回到 sammy 用户:

代码语言:javascript
复制
tunnel@app-server$ exit

接下来,在 app-server 上显示 tunnel 用户的公钥- 位于/home/tunnel/.ssh/id_rsa.pub- 并将其粘贴到 数据库服务器 上的/home/tunnel/.ssh/authorized_keys文件中:

代码语言:javascript
复制
sammy@app-server$ sudo cat /home/tunnel/.ssh/id_rsa.pub
代码语言:javascript
复制
sammy@database-server$ sudo su tunnel

因为您没有在 数据库服务器 上生成SSH密钥对,所以您必须创建/home/tunnel/.ssh文件夹并调整其权限:

代码语言:javascript
复制
tunnel@database-server$ mkdir /home/tunnel/.ssh
tunnel@database-server$ chmod 700/home/tunnel/.ssh

然后将 app-server 的公钥添加到authorized_keys文件并调整其权限:

代码语言:javascript
复制
tunnel@database-server$ echo "tunnel_ssh_publickey_copied_from_app-server" >> /home/tunnel/.ssh/authorized_keys
​
tunnel@database-server$ chmod 600/home/tunnel/.ssh/authorized_keys

然后回到 sammy 用户:

代码语言:javascript
复制
tunnel@database-server$ exit

接下来,使用SSH测试第一个连接,以作为 tunnel 用户从您的 Web服务器 连接到 app-server

代码语言:javascript
复制
sammy@web-server$ sudo su tunnel
​
tunnel@web-server ssh tunnel@app-server

第一次从 Web服务器 连接到 app-server时 ,您将看到一条消息,要求您确认可以信任您要连接的计算机。输入yes以接受 app-server 的真实性:

代码语言:javascript
复制
Output
​
The 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服务器app-server 的SSH连接正常运行。

退出SSH连接到 app-server ,然后从 tunnel 用户退出,返回到 web服务器sammy 用户:

代码语言:javascript
复制
web-server$ exit
​
web-server$ exit

接下来,按照以下相同步骤测试从 app-server数据库服务器 的SSH连接:

代码语言:javascript
复制
sammy@app-server$ sudo su tunnel
​
tunnel@app-server ssh tunnel@database-server

当您从 数据库服务器 看到欢迎横幅和命令提示符时,您将知道从 app-server数据库服务器 的SSH连接正在按预期工作。

退出SSH连接到 数据库服务器 ,然后退出 tunnel 用户:

代码语言:javascript
复制
app-server$ exit
​
app-server$ exit

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

第四步 - 设置到数据库服务器的SSH隧道

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

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

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

代码语言:javascript
复制
sammy@app-server$ sudo su tunnel

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

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

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

代码语言:javascript
复制
tunnel@app-server$ exit

此时,隧道正在运行,但没有看到它以确保它保持运行。如果进程崩溃,tunnel将关闭,Rails应用程序将无法再与其数据库通信,您将开始看到错误。

杀死你现在创建的隧道,因为我们将建立一个更可靠的设置。由于连接在后台,因此您必须找到其进程ID才能将其终止。因为每个tunnel都是由 tunnel 用户创建的,所以您可以通过列出当前进程并过滤关键字tunnel的输出来查找其进程ID:

代码语言:javascript
复制
sammy@app-server$ ps axu | grep tunnel

这将返回类似下面的输出:

代码语言:javascript
复制
Output
​
tunnel   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来停止进程:

代码语言:javascript
复制
sammy@app-server$ sudo kill 21814

要在应用程序服务器和数据库之间保持持久的SSH连接,请安装autossh。autossh是一个启动和监视SSH连接的程序,如果连接中断或停止传递流量,则重新启动它:

代码语言:javascript
复制
sammy@app-server$ sudo apt-get install autossh

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

代码语言:javascript
复制
sammy@app-server$ sudo nano /lib/systemd/system/db-tunnel.service

将以下内容添加到新文件以配置systemd要管理的服务:

代码语言:javascript
复制
[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,然后运行autossh程序。

保存并关闭该文件,然后重新加载systemd配置以确保它获取新的服务文件:

代码语言:javascript
复制
sammy@app-server$ sudo systemctl daemon-reload

启用db-tunnel服务,以便在 服务器 启动时自动启动到 数据库服务器 的隧道:

代码语言:javascript
复制
sammy@app-server$ sudo systemctl enable db-tunnel.service

然后,启动服务:

代码语言:javascript
复制
sammy@app-server$ sudo systemctl start db-tunnel.service

再次运行以下命令检查tunnel是否已启动:

代码语言:javascript
复制
sammy@app-server$ ps axu | grep tunnel

在输出中,您将看到此时有更多进程在运行,因为autossh现在正在监视tunnel:

代码语言:javascript
复制
Output

tunnel   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

现在tunnel已启动并运行,您可以用psql测试与 数据库服务器 的连接,以确保它正常工作。

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

代码语言:javascript
复制
sammy@app-server$ psql -hlocalhost -p5433 sammy

如果看到类似以下输出的内容,则表明数据库连接已正确设置:

代码语言:javascript
复制
Output

psql (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 tunnel,可以加密 应用服务器数据库服务器 之间的流量。隧道的安全功能是关键,因为应用 程序服务器 上的Rails应用 程序 将通过此隧道与 数据库服务器 上的PostgreSQL实例进行通信。

第五步 - 配置Rails以使用远程数据库

现在已经建立了从 app-server数据库服务器 的tunnel,你可以将它用作Rails应用程序的安全通道,通过tunnel连接到 数据库服务器 上的PostgreSQL实例。

打开应用程序的数据库配置文件:

代码语言:javascript
复制
sammy@app-server$ nano /home/sammy/appname/config/database.yml

更新production部分,以便将端口号指定为环境变量。现在应该看起来像这样:

代码语言:javascript
复制
. . .
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文件并编辑环境变量:

代码语言:javascript
复制
sammy@app-server$ nano /home/sammy/appname/.rbenv-vars

如果在 数据库服务器 上为PostgreSQL角色设置了不同的名称和密码,请立即替换它们(在下面的示例中,PostgreSQL角色名为 sammy )。此外,添加新行以指定数据库端口。进行这些更改后,您的.rbenv-vars文件应如下所示:

代码语言:javascript
复制
SECRET_KEY_BASE=secret_key_base
APPNAME_DATABASE_USER=sammy
APPNAME_DATABASE_PASSWORD=database_password
APPNAME_DATABASE_PORT=5433

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

因为您现在在 数据库服务器 上使用PostgreSQL实例而不是在部署Rails应用程序的 app-server 上使用PostgreSQL实例,所以您必须再次设置数据库。

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

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

代码语言:javascript
复制
sammy@app-server$ cd /home/sammy/appname
sammy@app-server$ rake db:setup

一旦此命令完成,您的Rails应用程序将开始通过加密的SSH tunnel与 数据库服务器 上的PostgreSQL实例进行通信。接下来要做的是将Puma配置为systemd服务,以便于管理。

第六步 - 配置和启动Puma

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

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

代码语言:javascript
复制
sammy@app-server$ sudo nano /lib/systemd/system/puma.service

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

代码语言:javascript
复制
[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服务:

代码语言:javascript
复制
sammy@app-server$ sudo systemctl daemon-reload
sammy@app-server$ sudo systemctl enable puma.service
sammy@app-server$ sudo systemctl start puma.service

在此之后,通过检查服务的状态确认Puma正在运行:

代码语言:javascript
复制
sammy@app-server$ sudo systemctl status puma.service

如果它正在运行,您将看到类似于此的输出:

代码语言:javascript
复制
Output

puma.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您访问刚刚在端口9292上的在 app-server 启动的Puma服务器:

代码语言:javascript
复制
sammy@app-server$ curl localhost:9292/tasks

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

代码语言:javascript
复制
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实例,您就可以继续在 Web服务器应用服务器 之间设置SSH隧道。

第七步 - 设置并保持SSH隧道到App Server

现在 app-server 已启动并运行,您可以将其连接到 Web服务器 。与您在第四步中执行的过程类似,您将通过设置另一个SSH隧道来完成此操作。此隧道将允许 Web服务器 上的Nginx 通过加密连接安全地连接到 应用程序服务器 上的Puma 。

首先在 Web服务器 上安装autossh

代码语言:javascript
复制
sammy@web-server$ sudo apt-get install autossh

/lib/systemd/system/目录中创建一个新文件app-tunnel.service

代码语言:javascript
复制
sammy@web-server$ sudo nano /lib/systemd/system/app-tunnel.service

将以下内容添加到此文件中。同样,关键行是以ExecStart开头的那个。在这里,这一行将 Web服务器 上的端口9292转向 应用程序服务器 上的端口9292,该服务器由puma监听:

代码语言:javascript
复制
[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服务:

代码语言:javascript
复制
sammy@web-server$ sudo systemctl daemon-reload
sammy@web-server$ sudo systemctl enable app-tunnel.service
sammy@web-server$ sudo systemctl start app-tunnel.service

检查tunnel是否已启动:

代码语言:javascript
复制
sammy@web-server$ ps axu | grep tunnel

您应该看到类似于以下输出的内容:

代码语言:javascript
复制
Output

tunnel   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服务器app-server 之间创建实际的加密tunnel。

您的第二个tunnel现已启动并加密您的 Web服务器应用服务器 之间的通信。为了让你的三层结构的Rails应用程序启动并运行,你需要做的就是配置Nginx将请求传递给Puma。

第八步 - 配置Nginx

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

Web服务器上 ,在以下位置/etc/nginx/sites-available/appname创建新的Nginx配置文件:

代码语言:javascript
复制
sammy@web-server$ sudo nano /etc/nginx/sites-available/appname

将以下内容添加到文件中。这个配置将Nginx指向侦听端口9292的SSH tunnel:

代码语言:javascript
复制
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;
}

保存并关闭此文件,然后启用该站点并激活更改。

首先,删除默认站点:

代码语言:javascript
复制
sammy@web-server$ sudo rm /etc/nginx/sites-enabled/default

切换到Nginx sites-enabled目录:

代码语言:javascript
复制
sammy@web-server$ cd /etc/nginx/sites-enabled

sites-enabled目录中创建您刚刚在sites-available目录中创建的文件的符号链接

代码语言:javascript
复制
sammy@web-server$ sudo ln -s /etc/nginx/sites-available/appname appname

测试您的Nginx配置是否存在语法错误:

代码语言:javascript
复制
sammy@web-server$ sudo nginx -t

如果报告了任何错误,请在继续之前返回并检查您的文件。

准备好后,重新启动Nginx,以便它读取您的新配置:

代码语言:javascript
复制
sammy@web-server$ sudo systemctl restart nginx

如果您在先决条件中遵循了Puma教程,那么您将在 app-server 上安装Nginx和PostgreSQL 。两者都被在另外两台服务器上运行的单独实例所取代,因此这些程序是多余的。因此,您应该从 app-server中 删除这些包:

代码语言:javascript
复制
sammy@app-server$ sudo apt remove nginx

sammy@app-server$ sudo apt remove postgresql

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

您的Rails应用程序现已投入生产。在Web浏览器中访问 Web服务器 的公共IP以查看其运行情况:

代码语言:javascript
复制
http://web-server_public_IP/tasks

结论

通过本教程,您已经在三层体系结构上部署了Rails应用程序,并保护了从Web服务器app-server的连接,以及从 app-server 到带有加密SSH隧道的数据库服务器的连接。

将应用程序的各个组件放在不同的服务器上,您可以根据站点接收的流量为每个服务器选择最佳规格。执行此操作的第一步是监视服务器正在使用的资源。如果您发现一个层上的CPU或内存使用率非常高,则可以单独调整该层上的服务器的大小。

更多Linux教程请前往腾讯云+社区学习更多知识。


参考文献:《Securing Communications in a Three-tier Rails Application Using SSH Tunnels》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 准备
  • 第一步 - 为SSH隧道创建用户
  • 第二步 - 配置主机文件
  • 第三步 - 设置SSH登录
  • 第四步 - 设置到数据库服务器的SSH隧道
  • 第五步 - 配置Rails以使用远程数据库
  • 第六步 - 配置和启动Puma
  • 第七步 - 设置并保持SSH隧道到App Server
  • 第八步 - 配置Nginx
  • 结论
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档