在 Windows Server 上部署了一个 Web 服务、一个数据库或一套自研程序,本地自己访问好好的,别人就是连不上——十次有八次是端口没放开。而放开端口这件事,Windows 平台有个特殊之处:云服务器上存在两层独立的访问控制,只弄对一层是不行的。
这篇讲清楚三件事:Windows Defender 防火墙的入站/出站规则是怎么工作的;netsh advfirewall 和 PowerShell New-NetFirewallRule 两种配置方式的实际写法与取舍;以及如何用"作用域"把端口限定到具体的来源 IP,避免把服务裸奔到公网。所有命令都在 Server 2016 / 2019 / 2022 / 2025 上验证可用,Server Core 环境同样适用。
先搞明白:入站、出站与安全组的关系
Windows Defender 防火墙(早期叫 Windows 防火墙)是一个基于主机的有状态包过滤器。它的规则分两个方向:
| 方向 | 处理的流量 | 默认行为 | 典型用途 |
|---|---|---|---|
| 入站 Inbound | 外部主动连进本机的连接 | 未匹配规则则阻止 | 开放外部访问本机服务 |
| 出站 Outbound | 本机主动对外发起的连接 | 默认允许 | 限制本机程序访问外网 |
绝大多数人的需求都是入站规则。出站规则默认全放行,只有在防止失陷主机外联、禁止某个程序联网这类合规场景下才需要配,配置错了很容易导致 Windows Update、激活、NTP 全部失效,新手慎动。
云服务器的两层结构是这样的:
| 层级 | 位置 | 生效时机 | 是否记录日志 |
|---|---|---|---|
| 安全组 / 云平台防火墙 | 云厂商控制台,在虚拟机外部 | 流量到达虚拟机之前 | 部分厂商支持流日志 |
| Windows Defender 防火墙 | 操作系统内部 | 流量进入网卡之后 | 可通过 pfirewall.log 查看 |
数据包要先过安全组,再过系统防火墙,两者都放行才建立连接。判断是哪一层拦截的方法很简单:临时把系统防火墙全关(仅限内网测试环境),如果还是连不上,问题在安全组;如果能连上,问题在系统防火墙。反过来,安全组配错了,系统防火墙配得再正确也没用。
# 查看本机所有已启用的入站放行规则
Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True |
Select-Object DisplayName, Profile, Direction, Action |
Sort-Object DisplayName | Format-Table -AutoSize
# 只看某个端口
Get-NetFirewallRule | Get-NetFirewallPortFilter | Where-Object { $_.LocalPort -eq 8080 }
Get-NetFirewallRule | Get-NetFirewallAddressFilter | Where-Object { $_.RemoteAddress -ne 'Any' }
方式一:PowerShell New-NetFirewallRule(推荐)
PowerShell 的优势是规则可以带丰富的过滤条件,尤其是作用域(-RemoteAddress),这是 GUI 和 netsh 很难精细控制的部分。
放开一个 TCP 端口的基本写法:
# 放行 TCP 8080,作用于所有网络配置文件
New-NetFirewallRule -DisplayName "WebService-8080" `
-Direction Inbound -Protocol TCP -LocalPort 8080 `
-Action Allow -Profile Any
# 放行 TCP 3306,仅对私有网络配置文件生效(推荐)
New-NetFirewallRule -DisplayName "MySQL-3306-Private" `
-Direction Inbound -Protocol TCP -LocalPort 3306 `
-Action Allow -Profile Private,Domain
# 放行 UDP 端口(如 SNMP、NTP)
New-NetFirewallRule -DisplayName "NTP-123" -Direction Inbound -Protocol UDP -LocalPort 123 -Action Allow
关键参数说明:
| 参数 | 作用 | 常用取值 |
|---|---|---|
-DisplayName |
规则显示名,务必写清楚用途 | 自定义,建议含端口和用途 |
-Direction |
方向 | Inbound / Outbound |
-Protocol |
协议 | TCP / UDP / ICMPv4 / Any |
-LocalPort |
本机端口,支持范围和逗号列表 | 80,443 或 5000-5010 |
-Action |
动作 | Allow / Block |
-Profile |
生效的网络配置文件 | Domain / Private / Public / Any |
-RemoteAddress |
来源 IP 限制 | IP、网段 10.0.0.0/24、Any |
Profile 这一项很重要:服务器网卡通常会被识别为"公用"或"专用"网络。如果规则只作用在 Private,而网卡被识别成了 Public,规则就不生效,排查起来很费劲。生产环境建议用 Any,或者用组策略统一网络位置识别。
验证规则是否真的创建成功:
Get-NetFirewallRule -DisplayName "WebService-8080" | Format-List *
Test-NetConnection <服务器IP> -Port 8080
netstat -ano | findstr :8080
注意:防火墙规则只负责"放行",不代表有人在处理这个端口。
Test-NetConnection返回 False 时,先用netstat -ano | findstr :8080确认服务有没有在监听。没有监听的端口,防火墙配得再好也连不上。
方式二:netsh advfirewall(适合批处理与老脚本)
netsh advfirewall firewall 是经典写法,CMD 下可直接执行,适合写进批处理脚本和远程脚本,netsh -c 加上目标机器还能远程管理。
:: 放行入站 TCP 8080
netsh advfirewall firewall add rule name="WebService-8080" dir=in action=allow protocol=TCP localport=8080
:: 放行入站 TCP 3306,限定来源 IP
netsh advfirewall firewall add rule name="MySQL-3306" dir=in action=allow protocol=TCP localport=3306 remoteip=10.0.0.0/24,192.168.1.100
:: 限定到特定程序而不是端口(更安全)
netsh advfirewall firewall add rule name="nginx-in" dir=in action=allow program="D:\nginx\nginx.exe" enable=yes
:: 删除规则
netsh advfirewall firewall delete rule name="WebService-8080"
:: 查看全部规则
netsh advfirewall firewall show rule name=all dir=in
netsh 的 localport 不支持逗号列表式多端口,连续范围用 -;需要多个离散端口时可以写多条规则,或改用 PowerShell。
| 对比项 | PowerShell New-NetFirewallRule | netsh advfirewall |
|---|---|---|
| 运行环境 | 需要 PowerShell | CMD 直接跑,兼容性最好 |
| 多端口支持 | 支持 80,443,5000-5010 |
支持范围,不支持离散列表 |
| 远程管理 | 用 Enter-PSSession / -CimSession |
netsh -r 目标机 |
| 脚本可读性 | 好,管道组合强 | 一般,参数是缩写 |
| ID 更新 | 规则对象可直接 Set-NetFirewallRule 修改 |
只能删了重建 |
两种方式创建的规则在 GUI 里完全等价,都是同一套底层 WFAS(Windows Filtering Platform),混用没有问题,重要的是别重复创建一堆同名不同配置的规则。
除这两种之外,还有 GUI 路径,适合临时操作:wf.msc(高级安全 Windows Defender 防火墙) → 入站规则 → 新建规则 → 端口 → TCP → 特定本地端口。
限定来源 IP:最小权限原则的实际落地
开放端口最大的风险不是"开了端口",而是"对所有 IP 开了端口"。3389、3306、6379、27017 这几个端口是互联网上的高频扫描目标,开一天就能收到几千次爆破尝试。把来源限定到可信网段,风险下降一个数量级。
# 只允许单一 IP 访问
New-NetFirewallRule -DisplayName "SSH-like-8888" -Direction Inbound -Protocol TCP -LocalPort 8888 `
-RemoteAddress 203.0.113.50 -Action Allow
# 只允许内网网段
New-NetFirewallRule -DisplayName "RDP-Office-Only" -Direction Inbound -Protocol TCP -LocalPort 3389 `
-RemoteAddress 10.0.0.0/24,192.168.10.0/24 -Action Allow
# 排除法:允许一个网段但排除其中一台机器(Windows 防火墙语法限制,需要拆成两条)
New-NetFirewallRule -DisplayName "BlockBadHost" -Direction Inbound -RemoteAddress 10.0.0.66 -Action Block
| 服务 | 建议放行的来源 |
|---|---|
| 远程桌面 3389 | 办公网固定 IP 或 VPN 网段;公网直接开是高危操作 |
| MySQL 3306 | 同 VPC 内网应用服务器 IP,绝不对 0.0.0.0/0 |
| Redis 6379 | 仅 127.0.0.1,或内网单个 IP |
| Web 80/443 | 可以对全网开放,这是业务必需 |
| 自定义业务端口 | 按调用方 IP 白名单 |
修改已有规则的作用域比重建干净:
# 收缩已有规则的作用域
Get-NetFirewallRule -DisplayName "MySQL-3306" | Set-NetFirewallRule -RemoteAddress 10.0.0.0/24
# 禁用 / 启用规则(比删除安全,随时可回滚)
Disable-NetFirewallRule -DisplayName "MySQL-3306"
Enable-NetFirewallRule -DisplayName "MySQL-3306"
# 删除(不可逆,先确认规则名唯一)
Remove-NetFirewallRule -DisplayName "MySQL-3306"
风险提示:所有涉及 3389 / 3306 / 445 / 139 等高危端口的放行操作,务必同时做三件事:限定来源 IP、确认账号使用强密码、
-Profile不要设成包含 Public 的公网场景。改完之后从白名单外的一台机器验证一下应该被拒绝,而不是只验证白名单内能通。
云服务器安全组的配套配置
系统防火墙配好之后,还要在云平台控制台处理另一层。主流云厂商的控制台入口名称各不相同,通常在"安全组 / 防火墙 / 网络 ACL"下,规则字段基本一致:
| 字段 | 常见填法 | 说明 |
|---|---|---|
| 方向 | 入方向 / Inbound | 外部访问本机 |
| 协议类型 | TCP / UDP / ICMP | 与系统 -Protocol 对应 |
| 端口范围 | 8080 或 5000/5010 |
注意不同厂商分隔符是 / 还是 - |
| 授权对象(来源) | 0.0.0.0/0 或具体 IP/网段 |
CIDR 格式,/32 表示单 IP |
| 策略 | 允许 / 拒绝 | 拒绝规则优先级通常更高 |
有些厂商的安全组是有状态的,放行入站后回包自动放行;也有的网络 ACL 是无状态的,需要同时配出方向。CentOS/RHEL 那边的 iptables/firewalld 与这里的 Windows 防火墙是同一个位置,但 Windows 这套的作用域、配置文件(Profile)概念更细,别照搬 Linux 的经验。
一个实用的判断流程:外部连不上某端口时,按顺序验证三条命令,输出一致才说明配置完整。
# 1. 服务是否在监听(不监听则与应用无关)
netstat -ano | findstr LISTENING | findstr :8080
# 2. 系统防火墙是否放行该端口
Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True |
Get-NetFirewallPortFilter | Where-Object { $_.LocalPort -contains 8080 }
# 3. 从外部测试
Test-NetConnection <公网IP> -Port 8080
还可以在服务器上开防火墙丢弃日志辅助定位:
netsh advfirewall set allprofiles logging droppedconnections enable
:: 日志位置:%systemroot%\system32\LogFiles\Firewall\pfirewall.log
注意:日志会快速增长,长时间开建议限定大小
netsh advfirewall set allprofiles logging maxfilesize 8192,排完故障记得关掉。
常见问题
Q:规则配好了,Get-NetFirewallRule 也能看到 Enabled True,为什么还是连不上?
先查 -Profile。用 Get-NetFirewallProfile 看当前网卡活动的 Profile 是什么,如果规则只作用于 Private 而网卡是 Public,规则不会生效。改成 -Profile Any 或明确指定。
Q:想一次性开多个端口怎么办?
PowerShell 下一条规则可以写多个:-LocalPort 80,443,8080 或 -LocalPort 5000-5010。端口特别多且连续时,考虑改成应用白名单规则(按程序路径放行)而不是端口清单。
Q:改错规则导致自己被挡在外面怎么办?
别慌,用云控制台的 VNC 登进去。预防方法是在改之前导出全量规则备份:netsh advfirewall export "C:\fw-backup.wfw",需要时 netsh advfirewall import "C:\fw-backup.wfw" 一键还原。
Q:需要禁用防火墙吗?
不建议。除了内网隔离的测试环境,禁用防火墙从来都不是解决方案。真有全通需求的场景,用一条允许规则加 Any 作用域就够了,至少管理和审计上还是完整的。
Q:Windows 防火墙会不会影响性能?
在千兆网络下几乎感知不到。万兆或高并发超融合场景可以考虑通过 offload 特性与硬件卸载降低开销,常规业务服务器不必担心。真正影响性能的往往是规则数量过多导致匹配变慢,保持规则精简即可。
总结
- Windows 服务器开放端口要同时配安全组和系统防火墙两层,缺一层都不通;排障时二者分开验证。
- 日常推荐用 PowerShell
New-NetFirewallRule,批处理脚本或需要远程netsh -r的场景用netsh advfirewall,两者底层等价可混用。 - 防火墙放行不等于服务可用,先用
netstat -ano | findstr LISTENING确认进程在监听再排查规则。 - 高危端口(3389、3306、6379)务必用
-RemoteAddress限定来源网段,这是最低成本、最高收益的安全加固。 - 修改前用
netsh advfirewall export备份规则,误操作后用import还原,比手删手建可靠。
企业QQ咨询




