前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >帮Nginx升级,报错的却是OpenSSL?

帮Nginx升级,报错的却是OpenSSL?

原创
作者头像
林小帅
修改2019-11-15 14:53:12
2.2K0
修改2019-11-15 14:53:12
举报
文章被收录于专栏:林小帅的专栏

最近在复习 HTTP 协议的时候,突然想起来很早之前就对自己的项目进行过Nginx支持从 HTTP 1.1 -> SPDY 的升级。但是后来好像没成功就搁置了。

在复习的过程中看到过一篇文章,有提到 Nginx HTTP 1.1 -> HTTP 2.0 升级的一些前置需求,还给出了一些参考资料。这就挠得我心痒痒了,看完文章后赶紧的在把相关资料过一遍。发现其实这些资料也是较为大概的描述。

关于 HTTP 2.0

HTTP 2.0 是基于 HTTPS 的,而 HTTP 2.0 是 SPDY 的升级版也可以说是它的前身。最初设计还是支持明文的 HTTP,而 SPDY 则是强制使用 HTTPS,到后来 HTTP 2.0 也是强制使用了 HTTPS。(SPDY 到 HTTP 2.0 有一段历史,感兴趣的可以去查查。)

而真正需要开启 HTTP 2.0 模式,还是对一些前置要求明确的说明。

开启 HTTP 2.0 前置需求:

  • CA 证书(阿里云/腾讯云都有免费的CA证书服务。什么?!你说我是广告?行吧,我这有阿里云的优惠券和腾讯云的优惠券,你说的是哪家的优惠券?留言我发你哟。)
  • Nginx 1.10.0+
  • OpenSSL 1.0.2+
  • Nginx 支持模块(编译需要 OpenSSL 1.0.2+)
  • zlib(编译 OpenSSL 所需)
  • zlib-dev(编译 OpenSSL 所需)
  • 浏览器支持(chrome 51 以上,2015 年 9 月)

在此之前还是要说一下我的服务器情况:

系统:Ubuntu 14.04 x64

硬件:

  • 1 CPU
  • 1 G 内存
  • 1M 带宽

可能你们看起来也不太高级,就是最普通的配置,但是以我目前使用的情况下来看,已经足够了。

废话不多,开始动手

代码语言:javascript
复制
nginx -V

输出如下信息:

代码语言:javascript
复制
nginx version: nginx/1.14.0 (Ubuntu)
built with OpenSSL 1.0.1f    11 Sep 2014
TLS SNI support enabled
configure arguments:……

这里可以看出 Nginx 的版本信息以及配置项等,虽然 Nginx 版本符合了,但是 OpenSSL 的版本却不符合即将要升级使用 HTTP 2.0 的前置条件。

那么怎么办呢?

先将 configure arguments 后的内容复制出来保留一下,稍后会用到。

然后要先把 OpenSSL 的版本升级了,只要大于 1.0.2 版本即可。

01 - make OpenSSL

当然你可能想使用 update 的方式来实现 OpenSSL 的升级,但是很遗憾,我在尝试之后发现,并不能正常升级,我在查看源上的版本发现 1.0.1f 就是最高版本了。

OpenSSL 官方下载源:https://www.openssl.org/source/

OpenSSL Github:https://github.com/openssl/openssl

这里我以 1.1.1d 版本为例

代码语言:javascript
复制
wget https://www.openssl.org/source/openssl-1.1.1d.tar.gz

下载完成后解压该文件

代码语言:javascript
复制
tar -zxvf openssl-1.1.1d.tar.gz

进入解压后的文件夹

代码语言:javascript
复制
cd openssl-1.1.1d

使用 config 来对 OpenSSL 进行安装配置,配置文档以及压缩模块

代码语言:javascript
复制
./config shared zlib

接下来就可以尝试编译了

代码语言:javascript
复制
make

当然在此环节的时候,并没想象中顺利,因为我碰到了三种不同的错误:

第一次错误:

