Notes on keeping OpenVPN alive on a Mac
Let's say you have a Mac which is parked behind a distant NAT box, and yet you still need to log into it. You could set up a VPN of some sort, but of course, now you have two problems. Configuring it properly and keeping it up becomes a non-trivial affair until you figure out exactly how all of these things want.
I've learned a few things about making openvpn2 run on a Mac which I figured are worthy of a post to get them out there for the world.
First, if you dig around online, you can find any number of "plist" files for openvpn. The gist is that you create a file in /Library/LaunchDaemons called org.openvpn.plist or net.openvpn.plist, or really anything you want. Then you put a bunch of magic cruft in there, and it will start it up for you.
If you don't want to treat all of this as magic, the good news is that this file format has a man page: launchd.plist(5). If you read that, you will learn something I did not know up front: processes must not call daemon() or equivalent. Oops.
Historically, I've always run OpenVPN on machines where having it "daemonize" itself by forking and detaching from its ttys made sense. However, when I recycled a config file with the "daemon" directive on this Mac, all kinds of stupidity started happening. First, I could watch in the /var/log/system.log and it would keep restarting it over and over. The only thing keeping it from starting tons of copies was the fact that its local port was already bound.
Also, in this state, "launchctl list" would show something like "0x100402c30.anonymous.openvpn" instead of a reasonable entry. It turns out this happens when launchd starts a program and then "loses" it... like if it goes into the background by itself. This is not an easy thing to discover through the available documentation!
If you run into this, just figure out whatever is making your program jump into the background and force it to stay in the foreground instead. launchd really wants to keep its hooks in your program as a direct child, and gets seriously unhappy any other way.
It's also a good idea to take a look at "KeepAlive" and notice that it's possible to just set it to "true" to unconditionally keep things running. If you skim that paragraph and jump down to the four options (SuccessfulExit, NetworkState, PathState, OtherJobEnabled), it's easy to miss the fifth (true).
This seems to be the way of quasi-Unix systems these days. Everyone is reinventing init for one reason or another.