☰
CentOS 7.9 离线部署 LNMP 实战:本地源构建与依赖完整性校验
2026/10/26 5:26:39 网站建设 项目流程

1. 为什么离线部署LNMP值得单独拿出来讲

搞过内网交付的人都有一个共识:能联网的环境里装LNMP,一条包管理命令的事;一旦进了没有外网出口的机房,同样一套东西,难度直接翻好几倍。centos7.9离线部署LNMP这个标题,说的就是在完全断网或者只开放极少数端口的CentOS 7.9服务器上,把Linux、Nginx、MySQL、PHP这套经典Web运行环境从零搭起来。它解决的核心问题不是"怎么装软件",而是"在没有网络的情况下,怎么把依赖关系、软件包、配置、服务启动这一整条链路走通"。

这套东西适合谁看?一类是做内网项目交付的运维和实施人员,客户机房物理隔离,机器搬进去就出不来;一类是负责等保、专网、生产隔离区环境搭建的工程师;还有一类是想在自己实验室或测试环境里复现一套可控Web栈的开发者。哪怕你只是想在虚拟机上练手,把离线流程走一遍,对理解RPM依赖、systemd服务管理、PHP与Nginx的通信机制都有实打实的帮助。

我先说清楚一个前提:CentOS 7.9已经在2024年6月30日停止维护,官方源和镜像站陆续下架,这恰恰让"离线部署"从可选项变成了必选项——你没法再指望在线yum install了,所有包必须提前准备好。这也是为什么这个话题最近被反复提起。下面我按实际交付的顺序,把整套流程拆开讲,包括我踩过的坑和几个能省半天时间的技巧。

2. 整体方案设计与离线物料准备

2.1 为什么选"本地源+离线RPM"而不是源码编译

离线装LNMP有两条路:源码编译和RPM离线源。很多人第一反应是源码编译"更可控",但我实际交付下来,除非客户明确要求特定版本或需要打补丁,否则优先选RPM离线源。原因很直接:源码编译要处理gcc、make、cmake、各种-devel包,这些依赖本身在离线环境里就是一堆麻烦;而且编译参数一旦记错,排查成本极高。RPM方案的优势是依赖关系由yum的本地仓库自动解析,装完即用,systemd服务单元也是现成的。

具体做法是:在一台能联网、且系统版本与目标机完全一致的CentOS 7.9机器上(这点极其重要,版本不一致会导致glibc依赖对不上),用yumdownloader或reposync把Nginx、MySQL、PHP及其全部依赖下载下来,打包成一个本地仓库目录,拷到目标机后配置local.repo指向它。这样目标机上执行yum install时,yum会从这个本地目录解析依赖,效果和在线一模一样。

注意:准备物料的机器和目标机必须是同一小版本(都是7.9),架构一致(都是x86_64)。我见过用7.6的机器准备包,结果目标机7.9上glibc版本不匹配,装到一半报依赖冲突,只能重来。

2.2 离线物料清单与目录规划

物料准备阶段我习惯按下面的结构组织,拷过去之后一目了然:

目录内容说明
/opt/offline/rpm-repo所有RPM包及repodata本地yum源根目录
/opt/offline/softNginx/MySQL/PHP安装包若用官方二进制包则放这里
/opt/offline/conf预置配置文件nginx.conf、my.cnf、php.ini
/opt/offline/scripts部署脚本初始化、启动、校验脚本

软件版本选择上,CentOS 7.9自带的PHP是5.4,太老,实际项目基本都要7.x。我的常规组合是:Nginx 1.20+、MySQL 5.7或8.0、PHP 7.4。这里有个关键决策点——PHP 7.4在CentOS 7上需要额外启用remi源或epel源来获取,所以准备物料时要把这些源的包一起down下来。MySQL 8.0对glibc要求较高,如果目标机是很老的硬件环境,5.7更稳妥。

物料下载的核心命令(在联网准备机上执行):

# 安装下载工具 yum install -y yum-utils createrepo # 创建仓库目录 mkdir -p /opt/offline/rpm-repo # 下载nginx、mysql、php及其依赖(--resolve 解析全部依赖) yumdownloader --resolve --destdir=/opt/offline/rpm-repo \ nginx mysql-server php php-fpm php-mysql php-gd php-mbstring # 生成repodata索引 createrepo /opt/offline/rpm-repo

