Using Windows Firewall
Opening and closing ports on a Windows server from the GUI and with New-NetFirewallRule, and how that relates to the panel's port rules.
Windows Firewall decides what the server itself accepts, on the machine, after traffic has already arrived. This page covers opening a port, closing it again, scoping a rule to particular sources, and reading back what is actually in force.
The full name in the GUI is Windows Defender Firewall with Advanced Security,
and the console is wf.msc. The PowerShell cmdlets all end in
-NetFirewallRule.
Every rule below takes effect immediately, including on your own Remote Desktop connection. Blocking the wrong port, scoping to the wrong address, or turning a profile's default to block ends your session and refuses the next one.
Open Console access in another tab and confirm it works before you start. The console reaches the machine's screen directly, so it keeps working when the firewall is refusing everything else.
What the firewall does before you touch it
Two defaults explain most of the behaviour you will see:
- Inbound connections are blocked unless a rule allows them. A service you install and start is listening, and still unreachable, until something opens its port. Some installers add their own rule, some do not, and that difference is the usual reason a freshly installed service does not answer.
- Outbound connections are allowed unless a rule blocks them. The server can reach out to anything by default.
Windows keeps three sets of rules, called profiles: Domain, Private, and Public. Only the profile matching the network the interface is on is in force. On a standalone server on the internet that is normally Public, which means a rule created for Private only does nothing.
Check both at once:
Get-NetFirewallProfile | Format-Table Name, Enabled, DefaultInboundAction, DefaultOutboundAction
Get-NetConnectionProfileA DefaultInboundAction of NotConfigured means the built-in default applies,
which is to block. Get-NetConnectionProfile tells you which profile your
interface is actually using, under NetworkCategory.
Opening a port in the GUI
Open the firewall console
Run wf.msc, or find Windows Defender Firewall with Advanced Security in the
Start menu.
Start a new inbound rule
Select Inbound Rules in the left pane, then New Rule on the right.
Choose Port
Pick Port, then Next. The Program option is the other one worth knowing: it allows an executable whatever ports it opens, which suits software that picks its ports at runtime.
Enter the protocol and ports
Choose TCP or UDP, then Specific local ports. The box takes a single
port, a comma-separated list such as 80,443, or a range such as
30120-30130. A service that uses both protocols needs two rules.
Allow the connection
Pick Allow the connection, then Next.
Tick the profiles
Leave all three ticked unless you have a reason not to. A rule that is missing the profile your interface is on has no effect.
Name it something you will recognise
Use a name that says what the port is for, such as Game server UDP 30120, not
Rule 1. You will be reading this list in six months trying to work out what is
safe to remove.
To restrict the rule after creating it, double-click it in the list, open the Scope tab, and under Remote IP address choose These IP addresses and add the sources allowed to use it.
Opening a port with PowerShell
New-NetFirewallRule does the same thing in one line, and unlike the GUI it can
be pasted into a build script. Run PowerShell as Administrator.
New-NetFirewallRule -DisplayName "HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action AllowA UDP game port:
New-NetFirewallRule -DisplayName "Game server UDP 30120" -Direction Inbound -Protocol UDP -LocalPort 30120 -Action AllowSeveral ports, and a range. Quote a range so PowerShell passes it through as written:
New-NetFirewallRule -DisplayName "Web" -Direction Inbound -Protocol TCP -LocalPort 80,443 -Action Allow
New-NetFirewallRule -DisplayName "App ports" -Direction Inbound -Protocol TCP -LocalPort "30120-30130" -Action AllowA rule for a program rather than a port, which covers software that opens ports of its own choosing:
New-NetFirewallRule -DisplayName "MyApp" -Direction Inbound -Program "C:\apps\myapp.exe" -Action AllowThe parameters worth knowing:
| Parameter | What it sets |
|---|---|
-Direction | Inbound or Outbound. Defaults to Inbound. |
-Protocol | TCP, UDP, ICMPv4, Any. |
-LocalPort | The port on this server. A number, a list, or a quoted range. |
-RemotePort | The port at the far end. Used on outbound rules. |
-RemoteAddress | Which sources the rule applies to. Defaults to Any. |
-Action | Allow or Block. |
-Profile | Domain, Private, Public, or Any. Defaults to Any. |
-Program | Path to an executable, instead of a port. |
-Enabled | True or False. Create a rule switched off with False. |
Scoping a rule to specific sources
An open port that only answers the addresses that should be using it is dramatically safer than one that answers everybody. This is the single most useful thing on the page for a management port, a database port, or anything else that is not meant for the public.
Create the rule scoped from the start:
New-NetFirewallRule -DisplayName "MySQL from app server" -Direction Inbound -Protocol TCP -LocalPort 3306 -RemoteAddress "203.0.113.10" -Action AllowChange the scope of a rule that already exists, including one Windows shipped:
Set-NetFirewallRule -DisplayName "MySQL from app server" -RemoteAddress @("203.0.113.10", "203.0.113.20")CIDR ranges are accepted, so 203.0.113.0/24 covers a whole block. Read back
what a rule is scoped to:
Get-NetFirewallRule -DisplayName "MySQL from app server" | Get-NetFirewallAddressFilterPut it back to everything with -RemoteAddress Any.
Scoping the Remote Desktop rules is a special case with its own steps and its own risks, on Hardening Remote Desktop.
How rules are evaluated
There is no rule order to manage. Windows applies two principles:
- A block rule beats an allow rule. If any rule blocks the traffic, it is blocked, whatever else allows it.
- With no matching rule, the profile default applies, which is to block inbound and allow outbound.
The practical consequence is that you narrow an open port by scoping the allow rule that opens it, not by adding an allow rule for the sources you want. Adding one leaves the original wide-open rule in place next to it.
Inbound versus outbound
Inbound rules control what may reach services on this server. Outbound rules control what this server may reach elsewhere. Because outbound is allowed by default, most people never write an outbound rule, and that is a reasonable place to stay.
The case where one earns its place is containing a compromise or a misbehaving application: a server that has been broken into is usually being used to reach something else, whether that is sending spam or joining a botnet.
New-NetFirewallRule -DisplayName "Block outbound SMTP" -Direction Outbound -Protocol TCP -RemotePort 25 -Action BlockNote the parameter change. On an outbound rule the interesting port is at the
far end, so it is -RemotePort, not -LocalPort.
Windows Update, activation, certificate revocation checks, package managers, and your own application's API calls all go outbound. A broad outbound block does not announce itself, it makes updates stop working and requests hang. Block specific destinations for specific reasons, and write the reason in the rule name.
Listing what is in force
Every allow rule that is currently switched off is noise, so filter to the ones that matter:
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow |
Sort-Object DisplayName |
Format-Table DisplayName, Profile, EnabledThat does not show ports, because a rule and its port filter are separate objects. To see both:
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow | ForEach-Object {
$filter = $_ | Get-NetFirewallPortFilter
[pscustomobject]@{
Name = $_.DisplayName
Protocol = $filter.Protocol
LocalPort = ($filter.LocalPort -join ",")
}
} | Sort-Object Name | Format-Table -AutoSizeGoing the other way, to find every rule touching one port:
Get-NetFirewallPortFilter |
Where-Object { $_.LocalPort -eq 3389 } |
Get-NetFirewallRule |
Format-Table DisplayName, Direction, Action, EnabledThat last one is the query to run when a port is open and you cannot work out which rule is opening it.
Disabling and removing rules
Switch a rule off, keeping it for later:
Disable-NetFirewallRule -DisplayName "HTTP"
Enable-NetFirewallRule -DisplayName "HTTP"Delete it outright:
Remove-NetFirewallRule -DisplayName "HTTP"Several rules can share a display name, and Windows ships groups of rules that
do. Remove-NetFirewallRule -DisplayName deletes all of them without asking.
List first and check the count is what you expect:
Get-NetFirewallRule -DisplayName "HTTP" | Format-Table Name, DisplayName, Direction, ActionThe Name column is the unique identifier. Pass that with -Name when you want
to remove exactly one.
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled False exposes
every port anything on the machine is listening on, including SMB and RPC, to
the entire internet. On a public address that is measured in minutes, not days.
Test with a temporary rule scoped to your own address instead, and delete it when you are done.
How this relates to the panel's port rules
The two firewalls sit at different points in the same path, and traffic has to pass both.
Panel rules are applied at the network edge, before packets reach your server. Windows Firewall is applied on the machine, after they have arrived on its network interface. So:
- The panel stops traffic earlier. Something dropped at the edge never consumes your server's bandwidth, CPU, or connection table. A flood that Windows Firewall blocks has still arrived, and blocking it still costs the machine work. That is the whole reason the edge layer exists.
- Windows Firewall knows things the edge cannot. Which program is listening, which local account is running it, and what is happening on ports the edge was never asked about.
- A port needs to be open in both places. In the panel, a port with no rule
of its own falls to the Default for unlisted ports setting, which starts
on
Allow. So on a new server, opening a port in Windows is enough to make it reachable. Add the panel rule anyway: rate limits and protocol checks only apply to a port that has one. See Port rules. - Closing a port is worth doing in both places too. The edge rule saves your server the traffic, and the Windows rule means a mistake in one layer is not the whole story.
When a service is unreachable, this split is the first thing to check: run the listening-ports command from First steps to confirm something is actually bound to the port, then check the Windows rule, then check the panel rule. Those are three separate reasons for the same symptom.