本教程将讲解如何依托腾讯云主机(CVM),搭建前沿的安全高性能Web服务。具体将包括:配置域名解析、SSL证书申请等Web服务的前置依赖,以及安装部署最新版Nginx Web服务器,并支持当前最新的TLSv1.3协议从而做到安全高效的访问支持。
0x00 环境准备
在开始前,我们已经做好了以下两类资源的准备。
- 腾讯云实例一台:
腾讯云CVM产品主页中按需创建。本文采用机型为S4.SMALL2的云服务器,注意需要在选购时勾选上“免费分配公网IP”。我们选用操作系统是CentOS 7,当然对于其他系统如Fedora/Ubuntu等,本文的大部分步骤都是通用的。下文中所有命令均在该实例内部执行。
- 腾讯云域名一个:
腾讯云域名注册页中选择注册。挑一个喜欢的域名吧~
下文中用my-awesome-domain.com指代。
0x01 设置域名解析
所谓添加域名解析记录,就是将一条域名记录和一台公有云上的云服务器关联。
腾讯云的云解析产品,可以方便管理我们的域名解析工作。
所有解析记录的添加都可在云解析控制台,进行设置。
记录类型:选择“A”,这类解析记录可以关联IP和域名;
记录值:CVM云主机的公网IP;
主机记录:为我们需要的三级以上域名,如填写web,就是将域名“web.my-awesome-domain.com”关联到指定IP。
腾讯云的解析生效时间是极快的,这样我们就可以通过域名记录来登陆CVM了,如:
代码语言:txt复制ssh root@web.my-awesome-domain.com
0x02 申请SSL证书
下面我们来申请Let's Encrypt证书。通过官方提供的Certbot工具可以很方便地完成。Certbot实质上属于ACME协议的客户端,专门用于开发者自动化地管理证书申请流程。
安装Certbot
代码语言:txt复制yum install certbot
同时会安装相关依赖库,如openssl等。Debian/Ubuntu下换用apt install即可。
证书申请
代码语言:txt复制certbot certonly --standalone -n -m my-email-address@example.com --agree-tos -d web.my-awesome-domain.com
申请执行过程大约十秒左右,如下图:
成功后会在/etc/letsencrypt/live/web.my-awesome-domain.com/目录下生成证书相关的文件:证书文件 fullchain.pem和证书私钥文件 privkey.pem,后面在Nginx配置中将用到它们。
设置自动定期更新证书
申请的证书90天后会过期,不过Certbot自带了定时重新申请颁发(renew)证书的工具:certbot-renew。我们通过systemctl命令启动这个定时任务就不用担心证书过期的问题了。
代码语言:txt复制systemctl start certbot-renew.timer
0x03 安装Nginx
安装Nginx常见的两种方式:通过发行版包管理管理工具,或通过源码编译安装。如果采用前者仅需:
代码语言:javascript复制yum install nginx
# Debian/Ubuntu下:apt install nginx
然后跳过本节,开始下一节的配置过程即可。
但是就当前的主流发行版(如Centos7/Ubuntu18等)中,由于nginx/openssl等软件包的版本相对不高,将无法支持TLSv1.3等特性,所以请根据需求进行特性间的取舍。
那么,接下来我们来详细讲解下通过源码安装最新版Nginx,当前最新的稳定版本是1.16.0。注意尽量安装最新的稳定版本,过于久远的版本不支持很多特性,如HTTP/2(1.10后支持)和以及TLSv1.3(1.15后支持)等。
软件的最新版本通常是不会在发行版的包管理工具(如Yum, APT)的软件库中的,而是需要我们源码编译安装。不过对于我们CVM玩家来说这根本不是问题,下面跟我一起体验更大的自由与灵活吧~
我们选择在/opt目录下完成Nginx的安装,这通常是个合适的选择,当然你习惯工作的任何目录都可以。
代码语言:txt复制cd /opt
安装相关的依赖软件包
主要是编译器、PCRE包和zlib包
代码语言:txt复制yum install gcc pcre-devel zlib-devel
(Debian/Ubuntu系统下需要用apt install完成,对应的包名是libpcre3-dev和zlib1g-dev)
下载openssl源码
下载最新版本的openssl库,版本1.1.1b。这是因为Nginx中的TLS协议以及加密解密等工作是由外部的库(如libssl/libcrypto等)来完成的,而它们都在openssl项目中实现。系统默认的openssl是比较老旧的,无法支持最新的HTTP/2和TLS特性。
只需要两步:下载和解压即可。无需编译安装。
代码语言:txt复制wget https://www.openssl.org/source/openssl-1.1.1b.tar.gz
tar -zxvf openssl-1.1.1b.tar.gz
源码编译Nginx
下载编译安装Nginx,版本1.16.0。
代码语言:txt复制wget http://nginx.org/download/nginx-1.16.0.tar.gz
tar -zxvf nginx-1.16.0.tar.gz
cd nginx-1.16.0
配置编译选项,注意这里我们需要指定openssl的代码目录,Nginx编译时会顺便完成编译openssl中所需要的部分。其选项我们这里重点关注http/2和ssl模块的启用。对于其他的选项,如果后续想改动只需重新配置和编译即可,源码安装就是这么方便又任性。
代码语言:txt复制./configure
--pid-path=/run/nginx.pid
--with-http_v2_module
--with-http_ssl_module
--with-openssl=/opt/openssl-1.1.1b
编译安装
代码语言:txt复制make && make install
Nginx会被默认安装在/usr/local/nginx目录下(也可由prefix编译选项指定)。
到这里,我们已完成了Nginx的安装。其实执行
代码语言:txt复制/usr/local/nginx/sbin/nginx
即可启动Nginx服务了。不过且慢,让我们把工作完成地更优雅一些。
配置Nginx服务为systemd系统服务
编辑文件:/lib/systemd/system/nginx.service,加入如下内容
代码语言:txt复制[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
然后执行
代码语言:txt复制systemctl daemon-reload
systemctl enable nginx.service
我们后续就可以通过systemctl命令来管理Nginx服务了,如重启(restart),加载配置(reload)等。
代码语言:txt复制systemctl restart nginx.service
0x04 配置Nginx
编辑nginx.conf(或类似配置文件)中的server段,设置证书/密钥等ssl相关参数,并将80端口的HTTP服务重定向至HTTPS的443端口。具体如下:
代码语言:txt复制server {
listen 443 ssl http2;
server_name web.my-awesome-domain.com;
ssl_certificate "/etc/letsencrypt/live/web.my-awesome-domain.com/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/web.my-awesome-domain.com/privkey.pem";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000";
location / {
root html;
index index.html;
}
}
server {
listen 80;
server_name web.my-awesome-domain.com;
if ($host = web.my-awesome-domain.com) {
return 301 https://$host$request_uri;
}
}
注意:我们支持了http2,并且对于SSL协议,我们同时支持了当前稳定的TLSv1.2和最新的TLSv1.3。
然后重启服务,完成!
代码语言:txt复制systemctl restart nginx.service
0x05 验证访问
浏览器验证
现在,让我们一起试试通过浏览器访问Nginx的测试主页吧:https://web.my-awesome-domain.com
"Welcome to nginx!",我们的Web服务基本搭建完成。
通过Chrome或Firefox的开发者工具,可以查看验证证书细节和TLS协议的版本。
查看请求是否通过HTTP/2协议:
查看相关的TLS连接信息,如协议版本、证书以及cipher suite:
我们可以看到,主流的浏览器,如Chrome70/Firefox63,均已经在2018年支持(即默认优先采用)TLSv1.3。
其他的浏览器(如微信或QQ浏览器)也相信会在不久的未来予以支持,但目前对于服务器端的配置,还应如上文所示尽量设置为TLSv1.2和TLSv1.3更加保险和兼容。
curl验证
针对高端玩家,非必要操作,如引起不适直接跳过。
用当前最新(版本7.64.1)的curl工具,(注意同样需要结合新版的openssl进行编译,过程略过),则可以通过指定tls版本来详细查看TLS握手过程的细节。对应的命令参数和握手细节如下
TLSv1.2
代码语言:txt复制curl https://web.my-awesome-domain.com -v --tlsv1.3 --ciphers ECDHE-RSA-AES256-GCM-SHA384
结果
代码语言:txt复制...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
...
TLSv1.3
代码语言:txt复制curl https://web.my-awesome-domain.com -v --tlsv1.3
结果
代码语言:txt复制...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
...
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
...
以上验证,对于TLSv1.3以及v1.2我们配置的服务器都能正常支持。
0x06 Bonus:HTTP/2、TLSv1.3简介
HTTP/2
HTTP/2是新一代的应用层协议,标准发布于2015年。相比HTTP/1.1(上世纪末),HTTP/2可以做到速度更快、更加节省资源。这主要是因为HTTP/2中,请求/返回可以完全地多路复用传输(Fully Multiplexed),即一个TCP连接内可以真正同时完成多个请求,而非简单流水线化。其二进制的协议内容(Binary Frame)以及压缩的请求头部(HPACK)也是效率提升的关键。HTTP/2还支持服务端推送等特性。另外重要一点,HTTP/2事实上必须结合TLS使用(各大浏览器厂商的要求,至少TSLv1.2),因此也更加安全。
TLSv1.3
TLSv1.3,即安全传输层协议( Transport Layer Security)的最新版。TLS可以认为是SSL协议(已经废弃)的升级版,通过对数据对称加密等方式保证客户端和服务器间通信的安全、可靠和完整。2008年到2018年是TLSv1.2版本,2018年8月TLSv1.3正式发布。其相比TLSv1.2有很多重要的变化,比如优化了密码组件、废除不安全的加密算法、简化密钥交换为PSK模式,简化的握手流程(甚至通过early-data实现0-RTT)、会话保存等。
总结起来就是TLSv1.3更加安全、更加快速的新一代标准安全协议。
0x07 One More Thing
以上本教程就全部完成。相信到这里,你已经明白如何为CVM关联域名解析以及搭建基于Nginx的 Web服务了,那么就快去动手亲自实践下吧!
觉得以上步骤略显繁琐?CVM全新的产品(PAI实例)可以帮你一键完成大部分任务,有兴趣可以尝试下。
一起来享受玩转CVM的乐趣吧~
0x08 参考资料
- https://letsencrypt.org/
- https://tools.ietf.org/html/rfc8555
- https://curl.haxx.se/
- https://www.openssl.org/