This tutorial goes through the process of setting up a Wireguard server on Windows. Most Wireguard tutorials on the internet only give you the choice of hosting a server in a Linux environment. However, it is very possible to setup a windows server.

After searching for a tutorial to no avail, I spent a couple days to figure out the best way to do it and how to automate the process. Ideally you would still want to run it in an Linux environment, but if you have a use case for a windows server like me, you would appreciate just how flexible Wireguard is!

Prerequisite

  • Latest Wireguard Windows Client installed (Download here from official site)
  • Setup firewall rules (just as you would for a Linux server setup: open and forward ports 51820, configure ddns etc)

Disclaimer: Using Wireguard on Windows as server is not officially supported. Use at your own risk.

Step 1: Prepare Wireguard Server and Client Config File

This step is the same as other Linux tutorials. I’ve provided my own server side and client side configs below, adjust to your own use case.

#Server Config
[Interface]
PrivateKey = #Replace with server private key#
ListenPort = 51820
Address = 192.168.200.1/24

[Peer]
#Client 1
PublicKey = #Replace with client public key#
PresharedKey = #Replace with pre-shared key#
AllowedIPs = 192.168.200.2/32
#Client Config
[Interface]
PrivateKey = #Replace with client private key#
Address = 192.168.200.2/24
DNS = 1.1.1.1, 8.8.8.8

[Peer]
PublicKey = #Replace with server public key#
PresharedKey = #Replace with pre-shared key#
AllowedIPs = 0.0.0.0/0
Endpoint = #Replace with server domain name or ip address#:51820

After you prepared the server config files, place it in a folder somewhere permanent. For this tutorial I will assume the server config file is placed at C:\wireguard\wg_server.conf

Step 2: Start up the server

Instead of using the GUI to start the server, we will start it using command options. At the time of this tutorial the official GUI only allows one connection at a time. If we use it to run the server, the GUI will be occupied and we won’t be able to make a new connection without dropping the server interface. Running the server using command line options allows us the keep the GUI free for daily use. If you don’t mind the GUI being occupied, you can just start the server on the GUI and skip to Step 3.

Use the following code to start / stop the server. Without saying, adjust the file paths if they are different on your system.

You need to run these with administrative privilege!

#Start server
C:\Program Files\WireGuard\wireguard.exe /installtunnelservice "C:\wireguard\wg_server.conf"

#Stop server
C:\Program Files\WireGuard\wireguard.exe /uninstalltunnelservice wg_server

You will only need to run the command once, wireguard’s background service will remember the run state over reboots. Once you start the server, wireguard will create a new network adapter as the same name as your server config file. Thus for our tutorial, the network adapter name would be “wg_server” Check if the network adapter is successfully created.

If you named your config file “Wireguard_Server.conf”, the network adapter created will also be name accordingly

Step 2.1: (Optional) Setting adapter profile

Now we have the wireguard adapter setup, it is recommended to change it to “Private” profile”, by defaults the adapter is added as “Public”. Private profile will allow greater compatibility for the clients (say you want to use some remote desktop etc.). Public profile may block these ports and services.

To Do this we run three simple PowerShell commands with admin privilege manually:

#Open powershell with admin privilege and run the following:

$NetworkProfile = Get-NetConnectionProfile -InterfaceAlias "wg_server"

$NetworkProfile.NetworkCategory = "Private"

Set-NetConnectionProfile -InputObject $NetworkProfile

Step 3: Enable server routing

Now that server is running, the client should be able to handshake (given that you have the correct ports open and forwarded correctly). However, you will notice the client won’t be able to access either the internet or the LAN network. This is because by default windows do not bridge or NAT the wireguard interface with your actual physical internet interface. In Linux this is done by some PostUp/PostDown firewall commands, which we do not use here. Instead, we use a PowerShell script to enable the NAT (or in Windows term “internet sharing”) function:

