阿里云ecs给tomcat9配置https与http2.0
背景:最新的http版本http2.0早在2015年就已经正式发布,随着近几年互联网的发展,许多web应用对安全性以及传输速率/延迟都有了新的需求。为了应对这些新需求,不少互联网公司也进行了许多开创性的尝试,其中最实用也最广泛的也就是https与http2.0了。这两种更先进的安全协议,都要求网站服务器具备CA认证的安全证书,不过近几年对个人免费的证书申请与认证也越来越多,越来越便捷。在得知http2.0的优势性后,我开始了对网站改造的新尝试,于是便有了如下的教程。
点击观看http2.0可视化对比http1.1:https://http2.akamai.com/demo
第一部分为操作方法
第二部分为相关的原理
第三部分为可能遇见的一些问题
本文共约一万字,阅读预估需要10分钟左右。
操作方法
系统环境
- os:阿里云ecs–ubuntu18.04
- java:jdk1.8.0_211
- application serser:tomcat9.0.21
注意:springboot内置的tomcat服务器可能还不支持http2.0配置,胆大的同学可以去碰一碰/滑稽,这里我没有尝试过使用内置的tomcat服务器进行配置。
所需下载的包
- CA认证的ssl证书(在阿里云其他相关的云服务厂商基本都有免费的单域名证书,自己申请个人认证通常10分钟内搞定)
- apr(apache portable runtime)相关:apr1.7.0,apr-util1.6.1,apr-iconv1.2.2
- openssl加密包:openssl1.1.1d(系统有自带的,不过版本比较低,apt仓库更新也比较慢,此处需要自行编译安装)
#这里某些版本的tomcat可能还需要额外下载tomcat-native组件,不过在tomcat8以后在tomcat安装目录下的bin目录下已经附带了tomcat-native压缩包(.tar.gz)
下载地址:(官方)
ssl证书申请(阿里云):https://www.aliyun.com/product/cas?spm=5176.12825654.h2v3icoap.115.e9392c4a89XCbG&aly_as=uBGTdgtv
apr:https://apr.apache.org/download.cgi
openssl:https://www.openssl.org/source/
tomcat-native:https://tomcat.apache.org/download-native.cgi
操作步骤
前提
将所有下载的包全部放在/opt/apache/目录下
将你的证书放在/opt/apache/apache-tomcat9.0.21/ssl(自己创建的目录,用于存放证书)中
JAVA_HOME=/opt/java/jdk1.8.0_211(这里每个人安装java的位置不一样,根据自己的情况填写)
先复习一下linux的一些常用操作:
- tar zxvf —解压操作
这里z:gzip压缩指令;x:extract提取压缩包文件;v:verbose显示解/压缩过程;f:指定备份文件
另:tar zcvf —压缩操作(c:compress,大写的C是输出文件操作别搞混了) - make编译,make install编译安装
证书操作
$/opt/apache/apache-tomcat9.0.21/ssl目录下
yourkey.pfx,password.txt(全默认操作的话会产生这两个文件)
另外,证书格式并不止pfx一种,还有一种在tomcat使用也比较广泛的是jks文件。这里以pfx为例。
Tomcat 9强制要求证书别名设置为tomcat。您需要使用以下keytool命令将protocol=”HTTP/1.1”转换为protocol=”org.apache.coyote.http11.Http11NioProtocol”
keytool -changealias -keystore yourkey.pfx -alias alias -destalias tomcat
#接下来若提示输入密码,则将password.txt中的内容手动输入
$/opt/apache/ 后文所有的指令都在该路径下,完全第一次配置http2的同学可以抄作业
先安装apr相关库
# 安装apr
tar zxvf apr-1.7.0.tar.gz
cd apr-1.7.0
#此时你所在的目录 $/opt/apache/apr-1.7.0
./configure --prefix=/usr/local/apr
# 这里--prefix为安装文件的前缀,即安装路径,可以根据自己需求选择性改变
make && make install
cd .. # 回到上一级目录
# 安装apr-util
tar zxvf apr-util1.6.4.tar.gz
cd apr-util1.6.4
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
make && make install
cd ..
# 安装apr-iconv
tar zxvf apr-iconv1.2.2.tar.gz
cd apr-iconv1.2.2
./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr
make && make install
cd ..
安装openssl
# 安装openssl
tar zxvf openssl-1.1.1d.tar.gz
cd openssl-1.1.1d
./config shared --prefix=/usr/local/openssl1.1.1d #切记切记这里要加上shared参数,用于创建动态链接库
make && make install
cd ..
安装tomcat-native组件
# 安装tomcat-native
cd apache-tomcat-9.0.21/bin
tar zxvf tomcat-native.tar.gz # 解压出来是源码形式,因此下一行为tomcat-native-1.2.21-src目录
cd tomcat-native-1.2.21-src/native
./configure --prefix=/usr/local/tomcat-native --with-apr=/usr/local/apr --with-java-home=/opt/java/jdk1.8.0_211 --with-ssl=/usr/local/openssl-1.1.1d
#这里为重点步骤
#--with-java-home命令后面填写自己的java_home,不知道自己java_home,使用echo $PATH命令查看
#--with-ssl命令后面填写自己安装的openssl路径,这里不指定ssl可能会导致tomcat出现ssl引擎初始化错误的问题
make && make install
cd ..
配置tomcat支持https和http2.0
在$/opt/apache/apache-tomcat-9.0.21路径下
# 配置tomcat支持https和http2.0
cd conf/
vi server.xml # 通过修改server.xml来配置
这里我将一些不需要的内容删除了以便于阅读,嫌麻烦的同学可以直接copy至你的server.xml,这里必要的内容都是健全的。
修改的地方分别为33,52,77行
52行处配置443端口的https服务时,证书路径及密码请根据自己的实际情况填写
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
# 这里修改了
<Connector port="80" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000"
redirectPort="443">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
# 这里为我配置出错的地方
<!--<Connector port="443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true"
scheme="https" secure="true" sslProtocol="TLS"
keystoreFile="/opt/apache/apache-tomcat-9.0.21/ssl/yourkey.pfx" # 你的证书路径
keystoreType="PKCS12"
keystorePass="passowrd" # 你的证书密码
clientAuth="false"
SSLProtocol="TLSv1+TLSv1.1+TLSv1.2"
ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>-->
# 这里修改了
<Connector port="443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true"
scheme="https" secure="true" sslProtocol="TLS"
keystoreFile="/opt/apache/apache-tomcat-9.0.21/ssl/yourkey.pfx" # 你的证书路径
keystoreType="PKCS12"
keystorePass="passowrd" # 你的证书密码
SSLProtocol="TLSv1+TLSv1.1+TLSv1.2">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
# 这里修改了,用于配置无项目名访问以及开启缓存
<Context path="" docBase="blog" reloadable="true">
<Resources cachingAllowed="true" cacheMaxSize="102400" />
</Context>
</Host>
</Engine>
</Service>
</Server>
配置完成后重启tomcat即可。
重启后访问https:// 加上你的ip/域名即可。
查看网站是否使用http2.0的方法:(在chromium系浏览器)F12打开console,在element中可以看到protocol为h2,表示该元素为http2.0协议传输的。
相关原理
从单机到联机
世界上第一台通用计算机“ENIAC”诞生于1946年2月14日,这台电脑“computer”在美国宾夕法尼亚大学首次登上历史舞台。在半导体产业还在襁褓中嗷嗷待哺的近八十年前,科学家们使用“电子管”来构建一个个运算器,使得这台“电脑”占地170平方米,重达30吨,耗电功率约150千瓦,但是每秒钟只能进行5000次运算。在当时,这样的庞然大物只能被用于高端的军事活动或是科学计算中,理所当然的,它也极少存在联机这样的需求。(大胆猜测当时有联机需求可能会直接发个电报来进行“人工”联机)
随着相关产业的发展,计算机经历了五次可定义的换代:
- 电子管计算机 (1946-1958年):用阴极射线管或汞延尺线作主存储器, 外存主要使用纸带、卡片等, 程序设计主要使用机器指令或符号指令, 应用领域主要是科学计算。
- 晶体管计算机 (1958-1964年):主存储器均采用磁蕊存储器, 磁鼓和磁盘开始用作主要的外存储器, 程序设计使用了更接近于人类自然语言的高级程序设计语言, 计算机的应用领域也从科学计算扩展到了某些工业领域。
- 小规模集成电路计算机 (1964-1971年):半导体存储器逐步取代了磁芯存储器的主存储地位, 磁盘成了不可缺少的辅助存储器, 计算机也进入了产品标准化、模块化、系列化的发展时期, 使计算机使用效率明显提高
- 大规模集成电路 (1972年-至今):随着半导体产业和集成电路的持续高速发展,微处理器应运而生,在此基础上还产生了微型计算机的概念。由于微型计算机体积小、功耗低、其性能价格比占有很大优势, 因而得到了广泛的应用,乃至于早已走进了家家户户。
- 人工智能计算机——神经计算机(将来):其特点是可以实现分布式联想记忆.并能在一定程度上模拟人和动物的学习功能。它是一种有知识、会学习、能推理的计算机, 具有能理解自然语言、声音、文字和图像的能力, 并且具有说话的能力, 使人机能够用自然语言直接对话, 它可以利用已有的和不断学习到的知识, 进行思维、联想、推理, 并得出结论, 能解决复杂问题, 具有汇集、记忆、检索有关知识的能力。
显然,随着计算机的换代,其呈现出体型越来越小,运算能力越来越强的发展趋势。在这样的条件下,每个人都有了使用计算机的机会,于是乎,计算机承载着人类沟通的希望,联机的需求越来越多,最后在科学家与工程师们的刻苦攻坚下,逐步形成了如今庞大的互联网。
从socket到http协议
复习:《计算机网络》–osi七层网络模型
socket套接字api
socket(20世纪八十年代)是一个基于tcp/ip协议的简单api,由操作系统实现并提供相应接口。在socket的基础上可以添加额外的协议来实现对应应用的网络通信功能。
根据tcp/ip协议,socket使用一个套接字创建一个socket连接进行网络通信。
套接字:
host主机ip号:端口号
根据套接字可以创建一个唯一标识的网络c/s端,创建socket c/s端后根据操作系统提供的相关接口(包含bind,accept,listen等方法)发送数据包来进行通信。
实际上有了socket接口之后,广大程序员们就已经可以开始方便快捷的开发具备网络通信功能的应用程序了,不过每个人都用不同的数据格式进行通信,难免会造成一些不必要的麻烦,或者说会导致通用度十分低下。随着时间的推移,在世界范围内陆陆续续产生了FTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet等等应用层协议,用于统一化的开发,其中应用最为广泛与知名度最高的就是http协议了。
http协议
http(hypertext transfer protocol,超文本传输协议,1989年提出) 是一个基于请求(request)与响应(response)模式的、无状态的、应用层的协议,通常基于TCP/IP(socket)的连接方式,用于构建在HTTP之上的Web应用。
理解超文本:
顾名思义,即使用格式化的文本来传输超过文本本身能表达的内容。
在互联网发展的初期,普通用户们往往是在互联网上进行各种内容,资料的查看,单纯的文本内容又不可避免的不如多媒体内容更易于被用户所接受,超文本传输协议也就随之而来。
通常超文本内容被定义为html格式的文件,这些文件被存放在一个server端,每个用户使用网络浏览器来获取服务内容,浏览器也就是client端,随着超文本传输内容与浏览器的普及化,这样的服务架构也被称为B/S(Browser/Server)架构。
http自被提出到现在,它的标准在万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)地协商下不断地发展,主要的版本却不多,只有4个:
- http0.9(1991年)(已废弃)
- http1.0(1996年)
- http1.1(1999年)
- http2.0(2015年)
HTTP/1.1相较于HTTP/1.0协议的区别主要体现在:
- 缓存处理
- 带宽优化及网络连接的使用
- 错误通知的管理
- 消息在网络中的发送
- 互联网地址的维护
- 安全性及完整性
从http1.1到https与http2.0协议
由上文可知,http1.1版本到http2.0版本之间相差16年,这足以说明http1.1版本是一个非常优秀地传输协议,不过在这16年内,互联网发展迅速,互联网规模今非昔比,在新需求下必然会迎来新的发展。实际上,在这16年内,官方虽然没有正式地发布过一款新一代协议,但是各种“魔改版本”地新协议也有不少被广泛的采用了。
安全套接层协议–ssl
SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
https(hypertext transfer protocol secure,安全超文本传输协议) 是一种基于http进行安全通信的传输协议,在tcp/ip传输层协议与http应用层协议之间加入了ssl安全套接层协议,通过对应地加密算法可以尽可能地保证http传输过程中地安全性与保密性。2000年代末至2010年代初,HTTPS开始广泛使用,以确保各类型的网页真实,保护账户和保持用户通信,身份和网络浏览的私密性。
http2.0是最新的http标准,正式发布于2015年。
主要的新特性
- 二进制分帧:HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。
- 多路复用:所有的请求都是通过一个 TCP连接并发完成。
- 首部压缩(Header Compression):HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http/2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。
- 服务端推送(Server Push):服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。
可能遇到的一些问题
下面的操作基本路径:
$/opt/apache/apache-tomcat9.0.21/
0.权限问题
此教程的所有操作均在root用户权限下进行,若遇到permission deny的问题
请自行解决。。。
1.安装openssl出错
cat logs/catalina.out
或者cat logs/catalina.out|grep 你要查找的内容
# 极有可能出现以下错误
SEVERE: Failed to initialize the SSLEngine.
org.apache.tomcat.jni.Error: 70023: This function has not been implemented on this platform
翻译翻译:
致命错误:初始化SSLEngine失败
错误代码:70023:这个方法还未在此平台上实现
这里并不是操作系统层面的平台不支持,而是tomcat-native组件配置的ssl出了问题
解决办法:重新编译安装openssl和tomcat-native
2.openssl安装后,terminal窗口中查看openssl版本仍为旧版本
linux读取可执行文件命令的顺序为$PATH中的顺序,请注意读取的ssl所处的优先级
解决办法:软链接一个openssl命令至最优先的bin目录下
ln -s /usr/local/openssl-1.1.1d/bin/openssl /usr/bin/openssl
或者直接复制文件也行
cp /usr/local/openssl-1.1.1d/bin/openssl /usr/bin/openssl
3.http2.0与websocket的不兼容问题
websocket是一个基于http的全双工通信协议,复用了http连接建立过程的握手通道,通过http1.x协议header中的upgrade属性来进行协议替换。
虽然http2.0中本身就有服务端推送的新特性,不过仅由浏览器内部实现,并没有提供相应的消息推送端口,因此截至2020/3/16,升级到http2.0以后有可能导致之前版本的websocket不兼容问题(博主并没有遇到)。有服务器端主动推送消息的应用程序可以使用SSE(server-send event)或长轮询来暂时替代websocket。
不过RFC8441中明确了将来会有基于http2.0的websocket实现。
参考内容
《论计算机发展史及展望》 – 杨露斯,黎炼
百度百科 – baike.baidu.com
wiki百科 – .wikipedia.org