Thursday, December 20, 2012

Simple KVM Server Virtualization

I want to virtualize a server from scratch. I have a server in mind already, but I don't want to bother with virtualizing it directly since it is running on a dated OS.  I figure I will build a new VM in parallel on some spare hardware and then migrate the image over to my beast server. Some key benefits of this are that I can use some of the spare capacity of that beast server to test out other server operating systems and software in parallel with my main server.  Also, I can install crashplan on the host itself and have it backup my server images for painless offsite backup whereas now I really don't have a backup of the physical server configs.

This guide will be devided into three stages as follows because this is the order I carried out the steps in.

  1. Set up a host CENTOS 6.3 server
  2. Set up a guest MINT 14 server (with MATE desktop)
  3. Set up a static bridged network and configure our VM to use it

1.Setting up host server

First thing, you should make sure your processor supports kvm virtualization. Install CENTOS 6.3 or later. I am not a redhat/centos guy for most of my home Linux systems, but it seems ideal for a VM host where I don't really need the latest and greatest packages and stability and concise configuration are key. I am assuming you can install this on your own with the graphical installer or however.

Now, we will need some special tools to get virtualization running.  As root, do the following on your fresh CENTOS box:

# I recommend you update your box first, this may take a while
yum update

# get the core virtualization pieces
yum groupinstall Virtualization "Virtualization Client" "Virtualization Platform" "Virtualization Tools"

# install and turn on the avahi daemon
yum install avahi
service avahi-daemon start
chkconfig avahi-daemon on

# I ran into this not being on.  The virt-manager just sat there trying to connect before I did this.
service libvirtd start
chkconfig libvirtd on

That's it, you are ready to virtualize!  Some people say you need to deactivate SELINUX, but some say it isn't needed.  You can do so by editing /etc/selinux/config if you think it is causing you troubles.

2.Setting up a guest server

This is pretty straight forward (except for the last little bit where we correct some video settings). Download  an ISO and/or burn it to a CD for the OS you want to install. In this example, I am using Linux Mint 14 with MATE desktop.

Open up the KVM manager tool you installed in step 1.


In the top left click play button on a monitor that says "Create a new virtual machine" when you hover over it.  Then, on the step 1 window name your server and pick ISO/CDROM.



On the step 2 windows, tell it where the ISO/CD is.  For OS type, just use Linux.  For version, go to "see all" and select the latest kernel available as shown.  The OS being installed is so far ahead (3.x) kernel, that there is no more up-to-date choice that I can tell.


On the step 3 window, set up your memory (give Mint 14 at least a gig) and select how many cores to set. There are ways to alter this later if you need to, so don't get too hung up on getting this just right now.  In my case, the host has too few cores and too little memory to set it up like I will after I migrate it to something more powerful.  


On the step 4 window, set up your storage. The default 8GB is probably a bit tight, 20GB+ may be better. After taking this screenshot, I chose 40GB. You don't have to "allocate entire disk now." I say let it grow dynamically.


On the step 5 window, review your selections and then hit finish.  If you carried out the final section of this guide before doing the VM setup, you could expand the Advanced options and choose your network now. However, I am trying to break this into quick chunks for time-crunched people like myself and getting your VM up feels like progress ;-).


Now launch your VM and install the OS as you would on a physical machine (except maybe more slowly and less responsively) in the window that pops up.  The blue "i" icon on the VM popup window (next to the terminal icon) will show you system stats and you can change things here.

I had an issue where every time I logged in, I got bounced back out.  To fix it, I had to do two things.  I did these out of order, so I don't know if they were both necessary.  I will share them in the opposite order I did them. If the first step works for you, don't bother with the second.

First, switch the virtual video adapter from cirrus to vga.


If you still can't login to the VM gui, then carry out this second part. At the login screen to your guest OS:
use the send menu to send ctrl alt f2           # to drop to virtual terminal on VM
login as root
apt-get install nvidia-current
reboot