Function Set-NetConnectionSharing
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [string]
        $LocalConnection,

        [Parameter(Mandatory=$true)]
        [bool]
        $Enabled        
    )

    Begin
    {
        $netShare = $null

        try
        {
            # Create a NetSharingManager object
            $netShare = New-Object -ComObject HNetCfg.HNetShare
        }
        catch
        {
            # Register the HNetCfg library (once)
            regsvr32 /s hnetcfg.dll

            # Create a NetSharingManager object
            $netShare = New-Object -ComObject HNetCfg.HNetShare
        }
    }

    Process
    {
		#Clear Existing Share	       
		$oldConnections = $netShare.EnumEveryConnection |? { $netShare.INetSharingConfigurationForINetConnection.Invoke($_).SharingEnabled -eq $true}           
		foreach($oldShared in $oldConnections)
        {
            $oldConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($oldShared)
            $oldConfig.DisableSharing()                        
        }        
	
        # Find connections
        $InternetConnection = Get-NetRoute | ? DestinationPrefix -eq '0.0.0.0/0' | Get-NetIPInterface | Where ConnectionState -eq 'Connected'        
        $publicConnection = $netShare.EnumEveryConnection |? { $netShare.NetConnectionProps.Invoke($_).Name -eq $InternetConnection.InterfaceAlias }
        $privateConnection = $netShare.EnumEveryConnection |? { $netShare.NetConnectionProps.Invoke($_).Name -eq $LocalConnection }

        # Get sharing configuration
        $publicConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($publicConnection)
        $privateConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($privateConnection)

        if ($Enabled)
        { 			
            $publicConfig.EnableSharing(0)
            $privateConfig.EnableSharing(1)
        }
        else
        {
            $publicConfig.DisableSharing()
            $privateConfig.DisableSharing()
        }
    }
}

Note: The shell script is originally created by igoravl, I made some modification to simplify the process and get rid of some errors for our wireguard server application.

This shell script is written as a custom function “Set-NetConnectionSharing” and needs to be loaded in PowerShell.

Save the script in the following location:

C:\Windows\System32\WindowsPowerShell\v1.0\Modules\wireguard\wireguard.psm1

wireguard.psm1 needs to be in a folder named wireguard for the function to be loaded by powershell

Now you can open a PowerShell window with administrative privilege and run the following commands to enable / disable NAT for our wireguard server interface.

#"wg_server" is the wireguard adapter name, replace it if you have something different.
#Enable NAT
Set-NetConnectionSharing "wg_server" $true

#Disable NAT
Set-NetConnectionSharing "wg_server" $false

If everything goes well, when you open the properties panel of your main internet network adaptor (Ethernet 3 in my case) the following options should be ticked:

Notice also the “Home networking connection” field should be populated with your wireguard interface name (picture shows Wireguar_Server but should be wg_server if you are following the tutorial).

Technically you can do this through the windows gui using the properties menu manually, but having this script will allow you to automate the server start/stop process as you will see later on in the tutorial.

Now everything should be working correctly, the client should be able to reach the internet and LAN network you allow it to.

Step 3.1: Change default Internet Connection Sharing IP

By default, when internet sharing (NAT) is enabled, Windows will change the IP address of the adapter to something else (to avoid conflicts). However, we already know what IP address we want to adapter to be (set in the [interface] block in our wireguard config), which is 192.168.200.1 in our case.

To modify the default IP Windows will switch to, we can simply change the setting in registry. Open Registry Editor and go to the following path:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\SharedAccess\Parameters

Then simply change ScopeAddress and ScopeAddressBackup to the IP address we desire (192.168.200.1 in our case).

Disable and re-enable Internet connection sharing (NAT) using the powershell command in Step 3 to make sure this change takes place (you might need to restart computer).

Step 4: Enable persistent Internet Sharing on restart (updated 2/12/2020)

Since there is a windows bug that internet connection sharing will not auto start on reboot, we need to change a few settings to make sure internet sharing is started. The earlier tutorial used a scheduled task to accomplish this, but I’ve found a better way after reading the windows bug fix here.

Open the Service window and find “Internet Connection Sharing”:

Chang the startup type to “Automatic”:

After that’s done, finally we add a registry:

Path: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\SharedAccess
Type: DWORD (32bit)
Setting: EnableRebootPersistConnection
Value: 1

Step 4.1 (optional) Bat files to easily start / stop server manually

For convenience I also made two bat files to run these commands so I don’t have to open command prompt or PowerShell every time to start and stop the server.

Server start batch script: (save as “start.bat” and run with admin privilege)

@echo off
"C:\Program Files\WireGuard\wireguard.exe" /installtunnelservice "C:\Henry-Scripts\Wireguard_Server.conf"
"%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" Set-NetConnectionSharing "Wireguard_Server" $true

Server stop batch script:  (save as “stop.bat” and run with admin privilege)

@echo off
"%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" Set-NetConnectionSharing "Wireguard_Server" $false
"C:\Program Files\WireGuard\wireguard.exe" /uninstalltunnelservice Wireguard_Server

Final Remarks:

Compared to Linux, setting up a windows wireguard server can be tricky. However, I have done most of the ground work for you (the PowerShell script to enable NAT). Running the PowerShell script on startup with 3 minutes delay is not elegant, but it works. There should be a way to run the task after the wireguard service is started and running, but I wasn’t able to get it to work. If you know how to get it to work, please share it with me.

If you like my work, feel free to buy me a coffee:

Leave a Reply