Running homebrewed Nginx with sudo and launchctl on MacOS X

Sometimes we need to run nginx server on the 80 port, but this can be possible only if run it with root privileges.

Updated on 9 January 2013 by Jim Cushing, jimothy [at] mac.com

Instead of moving the nginx bin and creating a shell-script to wrap nginx with sudo command we are able to keep nginx binary in place and use next .plist to start/stop it:

<?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>homebrew.mxcl.nginx</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/opt/nginx/sbin/nginx</string>
        <string>-g</string>
        <string>daemon off;</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/usr/local</string>
  </dict>
</plist>

This is basically the stock Homebrew launch agent plist for Nginx, but I removed the "UserName" so it will run as root. I also put it in /Library/LaunchAgents/ (or in /Library/LaunchDaemons/) rather than ~/Library/LaunchAgents/.

I can start and stop nginx with launchctl now.

It turns out the need for the shell script was because of the Homebrew plist didn't include "daemon off;".

Here is the previous version of this little how-to

Root privileges we can get with the sudo command.

This tip will work only if you configured your sudo command to prevent asking password for your user (or if you can configure it to prevent asking password only for next commands).

First of we need to rename original nginx binary in /usr/local/Cellar/nginx/ve.rs.ion/sbin directory to something like nginx_bin:

$ cd /usr/local/Cellar/nginx/ve.rs.ion/sbin
$ mv nginx nginx_bin

Then we need to create bash script with the nginx name in the sbin directory:

$ vim nginx
# ... put contents in it (showed below)
$ chmod +x nginx

and put this content in it (change 've.rs.ion' with your nginx installed version):

#!/bin/bash

NGINX_BIN="/usr/local/Cellar/nginx/ve.rs.ion/sbin/nginx_bin"

function on_die() {
    sudo $NGINX_BIN -s stop
    exit 0
}

trap on_die TERM

sudo $NGINX_BIN $@ &

wait

Another thing we need to do is add daemon off; string to nginx.conf file (placed in /usr/local/etc/nginx directory). You can place it on the top of this file.

Next we can use next .plist file, which you need to put into ~/Library/LaunchAgents/org.nginx.plist file (don't forget to replace ve.rs.ion with your installed version number):

<?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.nginx</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/Cellar/nginx/ve.rs.ion/sbin/nginx</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/usr/local</string>
  </dict>
</plist>

That's all!

Now you can use launchctl utility to load/unload your nginx server:

$ launchctl load -w ~/Library/LaunchAgents/org.nginx.plist 
$ launchctl unload -w ~/Library/LaunchAgents/org.nginx.plist
A+ a-
Clip in Evernote