--resolve这个参数是灵魂,它会把依赖树整个拉下来,少了它你到目标机上必然缺包。下载完用createrepo生成索引,目标机的yum才能识别这是一个合法仓库。

2.3 依赖完整性的预校验思路

物料拷到目标机之前,我强烈建议先在准备机上做一次"模拟安装"校验。方法是在准备机上临时把本地源配好,执行yum install --downloadonly或者干脆yum deplist看依赖是否齐全。更彻底的做法是找一台干净的同版本虚拟机,断网后实际装一遍,能装通再往客户现场搬。这一步花半小时,能避免现场抓瞎两小时。

还有一个容易被忽略的点:SELinux和防火墙。CentOS 7.9默认SELinux是enforcing,离线环境下如果没提前处理,Nginx访问PHP文件、MySQL写数据目录都可能被拦。我的做法是部署脚本里统一把SELinux设为permissive(setenforce 0并改配置文件),防火墙按需放行80/443/3306,而不是等到出问题再回头查。这个决策的理由是:内网交付环境通常已有边界防护,主机层再叠一层SELinux规则,排查成本远大于收益。

3. 核心组件安装与配置细节拆解

3.1 本地yum源的落地配置

目标机上第一步是把本地源配起来。把/opt/offline/rpm-repo整个目录拷到目标机同路径,然后新建/etc/yum.repos.d/local.repo:

[local] name=Local Offline Repo baseurl=file:///opt/offline/rpm-repo enabled=1 gpgcheck=0

gpgcheck=0是因为离线包通常没导入GPG key,关掉校验避免报错。配好后执行yum clean all && yum makecache,如果能看到仓库元数据加载成功,说明源通了。这里有个细节:如果目标机原来配了在线源,建议把/etc/yum.repos.d/下其他repo文件临时改名或移走,否则yum会尝试连外网,超时拖慢整个安装过程。

提示:yum makecache报"repodata不存在"时,八成是createrepo没执行或者目录层级不对。baseurl指向的必须是包含repodata子目录的那一层。

3.2 Nginx安装与关键配置项

源通了之后,yum install -y nginx基本一路顺风。装完先别急着启动,几个配置项要提前改。Nginx默认的nginx.conf里user是nginx,worker_processes是1,生产环境我一般改成worker_processes auto,让它按CPU核数自动分配。worker_connections默认1024,内网高并发场景可以提到4096。

真正影响LNMP联动的是location ~ \.php$这一段。默认配置里fastcgi_pass指向127.0.0.1:9000,这要求PHP-FPM监听9000端口。我倾向于保持TCP监听而不是unix socket,原因是跨进程排查时ss -lntp能直接看到端口状态,比查socket文件直观。对应的PHP-FPM配置在/etc/php-fpm.d/www.conf,要确认listen = 127.0.0.1:9000,user和group与Nginx保持一致(都是nginx),否则会出现权限拒绝导致502。

fastcgi_param SCRIPT_FILENAME这一行必须指向$document_root$fastcgi_script_name,这是Nginx把PHP文件路径传给PHP-FPM的关键。很多"PHP页面返回空白或下载文件"的问题,根源就是这行配错或者被注释掉了。

3.3 MySQL初始化与安全配置

yum install -y mysql-server装完后,CentOS 7上MySQL 5.7/8.0首次启动会自动初始化数据目录。启动命令systemctl start mysqld,然后从日志/var/log/mysqld.log里找临时root密码(8.0才有,5.7默认空密码)。拿到后执行mysql_secure_installation改密码、删匿名用户、禁止root远程登录。

这里有个离线环境特有的坑:mysql_secure_installation的密码强度策略在8.0里默认是MEDIUM,要求大小写数字符号齐全,随便设个简单密码会报错。如果项目允许,可以在my.cnf里加validate_password.policy=LOW降低要求,但生产环境我不建议这么干,老老实实设个复杂密码更省心。

数据目录权限也要留意:/var/lib/mysql的属主必须是mysql用户,如果之前有人手动改过权限,启动会失败。字符集方面,my.cnf里加上character-set-server=utf8mb4和collation-server=utf8mb4_general_ci,避免中文乱码——这是国内项目的高频需求,提前配好省得后面改表。

