Skip to main content

Automatically start Nginx as a daemon on Mac OS X Mountain Lion 10.8

As I'm setting up my new Mac Mini server running Mac OS X 10.8 Mountain Lion, I wanted to utilize my favorite web server, Nginx. Of course, I wanted to take full advantage of Nginx's multi-process architecture and privilege separation while running as a system daemon running and managed by launchd. This post assumes you've somehow managed to successfully install Nginx. Personally, I went the homebrew route and installed Nginx through the forumla, so all the paths will point to those locations. Naturally, adjust for your own installation.

You'll first need to create the user and group the Nginx daemon will run under. Unless otherwise noted, run the commands in your terminal as your user (yes, I use sudo constantly rather than get a root shell)

# I used a user/group id of 390. I hope it won't conflict
% sudo dscl . create /Groups/nginx PrimaryGroupID 390
% sudo dscl . create /Users/nginx UniqueID 390
% sudo dscl . create /Users/nginx PrimaryGroupID 390
% sudo dscl . create /Users/nginx UserShell /bin/false
% sudo dscl . create /Users/nginx RealName nginx
% sudo dscl . create /Users/nginx NFSHomeDirectory \
  /usr/local/var/run/nginx
% sudo dscl . create /Groups/nginx GroupMembership nginx

I then edited the Nginx configuration file at /usr/local/etc/nginx/nginx.conf to change the user and group to nginx and set the number of worker processes from 1 to 4.

user nginx nginx;
worker_processes 4;

Because the worker processes will be running as a non-root user, we need to update the log locations so the new user can write to them. I gave the nginx user ownership over the main Nginx log directory and associated log file.

# Give nginx ownership of its log files.
% sudo chown -R nginx /usr/local/Cellar/nginx/1.4.0/logs
% sudo chown nginx /usr/local/var/log/nginx

# The next is optional, based on your plist choices.
# Will be used to store the stdout and stderr files.
% sudo install -o nginx -g admin -m 0755 -d /usr/local/var/log/nginx-std

Now that we've got our new user and group created, the configuration file updated, and our permissions set, we can now create our property list file to feed to launchd so the system knows how to handle our process. Since this is an administratively installed background system daemon we'll be storing the file in /Library/LaunchDaemons. Note, we're not storing it in /System/Library/LaunchDaemons as those are strictly for Apple's use, and we don't want to mess around in there.

Following the proper reverse DNS notation, I've named my custom Nginx plist file com.gibixonline.nginx.plist. You can name yours whatever you want, obviously, but I aim for readability and being able to easily identify files as I add more.

<?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.gibixonline.nginx</string>
  <key>Program</key>
  <string>/usr/local/bin/nginx</string>
  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false />
  </dict>
  <key>RunAtLoad</key>
  <true />
  <key>WorkingDirectory</key>
  <string>/usr/local</string>
  <key>StandardOutPath</key>
  <string>/usr/local/var/log/nginx-std/stdout</string>
  <key>StandardErrorPath</key>
  <string>/usr/local/var/log/nginx-std/stderr</string>
</dict>
</plist>

If you chose not to create the nginx-std log directory, remove the StandardOutputPath and StandardErrorPath keys and strings from the XML file (the last four lines in the file before the </dict> tag). Now, with your property list file saved, we're ready to register it with launchd, which we manage by using the launchctl program. To register, you'll use the load command and give it the full path to your property list file and that's it!

% launchctl load /Library/LaunchDaemons/com.gibixonline.nginx.plist

If no output is generated, the command should have completed successfully, which you can verify by using the list command.

% sudo launchctl list com.gibixonline.nginx
{
    "Label" = "com.gibixonline.nginx";
    "LimitLoadToSessionType" = "System";
    "OnDemand" = true;
    "LastExitStatus" = 0;
    "TimeOut" = 30;
    "Program" = "/usr/local/bin/nginx";
    "StandardOutPath" = "/usr/local/var/log/nginx-std/stdout";
    "StandardErrorPath" = "/usr/local/var/log/nginx-std/stderr";
};

Now, on my own machine, Nginx did not start right away, in fact, it didn't start at all (even with the start command) but it did start automatically on reboot, which is what I really wanted. If I added <debug><true /> to my property list file, it started every time it was added, but I'm not entirely sure what debug does (it says it increases logging) so I don't want it in there.

If you need to make changes to your property list file, or what to remove it, you need to unregister it first!

% sudo launchctl unload /Library/LaunchDaemons/com.gibixonline.nginx.plist

# If you're uninstalling it, your'e done, just remove the plist file. If you're editing
# it's the same as before:
% sudo vim /Library/LaunchDaemons/com.gibixonline.nginx.plist
% sudo launchctl load /Library/LaunchDaemons/com.gibixonline.nginx.plist

Well, that's about it! I found that there wasn't a recent posting of setting up Nginx on OS X that had all the information in one place, so I hope this helps anyone else wanting to do the same as I did! My next entry will be about getting Nginx to run on port 80 (which it can, using the method above, since the master process runs as root) and getting it through the firewall without completely disabling it.