代码语言:javascript
复制
> ./config shared zlib
----- 这里顺利 -----
> make
……
……
……
make[1]: *** [crypto/comp/c_zlib.o] Error 1
make[1]: Leaving directory `/home/softback/openssl-1.1.1d'
make: *** [all] Error 2

查找相关资料和文档,有一条说到是可以尝试不使用压缩模块来进行配置和编译。

Ok,满怀信心的开始第二次尝试,取消模块压缩。

第三次错误:

代码语言:javascript
复制
> ./config shared
----- 这里顺利 -----
> make
……
----- 就是等待的时间比不压缩久了大概 2~3分钟 ----
……
apps/libapps.a -lssl -lcrypto -ldl -pthread
./libcrypto.so: undefined reference to 'BI0_f_zlib'
collect2: error: Id returned 1 exit status
make [1]:*** [apps/openssl] Error 1
make [1]:Leaving directory '/home/openssl-1.1.Id'
make: *** [all] Error 2

说好的可以不压缩呢?Are you kidding me?行吧,继续查相关资料和文档把。

在文档中又看到可以只指定压缩其中的一个模块。

Fine!!!继续开始尝试。

第三次错误:

代码语言:javascript
复制
> ./config shared zlib --prefix=/home/openssl-1.1.1d/apps/openssl
----- 这里顺利 -----
> make
……
……
……
/usr/bin/ld: cannot find -lz
collect2: error: Id returned 1 exit status
make[1]: *** [libcrypto.so] Error 1
make[1]:Leaving directory '/home/openssl-1.1.1d
make: *** [all] Error 2

我的天!这它喵的都是什么文档,到底还有没有谱的啊!

不行,这不可能就我一个人错,中文搜索不行,我还不能用英文么?

但然而结果就是,还是在搜到了最终解决的结果,万万想不到居然是中文的。

代码语言:javascript
复制
apt-cache search zlib

Ubuntu 下 zlib 的包并不叫 zlib!!!

zlib -> zlib1g

zlib-dev -> zlib1g-dev

行吧!既然如此,在检查系统里安装 zlib 的情况后发现缺少了 zlib-dev

代码语言:javascript
复制
apt-get install zlib1g-dev

安装完成后继续尝试:

代码语言:javascript
复制
> ./config shared zlib
----- 这里顺利 -----
> make
……

----- 大概2分钟左右 -----

……
----- 顺利 -----

> make install

----- 顺利完成安装 -----

反正到这里虽然已经顺利完成安装了,但我的内心是崩溃的。

虽然到了这里,你以为就结束了?

天真,远远并没有结束!

当你想尝试查看 OpenSSL 是否正确安装的时候:

代码语言:javascript
复制
> openssl version -a
/usr/local/openssl/bin/openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory.

恭喜你又踩到另外一个坑。

不过没关系,这个并不是什么奇怪的错误,只是库的链接位置不对,找不到文件而已。

所以在这里让你不要害怕以及很不负责的强迫你按照以下命令一条一条的执行,如果报错也可以不用管。

为什么?!没有为什么,只是原路径没有这个文件而已,忽略即可。

代码语言:javascript
复制
> mv /usr/bin/openssl /usr/bin/openssl.old
> mv /usr/include/openssl /usr/include/openssl.old
> ln -s /usr/local/bin/openssl /usr/bin/openssl
> ln -s /usr/local/include/openssl/ /usr/include/openssl
> ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1
> ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1

其实呢,这里都是将 OpenSSL 的文件以及库文件进行了软链接到另外一个文件路径下而已,然后系统就可以通过这个软链接正确的找到相关的文件了。

至此,关于 OpenSSL 部分的编译就完成了。

02 - make Nginx

还记得文章开头我让你保存的 Nginx 的 configure argument 配置信息吧?

Ok,没错现在就是到了要使用的时候了。

首先要确认你的 Nginx 版本是多少,然后就需要从官网上下载一毛一样的版本了。不要问为什么,照做就对了。

官方下载源:https://nginx.org/en/download.html

这里我以 1.14.0 版本为例:

代码语言:javascript
复制
wget http://nginx.org/download/nginx-1.14.0.tar.gz

下载完成后解压该文件

代码语言:javascript
复制
tar -zxvf nginx-1.14.0.tar.gz

进入解压后的文件夹

代码语言:javascript
复制
cd nginx-1.14.0

使用 configure 来对 Nginx 进行安装配置,这里将如下信息与你之前保存的 Nginx 配置信息进行对比,看看到底缺哪个。

并且不要着急回车执行命令。

代码语言:javascript
复制
./configure --prefix=/你的文件夹路径 --with-http_v2_module --with-openssl=OpenSSL解压包的路径
  • --prefix=/你的文件夹路径
  • --with-http_v2_module
  • --with-openssl=OpenSSL解压包的路径

请千万确保处理好配置信息之前,不要贸然复制到命令行执行,不然 Nginx 无法工作了不要怪我!!!

配置完成后接下来就可以尝试编译了

代码语言:javascript
复制
make

这里不用 make install !!!

这里不用 make install !!!

这里不用 make install !!!

千万不要手贱!!!

坐等编译完成,然后执行如下命令:

代码语言:javascript
复制
> nginx stop
> cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.back

首先停止 Nginx 服务,然后在复制一份旧版作为备份。

然后再将你指定编译文件内的 nginx 复制过来替换。

这也就是我为什么要让你找同版本的 Nginx 的原因,这样就不会因为版本不对导致的其他问题。

替换完成后执行:

代码语言:javascript
复制
nginx -s restart

至此,如果你能像我一样没有发生其他错误,那么就恭喜你,你已经完成了 Nginx 的 HTTP 2.0 升级了。(什么?报错了?那你还不赶快去查资料?)

03 - 更新 Nginx 服务配置

申请证书

阿里云/腾讯云都有免费的CA证书服务。我这有阿里云的优惠券和腾讯云服务器的优惠券,留言我发你。

现在的云服务器提供商都有相关的配套服务了,所以不用担心太多问题。申请证书之后按照步骤操作,最后下载证书放到服务器上就好了。

部署证书

代码语言:javascript
复制
server {
  listen 443 ssl http2; # 添加 http 2.0 服务标识
  # 你的 CA 证书路径

  ssl_certificate /xxx/3076402_123456.com.pem;
  ssl_certificate_key /xxx/3076402_123456.com.key;
……
……
……
}

配置完成保存后就可以执行重新加载 nginx 配置的命令了。

代码语言:javascript
复制
nginx -s reload

如何验证?

  1. 打开浏览器 Network。
  2. 打开 Protocol 可以看到 http 所使用的版本。
  3. 刷新页面。

事实很残酷!并没有像预想中一样一次完成,又整了一出幺蛾子给我。

404 Not Found | http/1.1

为什么找不到资源,为什么还是 http 1.1?!!

但是这次我决定先解决 404 的问题,既然是访问错误那么就可以从日志中入手,查看了 nginx-error.log 文件发现:

代码语言:javascript
复制
open() "/www/error/443" failed (2: No such file or directory)

为什么会找不到文件路径?我仔细一看,这个路径为什么会是 /www/error + /443,难道我的配置路径错了?这也不应该啊,在没升级之前,都是可以正确访问的吖。

行吧,还是面向百度编程一下吧!然后发现是配置规则也更新了。

修改将目录路径闭合

代码语言:javascript
复制
location / {
  alias /www/error/; # root /www/error; 旧配置未闭合目录路径
  index 404.html;
}

修改完信息后执行重新加载 nginx 配置的命令

代码语言:javascript
复制
nginx -s reload

之后再刷新页面就可以看到正确的页面以及显示出 HTTP 2.0 版本的标识 h2 了。

HTTP 2.0 标识 h2
HTTP 2.0 标识 h2

Congratulations!!!

你已经完成了 Nginx HTTP 2.0 的升级了。

最后

  • 对于配置语法更严谨。
  • 如果需要直接访问到某一个静态文件(*.html)则需要配置为 alias 而不是 root。
  • 如果需要配置为子目录则需要闭合路径,例如 /error -> /error/
  • 否则会认为需要进入该目录而继续匹配目录路径 /error/443 下的 index 配置信息。

最后的最后

敢问少侠可知道七伤拳?

  1. 登录云服务器
  2. 打开控制台
  3. 备份数据
  4. 更换操作系统
  5. 等待2分钟
  6. apt-get update && upgrade && dist-grade 来一套。
  7. 恢复数据

参考来源:

阿里云ECS升级OpenSSL记录 - 杜先生的博客:(有用) https://www.cnblogs.com/dukuan/p/7833478.html 阿里云帮助文档:(至少一半无用信息) https://help.aliyun.com/knowledge_detail/52154.html 相似错误:(但并没解决我的问题) https://blog.csdn.net/java3344520/article/details/8612367 关于子目录路径: https://segmentfault.com/q/1010000006194225/a-1020000006195489

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于 HTTP 2.0
  • 01 - make OpenSSL
  • 02 - make Nginx
  • 03 - 更新 Nginx 服务配置
    • 申请证书
      • 部署证书
        • 如何验证?
        • 最后
        • 最后的最后
        • 参考来源:
        相关产品与服务
        SSL 证书
        腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档