How to Setup Wireguard VPN Server On Windows

wireguard server for windows tutorial

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!


  • 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)

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
PrivateKey = #Replace with server private key#
ListenPort = 51820
Address =

#Client 1
PublicKey = #Replace with client public key#
PresharedKey = #Replace with pre-shared key#
AllowedIPs =
#Client Config
PrivateKey = #Replace with client private key#
Address =
DNS =,

PublicKey = #Replace with server public key#
PresharedKey = #Replace with pre-shared key#
AllowedIPs =
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.

wireguard server for windows tutorial

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 adpater 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). Private 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


        $netShare = $null

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

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

		#Clear Existing Share	       
		$oldConnections = $netShare.EnumEveryConnection |? { $netShare.INetSharingConfigurationForINetConnection.Invoke($_).SharingEnabled -eq $true}           
		foreach($oldShared in $oldConnections)
            $oldConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($oldShared)
        # Find connections
        $InternetConnection = Get-NetRoute | ? DestinationPrefix -eq '' | 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)

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:


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 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:


Then simply change ScopeAddress and StandaloneDHCPAddress to the IP address we desire ( 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”:

wireguard server for windows tutorial

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 comman prompt or powershell everytime 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

This Post Has 44 Comments

  1. Fer Nando

    Thank you, I will do all the settings again. Let’s see if I can get the wireguard server up and running on windows.

  2. Fer Nando

    Good afternoon, after importing the wireguard module it generates the following error

    PS C: \ WINDOWS \ system32> Set-NetConnectionSharing “Windows10” $ true
    Exception when calling “Invoke” with arguments “1”: “The argument cannot be processed because the value of the
    argument “arguments” is NULL. Change the value of the “arguments” argument to a non-null value. ”
    In C: \ WINDOWS \ system32 \ WindowsPowerShell \ v1.0 \ Modules \ wireguard \ wireguard.psm 1:49 Character: 9
    + $ publicConfig = $ netShare.INetSharingConfigurationForINetConn …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~
    + CategoryInfo: NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId: PSArgumentNullException

    You cannot call a method on a NULL expression.
    In C: \ WINDOWS \ system32 \ WindowsPowerShell \ v1.0 \ Modules \ wireguard \ wireguard.psm 1:54 Character: 13
    + $ publicConfig.EnableSharing (0)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo: InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId: InvokeMethodOnNull

    1. Henry

      You seem to have an extra space in “$ true”, it should be just “$true”.

  3. Joe

    PS C:\> Set-NetConnectionSharing “Wireguard_Server” $true
    Exception calling “Invoke” with “1” argument(s): “Cannot process argument because the value of argument “arguments” is
    null. Change the value of argument “arguments” to a non-null value.”
    At C:\windows\system32\windowspowershell\v1.0\Modules\wireguard\wireguard.psm1:50 char:9
    + $privateConfig = $netShare.INetSharingConfigurationForINetConnection.Inv …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : PSArgumentNullException

    You cannot call a method on a null-valued expression.
    At C:\windows\system32\windowspowershell\v1.0\Modules\wireguard\wireguard.psm1:55 char:13
    + $privateConfig.EnableSharing(1)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    1. Joe

      Nevermind the above, i mistyped the tunnel config name! All works well!


  4. PrunusH

    You have to add the powershell module. To do that: Import-Module .\wireguard.psm1

  5. Ionut Tudor

    C:\windows\system32\WindowsPowerShell\v1.0\Modules\wireguard> Set-NetConnectionSharing
    The term ‘Set-NetConnectionSharing’ is not recognized as the name of a cmdlet, function, script file, or operable progr
    am. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:25
    + Set-NetConnectionSharing <<<<
    + CategoryInfo : ObjectNotFound: (Set-NetConnectionSharing:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

  6. Fabrice

    Thank you for this article.
    Can I setup a wireguard vpn between a windows client and a virtual Linux server (hosted by the windows client with VMWare Workstation) ?

  7. Terry

    How do I stop a specific network adapter from using the tunnel?

  8. nadinetheSCHLUT

    where to get the PresharedKey? is it really necessary?

    1. Henry

      Creating presharedkey, public key, and private key is not the focus of this tutorial. It is part of the standard server creation process, which there are already plenty of tutorials out there. You can even use the Windows Wireguard GUI tool to create them.

  9. nadinetheSCHLUT


    where to get “PublicKey = #Replace with client public key#
    PresharedKey = #Replace with pre-shared key#”

    best wishes!

  10. Mike

    Just a fyi, the EnableRebootPersistConnection registry fix doesn’t work for everyone (me included). No idea whether MS broke it again after the implementation or just didn’t fix it completely to start.

    Spent many many hours scouring for fixes to this problem and best I came up with was to have a .bat file run in startup the calls a powershell script that will toggle sharing on and off. This still needs the user to click ok on a powershell popup because MS doesn’t allow this type of function to be run without administrator input.

    Was very tempted to just use a VM running linux on the windows machine but since computer running server is basically always on I’ve learned to live with it.

    Nice writeup, wish it was around in December when I set my machines/devices up. Had to cobble together random posts from all over but once understood enough it was a breeze compared to openvpn.

    1. Henry

      You can use Task Schedule to run the bat files as administrator on startup to avoid the need to click the popup. This used to be part of the original tutorial before I found the hotfix.

  11. Tim Byng

    Great post! I was able to get it up and running with these instructions with a slight modification to not specify the DNS so that it uses the VPN server’s DNS. This works as expected for FQDNs ( by not host names (myserver). Do you know if there’s anyway to set the “DNS Suffix Search List” on the client?

  12. Edgar Robles

    Excellent. Thank you!!

  13. Benjamin

    Had been looking for this for quite a while. Thanks so much for taking the time!

  14. Hebar

    Thanks a lot for this thorough guide. You solved me a lot of headache with that script and detailed explanation.

    However, is it not at all possible getting this to work with multiple peers? I can get two servers running using the service method, although that method sucks if you would like to have a lot of clients. Still, the script that enables the network sharing/routing only works on a single interface. Is this a technical restriction?

    1. Henry

      You can have multiple peers connecting to one server, unless you meant you want to have multiple servers?
      To enable network sharing on multiple interfaces, you can use the bridge function. Make a bridge interface say “wg_bridge” and bridge the Wireguard interfaces (wg_server1, wg_server2… etc.) together, then run the script on the bridged “wg_bridge” interface.