httpd 与 SELinux
RHEL 9 搭 Apache httpd,用 firewalld 放行端口,并读懂 SELinux 安全上下文;附「网页打不开」三层排查。
本页目录
「服务装好了,网页却打不开」——十有八九不是 httpd 配错了目录,而是 防火墙没放行 或 SELinux 拦了标签。这一篇用一条最小 Web 实验,把三层一次跑通。
系列:从 RHCSA 到 RHCE · 第 12 / 17 篇 上一篇:服务与计划任务 下一篇:Podman 容器 总目录:系列索引
环境说明
- 系统:RHEL 9
- 身份:root
- 网络:另一台机器或宿主机能访问本机 IP(示例
192.168.56.20) - 前置:服务与计划任务(
systemctl)
三层模型(先记住这个)
浏览器访问 http://IP/ 时,请求要连过三关:
① httpd 进程在跑、目录里有网页
↓
② 防火墙允许 80(或你改的端口)
↓
③ SELinux 允许 httpd 读这些文件、占这个端口
| 层 | 典型命令 | 常见症状 |
|---|---|---|
| 应用 | systemctl status httpd | 连接被拒绝、打不开 |
| 防火墙 | firewall-cmd --list-all | 浏览器转圈、超时 |
| SELinux | ls -Z / getenforce | 403、改端口后起不来 |
下面按「先搭通 → 再挡防火墙 → 再踩 SELinux」学习。
1. 安装并启动 httpd
dnf -y install httpd
systemctl enable httpd --now
systemctl status httpd
默认关键配置(可用 VIM 查看,不必一次全懂):
less /etc/httpd/conf/httpd.conf
| 配置项 | 常见默认 | 含义 |
|---|---|---|
| Listen 80 | 80 | 监听端口 |
| DocumentRoot "/var/www/html" | 该目录 | 网页根目录 |
默认网页目录:
ls /var/www/html
2. 放一个测试页
echo 'hello from rhel9' > /var/www/html/index.html
cat /var/www/html/index.html
本机自测(不经过外网防火墙路径时也有用):
curl http://127.0.0.1/
curl http://localhost/
应看到 hello from rhel9。
从另一台机器访问:
curl http://192.168.56.20/
# 或用浏览器打开 http://192.168.56.20/
若本机 curl 127.0.0.1 成功、远端失败——先查防火墙。
3. 防火墙 firewalld
是什么
firewalld 按「服务名 / 端口」决定外网能不能进来。装了 httpd 不等于自动放行 80。
查看
systemctl status firewalld
firewall-cmd --list-all
看 services:、ports: 里有没有 http 或 80/tcp。
放行 http 服务(推荐,语义清晰)
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
firewall-cmd --list-all
| 选项 | 含义 |
|---|---|
| --add-service=http | 放行 http 相关端口(通常 80) |
| --permanent | 写入配置,重启后仍有效 |
| --reload | 让当前立即生效 |
| 不加 --permanent | 只影响当前,重启防火墙后可能丢失 |
也可以直接按端口:
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload
立刻生效(不重启 firewalld 时另一种写法):
firewall-cmd --add-service=http
# 当前会话生效;再补 --permanent 写入配置更稳妥
考点:考试常要求「永久放行」→ 必须
--permanent(或 equivalent),再验证--list-all。 易错:只--permanent不--reload,当前仍不通。 易错:firewalld 根本没启动,却以为「已放行」;先systemctl is-active firewalld。
4. SELinux:第二道闸门
它是什么
在用户/组权限之外,RHEL 默认还有一层 强制访问控制:按「程序」和「文件标签」决定能不能访问,不完全看 root。
查看状态:
getenforce
| 输出 | 含义 |
|---|---|
| Enforcing | 强制执行(默认,考试常见) |
| Permissive | 只警告、不拦截(排障时有用) |
| Disabled | 关闭(一般不推荐生产关闭) |
配置文件(改完通常要重启才切换模式):
less /etc/selinux/config
文件安全上下文(标签)
每个文件有 SELinux 上下文,ls -Z 可见:
ls -Zd /var/www/html/
ls -Z /var/www/html/index.html
示例:
system_u:object_r:httpd_sys_content_t:s0 /var/www/html/
httpd_sys_content_t 表示:这类标签允许 httpd 读取作网页内容。
实验:从「不对的目录」放网页
echo 'hello from wrong label' > /root/hello.html
ls -Z /root/hello.html
上下文多半是 admin_home_t 之类,不是 httpd_sys_content_t。
拷到网页目录(注意:mv 可能保留旧标签):
cp /root/hello.html /var/www/html/hello.html
# 若直接 mv,标签可能仍是 admin_home_t:
# mv /root/hello.html /var/www/html/hello.html
ls -Z /var/www/html/hello.html
cp 到正确目录后,新文件常能继承目录类型;若仍是旧标签,浏览器访问 http://IP/hello.html 可能 403。
改标签:chcon
chcon -t httpd_sys_content_t /var/www/html/hello.html
# 目录可递归:
chcon -R -t httpd_sys_content_t /var/www/html/
ls -Z /var/www/html/hello.html
再访问应正常。
考点:「内容在正确目录却 403」→ 查
ls -Z,用chcon改到httpd_sys_content_t。 说明:生产里更推荐restorecon按策略恢复默认标签;考试按题面用chcon即可。
实验:改端口被 SELinux 拦住
默认 httpd 用 80。改成 82 试试:
vim /etc/httpd/conf/httpd.conf
# 将 Listen 80 改为 Listen 82
systemctl restart httpd
常见失败:
Job for httpd.service failed ...
原因:82 端口没有 http_port_t 标签,SELinux 不让 httpd 用。
查看已允许的 http 端口:
semanage port -l | grep http
semanage 可能未安装:
dnf -y install policycoreutils-python-utils
semanage port -l | grep http
放行 82:
semanage port -a -t http_port_t -p tcp 82
# 若已存在同类型条目需修改,用 -m 而不是 -a
systemctl restart httpd
ss -lnt | grep 82
防火墙也要放行新端口:
firewall-cmd --add-port=82/tcp --permanent
firewall-cmd --reload
访问:
curl http://192.168.56.20:82/
易错:只改
Listen 82和防火墙,忘记semanage port。 易错:-a时端口已存在会报错,按提示改用-m修改。
5. 「网页打不开」排查清单
按顺序,不要跳:
- httpd 活着吗
systemctl is-active httpd - 本机 curl 通吗
curl -I http://127.0.0.1/ - 网页文件在吗
ls /var/www/html/;DocumentRoot是否仍是该目录 - 防火墙
firewall-cmd --list-all是否含http或对应端口 - SELinux 模式
getenforce - 文件标签
ls -Z是否为httpd_sys_content_t;不对则chcon - 非 80 端口
semanage port -l | grep http;防火墙是否放行该 port
# 一键自检(实验机)
systemctl is-active httpd firewalld
curl -sI http://127.0.0.1/ | head -1
firewall-cmd --list-all
getenforce
ls -Zd /var/www/html
排查决策(简图)
本机 curl 失败? → 查 httpd / 端口 / DocumentRoot
本机成功、外网失败? → 查防火墙
403? → 查 SELinux 标签(chcon)
改端口起不来? → semanage port + 防火墙
6. 推荐完整实验(约 30 分钟)
# 1) 装并启动
dnf -y install httpd
systemctl enable httpd --now
echo 'hello from rhel9' > /var/www/html/index.html
curl http://127.0.0.1/
# 2) 防火墙
firewall-cmd --list-all
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
firewall-cmd --list-all
# 远端再 curl / 浏览器访问
# 3) SELinux 标签
echo 'x' > /root/t.html
ls -Z /root/t.html
cp /root/t.html /var/www/html/t.html
ls -Z /var/www/html/t.html
# 若标签不对:
chcon -t httpd_sys_content_t /var/www/html/t.html
curl http://127.0.0.1/t.html
# 4)(可选)改 82 端口
# vim Listen 82
# semanage port -a -t http_port_t -p tcp 82
# firewall-cmd --add-port=82/tcp --permanent && firewall-cmd --reload
# systemctl restart httpd
7. 速查表
| 目标 | 命令 |
|---|---|
| 装/启 Web | dnf -y install httpd;systemctl enable httpd --now |
| 网页根目录 | /var/www/html |
| 本机测试 | curl http://127.0.0.1/ |
| 看防火墙 | firewall-cmd --list-all |
| 永久放行 http | firewall-cmd --add-service=http --permanent + --reload |
| SELinux 状态 | getenforce |
| 看标签 | ls -Z 文件 |
| 改标签 | chcon -t httpd_sys_content_t 路径 |
| 端口标签 | semanage port -a/-m -t http_port_t -p tcp 82 |
考点与易错
考点:httpd 起服务 + 写 index;防火墙
--permanent放行;SELinuxchcon/semanage port。 易错:--permanent后不--reload。 易错:用mv从家目录挪网页文件,标签仍是admin_home_t导致 403。 易错:改Listen非标准端口却不改 SELinux 端口类型。 练习环境:课堂若用blue做 Web,IP 与题面一致即可;三层命令相同。
小结
- Web 三层:httpd → 防火墙 → SELinux,一层一层查。
- 防火墙永久放行:
--add-service=http --permanent再--reload。 - SELinux:
ls -Z看标签,chcon -t httpd_sys_content_t;改端口用semanage port。 - 本机
curl 127.0.0.1成功、外网失败时,优先怀疑防火墙。
下一篇用 Podman 跑容器,并处理卷挂载时的 SELinux :Z。