After it reboots, it should work like a charm. Also, if you want to shut off the GUI later, you can always edit the /etc/inittab to prevent loading the GUI. I like having the option of the GUI on my servers since it really doesn't take up that much disk space and can be disabled as needed.

Your network should be set up fine for using this guest VM like a desktop to go on the internet, get updates, etc as long as your host's network is working right. Out of the box it gives you a virtual network using NAT which is fine for these purposes.  I could reach out to other boxes on my network just fine. The show-stopper for virtualizing a server, is that nothing else on my network can reach out to the VM except its own host.  In the next step, we fix that nonsense.

3.Setting up a bridged network

Okay, this was a bit foreign to me. I have used a wireless network bridge, but I never built a virtual bridge on a box off of a physical NIC before. I am doing something odd here in using a static IP for the bridge itself which nobody seemed to do in their guides, but it is easy enough.

I have to give some credit here as I got started with bridging using information from this site.  I also found a good reference on killing NetworkManager which doesn't play nice with your bridge.  Anyway, here is my condensed version.

As root on the host:

service NetworkManager stop
chkconfig NetworkManager off
chkconfig network on

Clear out any crappy config files you have like /etc/sysconfig/network-scripts/ifcfg-Auto_eth0 that were made by NetworkManager. 

vi /etc/syconfig/network-scripts/ifcfg-eth0   #(this may be different on your system if eth0 isn't your NIC)

DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
BRIDGE=br0
------------------------
vi /etc/syconfig/network-scripts/ifcfg-br0  # set up your static IP and DNS entries

DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
DNS1=192.168.0.1
DNS2=8.8.8.8
GATEWAY=192.168.0.1
IPADDR=192.168.0.205
NETMASK=255.255.255.0
ONBOOT=yes
DELAY=0
------------------------

Make sure you have DELAY=0 and ONBOOT=yes.  Usually DNS points to your router (gateway) and/or a service like google (8.8.8.8).


vi /etc/sysconfig/iptables  #edit the firewall definititions by adding a line
.....
-A INPUT -i lo -j ACCEPT  # EXISTING LINE
-A INPUT -i br0 -j ACCEPT # ADD LINE SIMILAR TO THE ABOVE EXCEPT CHANGE lo TO br0
.........

service network start  # should give all OK's
service iptables restart  # restart the firewall

Now you need to edit your VM settings. While the VM is off, open it and hit the blue "i" like we did to alter the video adapter. I used device model vertio because it was the default, but there may be merit in some of the other options. Anyway, go to the NIC device and set it up as shown:


Then click apply. Now you can boot up the guest OS and configure its network settings with a normal static IP or even DHCP. It will work just like it is on the network directly using its own NIC.

I hope this guide has been helpful for you. Feel free to offer any tips or improvements or ask questions. Now go forth and virtualize!

Sunday, August 12, 2012

Linux Apache2 Reverse Proxy With SSL Termination and Basic Auth For Sickbeard, Sab, Couchpotato, etc.

I just finished completing one of the hardest home server administration tasks I have ever embarked on, and I thought I would share my efforts since I had to pour through over a boatload of sources to get all the information needed to do it.  If anyone has suggestions on how to improve this, I am all ears so leave a comment.  I used Linux Mint which is very close to Ubuntu so the commands ought to work on it too.

I wanted to get this.  We'll call it option A:

[User]-----HTTPS over Internet----->[Single Login Proxy]----HTTP------>[Web Applications At Home]

It is also trivial then to set up this (Option B) since it only requires the removal of some configuration (comment out the A-only sections labeled in the config files) and then configuring each individual application with a password:

[User]-----HTTPS over Internet----->[No Login Proxy]----HTTP------>[Web Applications At Home]

Ensure you have your applications (Sab, Sickbeard, Couchpotato, etc) running already on their own port and record those port numbers.  Don't bother enabling SSL on any of those individual apps since we are going to handle it on Apache directly and tunnel the LAN HTTP traffic through HTTPS across the net.

