ARM架构离线部署Nginx实战:源码编译与国产系统适配指南

发布时间:2026/9/28 17:43:34
ARM架构离线部署Nginx实战:源码编译与国产系统适配指南 1. 为什么ARM架构下的离线部署值得单独写一篇搞过ARM服务器交付的人都有一个共识x86上装nginx是喝口水的事ARM上离线装nginx是啃硬骨头。我最近刚完成一个飞腾ARM64平台的交付项目客户环境完全隔离外网连内网yum源都没有只有一台跳板机能拷文件进去。这种场景下yum install nginx、apt install nginx全部失效必须走源码编译或者离线包安装的路子。这篇文章要解决的问题很具体在ARM架构aarch64/arm64的Linux服务器上没有任何外网连接的情况下把nginx完整跑起来。覆盖银河麒麟V10、统信UOS、AlmaLinux 9、Ubuntu ARM等常见国产和通用系统。适合谁看做信创交付的运维、需要在隔离环境搭反向代理的后端、以及手上有ARM开发板想跑Web服务的嵌入式玩家。核心难点其实不在nginx本身而在于三个坑编译工具链的ARM适配、第三方依赖库的离线获取、以及systemd服务在国产系统上的路径差异。这三个坑我在不同项目里各踩过至少两次下面把完整方案和踩坑记录都摊开讲。2. 部署方案选型源码编译还是离线RPM/DEB包2.1 两种路线的适用场景对比离线部署nginx本质上就两条路选错了会浪费大量时间。对比维度源码编译安装离线RPM/DEB包安装适用系统任意ARM Linux与打包系统严格一致依赖处理需手动编译pcre/zlib/openssl依赖包需一并下载版本控制完全自由受限于打包版本国产系统兼容最好麒麟/UOS的包难找编译耗时5-15分钟1分钟可定制模块完全可控固定我的建议很直接如果是银河麒麟、统信UOS这类国产系统走源码编译。原因很简单这些系统的ARM64仓库包版本老、依赖关系复杂你从别处下载的RPM大概率装不上报一堆libpcre.so.3 not found之类的错。而源码编译只要工具链齐全一次成功。如果是AlmaLinux 9或者Ubuntu 22.04 ARM这种通用发行版且能提前在同版本联网机器上yumdownloader或apt-get download把依赖包全部拉下来那离线包安装更快。2.2 源码编译方案的核心考量选源码编译绕不开三个依赖库PCRE正则表达式用于location匹配、zlibgzip压缩、OpenSSLHTTPS支持。这三个库在ARM上编译本身不难难的是版本匹配。我实测下来最稳的组合是nginx 1.24.x 或 1.26.x1.31.5这种高版本对OpenSSL 3.x要求严格国产系统自带的OpenSSL版本往往偏低pcre 8.45不要用pcre2nginx对pcre2的支持在部分版本有兼容问题zlib 1.2.13OpenSSL 1.1.1w如果系统自带OpenSSL 3.x且你不需要自定义可以--with-http_ssl_module直接链接系统的注意不要盲目追新版本。我在一个麒麟V10项目上用了nginx 1.27结果它默认要求OpenSSL 3.0而系统自带的是1.1.1编译直接报错。退回1.24.0后一次通过。2.3 交叉编译还是本地编译热词里出现了arm交叉编译这里要澄清一个常见误区如果你的目标机器本身就是ARM架构直接在目标机器上本地编译就行不需要交叉编译。交叉编译适用于x86开发机给ARM板子编译的场景比如你在x86笔记本上给树莓派编译。但生产交付场景下目标服务器就是ARM的本地编译最省事也避免了工具链配置的麻烦。只有一种情况需要交叉编译目标ARM设备性能太弱比如某些嵌入式板子只有512MB内存编译nginx会OOM。这时候才在x86机器上用aarch64-linux-gnu-gcc交叉编译。本文主要讲本地编译路线交叉编译会在第5节单独说。3. 离线环境的前置准备与依赖打包3.1 在联网机器上准备离线包这一步是整个流程的关键准备不充分到了现场就是干瞪眼。我习惯在一台与目标机器同架构、同系统版本的联网机器上操作。先确认目标机器的系统信息在目标机器上执行uname -m cat /etc/os-release gcc --versionuname -m输出aarch64就确认是ARM64。然后在一台同版本的联网ARM机器上或者用Docker跑一个同版本ARM容器下载所有需要的源码包mkdir -p /opt/nginx-offline/src cd /opt/nginx-offline/src # 下载nginx源码 wget https://nginx.org/download/nginx-1.24.0.tar.gz # 下载依赖库源码 wget https://sourceforge.net/projects/pcre/files/pcre/8.45/pcre-8.45.tar.gz wget https://zlib.net/fossils/zlib-1.2.13.tar.gz wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz如果你用的是Docker方式准备可以这样起一个ARM容器docker run --platform linux/arm64 -it --name nginx-prep arm64v8/ubuntu:22.04 bash提示用Docker准备离线包时容器的基础镜像版本要尽量和目标系统接近。glibc版本差异过大会导致编译出的二进制在目标机器上跑不起来。3.2 编译工具链的检查清单ARM机器上编译nginx工具链必须齐全。在目标机器上逐项检查# 检查编译器 which gcc g make gcc --version # 检查开发头文件 ls /usr/include/pcre.h 2/dev/null || echo pcre头文件缺失 ls /usr/include/zlib.h 2/dev/null || echo zlib头文件缺失 # 检查系统库 ldconfig -p | grep -E libpcre|libz|libssl如果gcc都没有那说明系统是最小化安装需要从系统安装镜像的Packages目录里找gcc、make、glibc-devel、kernel-headers这些RPM包。麒麟V10的话安装镜像里通常在/Packages目录下。我整理了一份最小工具链清单缺一不可gcc、g、make编译核心glibc-devel或libc6-devC库头文件kernel-headers内核头文件pkg-config部分依赖查找需要tar、gzip解压源码包3.3 目录规划与文件传输我习惯把离线部署的所有东西放在一个目录里方便打包拷贝/opt/nginx-offline/ ├── src/ # 源码包 │ ├── nginx-1.24.0.tar.gz │ ├── pcre-8.45.tar.gz │ ├── zlib-1.2.13.tar.gz │ └── openssl-1.1.1w.tar.gz ├── rpms/ # 系统依赖RPM包如有 ├── install.sh # 一键安装脚本 └── nginx.conf.template # 配置模板传输到隔离环境用U盘或者跳板机scp都行。如果是通过跳板机建议先tar czf nginx-offline.tar.gz nginx-offline/打包再传避免文件权限丢失。4. 源码编译安装nginx的完整实操4.1 依赖库的编译顺序与参数依赖库的编译顺序有讲究先pcre再zlib最后openssl。因为nginx编译时会按这个顺序查找虽然理论上可以并行编译但串行更稳。先编译pcrecd /opt/nginx-offline/src tar -zxvf pcre-8.45.tar.gz cd pcre-8.45 ./configure --prefix/usr/local/pcre make -j$(nproc) make install-j$(nproc)是并行编译ARM服务器核数多的话能省不少时间。--prefix/usr/local/pcre指定安装路径方便后面nginx编译时用--with-pcre指定。再编译zlibcd /opt/nginx-offline/src tar -zxvf zlib-1.2.13.tar.gz cd zlib-1.2.13 ./configure --prefix/usr/local/zlib make -j$(nproc) make installzlib的编译很快ARM上也就一两分钟。最后编译opensslcd /opt/nginx-offline/src tar -zxvf openssl-1.1.1w.tar.gz cd openssl-1.1.1w ./config --prefix/usr/local/openssl --openssldir/usr/local/openssl shared zlib make -j$(nproc) make install注意OpenSSL编译一定要加shared参数否则生成的是静态库nginx链接时会报错。zlib参数是让OpenSSL支持zlib压缩。ARM上OpenSSL编译比较慢-j$(nproc)能明显加速。4.2 nginx编译参数详解依赖库就绪后开始编译nginx。这一步的参数决定了nginx的功能和性能我逐个解释cd /opt/nginx-offline/src tar -zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0 ./configure \ --prefix/usr/local/nginx \ --sbin-path/usr/local/nginx/sbin/nginx \ --conf-path/usr/local/nginx/conf/nginx.conf \ --pid-path/usr/local/nginx/logs/nginx.pid \ --error-log-path/usr/local/nginx/logs/error.log \ --http-log-path/usr/local/nginx/logs/access.log \ --with-pcre/opt/nginx-offline/src/pcre-8.45 \ --with-zlib/opt/nginx-offline/src/zlib-1.2.13 \ --with-openssl/opt/nginx-offline/src/openssl-1.1.1w \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_gzip_static_module \ --with-http_stub_status_module \ --with-stream \ --with-threads \ --with-file-aio参数说明--with-pcre、--with-zlib、--with-openssl指向源码目录nginx会自己编译这些依赖不需要提前make install。这是最省事的方式避免库路径问题。--with-http_ssl_moduleHTTPS支持必加。--with-http_v2_moduleHTTP/2支持现代Web服务标配。--with-http_realip_module反向代理场景下获取真实客户端IP做代理必加。--with-http_gzip_static_module预压缩静态文件支持。--with-http_stub_status_module状态监控页面排查问题用。--with-stream四层代理支持代理数据库、MQTT等TCP服务用。--with-threads线程池支持高并发场景提升性能。--with-file-aio异步文件IOARM上对磁盘IO有优化。配置完成后会输出一个summary重点看这几行Configuration summary using PCRE library: /opt/nginx-offline/src/pcre-8.45 using OpenSSL library: /opt/nginx-offline/src/openssl-1.1.1w using zlib library: /opt/nginx-offline/src/zlib-1.2.13 nginx path prefix: /usr/local/nginx确认路径都对然后编译make -j$(nproc) make installARM服务器上nginx编译大概3-8分钟取决于CPU性能。编译完成后验证/usr/local/nginx/sbin/nginx -V会输出nginx版本和编译参数确认--with-http_ssl_module等模块都在。4.3 编译过程中的典型报错处理报错一./configure: error: the HTTP rewrite module requires the PCRE library这是pcre路径不对。检查--with-pcre指向的目录里是否有configure文件必须是源码目录不是安装目录。报错二objs/Makefile:xxx: recipe for target objs/src/core/ngx_murmurhash.o failed这种一般是gcc版本问题。ARM上某些老版本gcc对nginx源码的某些语法支持不好。解决办法是升级gcc或者在./configure时加--with-cc-opt-Wno-error忽略警告。报错三undefined reference to SSL_CTX_set_optionsOpenSSL链接问题。确认--with-openssl路径正确且OpenSSL编译时加了shared参数。如果还是不行检查系统里是否有多个OpenSSL版本冲突。5. 交叉编译场景的补充方案5.1 交叉编译工具链配置前面说了交叉编译只在目标机器性能太弱时才用。假设你在x86 Ubuntu上给ARM64目标编译需要先装交叉工具链sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu然后nginx的configure要指定交叉编译器./configure \ --prefix/usr/local/nginx \ --crossbuildLinux::aarch64 \ --with-ccaarch64-linux-gnu-gcc \ --with-cppaarch64-linux-gnu-g \ --with-pcre/path/to/pcre-8.45 \ --with-zlib/path/to/zlib-1.2.13 \ --with-openssl/path/to/openssl-1.1.1w \ --with-http_ssl_module \ --with-http_v2_module--crossbuild参数告诉nginx这是交叉编译它会调整一些平台相关的编译选项。5.2 交叉编译的依赖库处理交叉编译最麻烦的是依赖库也要用交叉工具链编译。pcre、zlib、openssl都要重新用aarch64-linux-gnu-gcc编译一遍# 以zlib为例 CCaarch64-linux-gnu-gcc ./configure --prefix/opt/arm64/zlib make make install三个库都编译到/opt/arm64/下然后nginx的--with-pcre等参数指向这些交叉编译后的目录。提示交叉编译出来的nginx二进制拷到目标机器后先用file命令确认架构是ARM aarch64再用ldd检查动态库依赖是否都能找到。经常出现的情况是目标机器glibc版本比编译机低导致GLIBC_2.xx not found。6. 系统集成systemd服务与开机自启6.1 创建systemd服务单元源码编译的nginx默认没有systemd服务需要手动创建。在/etc/systemd/system/nginx.service写入[Unit] Descriptionnginx - high performance web server Documentationhttps://nginx.org/en/docs/ Afternetwork-online.target remote-fs.target nss-lookup.target Wantsnetwork-online.target [Service] Typeforking PIDFile/usr/local/nginx/logs/nginx.pid ExecStartPre/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf ExecStart/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf ExecReload/bin/kill -s HUP $MAINPID ExecStop/bin/kill -s TERM $MAINPID PrivateTmptrue LimitNOFILE65535 [Install] WantedBymulti-user.target关键点说明Typeforkingnginx是守护进程模式必须用forking。PIDFile必须和nginx.conf里的pid路径一致否则systemd找不到进程。ExecStartPre启动前先测试配置配置有错直接拒绝启动避免带病运行。LimitNOFILE65535ARM服务器上默认文件描述符限制可能只有1024高并发下会报too many open files。6.2 国产系统的路径差异处理银河麒麟V10和统信UOS的systemd版本和标准CentOS略有差异主要注意两点第一After里的network-online.target在部分麒麟版本上不存在会报warning但不影响启动。如果追求干净可以改成Afternetwork.target。第二麒麟V10默认的LimitNOFILE在/etc/security/limits.conf里配置systemd服务里的LimitNOFILE优先级更高建议两处都配。配置完成后systemctl daemon-reload systemctl enable nginx systemctl start nginx systemctl status nginx6.3 防火墙与SELinux处理离线环境经常忽略防火墙。麒麟V10默认开firewalld需要放行端口firewall-cmd --permanent --add-port80/tcp firewall-cmd --permanent --add-port443/tcp firewall-cmd --reload如果系统开了SELinuxnginx访问非标准目录会报403。临时关闭setenforce 0永久关闭改/etc/selinux/config里的SELINUXdisabled。生产环境建议用setsebool精细配置但离线交付场景下临时关闭更省事。7. 反向代理与HTTPS配置实战7.1 反向代理核心配置nginx在ARM上最常见的用途就是反向代理。一个典型的代理配置upstream backend { server 127.0.0.1:8080 weight1 max_fails3 fail_timeout30s; server 127.0.0.1:8081 weight1 max_fails3 fail_timeout30s; keepalive 32; } server { listen 80; server_name app.example.com; location / { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 5s; proxy_read_timeout 60s; proxy_send_timeout 60s; } }几个关键点keepalive 32和后端保持长连接减少TCP握手开销。ARM服务器CPU性能相对弱长连接能明显降低负载。proxy_http_version 1.1配合Connection 启用HTTP/1.1长连接缺一不可。X-Real-IP和X-Forwarded-For后端获取真实客户端IP需要--with-http_realip_module支持。7.2 自签名证书配置HTTPS离线环境没法申请Lets Encrypt证书自签名是唯一选择。生成证书mkdir -p /usr/local/nginx/conf/ssl cd /usr/local/nginx/conf/ssl # 生成私钥 openssl genrsa -out server.key 2048 # 生成CSR openssl req -new -key server.key -out server.csr \ -subj /CCN/STBeijing/LBeijing/OCompany/CNapp.example.com # 自签名有效期3650天 openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crtnginx配置server { listen 443 ssl; http2 on; server_name app.example.com; ssl_certificate /usr/local/nginx/conf/ssl/server.crt; ssl_certificate_key /usr/local/nginx/conf/ssl/server.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; location / { root /usr/local/nginx/html; index index.html; } }注意ARM上OpenSSL的AES硬件加速取决于CPU是否支持AES指令集。飞腾和鲲鹏较新版本都支持openssl speed aes-128-gcm可以测一下。如果不支持HTTPS性能会明显下降建议在nginx里优先用ECDHE系列加密套件。7.3 配置校验与平滑重载每次改完配置先校验再重载/usr/local/nginx/sbin/nginx -t输出syntax is ok和test is successful才说明配置没问题。然后平滑重载/usr/local/nginx/sbin/nginx -s reload或者用systemdsystemctl reload nginx平滑重载不会断开现有连接生产环境必须用这种方式不要restart。8. 常见问题排查速查表8.1 启动类问题现象可能原因排查方法解决nginx: command not foundPATH未包含sbin目录echo $PATH用绝对路径或加软链bind() to 0.0.0.0:80 failed端口被占用ss -tlnp | grep :80杀掉占用进程或换端口nginx: [emerg] getpwnam(nginx) failednginx用户不存在id nginxuseradd -r nginxPermission denied非root启动低端口id用root或setcap授权8.2 运行类问题问题访问返回502 Bad Gateway这是反向代理最常见的错误。排查顺序后端服务是否存活curl http://127.0.0.1:8080SELinux是否拦截setenforce 0后重试防火墙是否放行后端端口nginx错误日志tail -f /usr/local/nginx/logs/error.log问题静态文件403 Forbidden九成是权限问题。nginx的worker进程以nginx用户运行需要确保chown -R nginx:nginx /usr/local/nginx/html chmod -R 755 /usr/local/nginx/html如果开了SELinux还需要chcon -R -t httpd_sys_content_t /usr/local/nginx/html问题ARM上nginx启动后CPU占用100%这个坑我在鲲鹏上遇到过。原因是nginx的worker_processes设成了auto但ARM服务器的CPU核数多比如128核nginx起了128个worker进程每个都在抢锁。解决办法是worker_processes设为CPU核数的一半或固定值配合worker_cpu_affinity绑定核心。8.3 性能调优参数ARM架构的nginx调优和x86有差异重点在这几个参数worker_processes 8; worker_cpu_affinity auto; worker_rlimit_nofile 65535; events { worker_connections 10240; use epoll; multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; }use epoll在ARM Linux上是默认的但显式写上更保险。multi_accept on让worker一次接受多个连接ARM上网络中断处理比x86慢这个参数能提升吞吐。9. 我踩过的几个真实坑第一个坑是glibc版本不匹配。我在一台Ubuntu 20.04 ARM上编译好nginx拷到麒麟V10上跑直接报GLIBC_2.34 not found。麒麟V10的glibc是2.28Ubuntu 20.04是2.31。后来改成在麒麟V10本机编译才解决。所以离线部署的铁律是在哪台机器跑就在哪台机器编译或者用同版本系统的机器编译。第二个坑是OpenSSL版本冲突。系统自带OpenSSL 1.1.1我又编译了一个OpenSSL 3.0到/usr/local/openssl结果nginx编译时链接到了3.0但运行时ldd找的是系统的1.1.1导致启动报SSL_CTX_new: symbol not found。解决办法是在/etc/ld.so.conf.d/下加一个openssl.conf指向/usr/local/openssl/lib然后ldconfig。第三个坑是systemd的PIDFile路径。nginx.conf里默认pid logs/nginx.pid是相对路径相对于--prefix。但systemd服务里写的是绝对路径/usr/local/nginx/logs/nginx.pid。如果nginx.conf里没改成绝对路径systemd会找不到PID文件systemctl stop会超时。改法是在nginx.conf里写pid /usr/local/nginx/logs/nginx.pid;。第四个坑是ARM上的内存对齐问题。某些ARM CPU对未对齐内存访问会触发异常nginx编译时如果没开-marchnative可能生成未对齐访问的代码。解决办法是在./configure时加--with-cc-opt-O2 -marchnative让编译器针对当前CPU优化。但注意-marchnative编译出的二进制不能跨CPU型号用交付场景下如果目标机器CPU型号不确定就别加。10. 离线部署包的制作与复用一套离线部署流程跑通后建议做成可复用的部署包。我的做法是写一个install.sh把编译、安装、配置、systemd注册全部串起来#!/bin/bash set -e NGINX_VERSION1.24.0 INSTALL_DIR/usr/local/nginx SRC_DIR/opt/nginx-offline/src # 检查是否已安装 if [ -f ${INSTALL_DIR}/sbin/nginx ]; then echo nginx已安装跳过 exit 0 fi # 编译依赖 cd ${SRC_DIR} for lib in pcre-8.45 zlib-1.2.13 openssl-1.1.1w; do if [ ! -d ${lib} ]; then tar -zxvf ${lib}.tar.gz fi done # 编译nginx cd ${SRC_DIR}/nginx-${NGINX_VERSION} ./configure --prefix${INSTALL_DIR} \ --with-pcre${SRC_DIR}/pcre-8.45 \ --with-zlib${SRC_DIR}/zlib-1.2.13 \ --with-openssl${SRC_DIR}/openssl-1.1.1w \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-stream \ --with-threads make -j$(nproc) make install # 注册systemd cp /opt/nginx-offline/nginx.service /etc/systemd/system/ systemctl daemon-reload systemctl enable nginx echo nginx离线部署完成这个脚本配合前面的目录结构拷到任何同架构同系统的ARM机器上都能一键部署。我在三个项目里复用了这套方案从准备到跑起来不超过30分钟。最后分享一个实用技巧如果目标机器连gcc都没有而你又不想装整个开发工具链可以用static方式编译nginx。在./configure时加--with-cc-opt-static和--with-ld-opt-static编译出的nginx二进制不依赖任何动态库拷过去就能跑。代价是二进制体积大大概10MB且OpenSSL的某些功能受限。这个方案适合嵌入式ARM板子不适合生产服务器。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询