本系列分三篇,记录了 Rails+Puma+Nginx+HTTPS(SSL) 网站服务搭建的全部过程
(一):Ubuntu 下 Ruby on rails 环境搭建及测试
(二):nginx 安装及配置,及 puma+nginx 运行 rails app
(三):SSL(HTTPS) 证书申请及 nginx 配置

申请 SSL 证书

为了在网站上启用 HTTPS,需要从证书颁发机构(CA)获取证书(一种文件)。此处我们从 Let’s Encrypt 处申请这种证书。Let’s Encrypt 是一个证书颁发机构(CA)。要从 Let’s Encrypt 获取您网站域名的证书,需要对域名有实际控制权。有些托管服务提供商提供 Let’s Encrypt 支持,可以帮助申请免费证书,安装并配置自动续期。此处我们使用手动方式说明如何在 Let’s Encrypt 使用 Certbot 申请 SSL 证书。

上述官网中有 SSL 证书在不同系统,不同web服务器下申请的流程,下面仅为在 ubuntu 下的申请流程。

基本步骤

1. SSH 登陆到服务器

SSH 登陆到服务器,使用带有sudo权限的用户运行 HTTP 网站

2. 安装 snapd

有些系统默认已经预安装好了 snap,可不用安装,如下图所示。如需安装,可参考 https://snapcraft.io/docs/installing-snapd 进行安装。

3. 移除所有 Certbot OS 包

如果当前系统存在通过系统包管理软件(如 apt,dnf,yum等)安装的 cerbot 包,那么在使用 snap 安装之前需要首先移除他们来确保之后使用 certbot 命令时,用的是 snap 而不是系统自带的 cerbot。具体操作据系统而定,如

1
2
3
4
5
6
# Ubuntu
sudo apt-get remove certbot
# Fedora
sudo dnf remove certbot
# CentOS
sudo yum remove certbot

4. 安装 Certbor

在命令行中可使用以下命令安装

1
sudo snap install --classic certbot

5. 运行 Certbot ,获取证书

停止当前运行的网站服务,通过以下命令获得证书。在申请过程中,Certbot 会临时在当前机器启动一个网络服务器。注意:申请 HTTPS 证书的域名需被解析到当前服务器的 IP 地址才可完成认证。

1
sudo certbot certonly --standalone

之后按照提示操作即可。默认会生成以下两个文件:

  • 证书链(certificate and chain):/etc/letsencrypt/live/your_url.com/fullchain.pem
  • 密钥文件(key file):/etc/letsencrypt/live/your_url.com/privkey.pem

并会提示过期时间,一般有效期为3个月。

6. 安装证书

需要通过修改web服务器的配置文件进行安装,不同的 web 服务器安装方式有所不同,此处我们使用 nginx 进行安装,具体可参考下一节。

7. 测试证书的自动更新

Certbot 会自动在证书快要过期时进行更新,如果没有修改证书的设置,不需要每次都手动运行 certbot。可通过以下命令测试证书的自动刷新

1
sudo certbot renew --dry-run

注意,证书更新需要开放服务器的 80 和 443 端口,如果更新失败,可先尝试暂停 nginx 服务后再手动更新。

8. 确认 certbot 正常运行

使用 HTTPS 访问自己的网站,如 https://yourwebsite.com/ ,如果在浏览器 url 栏左侧出现了小锁的标志,说明已经安装成功。

nginx 配置 SSL 访问

此处对 nginx 配置 SSL 访问,并将所有 HTTP 和 www 请求重定向到不带 www 的 HTTPS 站点上。

修改之前的 nginx 配置文件 /etc/nginx/sites-available/my_app.conf 如下即可,具体每项功能见注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
upstream my_app {	# 定义 upstream,告诉 nginx 将请求代理解析到哪里
server unix:///var/run/my_app.sock;
}

server { # 将来自 www.my_app.com 和 my_app.com 的 http 请求301重定向到 https 的 my_app.com (no-www)
listen 80 default_server;
listen [::]:80 default_server;

server_name www.my_app.com my_app.com;

return 301 https://my_app.com$request_uri;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

if ($host = www.my_app.com) { # 将来自 www.my_app.com 的 https 请求301重定向到 my_app.com (no-www)
return 301 https://my_app.com$request_uri;
}

server_name my_app.com;
root /var/www/my_app/public;

# SSL configuration
ssl_certificate /etc/letsencrypt/live/my_app.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my_app.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;

# Other configurations
location / {
proxy_pass http://my_app; # match the name of upstream directive which is defined above
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location ~* ^/assets/ {
# Per RFC2616 - 1 year maximum expiry
expires 1y;
add_header Cache-Control public;

# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
}

此时,来自以下四个域名的请求:

都将被301重定向到 https://my_app.com,且这种方式,比在 nginx 中配置 rewrite 会更加高效。

至此,Rails+Puma+Nginx+HTTPS(SSL) 网站服务搭建过程全部记录于此。