Saturday, January 16, 2016

Setup of Ruby Development Environment VM

I recently needed to provide some development environment setup instructions to a friend, so I figured it would be a good idea to document them here in case I need them again or if it helps anyone else.

Let me start off with a few premises:

  • I like doing Ruby on Rails development.
  • Ruby development on Windows is not pretty.
  • The computer I'm using most often is Windows-based (provided for my "real" job which is not Ruby development).
  • My personal computers are Macs.
  • I want to be able to work from any computer but don't want to hassle with keeping the environments in sync.
  • I've used multiple flavors of Linux over the years back to the SLS days (Linux version 0.9x), and am very comfortable with it.
With those premises in mind, I've adopted the use of a virtual machine (VM) to be my development environment.  It allows me to separate my personal development environment from other clutter (or even probing by workplace compliance scans), and allows me to readily move it from machine to machine as necessary.  I also usually host my applications on Linux-based servers, so it provides me more confidence in an environment that matches the deployment environment.

I personally don't like living in a VM window to work.  I also feel that I'm already running a windows manager (Windows or OSX) on my host operating system, so why incur the overhead of running another one in the VM.  Therefore, I run a "headless" Linux in the VM, and open X windows on the host by running a simple X server on the host OS.

Step 1 - Setup an X server on the host OS

For Windows, I recommend VcXsrv (see http://sourceforge.net/projects/vcxsrv/), but if you're already using Cygwin for other UNIX applications, the Cygwin Xserver (see http://x.cygwin.com/docs/ug/setup-cygwin-x-installing.html) works well, or alternatively you could try Xming (http://sourceforge.net/projects/xming/files/latest/download).

For OSX, I use XQuartz (see http://www.xquartz.org/)

Step 2 - Install VMWare (or VirtualBox, Parallels, etc.)

I'm not going to provide instructions for every virtualization software out there.  I use VMWare so that's what I'm describing.  Other solutions work just as well.

For Windows, VMWare Player does everything you need, and it's free!

For OSX, there's no free player, so you have to purchase VMWare Fusion.  (but, hey, it's the only thing you need to buy!).

Step 3 - Download a Linux distribution ISO

Again, there are plenty of options (Ubuntu, Red Hat, SuSE, etc), but I'm using Ubuntu here as it is frequently used for hosting.  You want the Server version (not Desktop) as it will be more light-weight without all the X11 + window manager overhead.  Also, I recommend the LTS (longer term service) version so you don't have to deal with upgrading your OS all the time (besides security fixes of course).

Step 4 - Create a New Virtual Machine

Select the VMWare option to create a new virtual machine, point it to the ISO and it should be pretty straight forward.

You don't have to be excessive with the resources you allocate for the VM.  The default recommendations by VMWare will probably suffice, but if you have a little more to give, then bump it up a little.  For example, the VMWare recommendation for the memory is 1GB, my system has 16GB so I gave the VM 2GB.  I allowed it 4 out of the 8 processor cores, and give it up to 40GB of disk space.

Step 5 - Forward local ports to VM

While this is not strictly necessary, it is useful.

For Windows, in earlier versions of VMWare Player, the Virtual Network Editor was included, but you needed to know the right command to access it.  In case the current omission is unintentional and they add the network editor back in future releases, the method to access the network editor for VMPlayer was:

  1. Open command prompt as administrator
  2. cd "C:\Program Files (x86)\VMware\VMware Player"
  3. rundll32.exe vmnetui.dll VMNetUI_ShowStandalone

As it stands currently, that will give you an error that the vmnetui.dll is not found.  So instead, you need to extract the Virtual Network Editor from the VMWare Workstation package.  This is done by:

  1. Download the latest VMWare Workstation package.
  2. unpack it locally with this command :
    "
    VMWare-worksation-full-10.0.1-xxxxxx.exe /e .\ext"
    note the xxxxxx is the release id you got at download
  3. Go to the newly created "ext" directory and open the "core.cab" (use your favorite zip util)
  4. Get the "vmnetcfg.exe" from there, and copy it to the vmwareplayer install directoryGet the "_vmnetcfglib.dll" file and rename it "vmnetcfglib.dll", and then copy it to the same directory than for vmnetcfg.exe
OR  

Download vmnetcfg.exe and vmnetcfglib.dll and put them in your VMWare Player install directory.

Once you have the Virtual Network Editor, select the NAT adapter (should be VMnet8), click on the "NAT Settings..." button, and add whatever ports you'll be using as shown below.  In this example, my VM IP is 192.168.216.131 and I'm forwarding ports 22 for SSH and 3000 as the default Rails server port.  Add port 80 if you'll be running your apps through a normal HTTP server like Apache or nginx (ex. via Passenger).




For Macs using VMWare Fusion, edit the vmnet8 NAT config file using the terminal and your favorite editor

sudo emacs /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf

or
 
sudo vim /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf
 
 
Near the bottom you’ll see something like this
 
[incomingtcp]
 
# Use these with care - anyone can enter into your VM through these...
# The format and example are as follows:
# = :
#8080 = 172.16.3.128:80
 
This is where we’ll be putting the port forwarding.  We'll assuming the same VM IP and that we still want to forward to the Rails server port 3000 and SSH port 22.   Since OSX is likely already running an SSH server on port 22, we'll forward from port 2222 instead.  So, add the lines:

3000 = 192.168.216.131:3000
2222 = 192.168.216.131:22 


Restart VMWare Fusion and it should be forwarding to these ports for you.  Alternatively, you could restart the VMWare networking using the command line:


sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --stop
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --start


Optionally, if you want to ensure your VM always gets the same IP address, you can edit /Library/Preferences/VMware\ Fusion/vmnet8/dhcpd.conf and add a clause to the bottom with the format of:


host <some-name> {
    hardware ethernet <MAC-ADDRESS>;
    fixed-address <IP-address>;
}

You can determine the VMWare assigned MAC address for your VM by looking in your VM's *.vmx file and look for a line like:

ethernet0.generatedAddress = "00:0c:29:42:f0:54"

Then to assign a static IP address of 192.168.216.131 to this VM, you could add the clause:

host ubuntu {
    hardware ethernet 00:0c:29:42:f0:54;
    fixed-address
192.168.216.131;
}


Remember to restart the Fusion Networking services either by restarting Fusion or using the command line option.
Most of the OSX instructions came from http://encyclopediaofdaniel.com/blog/fusion-dhcp-port-forwarding/ where you can also find information on a Ruby gem to make the changes for you.

Step 6 - Connect using SSH with X forwarding

X11 forwarding needs to be enabled on both the client side and the server side.

On the client side, the -X (capital X) option to ssh enables X11 forwarding, and you can make this the default (for all connections or for a specific conection) with ForwardX11 yes in ~/.ssh/config.

On the server side, X11Forwarding yes must specified in /etc/ssh/sshd_config. Note that the default is no forwarding (some distributions turn it on in their default /etc/ssh/sshd_config), and that the user cannot override this setting.

The xauth program must be installed on the server side. If there are any X11 programs there, it's very likely that xauth will be there. In the unlikely case xauth was installed in a nonstandard location, it can be called through ~/.ssh/rc (on the server!).

Note that you do not need to set any environment variables on the server. DISPLAY and XAUTHORITY will automatically be set to their proper values. If you run ssh and DISPLAY is not set, it means ssh is not forwarding the X11 connection.

To confirm that ssh is forwarding X11, check for a line containing Requesting X11 forwarding in the ssh -v -X output. Note that the server won't reply either way.

(credit to http://unix.stackexchange.com/questions/12755/how-to-forward-x-over-ssh-from-ubuntu-machine)