3.4 PHP-FPM与扩展的联动

PHP装完核心包后,php-fpm服务要单独启动。扩展方面,php-mysql(连接MySQL)、php-gd(图像处理)、php-mbstring(多字节字符串)、php-xml基本是标配,物料准备阶段就要一起down下来。装完用php -m确认扩展加载,用php -v确认版本。

PHP-FPM的进程管理参数值得调一调。pm = dynamic配合pm.max_children、pm.start_servers这几个值,默认配置偏保守。内网小项目max_children设20-30够用,具体按内存估算:每个PHP进程约占30-50MB,max_children乘以单进程内存不能超过可用内存的70%。这个计算过程很多人跳过,结果并发一上来就OOM。

Nginx和PHP-FPM都起来后,在web根目录放一个info.php(内容<?php phpinfo(); ?>),浏览器访问验证。能出页面说明整条链路通了;出502说明PHP-FPM没起或端口不对;出403说明权限或SELinux问题;直接下载文件说明Nginx没把php交给FPM处理。这四种现象基本覆盖了90%的联动故障,记住这个对照关系排查效率极高。

4. 完整实操流程与现场记录

4.1 从零到服务可用的执行顺序

我把整个部署拆成可脚本化的阶段,实际现场按这个顺序走,每步都有校验点:

  1. 系统基线检查:cat /etc/redhat-release确认7.9,uname -m确认x86_64,getenforce看SELinux状态,systemctl status firewalld看防火墙。这一步是防止在错误的环境上白干。
  2. 物料落地:拷贝/opt/offline目录,校验文件完整性(md5sum对比准备机生成的清单)。
  3. 本地源配置:写local.repo,yum clean all && yum makecache,yum repolist确认local源可见。
  4. 组件安装:yum install -y nginx mysql-server php php-fpm php-mysql php-gd php-mbstring,观察是否有依赖报错。
  5. 配置下发:把预置的nginx.conf、my.cnf、www.conf覆盖到对应位置。
  6. 服务启动与开机自启:systemctl enable --now nginx php-fpm mysqld。
  7. 联动验证:放info.php,curl -I http://127.0.0.1/info.php看返回200。
  8. 安全收尾:mysql_secure_installation,清理测试文件,SELinux置permissive。

这个顺序的关键在于"先校验环境再动手",以及"配置先于启动"。我见过先启动服务再改配置,结果改完忘了reload,排查半天以为是配置没生效。

4.2 关键配置文件的实操内容

Nginx的server块我通常这样写,直接可抄:

