Automatically start a Parallels Virtual Machine at boot on Mac OS X 10.8

May 3, 2013 at 12:56 AMJoshua Harley

Setting up my new Mac OS X server, I have a need to set up a virtual Windows Server to host some of my ASP.net websites under IIS. Knowing that there are several virtualization options available for OS X, including VMware Fusion, Oracle VM VirtualBox, and Parallels Desktop, I decided to go with Parallels as I am already used to its interface and how it works (since I use it on my MacBook to virtualize Windows 8) and I happened to have an available license for it. While the instructions below are explicit for Parallels Desktop 8, I imagine the other solutions should work in a similar fashion, especially VirtualBox since I know it has a command line interface and can easily run in headless mode.

Installing Windows Server 2012 was pretty straightforward and uneventful, the only option I can think of that might have an impact is I selected the "Share this virtual machine with others" option when creating the virtual machine. Selecting this option caused the virtual machine to be stored at /Users/Shared/Parallels instead of being placed in the signed in users home directory. This should definitely be selected if you plan on running the virtual machine under a service account rather than the owner account.

Since we're wanting to run this on machine boot without using auto login and the user's login items (as suggested in many places online) we're going to need another launchd property list file to instruct launchd to start our virtual machine for us.

<?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.miu</string>
  <key>UserName</key>
  <string>miu-owner</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/prlctl</string>
    <string>start</string>
    <string>{ffae2c75-8f39-4ac5-9585-868bdfa91014}</string>
  </array>
  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false />
  </dict>
  <key>RunAtLoad</key>
  <true />
  <key>LaunchOnlyOnce</key>
  <true />
  <key>AbandonProcessGroup</key>
  <true />
</dict>
</plist>

The above file is saved using the reverse DNS style in the /Library/LaunchDaemons folder (since this is a non-interactive system process added by us) and the label matches the file name. In case I have other virtual machines in the future, I decided to use the virtual machine's name (Miu) as part of the file name (com.gibixonline.miu.plist) and label (com.gibixonline.miu). There are a couple significant items I would like to point out this particular property list file.

  • We're making use of the UserName key to launch the VM as the owner (the user which created the VM). I intend on making a service account like I did for Nginx, but I haven't done so yet. I don't think there will be any problems since I marked the VM as "Shared." Of course, if your VM lives in a home directory, the user will need to be able to write there to boot.
  • We switched from using the Program key to ProgramArguments. The last item in the array is the machine's unique identifier. You can use either the unique id or the name of the machine, I chose to use the unique identifier in case I ever changed the name of the machine.
    You can get the unique id by running prlctl list -a
  • LaunchOnlyOnce is added, since there is no way for launchd to know the status of the VM. This indicates that the property list should be loaded and executed once and discarded. You won't find the status of this job in the list.
  • Most importantly, AbandonProcessGroup is set. Without it, when prlctl exits, launchd will automatically terminate any process with a parent process id that matched prlctl. This meant the machine wouldn't boot for more than a second or two.

After creating the plist file, don't forget to register it with launchd by running sudo launchctl load /Library/LaunchDaemons/com.gibixonline.miu.plist. I've had no issues with the machine booting when the host boots and I haven't run in to any stability problems with the VM.

One important thing I would like to point out. When launching in headless mode like this you should avoid opening the Parallels Desktop app in your login session. In doing so, the VM will show its screen (which is nice) but you won't be able to close Parallels Desktop or log out of your Mac without suspending or stopping the virtual machine. If you accidentally do this (or had to because it disappeared from the network) simply make sure Parallels Desktop has quit and either ssh or open a terminal and type in the start command (no need for sudo, su maybe, if you're running as another user): prlctl start Miu will bring the VM right back up.

In fact, to avoid this, I installed a remote desktop client and will connect through there if I need a "console." Since the official Microsoft Remote Desktop client for Mac crashes so much and has issues with accessing a tunneled RDP session, I recommend using the free CoRD remote desktop software.

Posted in: osx

Tags: , , ,

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

April 29, 2013 at 11:23 PMJoshua Harley

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.

Posted in: osx

Tags: , , ,

wlalias.com is live!

January 20, 2013 at 6:03 AMJoshua Harley

The wlalias tool now has an official site at http://wlalias.com. All major information will be posted there with better documentation and information. I'll add a feed of some sort relatively soon so that people can follow that for proper updates to the application.

As always, if there is any issues to report, please use the BitBucket Issue tracker for wlalias.

Posted in:

Tags:

wlalias 1.5 released - Create email aliases for Domains for Windows Live

December 23, 2012 at 11:06 PMJoshua Harley

An update to the wlalias tool has been released. This release is mostly a bug fix release. The most significant change is that SoapExceptions now attempt to retrieve the internal error information provide the information to the user.

A couple of questions by users have come up, so without further ado, a mini FAQ:

  • How many aliases can I add to a user?

    The actual Windows Live documentation says 15 aliases can be added (see the remarks section) but end users have reported that they can only add 5 aliases to one user using this tool. I am still looking in to the issue.

  • I've received a SoapExecption. What do I do?

    If you're using version 1.0 of the tool, upgrade now to 1.5 and try again. There are many, many reasons why the SoapException can occur, but the most common reason mentioned occurs when attempting to add an alias using an email address that is already in use by an actual Windows Live account. Until I see what the actual error description is, I can't really know though.

  • What's next for the tool?

    I have plans to add support to evict and import members. Evicting members will allow you to kick out existing accounts that may have been registered using your domain before it was added to Windows Live for Domains. Importing members will allow you to import an unmanaged user in to your domain if it was registered in your domain. These two methods should help provide solutions for the question above.

If you haven't already, go download release 1.5 now and see if it helps. If you haven't used it, but want to add aliases to your Windows Live domain, give it a run, it should work. No new features have been added, so see the initial post on wlalias 1.0 on a tutorial of the program.

Posted in: Programming | wlalias

Tags: