2018 年的最后一个月,我终于决定给本身 3 年前申请的域名搞个 SSL 证书,让网站能够上车 HTTPS。免费、适合我的网站(玩票)的 SSL 证书方案,首选 Let's Encrypt。可是与一开始「一小时搞定」的预期不一样,最终完成整件事情花了我一个周末的时间,仍是有必要记录下来。html
固然 HTTPS 是大势所趋,但由于懒本身并无真正地搞过 SSL 证书、部署 HTTPS 网站。终于痛下决心部署 HTTPS 是源于本身想要在本身申请的腾讯云 VPS 主机上部署一套 jenkins 站点,而由于我域名没有在国内备案,致使使用域名访问时被腾讯云限制不可访问。 从我的开发者手动部署一个可运行网站的方案提及:node
完成第 2 步后,咱们就已经能够经过 IP 和端口(默认 80)直接访问网站,验证也经过。nginx
curl http://118.24.121.85
复制代码
完成第 3 步后,原本指望的表现是访问 http://c.myan.im
也有一样的表现,但很不幸:git
经过 curl 检查也可发现,http 请求返回的是 302 头,Location 头为 dnspod.qcloud.com/static/bloc…程序员
> curl http://c.myan.im -v
< HTTP/1.1 302
< Location: https://dnspod.qcloud.com/static/block.html?d=c.myan.im
复制代码
总算见识到了网站不备案的后果!可见咱们把我的网站域名解析到国内主机,没有问题。但若是网站没有备案,对不起门都不让你进🤷。web
至于技术上如何实现,其实这就是典型的 HTTP 劫持问题,站在腾讯云的角度思考:chrome
问题出如今第 3 步,由于 HTTP 是明文传输协议,意味着不光腾讯云,甚至客户端到服务端网络链路上的任何一个环节,都能够读取 HTTP 报文内容。apache
HTTP 劫持案例后端
从基本原理上讲,HTTPS 能够说是 HTTP 与 SSL/TLS 协议的结合。在进行应用层的报文传输前,要经过 TLS 协议创建加密会话。浏览器
固然这个图的握手原理并非本文的重点,咱们关注的是所谓证书在 SSL 链接中的做用。在 Let's Encrypt 的工具 certbot 文档页,他们这样解释什么是证书:
A public key or digital certificate (formerly called an SSL certificate) uses a public key and a private key to enable secure communication between a client program (web browser, email client, etc.) and a server over an encrypted SSL (secure socket layer) or TLS (transport layer security) connection. The certificate is used both to encrypt the initial stage of communication (secure key exchange) and to identify the server. The certificate includes information about the key, information about the server identity, and the digital signature of the certificate issuer. If the issuer is trusted by the software that initiates the communication, and the signature is valid, then the key can be used to communicate securely with the server identified by the certificate. Using a certificate is a good way to prevent “man-in-the-middle” attacks, in which someone in between you and the server you think you are talking to is able to insert their own (harmful) content.
能够总结为如下几点:
除了咱们平常在浏览器中访问 HTTPS 网站,能够在点击地址栏左侧看到正在访问网站的 SSL 证书,还有这些案例,咱们能够感知到证书的存在的:
从自签名证书提及:咱们能够本身签名,本身生成一个证书,并在 nginx 部署。
浏览器同样会发起请求,但在与服务器端创建安全套接层过程当中,浏览器会认为该证书不可信任。理论上:咱们能够把本身的证书,内置在浏览器中,就能够解决这个问题。
如下是实践步骤:
生成 key 与证书
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
复制代码
该命令生成的证书是 CA 根证书,使用
检查证书
openssl x509 -text -noout -in certificate.pem
复制代码
有了证书文件、key 文件后,就能够在 nginx 里使用以下配置,启用 HTTPS 支持,并监听 443 端口:
server {
listen 80;
listen 443 ssl;
server_name fake.myan.im;
root /usr/share/nginx/html;
ssl on;
ssl_certificate /path/to/certificate.pem; # 证书文件路径
ssl_certificate_key /path/to/key.pem; # key 文件路径
error_page 404 /404.html;
location = /40x.html {
root html;
}
location / {
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
复制代码
其后,使用经过 sudo systemctl restart nginx
命令重启 nginx 进程。
浏览器访问 fake.myan.im 被浏览器告警:证书无效
scp 下载证书文件到本地,并双击打开证书文件,安装并信任该证书
# remote.host 为远程主机地址
# ~/local/path 为本地下载目录
scp remote.host:/path/to/certificate.pem ~/local/path
复制代码
使用 Safari 浏览器查看,即发现已经能够访问了。
若是使用 Chrome 浏览器访问,会发现仍是会证书错误。这是由于 Chrome 58 后的版本,对自签名证书的安全性要求更高,须要更复杂的自签名过程。参考 serverfault.com/questions/8…
如今咱们知道,自签名证书也好,真实有含金量的真实证书也好,归根结底都只是一个证书文件。咱们须要把它放在咱们的主机上,再配置一下 nginx 使用这个证书来 Serve HTTPS 服务。
免费的证书最流行的选择是 Let's Encrypt,由国内云服务商也有本身配套的 SSL 证书可以使用,但 Let's Encrypt 胜在足够通用。其限制是默认只有 3 个月有效期,到期后须要从新 renew 操做。
要了解 Let's Encrypt 的工做原理,参考:How It Works - Let's Encrypt - Free SSL/TLS Certificates
关于 Let's Encrypt 常见问题,参考:FAQ - Let's Encrypt - Free SSL/TLS Certificates。
Let's Encrypt 提供的核心服务是证书颁发的基础服务,不少第三方服务在此基础上作了封装,给用户提供免费证书服务。一个典型的例子是咱们不少人耳熟能详的 Github Pages 服务,Github Pages 支持绑定自定义的域名,启用域名绑定后无需用户自行配置,就能够经过 https:// 协议访问。
要手动获取证书,并自行部署 HTTPS,Let's Encrypt 推荐使用 eff.org 的命令行工具 Certbot。
TL;DR:不要使用 yum 安装的包,wget 下载脚本便可
参考 certbot.eff.org/docs/instal… 说明文档,直接把命令行工具下载到本地。
> wget https://dl.eff.org/certbot-auto
> chmod a+x ./certbot-auto
> ./certbot-auto --help
复制代码
certbot 有自动模式,能够帮 nginx,apache 等服务器自动生成证书文件并配置网站。
咱们以 real.myan.im 为例,示范如何获取该域名的证书。
首先须要配置 http 服务,关键配置以下。在 conf.d 目录下新建文件,并重启 nginx 服务
server {
listen 80;
server_name real.myan.im;
root /usr/share/nginx/html;
location / {
}
}
复制代码
执行 certbot-auto 命令,默认即会使用自动模式进入 CLI 交互
~ > ./certbot-auto
复制代码
依次选择指定域名,如下是交互式输出:
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: g.myan.im
2: real.myan.im
3: v.myan.im
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 2
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for real.myan.im
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/conf.d/real.conf
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/real.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://real.myan.im
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=real.myan.im
复制代码
访问 real.myan.im 见证奇迹
certbot 工具自动模式,帮助咱们傻瓜式地完成了证书申请、网站全部权验证、nginx 配置三个过程。
输出文件保存在指定目录下,其中最重要的证书文件和私钥文件,咱们能够保存到其余地方。
要了解自动模式的工做原理,咱们要来读一下 log 输出。
首先自动模式会去读取 nginx 已有的网站配置,须要依赖咱们实现配置好 http 格式的 Web 服务。
自动模式下,有一个自动完成的步骤:
Performing the following challenges:
http-01 challenge for real.myan.im
Waiting for verification...
Cleaning up challenges
复制代码
背后所作的事情,是向咱们的 real.myan.im
发送一个特定 URL 的 http 请求,指望获得某随机值,该数值由 Lets Encrypt 指定。若匹配,则认为申请该证书的操做人员,拥有该网站全部权。
这里意味着,若是我在国内的主机上使用 certbot 执行以上操做,命令执行到此会出错。由于全部使用 HTTP 方式访问的请求,都会被劫持,返回 302 重定向。
此后继续执行,certbot 就得到到了证书和密钥文件,并完成了指定 nginx 服务的 ssl 配置过程。
若是有多个子域名想要支持 https,一个个地使用通配符能够更加方便节省人力。
对于我的来讲,通配符证书更加适合咱们使用手动模式完成。
以 *.subdomain.myan.im 为例,咱们执行如下命令。
> ./certbot-auto certonly --manual --preferred-challenges=dns --email mamengguang@gmail.com -d *.subdomain.myan.im
复制代码
certbot 将会输出:
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for subdomain.myan.im
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.subdomain.myan.im with the following value:
KCH1u2GEXay6HNkfbfQd5zqP4tvp-sMFtF9UXHmRRpU
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
复制代码
此时,咱们须要停下来,登陆 DNS 服务控制台,按照要求添加一条 TXT 类型的 DNS 记录。
使用如下命令能够验证
dig -t txt _acme-challenge.subdomain.myan.im
复制代码
点击 Enter,继续向下执行:
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
...
复制代码
到此咱们就获得了一个支持通配符的 SSL 证书,为了验证其有效性,咱们能够新增多个符合通配符的子域名,部署在这台主机上。
/etc/nginx/conf.d/x.subdomain.myan.im
绝对域名 | 通配符域名 | |
---|---|---|
适用环境 | HTTP 网络通畅,无劫持 | A. 子网站无需分开管理 B. 操做者拥有域名 DNS 管理权 |
验证方式 | 经过 HTTP 请求验证 | 经过 DNS Record 验证 |
certbot 操做 | 自动模式,傻瓜式操做 | 手动模式,须要自行切到 DNS 管理平台添加 |
咱们这里为表达方便所说的所谓“绝对域名”和“通配符域名”,实际对应着 SSL 证书的 Common Names 信息。但 Common Names 值与证书所适配的域名严格来讲不是一个概念,由于 SSL 证书最新标准支持主题备用名称(Subject Alternative Name,SAN)特性,该特性容许一个证书能够保护主域名和其余多个额外的备用域名。
一个典型的例子是 Google 的 *.google.com 证书,证书的 Common Names 为 *.google.com 可是它除了支持 google.com 下的各级子域名,也支持 google.cn,google.ca 等 Google 各国家顶级域名甚至 youtube.com 等 Google 旗下域名。
以下图是 youtube.com 网站的 SSL 证书 *.google.com。
上面的例子中,咱们使用 *.subdomain.myan.im 这样的 “通配符证书” 保护 subdomain.myan.im 的子域名,也是由于 SAN 特性的支持。
在实际使用 certbot 过程当中,考虑 Let's Encrypt 免费证书 90 天的有效期限制,务必还要在到期前自行 renew 证书。
这里能够配置 crontab 任务自动定时执行 renew 操做,再也不赘述,可参考这一篇博客文章 Let's Encrypt 终于支持通配符证书了。
以上是我使用 Let's Encrypt 为我的网站部署 HTTPS 的踩坑记录,顺便还有部署过程当中关于 HTTPS 的知识点探索:
篇幅所限内容省去很多细节,仅偏向于基本概念与操做流程。
固然在公司的实际工做中,HTTPS 证书的维护和部署通常都由专业运维人员负责,但做为先后端程序员,本身上手部署一下 HTTPS,更有利于让咱们知晓 HTTPS 其然与其因此然。因此 Just Do It 吧!