Setting a static route every boot with launchd / plist is failing

I hope to use launchd to set a static route on a server at boot time since I haven't figured a better way to configure this sort of networking on a server.

My problem is that the command seems to be running before the network stack is set up, so I'm looking for advice how to change my plist to somehow depend on the system routing being set up before it runs.

Jan 16 14:39:45 server com.company.route.legacy_printer[149]: route: writing to routing socket: Network is unreachable

Jan 16 14:39:45 server com.company.route.legacy_printer[149]: add net 10.1.1.1: gateway 10.0.1.2: Network is unreachable

I get this error after a reboot, but loading the same plist as root once the mac has booted works just fine so I'm hoping it's an easy tweak or someone clueing me into a better way to get a static route reliably after each boot.

<?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.company.route.legacy_printer</string>
    <key>ProgramArguments</key>
    <array>
        <string>/sbin/route</string>
        <string>-n</string>
        <string>add</string>
        <string>-net</string>
        <string>10.1.1.1</string>
        <string>10.0.1.2</string>
        <string>255.255.255.0</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>AbandonProcessGroup</key>
    <true/>
</dict>
</plist>

I have reviewed both Running a command whenever Mac boots up with launchctl/plist and How can I run/stop/relaunch an application automatically, at boot/login/some other time? to get this far, but need an extra nudge on finding the correct dependency to get the timing right for the route command.


A short call to scutil should help with testing whether the network is up for a specific interface on IPv4 which should suffice to determine when you can add an IPv4 route. The following command will return a 0 if the first ethernet connection has a viable IPv4 address within the default 15 second timeout period.

  • /usr/sbin/scutil -w State:/Network/Interface/en0/IPv4

You could instead call a script to do the testing and routing - perhaps using the -t command to adjust the timeout if needed. I don't know a way to overload the launchd arguments to have everything contained, but it should be fine to have launchd kick off a script on the local filesystem to accomplish this task. Use care if you are not using en0 for your IPv4 or wish to have routing on other than the default networking interface.

That script can then check for errors, perhaps check for other interfaces as well as log success and failure using the logger command.