Get a domain pointing towards your home IP and an SSL cert (OpenSSL type when the CA asks).  I used NameCheap and got everything (ssl and domain) for under 6 bucks before tax for a .info domain for one year, and they have free dynamic dns service.  You will need to generate a cert signing request on your Linux box to send off to the CA to get your cert, and there are a million guides for this.  You will also need dynamic DNS configured so your domain points to your home IP if it is dymanic and it probably is.  I will document the Dynamic DNS step in more detail in the future for my particular provider but it will be different if you use another service.

Install apache2 with apt-get install apache2. Configure a new site called proxy in /etc/apache2/sites-available with the following contents:

    <VirtualHost *:80>
      ServerName www.mywwwdomain.com
      Redirect permanent / https://www.mywwwdomain.com/
    </VirtualHost>
    <VirtualHost _default_:443>
    ServerName www.mywwwdomain.com
    SSLEngine on
    SSLProxyEngine On
    RequestHeader set Front-End-Https "On"
    ProxyPreserveHost On
    RewriteEngine on
    CacheDisable *
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
    SSLCertificateFile /local/path/to/certfile.cert
    SSLCertificateKeyFile /local/path/to/certkey.key
    
    ProxyRequests Off
    ProxyPreserveHost off
    
    DocumentRoot /var/www
    <Directory />
    ############ OPTION A ONLY##################
    AuthType Basic
    AuthName "My Homebrew Gateway"
    AuthUserFile /etc/apache2/passwords
    Require user your_login(s)_go_here
    ############# END OPTION A ONLY#############
    SSLRequireSSL
    SSLRequire  %{HTTP_HOST} eq "www.mywwwdomain.com"
    SSLOptions           +FakeBasicAuth +StrictRequire
    SSLRequire           %{SSL_CIPHER_USEKEYSIZE} >= 128
    ErrorDocument 403 https://www.mywwwdomain.com
      Options FollowSymLinks
      AllowOverride None
    </Directory>
    <Directory /var/www/>
    ############ OPTION A ONLY##################
    AuthType Basic
    AuthName "My Homebrew Gateway"
    AuthUserFile /etc/apache2/passwords
    Require user your_login(s)_go_here
    ############# END OPTION A ONLY#############
    SSLRequireSSL
    SSLRequire  %{HTTP_HOST} eq "www.mywwwdomain.com"
    SSLOptions           +FakeBasicAuth +StrictRequire
    SSLRequire           %{SSL_CIPHER_USEKEYSIZE} >= 128
    ErrorDocument 403 https://www.mywwwdomain.com
      Options Indexes FollowSymLinks MultiViews
      AllowOverride All
      Order allow,deny
      allow from all
    </Directory>
    
    <Location /sab>
       ProxyPass http://localhost:8080
       ProxyPassReverse http://localhost:8080
    </Location>
    <Location /couchpotato/>
       ProxyPass http://localhost:8084/couchpotato/
       ProxyPassReverse http://localhost:8084/couchpotato/
    </Location>
    <Location /subsonic>
       ProxyPass http://localhost:4040/subsonic
       ProxyPassReverse http://localhost:4040/subsonic
    </Location>
    <Location /sickbeard/>
       ProxyPass http://localhost:8081/sickbeard/
       ProxyPassReverse http://localhost:8081/sickbeard/
    </Location>
    <Location /manage>
       ProxyPass http://localhost:32400/manage/
       ProxyPassReverse http://localhost:32400/manage/
    </Location>
      RewriteEngine on
      RewriteOptions inherit
    </VirtualHost>
    
    Then set your /etc/apache2/httpd.conf file up like the following:
    ServerName www.mywwwdomain.com
    <Proxy *>
    Order deny,allow
    Allow from all
    ############ Option A Only ###################
    AuthType Basic
    AuthName "My Homebrew Gateway"
    AuthUserFile /etc/apache2/passwords
    Require user your_login(s)_go_here
    ############ End Option A Only #################
    SSLRequireSSL
    SSLRequire  %{HTTP_HOST} eq "www.mywwwdomain.com"
    SSLOptions           +FakeBasicAuth +StrictRequire
    SSLRequire           %{SSL_CIPHER_USEKEYSIZE} >= 128
    ErrorDocument 403 https://www.mywwwdomain.com
    </Proxy>
    