server { listen 80; server_name _; root /var/www/html; index index.php index.html; location / { try_files $uri $uri/ =404; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }

try_files这行保证静态文件找不到时返回404而不是把请求漏给PHP,安全性和性能都更好。server_name _表示匹配所有域名,内网IP访问场景够用。

PHP-FPM的www.conf关键几行:

listen = 127.0.0.1:9000 user = nginx group = nginx pm = dynamic pm.max_children = 30 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 10

pm.max_children = 30是按一台4GB内存机器估的,30乘40MB约1.2GB,留足余量。这个值不是拍脑袋,是"可用内存×0.7÷单进程内存"算出来的,你可以按自己机器调整。

MySQL的my.cnf最小可用配置:

[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock character-set-server=utf8mb4 collation-server=utf8mb4_general_ci max_connections=200

max_connections=200对中小项目足够,调太高反而占内存。字符集两行是中文项目的刚需。

4.3 服务自启与开机验证

systemctl enable --now一条命令同时完成开机自启和立即启动,比先enable再start省事。三个服务都起来后,systemctl status nginx php-fpm mysqld逐个确认active (running)。然后做一次重启验证——reboot之后再看三个服务是否自动起来。这一步很多人省略,结果交付后客户一断电重启,服务全挂,现场尴尬。重启验证是离线交付的必做项,别偷懒。

重启后如果某个服务没起来,journalctl -u 服务名 -n 50看最近日志,八成是配置语法错误或者依赖服务没起(比如PHP-FPM依赖网络就绪)。nginx -t可以单独校验Nginx配置语法,这个命令在改完配置后养成习惯执行一下。

5. 常见问题排查与避坑经验实录

5.1 高频故障速查表

现象可能原因排查命令解决
yum报无法解析依赖物料缺包或repodata未生成yum deplist 包名回准备机补down,重新createrepo
访问PHP返回502PHP-FPM未启动或端口不符ss -lntp | grep 9000启动php-fpm,核对listen配置
访问PHP返回403文件权限或SELinuxls -lZ 文件chmod/chown,setenforce 0
访问PHP直接下载Nginx未匹配php locationnginx -T看配置补location ~ .php$段
MySQL启动失败数据目录权限或残留锁tail /var/log/mysqld.log修属主,清ib_logfile重试
中文乱码字符集未设utf8mb4show variables like 'char%'改my.cnf重启

这张表是我这些年现场排查沉淀下来的,覆盖了绝大多数情况。遇到问题先对号入座,比盲目翻日志快得多。

5.2 几个只有踩过才知道的坑

第一个坑:yum makecache成功但yum install仍报找不到包。这种情况通常是包名写错,或者包在子目录里而repodata没递归索引。createrepo默认只索引当前目录,如果RPM分散在子目录,要加-g或者把包都挪到同一层。我现在的习惯是物料目录扁平化,所有rpm放一层,省得索引出问题。

第二个坑:PHP-FPM启动报"Address already in use"。9000端口被占,可能是之前装过别的PHP或者有残留进程。ss -lntp | grep 9000找到占用进程,kill掉再启动。如果确实有别的服务要用9000,就改PHP-FPM的listen端口,同时同步改Nginx的fastcgi_pass,两边必须一致。

第三个坑:MySQL 8.0在离线环境初始化卡住。8.0首次启动初始化数据目录耗时较长,如果机器IO慢,systemctl start mysqld可能超时被systemd判定失败。这时候别急着重装,journalctl看日志,如果还在初始化就等它跑完,或者调大TimeoutStartSec。我遇到过一次,等了近两分钟才初始化完,差点误判。

第四个坑:SELinux导致的"玄学"权限问题。文件权限明明对,Nginx就是读不了。ls -Z看安全上下文,/var/www/html下的文件上下文应该是httpd_sys_content_t。离线环境不方便装semanage工具,最省事的办法就是setenforce 0并改/etc/selinux/config为permissive,重启生效。这个决策前面提过,内网环境权衡下来是合理的。

5.3 交付前的自检清单

现场交付前我固定跑一遍这个清单,逐项打勾:

  • 三个服务systemctl is-enabled都是enabled
  • 重启后三个服务自动起来
  • curl -I http://127.0.0.1/返回200
  • info.php能正常显示PHP信息
  • MySQL能用业务账号登录并建库
  • 防火墙放行了业务端口
  • 测试文件已清理,root密码已改

这个清单看着简单,但每一条都对应过一次真实的翻车。尤其是"重启验证"和"测试文件清理",前者防交付后掉链子,后者防信息泄露。清单化执行,比凭记忆靠谱。

6. 我个人在离线交付中的几点体会

离线部署LNMP这件事,技术门槛其实不高,难在"没有退路"——在线环境出问题可以搜、可以重装,离线环境里每一步都得提前想清楚。我最大的体会是:物料准备的完整性决定了现场效率的上限。准备阶段多花一小时把依赖拉全、在干净虚拟机上预演一遍,现场就能少折腾半天。反过来,物料缺一个包,现场可能就要打电话回公司让人远程传文件,尴尬又低效。

另一个体会是配置的"预置化"。把nginx.conf、my.cnf、www.conf这些提前写好放在conf目录,现场直接覆盖,比现场手敲靠谱得多。手敲容易漏行、错字符,覆盖则是一次性的、可复现的。配合部署脚本,整套流程能压缩到二十分钟以内。

最后分享一个小技巧:物料目录里放一个README,写清楚每个包的版本、来源、下载日期,以及部署步骤和回滚方法。这东西平时没人看,但半年后别人接手或者自己回头维护时,它就是救命文档。离线环境最怕的就是"当时怎么装的没人记得",一份简单的记录能省掉大量考古时间。这套流程我用了很多次,每次微调一点点,现在基本能做到一次到场、一次装通。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询