CentOS 7下自编译、打包RPM最新版Apache2 (httpd 2.4.37) 并开启HTTP/2

之前一直没什么时间研究新东西,博客上写的也都是些没啥滋味的东西,今天记录的这个应该能算是有些滋味的吧,不过,在正文之前,先写点铺垫,为啥现在研究起http 2.0了?这个h2吧,其实很早以前就听说过,各种好吧就是,但之前一直都有一种还很理论还很遥远的感觉,直到最近研究Google GRPC的Web实现gRPC-Web(有兴趣的话,传送门在这里:https://grpc.io/docs/quickstart/web.html)时,发现其中用到了一个叫envoy的转发代理服务器(https://www.envoyproxy.io/)来实现gRPC传输层需要的h2协议,突然感觉h2要开始普及了,查了下资料,发现h2的server push设计很有吸引力(其间还找到个这个网站:https://http2.akamai.com/demo,直观的演示了http 1.1和2.0的差距),于是乎萌生了测试下h2用在普通网站服务器的想法。

一开始还觉得现在是不是主流Web服务器都支持http2了,一查发现本博用的lighttpd还没有加入http2的支持,而apache和nginx已经有稳定支持版本了,又搜索了下网上的评论,发现还是Apache跟的比较紧,所以就从老朋友Apache入手尝鲜吧。

我的测试环境是装在虚拟机里的CentOS Linux release 7.5.1804 (Core),直接yum安装httpd的话是2.4.6-80.el7.centos.1 这个版本,而Apache是从 2.4.17 才开始支持mod_http2正式支持h2的,残念之后习惯性的找各种第三方rpm源,看是否有能直接撞的2.4.17以上版本,结果发现虽然是有,但是很少,而且也不是特别新的版本(另外这里https://www.mf8.biz/apache-httpd-%E5%BC%80%E5%90%AF-https-%E5%92%8C-http2/也提到”截止发文切仍受支持的 RHEL、CentOS 5、6、7 均不提供 Apache Httpd(apache2) ≥ 2.4.17 和 OpenSSL ≥ 1.0.2 的支持,也没有提供支持的第三放软件源支持。”),于是就想不行就自己直接拿源码装吧。其实,如果只是拿源码装的话应该是挺简单的,要啥编啥就得了,不过我这还有个需求就是想把编译好的新版apache方便的装到远端VPS上测试,当然VPS也是CentOS的,所以就变成了不止要自编译还要打包RPM了…

Linux上源码编译安装的经验我倒是有不少,但打包rpm还是头一次,果然就遇到了不少坑,因此…终于可以进入正题了…记录下整个操作的关键步骤:

首先很容易的在官网上查到了这个 Using Apache With RPM Based Systems (Redhat / CentOS / Fedora)  https://httpd.apache.org/docs/trunk/platform/rpm.html,里面写的很简单哈,俩命令rpmbuild -ts httpd-2.4.x.tar.bz2,rpmbuild -tb httpd-2.4.x.tar.bz2,就搞定了,而实际上事情远没有这么简单!

先去官网上拿最新版源码包http://httpd.apache.org/download.cgi#apache24,此时我拿到的是httpd-2.4.37.tar.bz2,直接在CentOS里wget,然后放到~/rpmbuild/SOURCES/,然后就是需要使用rpmbuild,没有的话yum install一下就好了。之后如果按官网上RPM编译的教程的话是先用rpmbuild -ts把源码转换成SRPM包,然后再用rpmbuild -tb编译源码包生成rpm包,这里呢,就是第一个小坑,如果按这个操作的话,生成的apache是不带http2的,也就是没编译生成mod_http2,所以,这里先要把压缩包解开tar -xvf httpd-2.4.37.tar.bz2,然后感谢apache直接将rpmbuild需要的.spec放在源码包里了,我们需要把httpd.spec拿出来,放到~/rpmbuild/SPECS里,然后修改其中内容,在%configure段里加入–enable-http2,变成这样:

%configure \
–enable-layout=RPM \
–libdir=%{_libdir} \
–sysconfdir=%{_sysconfdir}/httpd/conf \
–includedir=%{_includedir}/httpd \
–libexecdir=%{_libdir}/httpd/modules \
–datadir=%{contentdir} \
–with-installbuilddir=%{_libdir}/httpd/build \
–enable-mpms-shared=all \
–with-apr=%{_prefix} –with-apr-util=%{_prefix} \
–enable-suexec –with-suexec \
–with-suexec-caller=%{suexec_caller} \
–with-suexec-docroot=%{contentdir} \
–with-suexec-logfile=%{_localstatedir}/log/httpd/suexec.log \
–with-suexec-bin=%{_sbindir}/suexec \
–with-suexec-uidmin=500 –with-suexec-gidmin=100 \
–enable-pie \
–with-pcre \
–enable-mods-shared=all \
–enable-ssl –with-ssl –enable-bucketeer \
–enable-case-filter –enable-case-filter-in \
–disable-imagemap \
–enable-http2

这是很常见的源码编译前的操作,指定编译生成参数,开启http2支持。然后就可以rpmbuild -bb httpd.spec试试了,这里可能会提示各种依赖不存在,或者编译工具没有安装,提示啥就先yum装就行了,基本都可以直接yum装过,然后rpmbuild -bb,工具,依赖devel库什么的都没问题的话就可以看到常见的编译检查输出了,这里我又遇到了一个小坑,还没开始编译前就报了个这个错:

checking for nghttp2… checking for user-provided nghttp2 base directory… none
checking for pkg-config along :/usr/lib64/pkgconfig:/usr/share/pkgconfig… checking for nghttp2 version >= 1.2.1… FAILED
configure: WARNING: nghttp2 version is too old

查了下发现这个nghttp2才是mod_http2背后真正实现h2协议的基础,看了下官网,更新也是挺频繁的,本来想不行也自己rpmbuild一个最新版吧,顺带连openssl 1.1一起(CentOS 7.5默认装的是 openssl 1.0.2k-12.el7,好在也满足mod_http2的最低要求了),结果发现这个nghttp2和openssl都不像apache那么仗义,源码包里提供了.spec,自己写吧又不会,找人家写好的也没找到…好在最后发现EPEL源里有libnghttp2-devel版本呢是1.31.1-1.el7,虽然不是最新版,但也差的不远,于是就配置了EPEL源(可以参考这里:https://blog.csdn.net/u011435712/article/details/48751275),然后sudo yum install libnghttp2-devel就可以了。
完事之后再次rpmbuild -bb,这次不出意外的话就可以看到期待已久的编译输出了…
漫长的等待之后,得到的并不是成功的结果,而是这么个错:

RPM 构建错误:
没有找到文件:/home/kres/rpmbuild/BUILDROOT/httpd-2.4.37-1.x86_64/usr/lib64/httpd/modules/mod_mpm_event.so

这个是个大坑,花了不少时间查问题以及解决问题。原因在于apr以及apr-util的版本,最开始rpmbuild时提示的这两个依赖是apr-devel >= 1.4.0, apr-util-devel >= 1.4.0,就可以,直接yum install出来的版本是:

apr.x86_64 1.4.8-3.el7_4.1 @base
apr-devel.x86_64 1.4.8-3.el7_4.1 @base
apr-util.x86_64 1.5.2-6.el7 @base
apr-util-devel.x86_64 1.5.2-6.el7 @base

emmm…这不是都符合要求么,实际上看到网上有人说这个没有找到文件的错误是因为apr和apr-util版本不统一导致的,于是又去apr的官网https://apr.apache.org/,找了个1.5.2-4版apr的源码(第三方源也没找到同版本apr,apr-util的,所以又自己编了…),一通rpmbuild后,把apr和apr-devel升到了1.5.2-4(没记错的话,反正是1.5,但小版本和build号和自带的apr-util不一样),重新rpmbuild -bb后,又出现了undefined reference to `apr_os_uuid_get’错误,估计还是版本不匹配的问题,索性直接apr官方取了最新的apr和apr-util源码:apr-1.6.5.tar.bz2,apr-util-1.6.1.tar.bz2,照方rpmbuild -bb,成功以后把现有的apr,apr-util全删了,然后更新为自己build出的最新版(本地yum install ~/rpmbuild/RPMS/x86_64/XXX.rpm即可),之后再次rpmbuild -bb,这次得到了这么个结果:

检查未打包文件:/usr/lib/rpm/check-files /home/kres/rpmbuild/BUILDROOT/httpd-2.4.37-1.x86_64
错误:发现已安装(但未打包的)文件:
/usr/lib64/httpd/modules/mod_http2.so

RPM 构建错误:
发现已安装(但未打包的)文件:
/usr/lib64/httpd/modules/mod_http2.so

又是一个小坑,研究后发现应该指的是build过程生成了mod_http2.so,但是spec里没指定进哪个rpm,解决方法是修改httpd.spec,加入%{_libdir}/httpd/modules/mod_http2.so,修改后的部分如下:

%{_libdir}/httpd/modules/mod_socache_dbm.so
%{_libdir}/httpd/modules/mod_socache_memcache.so
%{_libdir}/httpd/modules/mod_socache_shmcb.so
%{_libdir}/httpd/modules/mod_speling.so
%{_libdir}/httpd/modules/mod_status.so
%{_libdir}/httpd/modules/mod_substitute.so
%{_libdir}/httpd/modules/mod_suexec.so
%{_libdir}/httpd/modules/mod_unique_id.so
%{_libdir}/httpd/modules/mod_unixd.so
%{_libdir}/httpd/modules/mod_userdir.so
%{_libdir}/httpd/modules/mod_usertrack.so
%{_libdir}/httpd/modules/mod_version.so
%{_libdir}/httpd/modules/mod_vhost_alias.so
%{_libdir}/httpd/modules/mod_watchdog.so
%{_libdir}/httpd/modules/mod_http2.so

再次rpmbuild -bb,终于成功生成了若干rpm包:

检查未打包文件:/usr/lib/rpm/check-files /home/kres/rpmbuild/BUILDROOT/httpd-2.4.37-1.x86_64
写道:/home/kres/rpmbuild/RPMS/x86_64/httpd-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/httpd-devel-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/httpd-manual-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/httpd-tools-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/mod_authnz_ldap-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/mod_lua-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/mod_proxy_html-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/mod_ssl-2.4.37-1.x86_64.rpm
写道:/home/kres/rpmbuild/RPMS/x86_64/httpd-debuginfo-2.4.37-1.x86_64.rpm
执行(%clean): /bin/sh -e /var/tmp/rpm-tmp.tF7DRG
+ umask 022
+ cd /home/kres/rpmbuild/BUILD
+ cd httpd-2.4.37
+ rm -rf /home/kres/rpmbuild/BUILDROOT/httpd-2.4.37-1.x86_64
+ exit 0

赶紧测试下yum install,安装成功,systemctl start httpd,没问题,看到了It works!,然后测试开启http2,参考这里:https://http2.pro/doc/Apache,当然记得要yum install mod_ssl.rpm,ssl支持被分开打包了,并且要在httpd.conf里开启相关module,然后通过https访问apache服务器,可以看到浏览器的协议已经是h2了!

博主友情提示:

如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。