编译安装Apache httpd

几周前遇到的一个问题,需要在Ubuntu VPS上编译安装Apache httpd,并满足如下要求:

  1. 覆盖由包管理器(Debian apt)安装的版本
  2. 使用非操作系统提供的OpenSSL
  3. 使用最新版本的nghttp2*1
  4. 可执行文件名称与Debian apt安装的一致,为apache2(默认编译后为httpd,与CentOS的一致)

有这样的需求是因为这台VPS上的一个VirtualHost需要支持RC4及3DES等过时的加密套件,而最新的OpenSSL 1.0.2k需要在编译时添加参数enable-weak-ssl-ciphers才能启用.在尝试多种方式均未果后*2,编译安装并覆盖原版Apache httpd.


安装APR

cd ~
#下载APR并校验MD5
wget http://apache.osuosl.org//apr/apr-1.5.2.tar.gz
md5sum apr-1.5.2.tar.gz
tar -xvf apr-1.5.2.tar.gz
cd apr-1.5.2/
#设置安装目录
./configure --prefix-/opt/apr
#编译安装,-jN为编译的线程数,可根据CPU线程数调整
make -j2
make install

安装APR-util

cd ~
#下载APR-util并校验MD5
wget http://apache.osuosl.org//apr/apr-util-1.5.4.tar.gz
md5sum apr-util-1.5.4.tar.gz
tar -xvf apr-util-1.5.4.tar.gz
cd apr-util-1.5.4/
#设置安装目录,并指定APR所在目录
./configure --prefix=/opt/apr-util --with-apr=/opt/apr
#编译安装
make -j2
make install

安装PCRE

wget https://ftp.pcre.org/pub/pcre/pcre-8.40.tar.gz
wget https://ftp.pcre.org/pub/pcre/pcre-8.40.zip.sig
#下载并导入发布者公钥以验证签名
wget https://ftp.pcre.org/pub/pcre/Public-Key
gpg --import ./Public-Key
gpg --verify ./pcre-8.40.zip.sig
 
tar -xvf ./pcre-8.40.zip
cd pcre-8.40/
./configure --prefix=/opt/pcre
make -j2
make install

安装OpenSSL

cd ~
#下载OpenSSL 1.0.2k并校验SHA256
wget https://www.openssl.org/source/openssl-1.0.2k.tar.gz
sha256sum openssl-1.0.2k.tar.gz
tar -xvf openssl-1.0.2k.tar.gz
cd openssl-1.0.2k/
#设置安装目录并启用过时的SSL加密套件
./configure --prefix=/opt/openssl --openssldir=/opt/openssl/conf enable-weak-ssl-ciphers no-zlib
#编译安装
make -j2
make install

安装nghttp2

wget https://github.com/nghttp2/nghttp2/releases/download/v1.22.0/nghttp2-1.22.0.tar.gz
tar -xvf nghttp2-1.22.0.tar.gz
cd nghttp2-1.22.0/
./configure --prefix=/opt/nghttp2
make -j2
make install

安装httpd

cd ~
#下载httpd 2.4.25并校验SHA1
wget http://mirrors.ocf.berkeley.edu/apache//httpd/httpd-2.4.25.tar.gz
sha1sum httpd-2.4.25.tar.gz
tar -xvf httpd-2.4.25.tar.gz
cd httpd-2.4.25/

起初我将所有模块(Modules)以动态(shared)形式编译:

./configure --with-apr=/opt/apr \
--with-apr-util=/opt/apr-util \
--with-pcre=/opt/pcre \
--with-ssl=/opt/openssl \
--with-nghttp2=/opt/nghttp2 \
--prefix= \
--enable-so \
--enable-ssl \
--enable-http2 \
#按照Debian(Ubuntu)的目录格式安装
--enable-layout=Debian \
#可执行文件名称为apache2,而非httpd
--with-program-name=apache2 \
--enable-mods-shared=all \
--enable-mpms-shared=all \
 
make -j2
make install

如此安装后,试图启动apache2时却报了错,检索错误信息发现是没有加载mod_unixd导致的.用LoadModule命令将其加载后还是报错,这回变成配置文件中定义日志格式的LogFormat语句不能识别。

于是重新安装了包管理器提供的apache2,并对比/usr/lib/apache2/modules目录,发现自己安装的版本多出了5个文件:mod_log_configmod_logiomod_unixdmod_versionmod_watchdog,这5个模块本应被静态(static)编译,并不需要用LoadModule来加载。这解释了启动时报错的原因。

于是重新编译,将这5个模块静态编译

#清除之前编译好的Binary
make clean
#重新配置
./configure --with-apr=/opt/apr \
--with-apr-util=/opt/apr-util \
--with-pcre=/opt/pcre \
--with-ssl=/opt/openssl \
--with-nghttp2=/opt/nghttp2 \
--prefix= \
--enable-so \
--enable-ssl \
--enable-http2 \
--enable-layout=Debian \
--with-program-name=apache2 \
--enable-mods-shared=most \
#对以上5个模块静态编译
--enable-mods-static='log_config logio unixd version watchdog' \
--enable-mpms-shared=all 
 
make -j2
make install

这次启动apache2时不再报错,但是用nmap扫描加密套件,发现仍无法启用3DES.似乎所指定的OpenSSL目录并没被使用.后来发现ivan ristic*3.的一篇博客文章[1]提到了--enable-ssl-staticlib-deps这个编译参数,且在其文章中,mod_ssl也被静态编译.于是又进行了新的尝试

make clean
./configure --with-apr=/opt/apr \
--with-apr-util=/opt/apr-util \
--with-pcre=/opt/pcre \
--with-ssl=/opt/openssl \
--with-nghttp2=/opt/nghttp2 \
--prefix= \
--enable-so \
--enable-ssl \
--enable-http2 \
--enable-layout=Debian \
--with-program-name=apache2 \
--enable-mods-shared=most \
#将mod_ssl也静态编译
--enable-mods-static='log_config logio unixd version watchdog ssl' \
--enable-mpms-shared=all \
--enable-ssl-staticlib-deps
 
make -j2
make install

由于mod_ssl被静态编译,不再需要用LoadModule加载,因此还要加这个语句注释掉

vim /etc/apache2/mods-available/ssl.load

#LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so

再启动apache2,没有报错,3DES的加密套件也可用.


*1.一个以C语言编写的http/2库,Apache httpd的mod_http2依赖于它.<br >
*2.包括重新编译OpenSSL及在此前提下用apxs重新安装mod_ssl等.<br >
*3.SSL配置教学书籍《Bulletproof SSL》的作者.<br >
[1].https://blog.ivanristic.com/2013/08/compiling-apache-with-static-openssl.html