RHCE考试里有一类题,几乎是每次必考的:给一台全新系统配好一个能用的 nginx Web 服务器。说实话,这道题本身不算难,但它考核的东西很杂——从软件源、服务管理、防火墙到 SELinux 文件标签,再到虚拟主机、TLS 加密、PHP 动静分离,任何一个环节断了,最终 curl 出来的结果就不对。我也帮不少同事复盘过挂科原因,发现绝大多数人不是不会写 server 块,而是死在"配置写对了,但服务就是访问不了"这种环境类问题上。这篇文章就把我在实际备考和真实运维中积攒的 nginx 部署经验完整过一遍,从零开始搭一个经得起功能验证的 Web 服务器。
不管你是正在准备 RHCE 的考生,还是已经被 Windows Server 或 httpd 习惯束缚、想换个思路理解 Web 服务的运维同学,这篇文章的目标都一样:看完之后,你能在任何一台 Red Hat 系系统上,按一套稳定的流程把 nginx 配到"评分环境下挑不出毛病"的程度。
1. 从考试大纲到生产环境:为什么 nginx 能成为 RHCE 的常驻题目
RHCE 考的不是"会不会背配置",而是"能不能在受限环境里独立完成一次服务交付"。nginx 这类轻量级 Web 服务之所以常驻考题,背后是有逻辑的。
1.1 nginx 与 httpd 的定位差异
很多老运维的第一反应是:Red Hat 系自带 httpd,为什么 RHCE 还要专门考 nginx?答案其实很简单——考试要模拟的是现代企业里最常见的真实需求。nginx 在高并发静态资源、反向代理、负载均衡领域的占有率现在非常高,很多公司的新项目直接就上 nginx,反而 httpd 变成了遗留系统。RHCE 紧跟这个趋势,用 nginx 来考察你对 Web 服务原理的理解,比单纯考察 httpd 的配置文件更贴近实际。
另外一个关键原因是:nginx 的配置模型和 httpd 差异很大,能有效考察考生是否真正理解 Web 服务的工作机制,而不是死记硬背。比如 httpd 用"目录级别配置"(Directory、Location 等容器),nginx 用"location 块 + 正则匹配",匹配优先级完全不一样。你要是带着 httpd 的思路套 nginx,很容易写出诡异的配置。
1.2 RHCE 评分机制决定了"功能验证"比其他都重要
我在备考时专门研究过 RHCE 的评分方式。它不是"你写了这个配置就给分",而是通过实际访问、实际命令去检测服务功能是否正常。也就是说,评分脚本会像真实用户一样访问你的网站,检查 HTTP 状态码、响应内容、TLS 证书、虚拟主机匹配结果。这带来一个非常重要的结论:配置写得再规范,如果用户实际访问不到,等于零分。
所以整篇文章所有的操作,我都会围绕"最终功能是否可被外部验证"来展开。你在自己练习时也应该这样要求自己:每完成一步,就用 curl 或浏览器去实测,而不是看一眼配置文件觉得对就算完。
1.3 一套稳定的交付流程比单个知识点重要
我把 nginx 部署拆成一条流水线:
- 安装与源选择
- 服务管理(启动、开机自启)
- 网络层放行(firewalld)
- 文件层权限(SELinux 标签、属主属组)
- 配置虚拟主机/站点目录
- TLS 加密与访问控制
- PHP 动静分离(如果需要)
- 最后用功能验证命令做收尾
这套流程我在多台系统上重复过几十次,几乎没有翻过车。接下来就按这个顺序来。
2. 安装与初始环境:选对源,后面的坑少一半
2.1 RHEL 基础仓库里没有 nginx,必须配 EPEL
先记住一件事:在 RHEL 9 / RHEL 10 这类系统上,默认仓库是不包含 nginx 的。很多考生第一次练习时直接dnf install nginx,然后就收到 "Unable to find a match: nginx" 的报错,心态当场就崩了。
正确的做法是先安装 EPEL 源:
dnf install -y epel-release dnf makecache dnf install -y nginx如果你更喜欢 nginx 官方源,也可以额外配置官方仓库来安装。大多数情况下 EPEL 源就够了,它提供的是稳定版 nginx。装完之后用下面命令确认版本和安装路径:
nginx -v rpm -ql nginx | head -20你要重点确认/etc/nginx/nginx.conf和/etc/nginx/conf.d/这个目录存在。因为 nginx 主配置里有这么一行:
include /etc/nginx/conf.d/*.conf;这就是说,我们给每个站点写独立配置文件放进conf.d/,主配置会自动加载。这个设计非常干净,也是 RHCE 阅卷时比较认可的做法。
2.2 安装 nginx 后第一时间应该做的基础操作
装完 nginx 后,我建议立刻做三件事:
- 启动并设置开机自启:
systemctl enable --now nginx systemctl status nginx如果你发现 status 显示 failed,别急着怀疑配置文件,先看端口有没有被占用:ss -tlnp | grep -E ':80|:443'。
- 本机验证默认欢迎页:
curl http://127.0.0.1/如果能看到 nginx 默认欢迎页,说明服务本身没毛病,后面所有问题都只可能出在网络、端口、SELinux 或配置细节上。
- 备份原始配置:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak别小看这个备份,真实环境里改错了配置要回滚,没有备份就只能凭记忆恢复,那种痛苦经历过一次就懂了。
2.3 firewalld 与 SELinux 的初始状态处理
RHCE 考试环境的 SELinux 默认是 enforcing,firewalld 默认是开启的。这两个机制如果你一开始没处理好,后面 curl 通不通完全是玄学。
先看防火墙:
firewall-cmd --state firewall-cmd --list-all如果没放行 http 服务,curl 本机可能正常,但从外部访问就超时。放行命令:
firewall-cmd --add-service=http --permanent firewall-cmd --reload firewall-cmd --list-all | grep http--permanent参数必须加,否则重启后规则就没了。同理如果后面你要开 443 端口、8443 端口或自定义端口,也要通过firewall-cmd --add-port=8443/tcp --permanent这种方式放行。
SELinux 这块很多人会忽略。简单解释:SELinux 是一个强制访问控制层,即使文件权限是 644、属主是 nginx,只要文件的安全上下文不对,nginx 依然没有权限读取它。nginx 进程在 SELinux 里跑在httpd_t域,所以它要读的站点文件必须被打上httpd_sys_content_t标签。我们用标准路径时系统会自动打标签,但如果你自己 mkdir 了一个新目录放站点文件,SELinux 上下文默认可能是default_t,nginx 就读不了。
最经典的排错姿势是看日志:
ausearch -m AVC -ts recent如果看到大量avc: denied记录,基本就是 SELinux 在拦截。处理办法有两种:
# 方式一:临时改变(只影响该文件或目录) chcon -R -t httpd_sys_content_t /var/www/web1 # 方式二:写入策略,持久生效(更推荐) semanage fcontext -a -t httpd_sys_content_t "/var/www/web1(/.*)?" restorecon -Rv /var/www/web1注意:非 80/443 的标准端口也需要额外放行,比如你让 nginx 监听 8080:
semanage port -a -t http_port_t -p tcp 8080不添加这条,nginx 启动时会直接报bind() to 0.0.0.0:8080 failed (13: Permission denied)。
3. 虚拟主机与文档根目录:RHCE 实操题的主线得分点
RHCE 关于 nginx 的题目里,最常出现的就是:基于某台服务器配置两个 Web 站点,各自监听不同端口或用不同域名访问,要求返回不同的页面内容。这背后考的就是 nginx 虚拟主机机制。
3.1 server_name 匹配规则与 default_server
nginx 虚拟主机的核心是一个个server块。请求进来后,nginx 会根据监听端口和server_name选择一个 server 块处理。匹配规则是:
- 精确匹配优先;
- 通配符匹配(如
*.example.test); - 正则匹配(如
~^www\.\d+\.example\.test$); - 如果都没有匹配,则使用
default_server。
default_server的概念特别重要,它表示"这个端口上未匹配任何 server_name 的请求都交给这个块处理"。很多 RHCE 题的坑就在这里:你配置了两个站点,但第二个站点的 server_name 写错了,结果所有访问都落到了第一个站点上。
一个典型的虚拟主机配置长这样:
# /etc/nginx/conf.d/web1.conf server { listen 80; server_name web1.example.test; root /var/www/web1; index index.html; } # /etc/nginx/conf.d/web2.conf server { listen 80; server_name web2.example.test; root /var/www/web2; index index.html; }如果你需要让"任何未匹配域名的访问都落到某个默认站点",可以在该 server 块里写listen 80 default_server;。这个写法在很多评分环境里是送分点,但也最容易忘。
3.2 站点目录的规划与索引页面
站点文件放在哪里,RHCE 不会硬性规定,但我的建议是统一放在/var/www/<站点名>/下。这样结构清晰,后续打 SELinux 标签也方便。创建目录并写入测试页:
mkdir -p /var/www/web1 echo '<h1>Welcome to web1</h1>' > /var/www/web1/index.html如果你想模拟一个稍微真实点的站点,可以放一个完整的 HTML 文件进去。但考试和练习环境下,一个能让 curl 明确区分站点的测试页就够了。关键在于:你的 index.html 内容必须能让你一眼看出当前访问的是哪个站点,否则后续验证时分不清对错。
目录权限也要注意。nginx 的 worker 进程以 nginx 用户运行,所以站点目录至少需要others可读、可执行权限,也就是 755:
chown -R root:root /var/www/web1 chmod -R 755 /var/www/web1如果图省事把属主直接设为 nginx 也行,但chmod 755别丢,否则首页文件本身不可读,curl 回来就是 403。
3.3 从"评分视角"验证虚拟主机
配置写完必须走一遍语法检查:
nginx -t只有syntax is ok和test is successful都出现,才能重载服务:
systemctl reload nginx然后模拟评分脚本去请求:
curl -H "Host: web1.example.test" http://127.0.0.1/ curl -H "Host: web2.example.test" http://127.0.0.1/如果配置正确,两个请求会返回不同内容。如果你用内网 IP 访问,也应该能正常返回:
curl http://192.168.x.x/ -H "Host: web1.example.test"RHCE 评分环境里,评分脚本很可能就是从别的机器带上 Host 头来访问你的 IP。所以你不仅要保证本地 curl 通,还要保证防火墙放行了、服务在启动状态、开机自启已打开。这三点少了任何一个,功能验证都过不了。
4. TLS 加密站点:自签证书、443 监听与跳转规则
RHCE 关于 nginx 的考题里,TLS 加密站点是进阶题型。它往往和虚拟主机混合出现,要求某个站点支持 HTTPS 访问,或者把 HTTP 请求强制跳转到 HTTPS。这个考点其实不难,但步骤多,一步做错就白搭。
4.1 生成自签证书前需要想清楚的几件事
考试环境一般不会给你现成的证书,而是要求考生自己生成自签名证书。命令如下:
mkdir -p /etc/nginx/ssl openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/nginx/ssl/web1.key \ -out /etc/nginx/ssl/web1.crt \ -subj "/CN=web1.example.test"关键参数的含义:
-x509:生成自签名证书文件;-nodes:不对私钥加密,这样 nginx 启动时不用输入密码,否则 systemd 启动时会卡住;-days 365:证书有效期;-subj:主题信息,CN要和站点域名一致。
有些同学会问,CN写错了影响大吗?如果评分脚本是curl -k忽略证书校验去看返回内容,那 CN 不对也能通过;但如果评分脚本校验证书主机名,CN 就必须匹配。保险起见,CN 一定写成你配置的 server_name。
私钥文件权限建议设置成 600,这个习惯在真实生产环境里很重要:
chmod 600 /etc/nginx/ssl/web1.key4.2 配置 TLS server 块与 HTTP 强制跳转
在/etc/nginx/conf.d/web1-ssl.conf里写入:
server { listen 443 ssl; server_name web1.example.test; root /var/www/web1; index index.html; ssl_certificate /etc/nginx/ssl/web1.crt; ssl_certificate_key /etc/nginx/ssl/web1.key; ssl_protocols TLSv1.2 TLSv1.3; }如果要让 http 自动跳转到 https,可以在另一个 server 块里写:
server { listen 80; server_name web1.example.test; return 301 https://$host$request_uri; }注意这个跳转配置与原本的 80 端口 server 块不能共存,否则会冲突。设计时需要想清楚:是"80 端口只做跳转",还是"80 端口也提供正常访问,另外再开 443 做加密访问"。RHCE 题目一般会明确说"要求所有访问都走 HTTPS",那就直接 80 跳 443。
4.3 TLS 配置的验证与隐藏扣分点
配置完成后,同样先nginx -t再 reload。验证命令:
curl -k https://127.0.0.1/ -H "Host: web1.example.test"-k是为了忽略自签证书的信任问题,目的是检查 TLS 握手和返回内容是否正常。如果 curl 报SSL: certificate verify failed,属于预期行为,因为自签证书不在系统信任列表里。但如果报Could not resolve host或Connection refused,就要排查 DNS、端口监听和防火墙了。
我再补一个经常被忽略的点:如果题目要求监听 8443 这类非标准端口,光写listen 8443 ssl;还不够,必须同时放行防火墙端口和 SELinux:
firewall-cmd --add-port=8443/tcp --permanent firewall-cmd --reload semanage port -a -t http_port_t -p tcp 8443这类非标准端口的 SELinux 放行是最容易被忽略的坑。我在一次模拟练习里就栽过:nginx 配置完全正确,但systemctl restart nginx直接失败,日志里写着Permission denied,当时就差这一条semanage port。
5. PHP 动静分离与反向代理:nginx + php-fpm 的实操细节
RHCE 的 nginx 题目中,如果出现"动态站点"要求,通常会让你把 PHP 请求交给 php-fpm 处理,同时保留 nginx 对静态文件的高效响应。这就是经典的动静分离。
5.1 安装 php-fpm 并解决 socket 权限问题
php-fpm 在 EPEL 源里通常也有,安装方式:
dnf install -y php-fpm php systemctl enable --now php-fpmphp-fpm 默认监听/run/php-fpm/www.sock(不同系统可能路径略有差异),这个 socket 文件默认可能归 apache 用户所有,nginx 的 worker 进程会因为没有权限访问而返回 502 Bad Gateway。
处理办法有两个方向:
一是修改 php-fpm 的www.conf,把 socket 的属主改成 nginx:
; /etc/php-fpm.d/www.conf listen.owner = nginx listen.group = nginx listen.mode = 0660二是把 nginx 用户加入相应组,这个不如方式一干净,所以推荐直接用方式一。修改后重启 php-fpm:
systemctl restart php-fpm你可以用ls -l /run/php-fpm/www.sock确认 socket 权限是否正常。
5.2 配置 PHP location 块:fastcgi 参数不能省
nginx 处理 PHP 请求的核心是下面的配置段:
server { listen 80; server_name app.example.test; root /var/www/app; index index.php index.html; location / { try_files $uri $uri/ =404; } location ~ \.php$ { root /var/www/app; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }很多新手死在第 3 步:忘记include fastcgi_params;或SCRIPT_FILENAME没配,结果 PHP 文件被 nginx 当静态文件直接下载了。这两个参数的作用是告诉 php-fpm "要执行哪个文件"。逻辑其实不复杂:nginx 收到.php请求 → 通过fastcgi_pass把请求转发给 php-fpm → php-fpm 根据SCRIPT_FILENAME找到磁盘上的 PHP 文件并执行。
实测时,如果你发现curl返回的是 PHP 源码而不是执行结果,95% 是SCRIPT_FILENAME或者include fastcgi_params;丢了。
5.3 location 匹配优先级:为什么你的规则不生效
nginx 的 location 匹配有一套固定优先级,它决定了动静分离到底"分"得对不对。我把常用规则整理成了表:
| 写法 | 含义 | 优先级 |
|---|---|---|
location = /path | 精确匹配 | 最高 |
location ^~ /path | 前缀匹配,且命中后不再做正则检查 | 高 |
location ~ \.php$/location ~* \.php$ | 正则匹配(区分大小写/不区分) | 中 |
location /path | 普通前缀匹配 | 低 |
一个典型动静分离配置:
server { listen 80; server_name app.example.test; root /var/www/app; # 静态请求直接走 nginx location ^~ /static/ { alias /var/www/app/static/; expires 7d; } # 动态请求交给 php-fpm location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }expires 7d;表示对静态资源下发 7 天的浏览器缓存,是生产环境常用优化,也是考试中容易加分的"亮点配置"。不过要记住:alias与root的路径拼接逻辑不一样,alias会把 location 的匹配部分替换成后面的路径,而root是在路径前追加。这个区别想不清楚的话,静态文件 404 了都不知道为什么。
5.4 反向代理与负载均衡的常见考法
RHCE 里还可能出现"将某个路径的请求代理到后端服务器"的题目,比如:
location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }这里需要理解proxy_pass的处理逻辑:如果location后面带路径,而proxy_pass不带 URI,则原始请求 URI 会完整传给后端;如果proxy_pass带 URI,则匹配部分会被替换。比如:
location /api/ { proxy_pass http://backend:8080/; }浏览器请求/api/user,后端收到的实际是/user,因为/api/被替换成了/。这是新版配置里最经典的坑,RHCE 和真实笔试里都爱考。
6. 访问控制、重定向与错误页:那些"小而杂"的考点
nginx 题目不会只考"能不能访问",还常要求"谁能访问、谁不能访问、访问错了显示什么"。这些细节不长篇大论,但控制着最终功能是否完全符合题意。
6.1 allow/deny 的网段含义与顺序陷阱
RHCE 很爱考"只允许某个网段访问某目录"。配置写法:
location /private/ { allow 192.168.10.0/24; deny all; }allow放前面,deny all放后面,这个顺序不能乱。nginx 是自上而下匹配第一条规则的:如果deny all写在前面,那所有人都被拒绝了,后面的 allow 根本来不及生效。
还有个容易被误读的点:allow 192.168.10.0/24和allow 192.168.10.10的语义差别很大。如果题目说的是"只允许 192.168.10.0/24 整个网段访问",你不能图省事只放行一个 IP,否则评分环境从别的地址访问就直接 403,整道题白做。
实测命令:
curl -I http://127.0.0.1/private/ -H "Host: web1.example.test"如果返回 403,而你又确认自己处在允许的网段内,那可以检查一下访问来源 IP 是否真的落在网段规则里。
6.2 rewrite 跳转与自定义错误页
URL 重定向常用rewrite指令。RHCE 里出现过的场景是把旧路径永久跳到新路径:
location /old/ { rewrite ^/old/(.*)$ /new/$1 permanent; }permanent对应 301 永久跳转,redirect对应 302 临时跳转。用 301 还是 302 取决于题目语义,千万别混。
自定义错误页也是一种送分题:
error_page 404 /404.html; location = /404.html { root /var/www/web1; }注意这个location = /404.html用了精确匹配,是为了防止 404 页面自己加载时又触发 404 循环。如果你不加精确匹配,/404.html本身是个不存在的路径,请求它时会再次匹配到错误页配置,形成无限递归。
6.3 限速与其他加分小项
限速在真实场景下很实用,RHCE 偶尔也会出。比如要求"下载速度最大 100k":
location /download/ { limit_rate 100k; }这个配置对静态文件直传非常有效,适合一些做文件分享的小站点。如果你想控制规则更细,还可以结合limit_rate_after让前 N 字节不限速、之后才限速。不过考试一般不会考那么深,知道limit_rate就足够了。
7. 完整排错链路:从 nginx -t 到 SELinux 审计日志
前面所有配置都写得再漂亮,最终还是要过"服务能不能被正常访问"这一关。我在练习和指导别人的过程中发现,80% 的 nginx 访问失败都可以通过下面这条链路快速定位。
7.1 一个典型故障的完整排查过程
假设你配置好了虚拟主机,但curl http://127.0.0.1/ -H "Host: web1.example.test"访问超时或 403,不要慌,按顺序来。
第一步,确认 nginx 进程状态:
systemctl status nginx ss -tlnp | grep :80如果 [服务没起来],看日志:
journalctl -u nginx -n 30 --no-pagerPermission denied往往指向 SELinux 或端口冲突;address already in use说明 80 端口被别的进程占了。
第二步,确认防火墙:
firewall-cmd --list-all如果你从外部机器访问,且services: http不在返回结果里,那防火墙这层就没过。
第三步,确认配置语法与重载:
nginx -t systemctl reload nginx注意nginx -t只做语法检查,不会告诉你 server_name 写没写对、root 路径存不存在。
第四步,看 nginx 错误日志:
tail -n 30 /var/log/nginx/error.log这是信息量最大的一步。日志里常见的几类报错:
| 报错内容 | 原因 |
|---|---|
open() "/var/www/web1/index.html" failed (13: Permission denied) | SELinux 标签或目录权限问题 |
connect() to unix:/run/php-fpm/www.sock failed (13: Permission denied) | socket 属主/权限配置不对 |
bind() to 0.0.0.0:8443 failed (13: Permission denied) | SELinux 未放行该端口 |
no "ssl_certificate" is defined | TLS server 块没配证书路径 |
第五步,查 SELinux 审计记录:
ausearch -m AVC -ts recent如果这里出现了大量denied,那基本可以确定是 SELinux 的锅,按前文提到的方式补文件标签或端口策略。
7.2 考前自检清单与扣分点汇总
我把 RHCE 考场里最常出现的扣分点整理成一张自查表格,每次练完题对着过一遍,能发现不少隐蔽问题:
| 检查项 | 正确姿势 | 失败典型 |
|---|---|---|
| 服务状态 | systemctl is-enabled nginx返回 enabled | 服务没设置开机自启 |
| 防火墙 | firewall-cmd --list-services含 http/https | 考场上服务明明开着,外部访问却超时 |
| SELinux 标签 | ls -Z /var/www/web1/index.html显示 httpd_sys_content_t | 页面权限 644 但 SELinux 上下文是 default_t |
| 非标端口 | `semanage port -l | grep http_port_t` 已覆盖 |
| 语法检查 | nginx -t输出 successful | vim 里少写分号,reload 失败 |
| 站点内容 | curl能看到差异化测试页 | 两个虚拟主机返回同一页面,server_name 没区分开 |
| 证书路径 | ssl 配置文件里路径拼写正确 | 证书文件名写错,nginx -t直接报找不到文件 |
我建议你每次练完题,别急着关虚拟机,把这 7 项过一遍,尤其是用curl从模拟客户机的视角访问一次。RHCE 的核心不是"你觉得配好了",而是"物理世界中能验证到配好了"。
7.3 最后再分享两个我自己的习惯
第一,任何配置文件改动之前先cp一份备份,改动之后nginx -t再加systemctl reload,这是铁律。我曾经在紧急排查时直接 restart,结果发现配置文件里一个小语法错误,服务当场下线,线上业务全断。从那以后我都是先nginx -t再 reload,每一次都是。
第二,站点目录下不要只放一个空空的 index.html。我习惯在测试页里写上站点标识和日期,比如echo "web1 - $(date)" > index.html。这样 curl 回来之后一眼就能确认当前响应来自哪个站点、是不是旧缓存,排查时会省掉很多自我怀疑。
RHCE 里 nginx 这道题说简单也简单,说难也难。简单的部分在于它技术栈不深,难点全在于你对整个系统链路有没有完整的认知。当你把软件源、服务管理、防火墙、SELinux、虚拟主机、TLS、PHP-FPM、差异化验证这些环节全部串起来,形成一套肌肉记忆,考场上就只是按流程走一遍而已。说白了,评分环境验证的是结果,而结果靠的是流程的稳定性——这套流程,我今天完整地交给你了。