Nginx编译安装与多平台自动化构建
手动编译一次Nginx并不难,麻烦的是在多个发行版(openEuler、Kylin、CentOS)、多种架构(x86_64、aarch64)和不同安装路径下重复同样的工作。本文前半部分梳理手动编译的完整流程,后半部分介绍如何用GitHub Actions把这套流程重构为自动化的矩阵构建流水线:multi-platform-nginx-build-workflow。
手动编译
安装编译依赖
dnf install -y ca-certificates gcc glibc-devel git gzip make perl tar wget \
pcre-devel openssl-devel zlib-devel \
libxslt-devel gd-devel perl-devel gperftools-devel GeoIP-devel
最后一行的libxslt-devel、gd-devel、perl-devel、gperftools-devel、GeoIP-devel只有全功能编译才需要。
软件下载
从官网下载Nginx源码包。OpenSSL、PCRE2和zlib会在编译Nginx时从源码一并编译并静态链接,因此同时下载这三个依赖的源码。
wget https://nginx.org/download/nginx-1.31.3.tar.gz
wget https://www.openssl.org/source/openssl-3.0.12.tar.gz
wget https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.gz
wget https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz
tar -xzf nginx-1.31.3.tar.gz
tar -xzf openssl-3.0.12.tar.gz
tar -xzf pcre2-10.47.tar.gz
tar -xzf zlib-1.3.2.tar.gz
第三方模块从GitHub克隆。
git clone --recursive https://github.com/winshining/nginx-http-flv-module.git
git clone --recursive https://github.com/openresty/headers-more-nginx-module
编译参数的组织
编译参数可以拆成两部分,这也是后文自动化构建的组织方式:
- 基础参数:安装路径、依赖源码路径、编译和链接选项,所有场景一致;
- 模块参数:启用哪些模块,按需选择,对应一个构建profile。
基础参数中,--with-openssl、--with-pcre、--with-zlib指向依赖的源码目录,configure会在编译Nginx时一并编译这些依赖并静态链接进二进制,不依赖系统中安装的版本。
基础功能:SSL模块,适合以最小依赖部署到生产环境。
cd nginx-1.31.3
./configure \
--prefix=/usr/local/nginx \
--with-openssl=../openssl-3.0.12 \
--with-pcre=../pcre2-10.47 \
--with-zlib=../zlib-1.3.2 \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-cc-opt='-O2 -g -grecord-gcc-switches -pipe -fstack-protector-strong -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,-E'
全功能编译:参考YUM源内Nginx的nginx -V参数,包含HTTP/2、HTTP/3、stream、mail等全部模块。
全功能编译参数
cd nginx-1.31.3
./configure \
--prefix=/usr/local/nginx \
--with-openssl=../openssl-3.0.12 \
--with-pcre=../pcre2-10.47 \
--with-zlib=../zlib-1.3.2 \
--add-module=../nginx-http-flv-module \
--add-module=../headers-more-nginx-module \
--with-select_module \
--with-poll_module \
--with-threads \
--with-file-aio \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_xslt_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_geoip_module=dynamic \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_slice_module \
--with-http_stub_status_module \
--with-http_perl_module=dynamic \
--with-http_auth_request_module \
--with-mail=dynamic \
--with-mail_ssl_module \
--with-pcre-jit \
--with-stream=dynamic \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-stream_geoip_module \
--with-stream_ssl_preread_module \
--with-google_perftools_module \
--with-debug \
--with-compat \
--with-cc-opt='-O2 -g -grecord-gcc-switches -pipe -fstack-protector-strong -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,-E'
注意--with-cc-opt中的-m64只适用于x86_64,在aarch64上编译时需要去掉。
编译安装与验证
make -j$(nproc)
make install
编译完成后验证编译参数和默认配置。
/usr/local/nginx/sbin/nginx -V
/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf -p /usr/local/nginx
部署
创建用户并授权。
groupadd nginx
useradd -g nginx -s /bin/false nginx
chown -R nginx:nginx /usr/local/nginx/
增加软链接。
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
部署systemd监控,按需修改执行文件路径为实际的路径即可。
cat > /usr/lib/systemd/system/nginx.service << EOF
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
User=nginx
Group=nginx
LimitNOFILE=65535
LimitNPROC=65535
Type=forking
PIDFile=/usr/local/nginx/nginx.pid
# Nginx will fail to start if /usr/local/nginx/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running \`nginx -t\` from the cmdline.
ExecStartPre=/usr/bin/rm -f /usr/local/nginx/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP \$MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
这里使用/usr/local/nginx/nginx.pid存放pid文件,需要对应地将nginx.conf中的pid配置为相同的路径。
pid /usr/local/nginx/nginx.pid;
使用GitHub Actions自动化多平台构建
以上流程在一台机器上跑一次没有问题,但要覆盖「多种发行版 × 不同CPU架构」时,手动编译或为每个发行版维护一个Dockerfile都难以为继。multi-platform-nginx-build-workflow把这套流程搬到了GitHub Actions上,核心思路:
- 用matrix策略展开全部构建组合,各组合并行构建、互不影响;
- 用容器提供各发行版的编译环境(openEuler、Kylin官方镜像),aarch64跑在ARM Runner上原生编译,无需QEMU模拟;
- 把易变的部分抽离为配置文件:依赖版本放进
build-config.env,模块清单放进build-profiles/*.conf,工作流本身保持稳定。
项目结构
multi-platform-nginx-build-workflow
├── .github
│ └── workflows
│ ├── build-nginx-multi-distro.yml # 主工作流:openEuler/Kylin矩阵构建
│ └── build-nginx-centos_7.yml # CentOS 7独立工作流
├── build-config.env # 全局构建配置
└── build-profiles # 构建profile,一行一个configure参数
├── minimal.conf
└── standard.conf
构建矩阵
主工作流用系统、架构、安装前缀三个维度展开矩阵,每个组合是一个独立的job,运行在对应发行版的容器里。
strategy:
fail-fast: false
matrix:
os:
- name: kylin_v10
image: macrosan/kylin:v10-sp3-2403
openssl: "1.1.1w"
- name: openeuler_22_03
image: openeuler/openeuler:22.03-lts-sp4
openssl: "1.1.1w"
- name: openeuler_24_03
image: openeuler/openeuler:24.03-lts-sp3
openssl: "3.0.12"
arch:
- arch: x86_64
runner: ubuntu-24.04
- arch: aarch64
runner: ubuntu-24.04-arm
prefix:
- prefix_name: usr_local
INSTALL_PREFIX: /usr/local/nginx
PACKAGE_ROOT: /usr/local
- OpenSSL版本跟随发行版:Kylin V10和openEuler 22.03使用1.1.1w,openEuler 24.03使用3.0.12,所以它定义在os维度里而不是全局配置里;
fail-fast: false保证单个组合失败不会取消其他组合;- Nginx版本不写在矩阵里,release触发时取tag名,手动触发时由表单输入。
全局配置build-config.env
PCRE2_VERSION=10.47
ZLIB_VERSION=1.3.2
NGINX_BUILD_PROFILE=minimal
ALLOWED_PREFIXES=usr_local
- 升级PCRE2、zlib版本只需要修改这个文件,不用动工作流;
NGINX_BUILD_PROFILE指定release构建默认使用的profile;ALLOWED_PREFIXES限制release构建的安装前缀(逗号分隔,留空则全部构建),手动触发不受它限制,使用表单里的过滤器。
构建Profile
build-profiles/目录下每个.conf文件就是一份模块清单,一行一个configure参数,空行和#开头的行会被忽略。minimal.conf:
--with-http_ssl_module
--with-http_realip_module
--with-http_stub_status_module
standard.conf即前文全功能编译的模块参数。工作流读取profile后,与固定的基础参数拼接执行:
PROFILE_ARGS=$(grep -v '^#' "build-profiles/${NGINX_BUILD_PROFILE}.conf" | grep -v '^[[:space:]]*$' | tr '\n' ' ')
cd nginx-src
./configure \
--prefix="${INSTALL_PREFIX}" \
--with-openssl=../openssl-${OPENSSL_VERSION} \
--with-pcre=../pcre2-${PCRE2_VERSION} \
--with-zlib=../zlib-${ZLIB_VERSION} \
--with-cc-opt="${CC_OPT_FLAGS}" \
--with-ld-opt="${LD_OPT_FLAGS}" \
$PROFILE_ARGS
基础参数由工作流固定提供,profile只负责模块清单,-m64这类架构相关的编译选项也由工作流按架构动态追加。新增profile只需在目录下添加一个.conf文件,并把名字加进工作流build_profile的下拉选项。
触发方式
| 触发方式 | Nginx版本来源 | 产物去向 |
|---|---|---|
| release发布 | tag名(如1.31.3) |
上传为release附件 |
| 手动触发(workflow_dispatch) | 表单输入 | workflow artifact,保留3天 |
手动触发时可以按系统、架构、前缀过滤,只构建需要的组合。工作流的第一步会检查当前矩阵组合是否命中过滤条件(包括release构建的ALLOWED_PREFIXES),未命中的组合跳过所有后续步骤。
打包
每个组合编译安装并通过nginx -V、nginx -t验证后,把安装目录整体打包为nginx-{版本}-{架构}-{系统}-{前缀}.tar.gz,例如nginx-1.31.3-x86_64-openeuler_24_03-usr_local.tar.gz。包内目录有两种模式:
static:固定的nginx/目录,release构建固定使用这种;versioned(手动构建默认):版本号目录加一个指向它的软链接,方便多版本并存,回滚只需改软链接指向。
/usr/local/
├── nginx -> nginx-1.31.3
└── nginx-1.31.3/
├── sbin/nginx
├── conf/
├── html/
└── logs/
CentOS 7的特殊处理
CentOS 7没法走主工作流的container:方式:GitHub Actions要求容器内能运行基于Node 20的action(checkout、upload-artifact等),CentOS 7的glibc太旧。因此单独建一个工作流,在job里手动docker run centos:7,构建逻辑以内联脚本执行。
另外CentOS 7已经EOL,官方源已下线,构建前需要把YUM源切到vault归档源。
cd /etc/yum.repos.d
mkdir -p backup
mv -f *.repo backup/
cat > CentOS-Vault.repo << 'EOF'
[base]
name=CentOS-7 - Base
baseurl=http://vault.centos.org/7.9.2009/os/$basearch/
enabled=1
gpgcheck=0
[updates]
name=CentOS-7 - Updates
baseurl=http://vault.centos.org/7.9.2009/updates/$basearch/
enabled=1
gpgcheck=0
[extras]
name=CentOS-7 - Extras
baseurl=http://vault.centos.org/7.9.2009/extras/$basearch/
enabled=1
gpgcheck=0
EOF
yum clean all
yum makecache
下载使用
构建产物随release发布,按平台拼接下载地址。
VERSION=1.31.3
ARCH=x86_64 # x86_64 / aarch64
PLATFORM=openeuler_24_03 # openeuler_24_03 / openeuler_22_03 / kylin_v10 / centos7(仅x86_64)
PREFIX=usr_local # usr_local
wget https://github.com/lamess233/multi-platform-nginx-build-workflow/releases/download/${VERSION}/nginx-${VERSION}-${ARCH}-${PLATFORM}-${PREFIX}.tar.gz
tar -xzf nginx-${VERSION}-${ARCH}-${PLATFORM}-${PREFIX}.tar.gz -C /usr/local
解压到前缀对应的父目录(/usr/local),再按前文「部署」一节创建用户和systemd服务即可使用。