John Elliott

OpenVPN Launch Daemons on MacOS

Launchd is the init system on MacOS. I need to create services infrequently, so I replenish my launchctl knowledge each time. https://launchd.info/ deserves a lot of credit for bringing commonly-used knowledge out of the man pages and to the web where it’s easily discoverable.

This week I need to connect to two OpenVPN networks with different transport types (UDP and TCP) and it’s easiest to run two OpenVPN instances to do this.

What follows are some steps to aid my memory.

  1. Install OpenVPN with homebrew
  2. Create a plist file with your OpenVPN config path
<?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>org.johnelliott.ovpn</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/sbin/openvpn</string>
        <string>--config</string>
        <string>/Users/john/john.ovpn</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/tmp/ovpn.stderr</string>
    <key>StandardOutPath</key>
    <string>/tmp/ovpn.stdout</string>
</dict>
</plist>
  1. Change ownership of the plist file to root/wheel
sudo chown root org.johnelliott.ovpn.plist
sudo chgrp wheel org.johnelliott.ovpn.plist
  1. Load and start the service
sudo launchctl bootstrap system org.johnelliott.ovpn.plist
  1. Check how the service is running in the logs
tail -f /tmp/ovpn.std*
  1. Check in on your service as launchd sees it
sudo launchctl print system/org.johnelliott.ovpn