WireGuard and Windows Defender Firewall
If you set up WireGuard on a machine running Microsoft Windows, you should be able to access remote servers from that machine through WireGuard, without making any changes to that machine’s firewall. However, to allow other endpoints in the WireGuard network to access that Windows machine — for example, to access a fileshare, or simply to “ping” it — you usually will have to adjust that machine’s Windows Defender Firewall (WDF).
This guide will show you how to adjust the firewall settings on Windows to allow remote access from a WireGuard network, including:
This guide assumes you have already have set up a working WireGuard connection on the Windows machine. If not, consult one of the following tutorials:
-
WireGuard Point to Point Configuration (set up the Windows machine like the example Endpoint B)
-
WireGuard Hub and Spoke Configuration (set up the Windows machine like the example Endpoint B)
-
WireGuard Point to Site With Port Forwarding (set up the Windows machine like the example Endpoint A)
Also note that you will have to run most of the example commands in this guide as an Administrator user.
Setting Firewall Profiles
Each network interface on a Windows machine belongs to one of the three following network categories (aka network profiles, aka firewall profiles):
- Public
-
an untrusted network, such as the Wi-Fi at a coffee shop
- Private
-
a trusted network, such as your home Local Area Network (LAN)
- DomainAuthenticated
-
(aka Domain) a network on which the machine is authenticated with an Active Directory (AD) Domain Controller (DC)
When you add a new network interface, the Windows Network Location Awareness (NLA) service will probe it to determine whether it can connect to a local AD DC, and to certain public Internet services. If it finds a DC, it will categorize the network interface as Domain; otherwise, most of the time it will categorize the interface as Public.
Most preset WDF rules apply to a specific firewall profile; for example, Windows 10 and 11 have separate “File and Printer Sharing” preset rules for Public, Private, and Domain profiles — and only the Private profile rules are enabled by default.
So the simplest way to enable inbound access to many common network services (like filesharing or ping) on a Windows computer through WireGuard is to change the firewall profile of the WireGuard interface from Public to Private. There are several ways to do this (see the Set Network Location article from the Windows Ten Forums for a full walkthrough of the various options), but a convenient way is through the Set-NetConnectionProfile
PowerShell command:
PS C:\> Get-NetConnectionProfile -InterfaceAlias wg0 Name : wg0 3 InterfaceAlias : wg0 InterfaceIndex : 15 NetworkCategory : Public IPv4Connectivity : NoTraffic IPv6Connectivity : NoTraffic PS C:\> Set-NetConnectionProfile -InterfaceAlias wg0 -NetworkCategory Private
The above commands will display and then set the firewall profile of the WireGuard interface wg0
. This setting is persisted in the Windows registry, under a key that includes the unique GUID for the interface:
C:\> reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles" /s /f wg0 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{3BA24925-42E0-4035-94DD-B563DBA69EB5} ProfileName REG_SZ wg0 3 Description REG_SZ wg0 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{D5239A1F-B71E-4EF8-8EA6-C6A9CD1BDB9C} ProfileName REG_SZ wg0 Description REG_SZ wg0 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{F7B2DF09-72C4-4E15-B3B8-BD531309A1DB} ProfileName REG_SZ wg0 2 Description REG_SZ wg0 End of search: 6 match(es) found. C:\> reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{4EF39DC0-8569-417D-801E-8C582B9D8565}" /v Category HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{4EF39DC0-8569-417D-801E-8C582B9D8565} Category REG_DWORD 0x1
The Category
field will be 0x0
for Public profiles, 0x1
for Private profiles, and 0x2
for Domain profiles.
In the above example, note that there are several different entries for the WireGuard wg0
interface (named wg0
, wg0 2
, and wg0 3
). This is because every time any of the following changes are made to a WireGuard interface, a new interface GUID will be generated for the interface:
-
The interface name changes
-
A peer is added or removed
-
The
AllowedIPs
setting of any peer is changed
Beware that when this happens, the Windows NLA service will try to re-categorize the interface — and any profile setting you’ve made to a previous version of the interface will be ignored.
By PostUp Script
A convenient way to make sure that the current version of any WireGuard interface you’re using has the Private firewall profile set is to run the above Set-NetConnectionProfile
command as a PostUp
script. However, before doing so, you may have to take the following steps:
First, enable the execution of Pre/Post/Up/Down WireGuard scripts in general, by setting the following registry key:
C:\> reg add HKEY_LOCAL_MACHINE\SOFTWARE\WireGuard /v DangerousScriptExecution /t REG_DWORD /d 1 /f
Next, allow the unrestricted execution of PowerShell scripts in general:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy Unrestricted
Finally, edit the WireGuard tunnel to add the following PostUp
script (to the [Interface]
section of the configuration):
PostUp = powershell -Command "Set-NetConnectionProfile -InterfaceAlias wg0 -NetworkCategory Private"
The command execution will be recorded in WireGuard’s log, like the following:
2024-06-16 01:40.14.042: [TUN] [wg0] Executing: `powershell -Command "Set-NetConnectionProfile -InterfaceAlias wg0 -NetworkCategory Private"`
If the command has any output, its output will be displayed as additional entries. And if the command fails, the interface will fail to start up, with a log entry like the following:
2024-06-16 01:40:17.423: [TUN] [wg0] An error occurred while running a configuration script command: A generic command executable returned a result that indicates failure.
To Domain Authenticated
The Set-NetConnectionProfile
command only works to switch the firewall profile between Public and Private — it does not allow a profile to be changed to (or from) Domain. If an AD DC is serving a domain on a WireGuard network, the NLA service on other Windows machines that connect to that network should automatically detect this, and set their WireGuard interface profile to Domain.
However, sometimes the NLA service doesn’t automaticaly switch the WireGuard interface to Domain; this is a known NLA issue. The most reliable fix for it, when it happens, is to toggle the WireGuard interface disabled, and then re-enable it again:
C:\> netsh interface set interface wg0 disabled C:\> netsh interface set interface wg0 enabled
This will trigger the NLA service to re-probe for an AC DC, an re-try authentication.
Also, setting the negative cache period (the number of seconds a “miss” is cached) for the Netlogon service to 0
can help avoid triggering this issue:
C:\> reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters /v NegativeCachePeriod /t REG_DWORD /d 0 /f
Doing the same for the general DNS cache may also help:
C:\> reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters /v MaxNegativeCacheTtl /t REG_DWORD /d 0 /f
On a Domain Controller
On an AD DC, the DC should automatically start serving the domain on its WireGuard interface whenever you start up the tunnel. However, if you find that the DC doesn’t automatically start serving the domain, you may have to edit the registry setting for its interface profile (identifying the GUID for the active version of the interface as shown earlier), and change its Category
field to 2
(Domain):
C:\> reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{4EF39DC0-8569-417D-801E-8C582B9D8565}" /v Category /t REG_DWORD /d 2 /f
Then reboot the DC.
Enabling Preset Firewall Rules
Once you have adjusted the WireGuard interface’s firewall profile to the value you want (Public, Private, or Domain), open up the Windows Defender Firewall with Advanced Security (WFAS) application. This will allow you to view and enable a variety of preset firewall rules that allow inbound access to the network services on the Windows machine:
By default, all inbound connections (connections initiated from another computer to this Windows machine) are blocked, but all outbound connections (connections initiated from this Windows machine to another computer) are allowed. Click the Inbound Rules item in its left-side panel. This lists all inbound preset rules, with a green checkmark next to the enabled rule. Most of these rules enable access to a specific network service for a specific firewall profile:
To enable a preset rule, right-click the rule, and select the Enable Rule menu item. Make sure you select the rule that corresponds to the firewall profile you want to allow — most preset rules have separate, otherwise-identical rules for each of the Public, Private, and Domain profiles; although some rules apply to several profiles (like both Public and Private, or both Private and Domain), or to all of them.
Changes will take effect immediately. A few common rules you may wish to enable (if not already enabled) are:
- File and Printer Sharing (Echo Request - ICMPv4-In)
-
Allows the machine to respond to ping requests made to its IPv4 addresses. (An alternative rule that does the same thing is Core Networking Diagnostics - ICMP Echo Request (ICMPv4-In).)
- File and Printer Sharing (Echo Request - ICMPv6-In)
-
Allows the machine to respond to ping requests made to its IPv6 addresses. (An alternative rule that does the same thing is Core Networking Diagnostics - ICMP Echo Request (ICMPv6-In).)
- File and Printer Sharing (SMB-In)
-
Allows the machine to serve fileshares.
- Remote Desktop - User Mode (TCP-In)
-
Allows RDP (Remote Desktop Protocol) connections to the machine. (The TCP version of this rule is required for RDP access; you may also want to enable the Remote Desktop - User Mode (UDP-In) rule for improved network performance in some situations.)
- Windows Remote Management (HTTP-In)
-
Allows the execution of PowerShell commands on the machine from a remote computer (aka PowerShell remoting).
Adding Custom Firewall Rules
If you don’t find preset rules that match what you need, you can create custom firewall rules. Doing so via the New-NetFirewallRule
command enables you to do so with some options that aren’t readily available through the WFAS UI, such as interface-specific rules.
One thing to keep in mind with WDF rules, however, is that, unlike other firewall systems, WDF rules do not support fine-grained ordering. “Block” rules always take precedence over “Allow” rules; so in practice, custom Block rules are rare — usually you keep in place the profile’s default setting of blocking all inbound connections that don’t match any rules, and then add discrete Allow rules to match each specific kind of connection that you do want to allow.
By Profile
If you move a Windows machine’s WireGuard interface to the Private profile, you may want to add some custom rules that apply to just the Private profile. For example, if you’ve disabled the preset rule that allows RDP access for all profiles, you might add the following rule to allow RDP access only to interfaces in the Private profile:
PS C:\> New-NetFirewallRule ` -Name private3389tcp ` -DisplayName "Remote Desktop TCP-In Private" ` -Group "Custom" ` -Enabled True ` -Profile Private ` -Program C:\Windows\system32\svchost.exe ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 3389
When you add new rules, use the -DisplayName
and -Group
fields to set descriptive names that will allow you to identify your custom rules in the WFAS UI; and use the -Name
option to set a short name that will make it easy to update or remove the rule through PowerShell. For example, to remove the above rule, you can simply run the following command:
PS C:\> Remove-NetFirewallRule -Name private3389tcp
By Interface
For the tightest security, you may want to add some custom rules that allow access to network services exclusively through the machine’s WireGuard interface. For example, you might add the following rule to allow access to a custom web app listening on TCP port 8080 only through its WireGuard interface (where its WireGuard tunnel name is wg0
):
PS C:\> New-NetFirewallRule ` -Name wg0tcp8080 ` -DisplayName "Web App 8080-In wg0" ` -Group "Custom" ` -Enabled True ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 8080 ` -InterfaceAlias wg0
Following are a set of rules that allow access to common network services through the wg0
WireGuard interface:
# allow IPv4 ping New-NetFirewallRule ` -Name wg0ping4 ` -DisplayName "Echo Request ICMPv4-In wg0" ` -Group "Custom" ` -Enabled True ` -Program System ` -Direction Inbound ` -Action Allow ` -Protocol ICMPv4 ` -IcmpType 8 ` -InterfaceAlias wg0 # allow IPv6 ping New-NetFirewallRule ` -Name wg0ping6 ` -DisplayName "Echo Request ICMPv6-In wg0" ` -Group "Custom" ` -Enabled True ` -Program System ` -Direction Inbound ` -Action Allow ` -Protocol ICMPv6 ` -IcmpType 128 ` -InterfaceAlias wg0 # allow filesharing New-NetFirewallRule ` -Name wg0smb ` -DisplayName "File and Printer Sharing SMB-In wg0" ` -Group "Custom" ` -Enabled True ` -Program System ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 445 ` -InterfaceAlias wg0 # allow RDP New-NetFirewallRule ` -Name wg0rdptcp ` -DisplayName "Remote Desktop TCP-In wg0" ` -Group "Custom" ` -Enabled True ` -Program C:\Windows\system32\svchost.exe ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 3389 ` -InterfaceAlias wg0 # also allow RDP optimizations through UDP New-NetFirewallRule ` -Name wg0rdpudp ` -DisplayName "Remote Desktop UDP-In wg0" ` -Group "Custom" ` -Enabled True ` -Program C:\Windows\system32\svchost.exe ` -Direction Inbound ` -Action Allow ` -Protocol UDP ` -LocalPort 3389 ` -InterfaceAlias wg0 # allow powershell remoting New-NetFirewallRule ` -Name wg0pwsh ` -DisplayName "Remote Management PowerShell-In wg0" ` -Group "Custom" ` -Enabled True ` -Program System ` -Direction Inbound ` -Action Allow ` -Protocol TCP ` -LocalPort 5985 ` -InterfaceAlias wg0
For Full Access
If you want to allow unrestricted network access to the machine through the WireGuard tunnel, you can do so with the following command:
PS C:\> New-NetFirewallRule ` -Name wg0all ` -DisplayName "All-In wg0" ` -Group "Custom" ` -Enabled True ` -Direction Inbound ` -Action Allow ` -InterfaceAlias wg0
This may be useful temporarily when setting up a new system, before you’ve figured out which specific ports and protocols need to be exposed. The best practice for security, however, is to inventory the (usually very short) list of network services running on the machine to which remote machines will actually need access, and add a rule for each individually.
Listing Rules
Viewing the details of WDF rules can be a little cumbersome — the Get-NetFirewallRule command only lists rules’ basic information:
PS C:\> Get-NetFirewallRule -Name wg0tcp8080 Name : wg0tcp8080 DisplayName : Web App 8080-In wg0 Description : DisplayGroup : Custom Group : Custom Enabled : True Profile : Any Platform : {} Direction : Inbound Action : Allow EdgeTraversalPolicy : Block LooseSourceMapping : False LocalOnlyMapping : False Owner : PrimaryStatus : OK Status : The rule was parsed successfully from the store. (65536) EnforcementStatus : NotApplicable PolicyStoreSource : PersistentStore PolicyStoreSourceType : Local RemoteDynamicKeywordAddresses : PolicyAppId :
To see the full details, you need to run several additional filter commands:
PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallAddressFilter LocalAddress : Any RemoteAddress : Any PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallApplicationFilter Program : Any Package : PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallInterfaceFilter InterfaceAlias : wg0 PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallInterfaceTypeFilter InterfaceType : Any PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallPortFilter Protocol : TCP LocalPort : 8080 RemotePort : Any IcmpType : Any DynamicTarget : Any PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallSecurityFilter Authentication : NotRequired Encryption : NotRequired OverrideBlockRules : False LocalUser : Any RemoteUser : Any RemoteMachine : Any PS C:\> Get-NetFirewallRule -Name wg0tcp8080 | Get-NetFirewallServiceFilter Service : Any
To filter by a rule’s extended details, start with one of the filters, and then use the Get-NetFirewallRule
command (or other filters) to include other rule fields in the result list. For example, the following command will list the custom rules you’ve added that apply specifically to the wg0
interface:
PS C:\> Get-NetFirewallInterfaceFilter | Where-Object -FilterScript { $_.InterfaceAlias -Eq "wg0" } | Get-NetFirewallRule | Format-Table -Property Name, DisplayName Name DisplayName ---- ----------- wg0tcp8080 Web App 8080-In wg0 wg0ping4 Echo Request ICMPv4-In wg0 wg0ping6 Echo Request ICMPv6-In wg0 wg0smb File and Printer Sharing SMB-In wg0 wg0rdptcp Remote Desktop TCP-In wg0 wg0rdpudp Remote Desktop UDP-In wg0 wg0pwsh Remote Management PowerShell-In wg0