Windows Firewall prevents unauthorized incoming connections by blocking inbound traffic that no rule allows, but installing a server role such as IIS or SQL Server often adds rules that open a port to every address on the internet. This guide walks you through auditing those rules, scoping them to the hosts that actually need the service, and confirming the result with firewall logs.
You will work in an elevated PowerShell session on the server. Nothing here requires a reboot, but one step changes the default inbound action, so read the warning before you run it.
Before you start
- An elevated PowerShell session on the Windows VPS. Right-click PowerShell and choose Run as administrator.
- Administrator access to your VPS provider's control panel, where you can open a browser console if a change locks you out of RDP.
- A note of the source addresses that legitimately need each service — for example your office IP, a monitoring host, or an application server. Use
203.0.113.10as a placeholder while you test. - Remote Desktop on a Windows VPS and Admin RDP listens on TCP port 3389. Keep that in mind when you read rule names.
Warning: If you set the default inbound action to Block without an allow rule for port 3389, you will lose RDP access. Confirm the rule exists first with the guide Check the Windows Firewall rule for RDP port 3389, and keep your VPS provider's console open in a second tab.
Step 1: See what the firewall is doing now
Start by reading the three profiles. On a VPS the active network is usually classified as Public, so a rule that only applies to the Domain or Private profile does nothing.
Get-NetFirewallProfile -PolicyStore ActiveStore |
Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundActionNext, list what is actually listening. This is the ground truth — a firewall rule for a port nothing listens on is harmless, and a listening port with no rule is unreachable.
Get-NetTCPConnection -State Listen |
Sort-Object LocalPort |
Select-Object LocalAddress, LocalPort, OwningProcessTo see which program owns a port, take the process ID from the list:
Get-Process -Id 4 | Select-Object Id, ProcessName, PathNow list the inbound allow rules that apply to all addresses, which is where the risk usually sits:
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow |
Where-Object { $_.Profile -in 'Any','Public' } |
Select-Object DisplayName, Profile, ActionStep 2: Confirm the RDP rule on port 3389
Before you tighten anything, prove that RDP still has a path in. Run:
Get-NetFirewallRule -DisplayName "*3389*" |
Get-NetFirewallPortFilter |
Select-Object Protocol, LocalPort, RemoteAddressYou want an enabled inbound allow rule for TCP 3389 that applies to the profile your VPS actually uses. If it is missing, create it — and only then continue:
New-NetFirewallRule -DisplayName "RDP 3389" -Direction Inbound -Action Allow `
-Protocol TCP -LocalPort 3389 -Profile AnyIf you want to restrict RDP to known addresses, add -RemoteAddress 203.0.113.10 to that command. Test the connection from a second machine before you close your current session.
Step 3: Replace broad role rules with scoped rules
Role installers tend to create rules named after the role, with Profile = Any and no remote address limit. Find them by name:
Get-NetFirewallRule -Direction Inbound |
Where-Object DisplayName -match 'IIS|SQL|World Wide Web|MSSQL' |
Select-Object DisplayName, Enabled, Profile, ActionFor each rule you do not need, disable it rather than delete it, so you can re-enable it quickly if something breaks:
Disable-NetFirewallRule -DisplayName "World Wide Web Services (HTTP Traffic-In)"Then create a narrow rule for the same port. This example allows HTTPS to IIS only from one application host:
New-NetFirewallRule -DisplayName "IIS HTTPS from app host" `
-Direction Inbound -Action Allow -Protocol TCP -LocalPort 443 `
-RemoteAddress 203.0.113.10 -Profile AnyFor SQL Server, scope TCP 1433 to the web server that queries it and nothing else:
New-NetFirewallRule -DisplayName "SQL 1433 from web tier" `
-Direction Inbound -Action Allow -Protocol TCP -LocalPort 1433 `
-RemoteAddress 203.0.113.10 -Profile AnyIf a service should only be reachable from the machine itself, skip the firewall rule entirely and bind the service to the loopback address. A port listening on 127.0.0.1 is not reachable from outside regardless of firewall state.
Tip: You can scope a rule to a program instead of a port with -Program "C:\Program Files\...\app.exe". See Advanced Windows Firewall: Blocking Specific Application Executables for the full pattern.
Step 4: Set the default inbound action and enable logging
With the RDP rule confirmed, make the default explicit. Block rules always win over allow rules, so a default of Block is the safest baseline.
Set-NetFirewallProfile -Name Domain,Private,Public -DefaultInboundAction Block -DefaultOutboundAction AllowTurn on logging for dropped packets so you can see what is being refused, and where from:
Set-NetFirewallProfile -Name Domain,Private,Public `
-LogBlocked True -LogAllowed False `
-LogFileName "%systemroot%\system32\LogFiles\Firewall\pfirewall.log" `
-LogMaxSizeKilobytes 16384Read the tail of the log after a few minutes of traffic:
Get-Content "$env:systemroot\system32\LogFiles\Firewall\pfirewall.log" -Tail 40Check it works
From a host that should be allowed, test the port directly:
Test-NetConnection -ComputerName 203.0.113.10 -Port 443You want TcpTestSucceeded: True. Run the same test from a host that should not be allowed — you want it to fail, and the attempt should appear in pfirewall.log as a DROP entry for that source address.
Finally, confirm RDP still answers on 3389 from your own machine, and confirm the profile settings stuck:
Get-NetFirewallProfile -PolicyStore ActiveStore |
Select-Object Name, Enabled, DefaultInboundActionTroubleshooting
- RDP stops responding after step 4. The default inbound action changed without a matching allow rule for TCP 3389. Open the browser console in your VPS provider's control panel, re-create the rule from step 2, and test again.
- A service is unreachable even though an allow rule exists. The rule applies to the Domain or Private profile while the VPS network is classified as Public. Re-create it with
-Profile Any, or check the profile withGet-NetConnectionProfile. - Traffic is blocked despite a correct allow rule. A block rule with the same or broader scope takes precedence. List them with
Get-NetFirewallRule -Action Block -Enabled Trueand disable the one that matches. Test-NetConnectionfails but the port shows as listening. The service is bound to127.0.0.1only. Change the binding in the application's own configuration, not in the firewall.- Old rules keep reappearing after a role reinstall. Installers recreate their rules on repair. Disable them again after each repair, or keep your scoped rules and leave the installer rules disabled.
Next steps
- Watch for scanning traffic against the ports you just closed with Network Hardening: Monitoring for Unauthorized Port Scans on the VPS.
- Record who changes firewall rules and when using Windows Server: Implementing Auditing Policies to Track Security Events.
- Harden the remote access path itself with Secure Remote Desktop on Windows Server.
