用 nftables 替代 iptables 配置 Squid 透明代理网关更现代清晰:需启用 Squid 透明模式(http_port 3128 transparent)、开启系统 IP 转发、在 nftables nat 表 prerouting 链中添加 redirect 规则重定向内网 HTTP/HTTPS 流量至 3128 端口,并验证规则、日志与网络连通性。

用 nftables 替代 iptables 配置 Squid 透明代理网关是更现代、更清晰的做法。nftables 的语法结构化强、规则管理更直观,且原生支持 IPv4/IPv6 双栈和更细粒度的链处理。核心思路不变:通过 PREROUTING 链拦截内网流量并重定向到本地 Squid 监听端口,Squid 以 transparent 模式运行,同时系统开启 IP 转发。
一、Squid 必须启用透明模式
Squid 不默认支持透明代理,需显式声明:
编辑 /etc/squid/squid.conf,找到或添加以下行:
-
http_port 3128 transparent —— 表示监听 3128 端口并接受透明代理请求(不加
intercept或ssl-bump时仅处理 HTTP) - 若需 HTTPS 支持(如 TLS 透传或 SSL 解密),还需额外配置
https_port和证书策略,但普通透明代理通常只重定向 HTTP 流量;HTTPS 重定向需配合 TPROXY 或专用解密方案,风险与复杂度显著上升 - 确保
cache_effective_user和cache_effective_group设置正确(如squid),避免权限拒绝 - 重启服务:
systemctl restart squid,并确认监听状态:ss -tlnp | grep :3128
二、启用系统 IP 转发
透明代理网关本质是路由节点,必须开启转发能力:
- 临时启用:
echo 1 > /proc/sys/net/ipv4/ip_forward - 永久生效:在 /etc/sysctl.conf 中追加
net.ipv4.ip_forward = 1,再执行sysctl -p - IPv6 如需支持,同步设置
net.ipv6.conf.all.forwarding = 1
三、nftables 配置 REDIRECT 规则
使用 nftables 实现与 iptables REDIRECT 等效功能,推荐使用 redirect to 语句(属于 nat 表的 prerouting 链):
- 创建基本 nat 表(如不存在):
nft add table ip nat - 添加 prerouting 链:
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; } - 重定向内网 HTTP 流量(假设内网接口为
ens33,子网为192.168.1.0/24):nft add rule ip nat prerouting iifname "ens33" ip saddr 192.168.1.0/24 tcp dport 80 redirect to :3128 - 如需 HTTPS 重定向(仅限 TCP 层转发,Squid 默认不处理 HTTPS 原始连接):
nft add rule ip nat prerouting iifname "ens33" ip saddr 192.168.1.0/24 tcp dport 443 redirect to :3128(注意:此操作需 Squid 启用https_port并配置 ssl-bump,否则连接将失败) - 保存规则(Debian/Ubuntu):
nft list ruleset > /etc/nftables.conf;RHEL/CentOS 可用nft list ruleset | sudo tee /etc/sysconfig/nftables.conf
四、验证与排错要点
规则生效后,客户端只需将网关设为该服务器 IP,无需任何代理设置即可走 Squid:
- 检查 nftables 规则是否加载:
nft list chain ip nat prerouting - 查看 Squid 日志实时记录:
tail -f /var/log/squid/access.log,正常应看到内网客户端 IP + 目标域名 - 若无日志,先确认客户端网关和 DNS 设置正确;再检查
ip_forward是否为 1;最后用tcpdump -i ens33 port 80抓包,确认流量是否到达网关 - 常见失败原因:Squid 配置漏掉
transparent关键字;nftables 规则未指定源子网或接口名错误;防火墙(如 firewalld)冲突拦截了 3128 端口