After you have these files in place remove /etc/apache2/sites-enabled/000-default and from within  /etc/apache2/sites-enabled run ln -s ../sites-available/proxy to make a softlink to the proxy site configuration file we just made.
To review the files we just made:

The "option A only" sections deal with basic auth using passwords.  In order to have passwords you will also need to create a password file containing your login/password info using the htpasswd command.  In the example provided, the passwords are stored in /etc/apache2/passwords and you could set this up with htpasswd -c /etc/apache2/passwords your_login.  It will then prompt you for the password.  If you want to enforce use hashed passwords there is an htpasswd option for that.  Basic auth is perfectly secure when used behind SSL encryption as is anything tunneled through an encrypted protocol.  So if anyone tells you different, punch them in the groin and scream like a rabid hyena.

The SSL options ensure https is enforced at specific locations and in general.  The httpd.conf file generally applies these settings, but I wanted to be super-sure that we are getting SSL on the auth in a few places where it didn't happen with the httpd.conf alone.

You should replace www.mywwwdomain.com with your actual internet-accessible domain.  Also, you should replace the your_login(s)_go_here with your actual login names as set up in your htpasswd created file.  There is a "Require group" directive if you want to use that instead.

In the location sections, the references to localhost are because these different applications are all hosted on various ports of the same machine that is acting as the reverse proxy.  If you have your apps on a different machine in your local network, replace localhost with the local static ip address (e.g. 192.168.0.x) for that server.

The location sections set domain subdirectories that proxy to the port numbers transparently.  The reason for doing this instead of something like sickbeard.mywwwdomain.com is because the cheap SSL certs are only licensed to www.mywwwdomain.com and can't do wildcards to match each subdomain.  If you want to drop hundreds of dollars a year on a wildcard cert, knock yourself out.  The method I used lets one cert work for unlimited applications.  Check that your own port numbers are used in the configuration.  Most of mine are probably not the defaults for these apps.

Lastly, we also set up a redirect here so that traffic coming to mywwwdomain.com will get sent to https://www.mywwdomain.com.  From there they may be asked to login (if using option A) and then sent to the landing page.  Also, it is important to know that each subdomain also requires authentication on the proxy if you go straight to them instead of the main landing page which we will make later, but once you are logged in it will not ask again until your browser is restarted.  This Option A authentication is really neat if you are only accessing things on the web, but it can hinder any third party applications you might want to use.  If using webapp-specific phone apps for instance, they will not understand the auth popup.  In those cases, omit or comment out the option a authentication and just turn on passwords on each individual app.  The proxy will still handle SSL for everything so you don't need it on each individual webapp.

None of this is going to work yet.  And we don't want it to yet.  First we need to do some app configuration. Here is the rundown:

Sickbeard will need extra configuration.  Stop sickbeard from running.  If you have a service setup for it this is as easy as service sickbeard stop. Then edit sickbeard's config.ini file and set web_root = /sickbeard with no quotes.  Then start sickbeard back up again.

Sab is already ready.

Couchpotato (V2) needs extra configuration.  If you are not using V2, you are on your own.  It is what I used and I am not going to muck with an older version for your benefit.  Go to settings, check advanced, in general enter "couchpotato" in the Url Base field.  Then restart it.

Subsonic requires additional configuration as well.  Turn subsonic off service subsonic stop.  Open up /usr/bin/subsonic (it is a script not a bin file) and set "SUBSONIC_CONTEXT_PATH=/subsonic".  Turn subsonic back on service subsonic start.  Note that you can't get rid of the login on subsonic.

You might not care about these last two since the above are the big four, but in case you do they are in there.  Of course, comment out any of the location sections in your proxy configuration file for apps you aren't using. 

Plex will work out of the box with the configuration I gave you and it using its default port.

