本来在x86的CentOS上装nginx,我闭着眼睛都能装完。但这次是在麒麟KY10的aarch64架构上部署,开头我还是轻敌了,结果差点在依赖和配置上翻了车。折腾完这一轮,我把整个部署过程、配置思路和踩过的坑都整理出来,给正好要在麒麟系统上装nginx的朋友一个能直接抄作业的版本。
先交代一下背景:麒麟KY10,也就是银河麒麟V10,系统内核基于Linux,aarch64架构对应的是ARM64处理器,常见于鲲鹏、飞腾等国产芯片平台。很多人拿到这种环境后的第一反应是“这不就是个Linux嘛,照常装不就完了”,真这么想就天真了。默认软件源里可能压根没有nginx,就算有也可能因为架构、依赖版本不匹配装到一半卡死。与其等它出幺蛾子,不如直接采用源码编译的方式,把主动权抓在自己手里。这篇文章适合要在国产化服务器上部署web服务、搭建反向代理或者给内网业务做统一入口的运维、研发朋友参考,内容覆盖从环境准备、源码编译、systemd托管到常见坑位排查的全部过程。
1. 部署前要先想清楚的事
1.1 麒麟KY10 aarch64到底是一个什么环境
很多第一次接触麒麟系统的人会误以为它是个特殊系统,其实从技术底层看,它就是一个Linux发行版,内核、文件系统、网络栈这些和主流Linux一脉相承。KY10的aarch64版本专门跑在ARM64指令集的处理器上,常见的有华为鲲鹏920、飞腾FT-2000等。
但是有一个关键差异:软件生态的完整度。x86_64架构下的绝大多数二进制包可以直接拿来用,而aarch64架构下,很多软件要么得从源代码重新编译,要么得下载专门的arm64版本。nginx就是一个典型例子。你在x86服务器上习惯用的那种“直接yum install nginx”的方式,在KY10上往往会遇到找不到安装包、依赖冲突、或者干脆连epel源都不兼容的情况。
所以部署前第一件事就是放平心态,不要拿x86的经验硬套。先把系统的确切口味摸清楚,再决定用什么安装策略。我这次先跑了一条命令查看系统信息,后面所有操作都以这个为基础。
bash复制cat /etc/os-release
uname -a
输出里能看到系统版本为Kylin V10,内核如果是4.19或者相近的大版本,就说明这套基本环境是标准的。确认完架构是aarch64之后,直接放弃找现成rpm包的想法,走源码编译路线,目标更明确。
1.2 为什么选择nginx而不是其他Web服务
在麒麟系统上部署web服务,理论上有Apache、Tomcat、Caddy等一堆选择,但nginx在性能、资源占用和配置灵活度上占据明显优势。尤其对于aarch64这种强调并发和能效比的平台,nginx的异步事件驱动模型能把硬件的每一点性能都榨出来。
具体到我的场景,我需要一个既能把前端静态页面发布出去,又能作为后端API服务的反向代理入口,还要顺带承担负载均衡的角色。nginx一个工具就能把这三件事全部搞定,不需要再引入额外的组件。而且nginx配置文件的写法非常直白,就算后面换一台机器,配置迁移的成本也极低。
还有一个很实际的原因:nginx源码编译在aarch64架构下非常成熟,本身对ARM平台支持得很好,不像某些中间件需要打补丁才能跑。如果你们公司后续要做鲲鹏环境的信创适配,先把nginx这套链路跑通,相当于把最外围的web接入层打通了,后面接什么应用都顺很多。
提示:如果你只是临时起一个页面做测试,那就别折腾编译,直接python3 -m http.server 8080拉个临时服务就行。但要做正式的web入口、反向代理、负载均衡,nginx是不可跳过的第一步。
1.3 部署方案选型:RPM包还是源码编译
我原来在x86服务器上部署nginx,优先走的是发行版软件源,能用包管理器搞定的事情绝对不自己编译。但换到麒麟KY10 aarch64之后,这个思路必须调整。
先来看看几种安装方式的差别:
| 安装方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 软件源yum/dnf安装 | 命令简单,自动处理依赖 | KY10默认源不一定有nginx;版本普遍偏旧 | 对版本不敏感、内网有同步源 |
| 离线rpm包安装 | 安装速度快,可离线 | 依赖包需要手动收集,容易出现死循环依赖 | 完全内网隔离环境 |
| 源码编译安装 | 版本可控,功能可裁剪 | 编译时间长,依赖需自己装 | 生产环境、需要自定义模块 |
| 容器方式部署 | 环境隔离,交付一致 | 需要先装docker,内网镜像麻烦 | 已有容器平台 |
我的结论是:在KY10上做生产级nginx部署,源码编译是最稳妥的方案。虽然麻烦了一点,但可控性最高。不会因为系统源更新导致依赖突然崩掉,也能在configure的时候按需裁剪模块,去掉不需要的东西,让二进制的体积更精简、安全性更可控。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与依赖安装
2.1 检查系统版本与CPU架构
在动手安装前,先花一分钟确认环境信息。我见过不少翻车案例,都是因为环境没确认清楚就开始安装,最后发现系统版本和网上教程对不上,硬是浪费时间。
bash复制# 查看发行版信息
cat /etc/os-release
# 查看内核与架构
uname -a
# 查看CPU详情,确认芯片型号
lscpu | grep -E "Architecture|Model name|CPU\(s\)"
这里特别强调一下,lscpu里显示的Architecture必须是aarch64,这决定了后面所有依赖包的选择。如果你拿到的是x86_64的麒麟版本,那很多操作直接参考普通Linux教程即可,只有aarch64会有特殊的兼容性问题。确认完架构后,还要顺手确认系统有没有开启必要的网络通路。如果你处于内网隔离环境,后面下载源码包和依赖rpm就得提前准备好离线文件,避免卡在半路。
2.2 配置软件源与安装编译工具链
源码编译nginx最少要依赖几个基础组件:编译器、make工具、openssl、pcre、zlib的头文件。在麒麟系统上,这些依赖可以通过系统的包管理器装上。先检查一下当前有没有可用的yum源或者dnf源:
bash复制# 麒麟KY10一般自带yum源,先查看源状态
yum repolist
# 安装编译工具链及相关依赖
yum install -y gcc gcc-c++ make
yum install -y openssl-devel pcre-devel zlib-devel
有些精简版系统可能还没有net-tools和vim,一并装上会更顺手:
bash复制yum install -y net-tools vim wget tar
这里有一个官方依赖的原理解释:pcre是nginx用正则匹配location规则必须的库,如果没有它,配置里带有正则的路径匹配会直接报错;openssl在处理HTTPS证书和加密通信时是底层依赖;zlib则负责gzip压缩响应内容。三个缺一不可,别想着省事跳过。
如果你所在环境断网,没法直接yum安装,可以去内网镜像站把gcc、make、openssl-devel、pcre-devel、zlib-devel这几个包下载成rpm,然后用rpm -ivh逐个安装。依赖关系比较复杂时,可以用rpm -Uvh *.rpm一条命令统一安装,但要注意包之间的顺序。
2.3 下载Nginx源码并校验完整性
编译安装的版本选择,我建议直接上nginx稳定版。我这次用的是nginx 1.24.0,这个版本在aarch64上编译没有任何障碍,网上资料也多,出了问题也好查。
bash复制# 下载源码包
mkdir -p /opt/src && cd /opt/src
wget https://nginx.org/download/nginx-1.24.0.tar.gz
# 解压
tar -zxvf nginx-1.24.0.tar.gz
# 下载官方签名文件校验(可选但推荐)
wget https://nginx.org/download/nginx-1.24.0.tar.gz.asc
提示:如果wget下载提示证书不信任,可以先加--no-check-certificate参数跳过,但下载后建议对比一下压缩包的md5或sha256值,确保文件完整。在内网环境没有外网权限的话,可以直接从能上网的机器下载源码包,再用scp传过去。
3. 源码编译安装nginx
3.1 configure参数逐个说明
nginx的编译安装核心就是configure这一步。这一步决定了nginx会编译进哪些模块、安装到哪个目录、开启哪些内置功能。我命令行参数这么写:
bash复制cd /opt/src/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/run/nginx.pid \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-stream \
--with-stream_ssl_module \
--with-pcre
把每个关键参数说明一下,方便你按需增减:
- --prefix:指定安装根目录,后续所有文件都在这个目录下,卸载时直接删目录就行,不会污染系统。
- --with-http_ssl_module:启用HTTPS支持,没有这个模块,配置443端口和证书会直接报错。
- --with-http_v2_module:启用HTTP/2协议,对现代浏览器访问体验提升很大。
- --with-http_realip_module:后端获取客户端真实IP时要用,尤其是层级代理场景。
- --with-http_stub_status_module:提供nginx状态页,方便后面监控连接数、请求数。
- --with-stream:开启四层TCP/UDP转发能力,等于把nginx变成了一个通用负载均衡器。
- --with-pcre:显式启用正则库支持,防止某些系统上头文件位置特殊没有自动找到。
configure执行完后,最后几行会输出一段配置摘要,说明nginx二进制文件将安装在哪里、配置文件在哪里、支持的模块有哪些。如果这一步报错缺少依赖,通常只有两种情况:对应-devel包没装全,或者头文件路径没有找到。按提示补齐依赖再重新执行即可。
3.2 make编译常见的warning与处理
configure通过后,接下来就是经典的make和make install:
bash复制# 编译,-j后面的数字根据CPU核心数调整,比如4核就写4
make -j4
# 安装到指定目录
make install
编译过程中可能会出现一些warning,比如某些模块的类型转换提示、废弃函数提示,这些在绝大多数情况下不影响最终使用。真正需要关注的是error级别的报错,一旦出现error,make会直接终止。
我见过最多的error是缺openssl相关头文件,报错长这样:“/usr/include/openssl/ssl.h: No such file or directory”。排查方法很简单,先确认openssl-devel是否真的装上了:
bash复制rpm -qa | grep openssl
如果没有输出,就重新装依赖。确认装上还报错的,可能是头文件路径不在默认搜索路径里,可以用--with-openssl参数指定openssl源码目录来规避。
编译安装完成后,先在sbin目录下确认nginx可以正常找到:
bash复制/usr/local/nginx/sbin/nginx -V
这个命令会输出nginx版本号以及当时configure的编译参数,同时这也验证了二进制文件能正常运行在aarch64架构上。
3.3 注册为systemd服务
源码编译安装的nginx不会自动注册成服务,也就是说重启机器后nginx不会自己启动。这个问题必须解决,不能每次手动去拉进程。我采用systemd方式托管nginx服务。
创建systemd服务文件:
bash复制vim /usr/lib/systemd/system/nginx.service
内容如下:
ini复制[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/run/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=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
这里有几个细节值得提一下。Type=forking是因为nginx主进程启动后会fork出worker进程,systemd得通过pid文件判断主进程是否存活。所以nginx.conf里的pid配置路径必须和这里的PIDFile路径保持一致。ExecStartPre先执行nginx -t检查配置,如果有语法错误,服务启动会直接失败,避免带病上线。
设置好后,依次执行:
bash复制# 重新加载systemd配置
systemctl daemon-reload
# 启动nginx并设置开机自启
systemctl start nginx
systemctl enable nginx
# 查看运行状态
systemctl status nginx
看到active (running)的绿色状态,就说明服务托管这一步彻底完成。后面改配置只需要systemctl reload nginx就行,不会中断现有连接。
4. 配置文件拆解与三个实战场景
4.1 nginx.conf主配置逐段说明
nginx.conf是整个nginx的核心,初次看到这个文件的人容易头皮发麻,各种块级嵌套让人眼花缭乱。其实它的逻辑很清晰,从上到下可以拆成三大部分:全局块、events块、http块。我以一份精简后的配置为例:
nginx复制user nginx;
worker_processes auto;
events {
worker_connections 10240;
use epoll;
}
http {
include /usr/local/nginx/conf/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server_tokens off;
# gzip压缩
gzip on;
gzip_min_length 1k;
gzip_types text/plain text/css application/javascript application/json;
include /usr/local/nginx/conf/conf.d/*.conf;
}
这段配置里的关键点在以下几点:
worker_processes auto会让nginx按CPU核心数自动生成worker进程,在aarch64多核服务器上非常有用,不用手动数核心。worker_connections是每个worker进程能同时维持的最大连接数,10240在绝大多数场景下都够用。use epoll指定使用epoll事件模型,Linux环境下的最高效模型,不用手动改,但如果你看到它没生效就要查一下事件驱动库是否被正确编译。
gzip压缩我建议在HTTP层开启,特别是前端页面和接口返回JSON数据,压缩率非常可观,能省掉不少带宽。server_tokens off能隐藏nginx版本号,一定程度上规避针对特定版本的扫描攻击。
最核心的是最后一行include,我把所有具体server配置拆分到conf.d目录下,每个站点一个独立配置文件,互不干扰。这种拆分方式,在维护大量站点时能把你从找配置的深渊里拉回来。
4.2 场景一:部署一个前端静态站点
在conf.d目录下新建站点配置文件:
bash复制mkdir -p /usr/local/nginx/conf/conf.d
vim /usr/local/nginx/conf/conf.d/web.conf
nginx复制server {
listen 80;
server_name demo.example.com;
root /data/www/demo;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
access_log /var/log/nginx/demo.access.log main;
error_log /var/log/nginx/demo.error.log warn;
}
这个配置对前端项目非常友好,try_files会把所有不存在路径的请求回退到index.html,正好适配Vue、React这类单页应用的路由模式。静态资源路径不存在时会按顺序找$uri、$uri/目录下的index文件,最后兜底到/index.html。
如果直接把一个打包好的前端项目放到了/data/www/demo目录下,就能直接访问了。建议把log单独分开一个文件,方便后面排查问题时按站点过滤日志,不用在几百MB的access.log里大海捞针。
启动前先验证语法:
bash复制/usr/local/nginx/sbin/nginx -t
systemctl reload nginx
很多新手一开始就直接重启,忽略了reload和restart的区别。生产环境里我习惯用reload,它只重新加载配置,不会中断正在处理的请求,对线上的影响最小。
4.3 场景二:反向代理后端接口服务(网关)
反向代理是nginx使用频率最高的场景,也是我这次部署的主要目的。前端站点请求后端API、Java进程、Python进程,统统可以通过nginx统一收口,内部再转发到对应服务。
配置示例:
nginx复制server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://127.0.0.1:8080;
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 15s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}
location /status {
stub_status;
access_log off;
}
}
这段配置里的proxy_pass是最容易被坑的地方。如果你写的是http://127.0.0.1:8080,不带路径,那么请求会被原样转发到后端;如果你写的是http://127.0.0.1:8080/,带了末尾斜杠,那就意味着location匹配部分的路径会被替换掉。这里的区别网上有很多争吵,实际验证一下就知道,不搞清楚会造成接口404的诡异问题。
几个proxy_set_header头信息是反向代理的标配。X-Real-IP和X-Forwarded-For用于后端程序获取客户端真实IP,否则后端日志里看到的全部是127.0.0.1,排查问题的时候会想哭。X-Forwarded-Proto用于告诉后端当前是HTTP还是HTTPS,在某些重定向场景下很重要。
我还顺手加了一个/status的location,开启stub_status状态页。访问http://ip/status就能看到当前活跃连接数、总请求数等信息,用于日常巡检足够了。
4.4 场景三:负载均衡与健康检查
当后端业务从单实例扩展到多实例时,nginx就变成了负载均衡器。这个配置也不复杂:
nginx复制upstream backend_java {
server 192.168.10.11:8080 weight=3;
server 192.168.10.12:8080 weight=1;
keepalive 32;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend_java;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
upstream块定义了一组后端服务器,默认采用轮询策略。weight参数用来设置权重,weight=3表示这台机器会收到大约3倍于weight=1那台的流量。在异构机器上,性能强的机器权重给高一点,这是最常见的调优手段。
keepalive 32表示nginx到后端保持32个空闲的长连接,避免每次请求都重新握手,对后端压力能轻不少。nginx的负载均衡算法至少有轮询、加权轮询、ip_hash、least_conn四种,默认轮询就够了,如果遇到需要会话保持的需求,ip_hash可以保证同一IP的请求始终转发到同一台后端,适合没有做分布式session处理的老系统。
需要提醒的是,nginx这个upstream默认不带健康检查,后端某台机器挂了,nginx依然会把请求转发过去,直到连接超时才知道有问题。所以生产环境建议配合脚本定时探活,或者使用nginx商业版的开源替代模块,比如nginx_upstream_check_module,但那个需要重新编译nginx,这又是另一个话题了。
5. 性能调优与那些aarch64专属踩坑
5.1 常见问题排查速查表
在aarch64部署过程中,有些问题反复出现,我把常见的记下来,方便检索。
| 问题现象 | 可能原因 | 解决方式 |
|---|---|---|
| configure报错找不到pcre.h | pcre-devel未安装 | yum install -y pcre-devel |
| make报错找不到ssl头文件 | openssl-devel未安装 | yum install -y openssl-devel |
| nginx启动后访问页面卡死 | worker_connections太小或fd限制 | 调大worker_connections,修改limits.conf |
| 接口请求出现502 Bad Gateway | 后端服务未启动或假死 | 检查后端进程和端口,看error.log |
| 配置reload后新配置不生效 | 语法错误导致reload失败 | nginx -t检查,再systemctl reload |
| aarch64上某些模块编译error | 模块与架构不兼容 | 去掉报错模块,改用官方标准模块 |
排查问题有一条铁律:永远先看日志。nginx的error.log和access.log是最有价值的定位工具,不要一上来就瞎猜。
5.2 aarch64架构下容易栽跟头的地方
aarch64架构和x86架构整体上差异不大,但细节坑真的不少。
第一个坑是二进制兼容。有些直接下载的Linux amd64二进制在aarch64上根本无法执行,报错通常为Exec format error。所以从外部下载编译好的nginx包时,一定要认准arm64或aarch64标识,比如官方nginx里就有Linux/arm64的版本。
第二个坑是内存分配和优化。aarch64服务器上,如果系统内存较小,nginx的worker进程可能会因为load过大导致内存吃紧。建议在nginx.conf里开启静态模块裁剪,不用的模块就不要编译进去。我见过有人把nginx所有模块全编进去,编译出来二进制十几MB,白白占用内存。
第三个坑是CPU亲和性。aarch64多核服务器上,建议worker进程的数量按照物理核心数设置,而不是按逻辑线程数。可以先用lscpu确认核心数,避免单核场景下auto模式反而变成了超线程上的频繁切换,导致性能不升反降。
第四个坑比较隐蔽,就是TLS加密的硬件支持。aarch64的鲲鹏芯片自带KAE加速引擎,支持硬件加速RSA和加解密。如果你在部署HTTPS,想充分调用硬件加速,单纯的nginx编译版本还不行,得安装KAE相关的openssl引擎。这是性能调优的大杀器,但安装门槛高一些,属于进阶玩法,普通业务场景可以先不折腾。
5.3 压测与调优
部署完成后,建议做个简单的压力测试,确认nginx在aarch64上能扛住预期流量。最简单的压测工具是ab,装一下就能用:
bash复制yum install -y httpd-tools
# 并发100,共发10000个请求
ab -n 10000 -c 100 http://127.0.0.1/
压测时主要关注平均响应时间、失败率、吞吐量三个指标。如果失败率明显偏高,优先排查worker_connections是否太小。Linux默认的文件描述符限制是1024,当并发连接数上来后,要么放开系统的文件描述符限制,要么调大worker_connections:
bash复制# 修改系统最大文件句柄数
ulimit -n 65535
# 永久生效:写入limits.conf
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
还有内核层面的网络参数也值得关注:
bash复制# 查看当前的backlog队列长度
sysctl net.core.somaxconn
# 临时调大
sysctl -w net.core.somaxconn=1024
# 永久生效
echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
sysctl -p
优化完这几项,nginx在并发连接上的表现会有明显改善。当然压测只是验证手段,具体压到多少算达标,还得看实际业务模型和硬件资源。
5.4 几句实在的补充经验
最后聊几句我自己的实操体会。很多人拿到KY10 aarch64环境后,习惯搬运x86平台上的rpm包,结果遇到各种依赖地狱,一遍遍地装依赖,最后甚至把系统搞到不可用。建议不要这么操作,直接源码编译省心得多。
还有一点关于配置管理的习惯。我推荐把所有server配置按域名拆分成独立文件放到conf.d目录下,每新增一个站点就新增一个conf文件。这样不会在几百行的nginx.conf里迷失方向,也便于做版本管理。如果你们团队有配置中心,甚至可以把nginx.conf模板化,通过自动化工具下发。
再提醒一个安全习惯:如果nginx只用于内网服务,建议默认别开80端口对外开放,用防火墙只放行必要的来源IP。Linux防火墙命令在麒麟系统上同样有效:
bash复制# 开放8080端口(按需调整)
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
我最初忘了配防火墙,nginx启动后外网一直访问不通,查了半天才发现是防火墙拦截了端口,这个问题在真实环境里太常见了。
整套操作下来,nginx在麒麟KY10 aarch64上的部署链路已经很清晰了:环境确认、源码编译、systemd托管、站点配置、压测调优,每一步都有章可循。真正干起来,最快一小时内可以把一套生产可用的nginx拉起来。如果你正好也在这个平台上折腾nginx,希望这篇能帮你省下我踩过的那些坑。
