周五登录服务器安装的 showdoc 文档服务,发现 ssl 证书过期了。于是下班前去阿里云做了免费证书申请,到家后审核通过下载下来,并通过 filezilla 上传到服务器 apache2 配置目录下替换。替换之后发现证书没有生效,想着重启一下 apache2 应该就可以了。httpd -h 查看到重启指令 httpd -k restart,然后执行报错了:httpd: symbol lookup error: /alidata/server/httpd/lib/libapr-1.so.0: undefined symbol: dlopen

距离上一次折腾编译 apache2 好久了,早就忘记了什么 apr。尝试使用 yum install apr 安装之后,问题并没有得到解决。找到一篇错误提示基本一致的博文,里面说重新编译安装apr。并且apr的位置一定是原来安装apache的位置就可以解决。当时并不理解这是什么意思,并且原博文并没有提示哪里去下载这个 apr,而且 apachelib 目录下可以看到 libapr-1.solibapr-1.so.0 都是软链指向目录下的 libapr-1.so.0.6.5,文件并没有缺失。现在回顾重新编译安装新版本的 apache-2.4.54 来看,通过重新编译得到新的 apr 类库并替换回去确有可能解决问题:

2022-08-28 101835.png

也清楚了上一个 apache2 版本明显没有单独去编译 apr,而是用了 --with-included-apr,将 apraprutil 相关的类库放到了 apache2 下的 lib 中,新版本独立编译之后通过 --with-apr--with-apr-util 关联 apr 安装目录。

[root@iZ23bzdzkeaZ httpd-2.4.41c]# cat config.nice
#! /bin/sh
#
# Created by configure

"./configure" \
"--prefix=/alidata/server/httpd" \
"--with-mpm=prefork" \
"--enable-so" \
"--enable-rewrite" \
"--enable-mods-shared=all" \
"--enable-nonportable-atomics=yes" \
"--disable-dav" \
"--enable-deflate" \
"--enable-cache" \
"--enable-disk-cache" \
"--enable-mem-cache" \
"--enable-ssl" \
"--enable-file-cache" \
"--with-ssl=/usr/local/ssl" \
"--with-included-apr" \
"--with-pcre=/usr/local/pcre/" \
"$@"

[root@iZ23bzdzkeaZ httpd-2.4.54c]# cat config.nice
#! /bin/sh
#
# Created by configure

CPPFLAGS="-I/usr/include/openssl"; export CPPFLAGS
LDFLAGS="-L/usr/lib"; export LDFLAGS
"./configure" \
"--prefix=/alidata/server/httpd" \
"--with-mpm=prefork" \
"--enable-so" \
"--enable-mods-shared=most" \
"--enable-nonportable-atomics=yes" \
"--disable-dav" \
"--enable-cache" \
"--enable-disk-cache" \
"--enable-mem-cache" \
"--enable-ssl" \
"--with-crypto" \
"--enable-rewrite" \
"--enable-headers" \
"--enable-deflate" \
"--enable-socache-shmcb" \
"--enable-negotiation" \
"--enable-file-cache" \
"--with-ssl=/usr/local/ssl" \
"--with-pcre=/usr/local/pcre/" \
"--with-apr=/usr/local/apr/apr" \
"--with-apr-util=/usr/local/apr/util" \
"LDFLAGS=-L/usr/lib" \
"CPPFLAGS=-I/usr/include/openssl" \
"$@"

下载编译 apache-2.4.54,参考了 Linux编译安装Apache,对我有帮助的主要是安装 aprapr-utilpcre

apr 和 apr-util 下载地址

pcre 下载地址

apache 下载地址

如果在编译 apache2 过程中像原博文一样只加这三个配置项,就会向我一样一头栽进去爬不起来。后续几次的不断编译安装发现了对我的服务器环境必要的一些模块或配置项,比如 ssl(解析域名证书)、deflate(压缩网站文档)、rewrite(对特定网站访问地址重写)、socache-shmcb(默认配置项需要开启模块)。-–enable-mods-shared=all 意思是动态加载所有模块,如果去掉 -shared 话,是静态加载所有模块。这边用了 --enable-mods-shared=most 大概意思是动态加载大部分模块。

