Mac VPN server startup fix

If you can’t connect to your VPN server upon startup, then read on.

Although Apple decided to abandon the Server.app and completely shut down internal efforts to provide a solutions that would help using a Mac as a server, macOS still comes with a built-in VPN server we can engage.

Basically it needs two plists: one that contains the configuration including the DHCP IP range etc., and the other one that is called by the launchctl daemon and starts the vpnd command.

You can create both manually, but it’s much easier to do it with a third-party app called VPN Enabler that works up to 10.14 Mojave. On newer OSes you may try the Open VPN Enabler for Catalina.

The issue with both the publicly available .plist files and VPN Enabler is that when the Mac that acts as a server is restarted, the vpnd process runs (we can see it in Activity Monitor), but you can’t connect to it and establish a VPN connection.

If you are using the VPN Enabler you have to launch it and click the ‘Restart VPN’ button, or simply issue this command via Terminal:

killall -HUP vpnd

or with 2 steps:

sudo launchctl unload -w /Library/LaunchDaemons/com.cutedgesystems.vpn.plist

and then

sudo launchctl unload -w /Library/LaunchDaemons/com.cutedgesystems.vpn.plist


The reason vpnd daemon does not respond to a connection is that the process starts too early during the boot, before the network interface has been initialised.

The startup of vpnd is managed by a plist file that VPN Enable copies from here:

/Applications/VPN\ Enabler.app/Contents/Resources/VPNStuff/…


to here

/usr/local/cutedge/vpn/…


and then creates a link to

/Library/LaunchDaemons/…

if you have your self made plist, this is the location to put.


This .plist will be loaded by the launchctl process upon startup.

Apple does not provide a way to delay a startup of a process via launch daemon, but we can tell launchctl to wait for the network interfaces to complete the initialisation and then start up the vpnd binary that acts as a VPN server.

by the way the vpnd can be found here

/usr/sbin/vpnd

What you may want to fix in your existing plist are the following changes:


delete these lines if you have them

<key>OnDemand</key>
<false/>

and add these lines. here we are telling launchctl to wait for changes in the provided locations – that actually reflects the initialisation of network interfaces

</array>
<key>WatchPaths</key>
<array>
<string>/etc/resolv.conf</string>
<string>/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist</string>
<string>/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist</string>
</array>

At the end your plist should look like this:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
<dict>
<key>Label</key>
<string>com.cutedgesystems.vpn</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/vpnd</string>
<string>-x</string>
<string>-i</string>
<string>com.apple.ppp.L2TP</string>
</array>
<key>WatchPaths</key>
<array>
<string>/etc/resolv.conf</string>
<string>/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist</string>
<string>/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist</string>
</array> </dict>
</plist>

As a best practice, enter the code manually, do not copy-past as it might contain some invisible characters that can make the plist unusable. And make sure to check it with plist utility:

sudo plutil /Library/LaunchDaemons/com.cutedgesystems.vpn.plist