EXtplorer is a web-based file manager.  If you have it configured, it will work with a proxy out of the box.  As far as deploying it though, if you don't already have it setup, DO NOT USE THE DEBIAN PACKAGE FOR IT!!!!  Don't do it!!  It will mess up apache and steel port 80 from it, and there is no documentation on how to configure or use the packaged form of it at this point.  Download the normal zip file for it, and follow this guy's guide.  Chmod the whole extplorer unzipped directory with 777 recursively chmod -R 777 extplorer and then chmod the .htusers.php file with the devil's number (666) like he said.  Also ensure you jack up the upload size and post size to something you can live with.  When you are done with his guide, go and softlink your /extplorer directory from within /var/www using ln -s /path/to/extplorer extplorer.  When you log into it with admin/admin the first time (after we fire up apache) you will also want to change the root directory to something more useful like /mnt or /media (or / if you are bold) depending on what you want to see.  

You need to port forward your server using your router so the outside world can get to it.  Forward 80->80 and 443->443 on your proxy IP.  You should not be doing this without a static IP on your proxy box. 

Finally, you need to fire apache up service apache2 restart.  When you do this, you will see some errors about modules or something telling you to go to the error log /var/logs/apache/error.log.  You will need to use a2enmod to load the modules you need enabled.  When you run it, it will give you a list of what you can turn on.  Turn on the ones it is bitching about and then try to restart apache again.  Eventually it will stop bitching and everything will work if you get the right modules turned on.  You will also probably need to configure the apache init script to restart on reboot with update-rc.d apache2 enable.

Finishing Touches:
We already set up a webroot so you can alter the html files in there and make your own custom landing page at /var/www/index.html.  I highly recommend this instead of having to remember all your subdirectories as your setup grows.  My landing page looks like this:

It is just a bunch of logos (stored in /var/www) linked with relative paths to the various apps.  So use an href="/sickbeard/" as the link for example.

Final thoughts:
If Jerry Springer can have them, so can I.  A nice improvement would be to allow you to access this on your local network without having your traffic redirected to the authentication/ssl domain when you type your.local.proxy.ip/appname/.  It really shouldn't be hard to configure, but I sunk so much time into this I really don't want to mess with it at the moment.  My simple workaround is to add local links to your landing page that use your.local.proxy.ip:app_specific_portnum to access each thing and you will need to append the directory in addition to the port number for some of them.  Here are the ones I needed for my specific port setup 8081/sickbeard, 4040/subsonic, 32400/manage (plex).  The rest worked already.  You won't have to authenticate when using these local addresses, but they aren't accessible to the outside world this way since you are only forwarding ports 80 and 443.  Extplorer is running in apache, so it cannot be worked around like this.  That is fine for me at home since my server serves up files with NFS/SMB locally and that is a much more integrated solution for your local systems anyway.   

Also, I spared you the hassle of setting up SSL on each individual app.  Not that it is difficult for most of those that can do it, but couchpotato (for example) cannot and it is nice to get zero-configuration SSL on each app you add down the road especially when the app didn't even offer it.  

Subsonic is very painful to setup with SSL directly because it uses utterly retarded java keystores that require converting your ssl cert into a pkcs12 type and then running it through some retarded java keystore importer app with a load of retarded flags and retarded options to generate a retarded file that retarded java can retardedly accept.  Then you have to stick options in /usr/bin/subsonic to tell it about that file and how to access it.  

Lastly, I expect some smart ass to say, "Hey, Mr. Sheez.  I noticed that the auth pops up before my browser says it is encrypted https."  Really punk?  Does it?  No, not really.  Your browser might make it look like the authentication is going to happen in plain text.  However, intercept your traffic like a grown-ass man and you'll see that nothing is being sent in non-encrypted http.  If it is, I'll eat my hat.  If not, you'll eat my hat.

Do let me know if anything legitimately needs correction or updating.  If you need clarification on anything I covered, then let me know in the comments.  Don't ask me some random apache question about an unrelated setup because you are too lazy to look it up.  I am not an apache guru in general.  I figured all this out through sheer force of will and shared it out of some twisted sense of altruism toward the reddit usenet community.  Anyway, have fun with this info mateys.