该博文有问题的点不是因为配置太简单了,如果不考虑这些硬性的需求,apache2 本身是可以正常启动起来的。主要中间编译过程中发生了修改安装目录的问题,一开始安装博文里默认安装到 /usr/local/httpd,后来觉得要统一安装环境(服务器镜像原来的 httpd、MySQL、php 都安装到了 /alidata/server/ 下)。这就在启动和检测配置指令中冒出来一个错误:httpd: Could not open configuration file /usr/local/httpd/conf/httpd.conf: No such file or directory 这个问题我搞了很久都没有解决,唯一一个不算解决的方法是在执行 httpd 指令时增加一个 ./httpd -f /alidata/server/httpd/conf/httpd.conf -k start。明明当前指定了安装目录 --prefix=/alidata/server/httpd,安装过程中也没有发现问题,但只要不带参数启动,就会报这个错误。

找了很久都没有发现这个配置项到底写在了哪里,无奈放弃,当时想着大不了每次启动都加上配置文件地址好了。然后启动又出现了另外一个错误:mod_ssl.so: undefined symbol: SSL_get_srp_userinfo。openssl 用的是上次编译安装好的 --with-ssl=/usr/local/ssl 加上 --enable-ssl 也不管用。因为上次升级 apache2 的时候搞过 openssl 的升级有不好的感觉,就没有第一时间去考虑升级 openssl。先去网上找了一遍,有两篇文档都提到了设置 CPPFLAGSLDFLAGS

upgrade to apache 2.4.9 opensssl error SSL_get_srp_userinfo
mod_ssl.so: undefined symbol: SSL_get_srp_userinfo

前面一篇里回答没有高赞,就没敢尝试。后面一篇作者很笃定可以解决,在编译前增加 export CPPFLAGS="-I/usr/include/openssl" LDFLAGS="-L/usr/lib"。并结合他编译的参数,得到我成功编译和启动的 apache2 配置项:

export CPPFLAGS="-I/usr/include/openssl" LDFLAGS="-L/usr/lib"

./configure --prefix=/alidata/server/httpd --with-mpm=prefork --enable-so --enable-rewrite --enable-mods-shared=most --enable-nonportable-atomics=yes --disable-dav --enable-deflate --enable-cache --enable-disk-cache --enable-mem-cache --enable-ssl --with-crypto --enable-rewrite --enable-headers --enable-deflate --enable-socache-shmcb --enable-negotiation --enable-file-cache --with-ssl=/usr/local/ssl --with-pcre=/usr/local/pcre/ --with-apr=/usr/local/apr/apr --with-apr-util=/usr/local/apr/util

后面的几项 --with-xxx=xxx 都是需要独立编译安装的。并且在这次成功之后,上面提到了让人很烦躁的 httpd: Could not open configuration file /usr/local/httpd/conf/httpd.conf: No such file or directory 问题也解决了。

之后迁移备份的 vhosts 和 cert(虚拟主机配置和证书目录),引入之前的虚拟主机配置,修改文档根目录,根据 httpd -t 反馈的问题并一一解决,直到 Syntax OK

service start php-fpm 启动 php-fpm 访问网站,得到一个 403 Access forbidden 报错,此时如果按照之前的方案是使用 /aliata/serve/httpd/bin/apxs (Apache HTTP服务器编译和安装扩展模块的工具) 重新编译 php (--with-apxs2=/usr/local/apache/bin/apxs)得到 libphp7.so 放到 modules 目录下,并增加配置 LoadModule php7_module modules/libphp7.so。考虑到再去重新编译 PHP 大概率会产生未知风险,就想看看有没有不需要编译 php 模块化运行的方案。

果然是有的。如果不使用 php 模块化运行,那就需要配置文件匹配,将识别到的 php 文件访问转发到 php-fpm 上,这点跟 Nginx 的运行方式是一样的。修改站点目录用户和用户组为 www,并增加 DirectoryIndex index.html index.php,在 mine_module 中增加

    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps

此时访问变成了下载。增加 php 文件访问转发:

<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

fcgi 后面跟 unix pid 还是这里的本地回环地址加端口9000,这个是由 php-fpm 运行配置文件决定的(/path/to/php/etc/php-fpm.d/www.conf)。

此时站点首页可以访问,但其他页面由于使用了伪静态,文件后缀是 html,照理说此时根据 .htaccess 中的改写规则应是无碍的:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST}% !^www.seasidecrab.com$ [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.seasidecrab.com/$1 [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>

改写规则不生效,大概率是修改了 php-fpm 的运行方式,由模块运行改成了 fastcgi。找到一篇 apache rewrite 详解,里面提到一项启用 .htaccess:AllowOverride None 修改为: AllowOverride All。这在根目录配置项 <Directories /path/to/www> 中修改,当然也可以像详解里的在虚拟主机里配置。

至此,更换 ssl 证书终于结束了。