When I switched from Apache2 to nginx, the software used to run my pastebin needed to be changed (I used Perl NoPaste, which is CGI based and I didn’t feel like messing with FastCGI wrappers). Instead I chose LodgeIt.

LodgeIt is not just another pastebin, it features a clean user interface, different color schemes for sourcecode, reply to pastes, support for all languages Pygments supports, and XMLRPC support

LodgeIt spawns it’s own webserver, which I placed behind nginx.

  1. Install required packages
    sudo apt-get install python-imaging python-sqlalchemy python-jinja2 python-pybabel python-werkzeug python-simplejson mercurial python-pygments
  2. Go to the directory where you want LodgeIt to live and check out the Mercurial repository
    hg clone http://dev.pocoo.org/hg/lodgeit-main
  3. cd into lodgeit-main, open manage.py and change the lines
    dburi
    SECRET_KEY
  4. Download the init script and place it in /etc/init.d and change the lines
    APP_PATH
    DAEMON_OPTS
    RUN_AS
  5. Configure autostart
    sudo update-rc.d lodgeit defaults
  6. Start the program
    sudo service lodgeit start

The init-script is also available for viewing

The nginx configuration is pretty easy – the only caveat is the fact that nginx does not support IPv6 for upstream servers, which is why lodgeit is configured to explicitly to listen on 127.0.0.1 (and not localhost which on a IPv6-enabled host is ::1).

server {
                listen [::]:80;
                server_name my.server;

                access_log /var/log/nginx/my.server-access.log;
                error_log /var/log/nginx/my.server-error.log;

                location / {
                                proxy_pass http://localhost:20000/;
                }
}

After upgrading to Natty Narwhal I couldn’t connect to my Linux based jump host (connected via VPN):

OpenSSH_5.8p1 Debian-1ubuntu2, OpenSSL 0.9.8o 01 Jun 2010
debug1: Reading configuration data /home/alj/.ssh/config
debug1: Applying options for *
debug1: Applying options for smallpox.xxx.dk
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to smallpox.xxx.dk [xxx.xxx.xxx.xxx] port 22.
debug1: Connection established.
debug1: identity file /home/alj/.ssh/id_rsa type -1
debug1: identity file /home/alj/.ssh/id_rsa-cert type -1
debug1: identity file /home/alj/.ssh/id_dsa type 2
debug1: Checking blacklist file /usr/share/ssh/blacklist.DSA-1024
debug1: Checking blacklist file /etc/ssh/blacklist.DSA-1024
debug1: identity file /home/alj/.ssh/id_dsa-cert type -1
debug1: identity file /home/alj/.ssh/id_ecdsa type -1
debug1: identity file /home/alj/.ssh/id_ecdsa-cert type -1
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.5p1 Debian-4ubuntu4
debug1: match: OpenSSH_5.5p1 Debian-4ubuntu4 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_5.8p1 Debian-1ubuntu2
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 [email protected]
debug1: kex: client->server aes128-ctr hmac-md5 [email protected]
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
Read from socket failed: Connection reset by peer

The key seem to be that Natty uses OpenSSH 5.8p1 – This problem seem to affect clients newer than 5.7p1, when connecting to older servers. And the problem seem to be restricted to connecting through some firewalls, I have no problem on my home network and when connecting to hosts running iptables.

If have found this workaround. Apparently is has something to do with the length of the cipher list and is not isolated to Ubuntu.

Edit /etc/ssh/ssh_config or $HOME/.ssh/config and add this in the Host * stanza or for the host you have problems connecting to:

        Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc
        MACs hmac-md5,hmac-sha1,hmac-ripemd160

In the pre-10.04 days it was possible to make a Gobi 200(0) modem work by installing gobi_loader and using it to load the firmware for the modem.

However, with the release of Ubuntu 10.04 (which sports a shiny 2.6.35 kernel) gobi_loader stopped working. Because gobi_loader (according to the homepage) does not support 2.6.32+ I stopped caring and used my Huwai stick instead.

Recently one my colleagues noted that after upgrading to 10.10 the wireless broadband connection seemed to be available from time to time – and having recently upgraded to Natty (11.04) I decided to see if I could get it to work again.

My system consists of:

  • Computer: HP Elitebook 2540p
  • Modem: Gobi 2000 with GPS
  • OS: Windows 7 and Ubuntu 11.04

The easiest way to get the modem working is to install HP Connection Manager in Windows to get the firmware and to make sure the modem works.

In Ubuntu, make sure the package gobi-loader

$ sudo apt-get install gobi-loader

Now mount your Windows partition

$ sudo mount /dev/sda1 /mnt

and copy the needed files

$ cd cd /mnt/Program\ Files\ \(x86\)/QUALCOMM/Images/HP/
$ sudo mkdir /lib/firmware/gobi
$ sudo cp 0/uqcn.mbn UMTS/* /lib/firmware/gobi

That’s it; Reboot or reload udev and the modem should now be available in Network Manager.

(I might have missed something, this article is done from memory; once VirtualBox is working again I will verify the details – and test of this fix also works in 10.10)

It’s been a while since I last had to run Windows on my laptop; back then I used Ext2 Installable File System For Windows to access data on my Linux-formated partitions.

In the meantime a few things have changed: Windows 7 and Ubuntu formating ext3 with a inode size of 256 – none of these are supported by ext3 ifs.

Ext2read supports Windows 7 (as well as ext4 and LVM2) but it’s more like a file browser and does not support assigning drive letters to Linux filesystems and since my /home is formatted with XFS it does not help me anyway.

Instead of going through reformatting the filesystems I wanted to access from Windows, I decided to build a virtual file server instead; that way I can access any filesystem type supported by Linux.

Software used: Windows 7, Virtualbox and Ubuntu (server edition)

This guide will work with other versions of Windows (and other OS’es as well), there are no ties to Virtualbox and the Linux version used can be anyone you like.

Continue reading

Let’s say you have three disks but you wish to share with Samba or NFS clients.

Of course you could just mount the disks on three separate mount points and export those. Or you could mount the three disks on three mount points inside the same directory and export the parent directory. The problem with both solutions is you have to “balance” the data among the disks – and it will make navigating your TViX, WDTV or Popcorn more annoying.

You could use RAID or LVM to handle all this for you. But. What if you already have data on the disks? What happens if one of the disks dies? With RAID0 or LVM your data is gone.

Luckily you can have the best of both worlds: mhddfs

mhddfs is a FUSE plugin that combines data from several directories and present it in one directory. The only downside is that you do not know (or control) where a file is created. Let’s say you combine /dir1, /dir2 and /dir3 under /virtual. Previously you had /dir1/my_content. This is now /virtual/my_content. If you write a file to /virtual/my_content it will not necessarily end up in /dir1/my_content. This also mean you can not predict what data is lost if you lose a disk.

The plugin is available in Ubuntu

$ sudo apt-get install mhddfs

Using it is pretty simple

$ sudo mkdir /export/hest
$ sudo mhddfs /dir1,dir2,dir3 /export/hest
[sudo] password for alj:
mhddfs: directory '/dir1' added to list
mhddfs: directory '/dir2' added to list
mhddfs: directory '/dir3' added to list
mhddfs: mount to: /export/hest
mhddfs: move size limit 4294967296 bytes

The “move size limit” deserves an explanation:

if free space size threshold if a drive has the free space less than the threshold specifed then another drive will be choosen while creating a new file. If all the drives have free space less than the threshold specified then a drive containing most free space will be choosen.

Default value is 4G, minimum value is 100M.

Now you have the combined space of all three disks

/dir1;/dir2;/dir3
                      589G  329G  260G  56% /export/hest

To mount the combined directory during boot, at this to /etc/fstab:

mhddfs#/dir1,/dir2,/dir3 /export/hest fuse defaults,allow_other 0 0

You can export the combined directory using NFS or Samba. If you export the combined directory using NFS you need to add the fsid option in /etc/exports

/export/hest 192.168.1.0/24(fsid=2,ro,sync,crossmnt,no_subtree_check,insecure)

I’ve been using the excellent terminal emulator Terminator for a long time. Terminator sports (among other things) split screen hand “cluster support” (grouping of screens, making it possible to type the same thing in all terminals).

Example

In previous versions of Ubuntu (Terminator versions prior to 0.14) Terminator would pick all settings from GNOME Terminal, including character encoding (ISO-8859-15 in my case). Apparently this is no longer the case in Ubuntu 10.04, which has Terminator 0.14.

To use another encoding than UTF-8, add the following to ~/.config/terminator/config:

encoding = ISO-8859-15

Substitute ISO-8859-15 with whatever encoding you want.

Some other nice configuration options

scrollback_lines = 10000 # Scroll back size
focus = sloppy # sloppy focus, ie. the focus follows the mouse when moving the pointer to another split-screen

for more options, run man terminator_config.

I was pretty happy with solution to get notifications from Irssi though it had some shortcomings.

A couple of days ago a colleague made me aware of a Perl modules written by another colleague (Anton Berezin) called IPC::Message::Minivan which, it turns out, is perfect for my notification script. Basing the notifications on Minivan combine the speed of using something like Dbus locally (instant notifications) with the convenience of my previous script (notifications over the network, able to handle multiple clients).

This setup consists of three parts: The Minivan daemon, the Irssi script and the notification script.

As always my instructions are based on Ubuntu but should work on most Linux and Unix systems.

Installing the Minivan

IPC::Message::Minivan is not yet available directly through CPAN so we need to install it manually

  1. Download IPC::Messaging and IPC::Message::Minivan (and unpack them).
  2. Install dependencies: sudo apt-get install libjson-xs-perl libregexp-common-perl
  3. One could use dh-make-perl but I chose to install the two modules manually
    Basically run “perl Makefile.pl && sudo make install
    :~/devel/IPC-Messaging-0.01_12$ perl Makefile.PL
    Cannot determine license info from lib/IPC/Messaging.pm
    *** Module::AutoInstall version 1.03
    *** Checking for Perl dependencies...
    [Core Features]
    - Test::More                ...loaded. (0.72)
    - B::Generate               ...missing.
    - IO::Socket::UNIX          ...loaded. (1.23)
    - IO::Socket::INET          ...loaded. (1.31)
    - Storable                  ...loaded. (2.18)
    - Time::HiRes               ...loaded. (1.9711)
    - IO::Select                ...loaded. (1.17)
    - Module::Load::Conditional ...loaded. (0.22)
    ==> Auto-install the 1 mandatory module(s) from CPAN? [y] y
    *** Dependencies will be installed the next time you type 'make'.
        (You may need to do that as the 'root' user.)
    *** Module::AutoInstall configuration finished.
    Checking if your kit is complete...
    Looks good
    Warning: prerequisite B::Generate 0 not found.
    Writing Makefile for IPC::Messaging
    :~/devel/IPC-Messaging-0.01_12$ sudo make install
    [sudo] password for alj:
    /usr/bin/perl "-Iinc" Makefile.PL --config= --installdeps=B::Generate,0
    Cannot determine license info from lib/IPC/Messaging.pm
    *** Installing dependencies...
    [MSG] No '/home/alj/.cpanplus/custom-sources' dir, skipping custom sources
    [MSG] No '/home/alj/.cpanplus/custom-sources' dir, skipping custom sources
    [MSG] No '/home/alj/.cpanplus/custom-sources' dir, skipping custom sources
    *** Installing B::Generate...
    Running [/usr/bin/perl /usr/bin/cpanp-run-perl /home/alj/.cpanplus/5.10.0/build/B-Generate-1.26/Makefile.PL INSTALLDIRS=site]...
    # running Build.PL installdirs=site
    /usr/bin/perl Build.PL installdirs=site
    Creating custom builder _build/lib/My/Builder.pm in _build/lib/My
    Checking whether your kit is complete...
    Looks good

    Checking prerequisites...
    Looks good

    Creating new 'Build' script for 'B-Generate' version '1.26'
    Unknown 'build_class', defaulting to 'Module::Build'
    Running [/usr/bin/make test UNINST=1]...
    make[1]: Entering directory `/home/alj/.cpanplus/5.10.0/build/B-Generate-1.26'
    /usr/bin/perl Build --makefile_env_macros 1 test
    t/basic............ok
            2/10 skipped: various reasons
    t/inspect-btest....ok
    t/inspect-this.....ok
    t/new_cv...........ok
    t/op_list..........ok
    t/op_list_bgen.....ok
    All tests successful, 2 subtests skipped.
    Files=6, Tests=721,  0 wallclock secs ( 0.24 cusr +  0.21 csys =  0.45 CPU)
    make[1]: Leaving directory `/home/alj/.cpanplus/5.10.0/build/B-Generate-1.26'

    *** B::Generate successfully installed.
    *** Module::AutoInstall installation finished.
    cp lib/IPC/Messaging.pm blib/lib/IPC/Messaging.pm
    Manifying blib/man3/IPC::Messaging.3pm
    Installing /usr/local/share/perl/5.10.0/IPC/Messaging.pm
    Installing /usr/local/man/man3/IPC::Messaging.3pm
    Writing /usr/local/lib/perl/5.10.0/auto/IPC/Messaging/.packlist
    Appending installation info to /usr/local/lib/perl/5.10.0/perllocal.pod
    :~/devel/IPC-Message-Minivan-0.01_08$ perl Makefile.PL
    Cannot determine license info from lib/IPC/Message/Minivan.pm
    Writing Makefile for IPC::Message::Minivan
    :~/devel/IPC-Message-Minivan-0.01_08$ sudo make install
    cp lib/IPC/Message/Minivan.pm blib/lib/IPC/Message/Minivan.pm
    cp minivan blib/script/minivan
    /usr/bin/perl "-Iinc" "-MExtUtils::MY" -e "MY->fixin(shift)" blib/script/minivan
    Manifying blib/man1/minivan.1p
    Manifying blib/man3/IPC::Message::Minivan.3pm
    Installing /usr/local/share/perl/5.10.0/IPC/Message/Minivan.pm
    Installing /usr/local/man/man1/minivan.1p
    Installing /usr/local/man/man3/IPC::Message::Minivan.3pm
    Installing /usr/local/bin/minivan
    Writing /usr/local/lib/perl/5.10.0/auto/IPC/Message/Minivan/.packlist
    Appending installation info to /usr/local/lib/perl/5.10.0/perllocal.pod
  4. Create an Upstart script for the Minivan daemon
    $ cat /etc/init/minivan.conf
    # minivan - minimalistic message bus
    #

    description     "minimalistic message bus"

    start on runlevel [2345]
    stop on runlevel [!2345]

    expect fork
    respawn

    exec /usr/local/bin/minivan -l /var/log/minivan -d
  5. Start the Minivan daemon
    $ sudo start minivan

Install the Irssi script

  1. Copy the script to ~/.irssi/scripts/notifier-minivan.pl (the script below is just for reference, it might not be up to date)
    ## Put me in ~/.irssi/scripts, and then execute the following in irssi:
    ##
    ##       /load perl
    ##       /script load notifier-minivan
    ##

    use strict;
    use Irssi;
    use vars qw($VERSION %IRSSI);
    use HTML::Entities;
    use IPC::Message::Minivan;

    $VERSION = "0.01";
    %IRSSI = (
        authors     => 'Allan Willems Joergensen',
        origauthors => 'Luke Macken, Paul W. Frields, Jared Quinn, Anton Berezin, Kristoffer Larsen',
        contact     => '[email protected],dk',
        name        => 'notifier-minivan.pl',
        description => 'Alert the user of new messages or hilights through IPC::Message::Minivan',
        license     => 'Beerware',
        url         => 'http://www.nowhere.dk/articles/irssi-notifications-minivan',
    );

    # Default settings in Irssi
    Irssi::settings_add_str('notifier','minivan_host', 'localhost');
    Irssi::settings_add_str('notifier','minivan_port', 6826);
    Irssi::settings_add_str('notifier','minivan_channel','#irssi');

    # Fetch settings from Irssi
    my $minivan_host = Irssi::settings_get_str('minivan_host');
    my $minivan_port = Irssi::settings_get_str('minivan_port');
    my $minivan_channel = Irssi::settings_get_str('minivan_channel');

    # Connect to the Minivan
    our $van = IPC::Message::Minivan->new(host => $minivan_host, port => $minivan_port);

    sub notify {
        my ($server, $summary, $message) = @_;

        # Encode certain characters using HTML
        my $safemsg = HTML::Entities::encode($message, '<>&"');

        # Load everyone into the minivan
        $van->msg($minivan_channel, {summary => $summary, msg => $safemsg});
    }

    sub print_text_notify {
        my ($dest, $text, $stripped) = @_;
        my $server = $dest->{server};
        return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT));
        my $sender = $stripped;
        $sender =~ s/^\<.([^\>]+)\>.+/\1/ ;
        $stripped =~ s/^\<.[^\>]+\>.// ;
        my $summary = "Hilite in " . $dest->{target};
        notify($server, $summary, $stripped);
    }


    sub message_private_notify {
        my ($server, $msg, $nick, $address) = @_;
        return if (!$server);
        notify($server, "Private message from ".$nick, $msg);
    }

    sub dcc_request_notify {
        my ($dcc, $sendaddr) = @_;
        my $server = $dcc->{server};

        return if (!$dcc);
        notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick});
    }

    Irssi::signal_add('print text', 'print_text_notify');
    Irssi::signal_add('message private', 'message_private_notify');
    Irssi::signal_add('dcc request', 'dcc_request_notify');
  2. Load the script inside Irssi: /script load notifier-minivan.pl
  3. If your Minivan is not running on the same machine as Irssi, change the configuration inside Irssi:
    /set minivan_host your_hostname – IPC::Message::Minivan is tunnel-able through ssh, see client configuration
  4. Auto-load the script:
    ln -sf ~/.irssi/scripts/notifier-minivan.pl ~/.irssi/scripts/autoload/notifier-minivan.pl

The stuff running on your local machine

It is possible to use autossh to automatically setup the tunnel but since I am always connected to my server (at least when I am in front of a computer) I chose to use normal ssh port forwarding.

In ~/.ssh/config I have

Host my.server.bogus
        LocalForward 6826 localhost:6826

The stuff that actually shows the notifications

I did not want to bother trying to make the script error proof so I simply call the Perl script from a shell script like so

#!/bin/bash

wait=0
while true
 do
    $HOME/bin/irssi-notify-client.pl

    let wait=$wait+5
    if [ $wait -ge 30 ]
     then
        sleep 30
    else
        sleep $wait
    fi
done

Save the script as ~/bin/start-irssi-notify-client.sh

The notification script requires Desktop::Notify – It is available in the Ubuntu repositories but it is an old version, so let’s use a newer:

$ sudo apt-get install dh-make-perl libnet-dbus-perl
$ cpan2deb Desktop::Notify
$ sudo dpkg -i ~/.cpan/libdesktop-notify-perl*.deb

The script

#!/usr/bin/perl

use strict;
use warnings;
use Desktop::Notify;
use IPC::Message::Minivan;
use Encode;

my $notify_timeout = 500;
my $icon = "/usr/share/pixmaps/pidgin/protocols/scalable/irc.svg";
#my $icon = "gnome-irc.png";

my $van = IPC::Message::Minivan->new(host => 'localhost');
$van->subscribe("#irssi");
our $notify = Desktop::Notify->new();
my $notification = $notify->create(summary => 'Minivan', body => 'Connection established', timeout => $notify_timeout, app_icon => $icon);
$notification->show();

while (1) {
    if (my $cmd = $van->get(5,[])) {
        if ($cmd->[0] eq '#irssi') {
            my $c=$cmd->[1];
           
            my $message = Encode::encode("utf-8",$c->{msg});
            my $summary = $c->{summary};
           
            $notification->summary($summary);
            $notification->body($message);
            $notification->show();
        }
    }
}

$notification->close();

Copy the script to ~/bin/irssi-notify-client.pl.

Remember to make both scripts executable.

The final thing to do is to add the notify client to your desktop environment’s autostart

In GNOME: System -> Preferences -> Startup Applications

Add Startup Program

Add Startup Program

Note: This is known to work for a machine acting as masquerading firewall for an entire network.

I wanted to block connections to certain outbound ports. After some trial and errors I found something that works

Add the following to /etc/ufw/before.rules:

-A ufw-before-forward -s <SOURCE IP> ! -d <LOCAL NET>/24 -p tcp -m tcp --dport <DEST PORT> -j DROP

it’s as simple as that.

Remember to reload all the rules:

$ sudo ufw reload

Since I run irssi all the time, packing as many features into it as possible seems like a nice idea.

So I use bitlbee to connect to Messenger, Google Talk/Jabber and ICQ and I have been using tircd (Twitter/irc gateway) and tweet.im (Twitter/Google Talk gateway) to connect to Twitter; but none of them works like I want them to.

Today I stumbled across Twirssi, a script for irssi to interact with Twitter.

Out of the box twirssi expects input to be UTF-8 which caused some grief because my terminal is ISO-8859-15.

First, lets install required modules for twirssi

I run Ubuntu Karmic Koala so Net::Twitter is available as a package

$ sudo apt-get install libnet-twitter-perl

If you run an older Ubuntu release or another Linux/Unix variant that does not have a native package, install it from CPAN (I will not go into the configuration of CPAN here – have a look at this article for more information).

$ sudo perl -MCPAN -e shell
cpan[1]> install Net::Twitter

Answer yes to all dependencies.

Next step is to install a Perl module for the URL shortening service you wish to use; I use Bit.ly so let’s install the module

$ sudo perl -MCPAN -e shell
cpan[1]> install WWW::Shorten::Bitly

Now, let’s install twirssi

Head to irssi’s scripts directory

$ cd ~/.irssi/scripts

Download the script

$ wget http://twirssi.com/twirssi.pl

Make sure the script is autoloaded at startup

$ cd autorun
$ ln -sf ../twirssi.pl .

Patch twirssi to support other charsets than UTF-8

$ cd ~/.irssi/scripts
$ wget http://people.freebsd.org/~garga/patches/twirssi_charset.diff
$ patch -p1 < twirssi_charset.diff

Finally, configure twirssi

The configuration is done from inside irssi

  1. Create a new window for twirssi
    /win new hidden
  2. Name the new window
     /win name twitter
  3. Optional: Move the new window to another location
    /win move <number>
  4. Optional: Save new window layout
    /layout save
  5. Load twirssi
    /script load twirssi.pl
  6. Configure URL shortening service
    /set short_url_provider Bitly

    /set short_url_args "Bitly API key"
  7. Configure Twitter usename
    /set twitter_usernames Your_Twitter_Username

    /set twitter_passwords Your_Twitter_Password

    (Note: This will store your Twitter password in clear text in irssi’s configuration)

  8. Set charset to use
    /set twirssi_charset ISO-8859-15
  9. Reload the script to pickup autologin to Twitter
    /script load twirssi.pl

More information on how to use twirssi is available here

Please go to the updated article.

Since I wrote the post about running Windows applications on Linux with Sun xVM VirtualBox and SeamlessRDP I have been using the system almost daily to run some applications needed at work. It has been running well except for crashes in VirtualBox from time to time. Two new releases of VirtualBox has not fixed the problem.

Growing increasingly tired of this I decided to look at KVM (Kernel-based Virtual Machine).

Installing KVM

I run Ubuntu Jaunty (9.04) and at the time of writing the version of KVM in the repository is kvm-84. If you are running an older version of Ubuntu there is a PPA with updated KVM packages. Add it to your apt sources:

$ echo 'deb http://ppa.launchpad.net/intuitivenipple/ubuntu hardy main' | sudo tee /etc/apt/sources.list.d/intuitivenipple.list
$ sudo apt-get update

You are now ready to install KVM (and some other programs we are going to use later):

$ sudo apt-get install kvm dnsmasq qemu uml-utilities

I opted to install a new virtual machine but it should be possible to convert an existing virtual machine (VMware or VirtualBox) by converting the disk image and using it in a KVM machine – The method for converting a VMware image is described in the VirtalBox article.

If you want to convert a VirtualBox VDI image do the following:

$ VBoxManage internalcommands converttoraw OldDisk.vdi NewDisk.img

this requires VirtualBox.

If you are creating a new virtual machine then create a disk image:

$ qemu-img create -f qcow2 WindowsDisk.img 10G

Setting up the network

Because I need to contact the virtual machine from the host using the “user” networking facility (NAT) of KVM was not a possibility. Instead I chose to use a tap-based solution (with NAT’ing done a the host using iptables).

First, create the configuration in

/etc/network/interfaces

(just add this):

iface tap0 inet static
address 192.168.10.1
netmask 255.255.255.0
up /usr/sbin/dnsmasq --interface=${IFACE}  --except-interface=lo --bind-interfaces --user=nobody \
--dhcp-range=kvm,192.168.10.150,192.168.10.250,255.255.255.0,192.168.10.255,8h \
--domain=kvm.lan --pid-file=/var/run/${IFACE}_dnsmasq.pid --conf-file
down kill -s TERM `cat /var/run/${IFACE}_dnsmasq.pid` && rm -f /var/run/${IFACE}_dnsmasq.pid
tunctl_user 

We also start dnsmasq (which will only listen in the tap0 interface) to act as DNS and DHCP server for virtual machines (the idea came from this HOWTO.

Test that everything works:

$ sudo ifup tap0

For some reason (security I guess) a normal user is, per default, not allowed to use the tap/tun interfaces. To fix this:

$ echo "KERNEL==\"tun[0-9]*\",GROUP=\"uml-net\" MODE=\"0660\"" | sudo tee -a /etc/udev/rules.d/40-permissions.rules

and then reread the udev rules:

$ sudo udevadm control --reload-rules

You also need to be member of the uml-net group:

$ sudo adduser $(id -un)

You need to log out and log on again for the changes to take effect.

If you want your virtual machine to be able to access the the outside world you need to setup NAT. One way of doing this is to Ubuntu’s Uncomplicated Firewall.

Configurating and running KVM

Installing Windows in KVM

There is the possibility of using one of the graphical interfaces for Qemu/KVM but I just created a script for my Windows machine, it looks like this:

#!/bin/sh
HD="-hda Windows.img"
NIC1MAC="00:16:3e:66:42:73"
KVM="kvm"
#VNC="-vnc :1"
NET="-net nic,model=rtl8139,macaddr=$NIC1MAC,vlan=0 -net tap,vlan=0,ifname=tap0,script=no"
SOUND="-soundhw es1370"
TIME="-localtime"
MEM="-m 512"
NAME="-name Windows"
CPU="-cpu core2duo"
KB="-k da"
OTHERARG="-daemonize"
$KVM $HD $NET $VNC $SOUND $MEM $TIME $NAME $CPU $KB "[email protected]"

Adjust MEM, NIC1MAC, CPU and KB to suit your setup, use this small script to generate a random MAC address:

#!/usr/bin/python
# macgen.py script to generate a MAC address for Red Hat Virtualization guests
#
import random
#
def randomMAC():
mac = [ 0x00, 0x16, 0x3e,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) ]
return ':'.join(map(lambda x: "%02x" % x, mac))
#
print randomMAC()

When installing the Windows guest run the script like this:

$ kvm-windows -cdrom /path/to/windows.iso -boot -d

Once the virtual machine is installed shut down Windows. We are going to switch the network card from an emulated Realtek rtl8139 to the much fast virtio, this reqiures paravirtual network drivers for Windows. Download it from here.

Change the NET= line in the kvm-windows script:

NET="-net nic,model=virtio,macaddr=$NIC1MAC,vlan=0 -net tap,vlan=0,ifname=tap0,script=no"

Boot the machine again:

$ kvm-windows -cdrom /path/to/NETKVM-20081229.iso

Once the virtual Windows machine comes up, install the driver from the CD-drive when Windows asks for drivers.

Let us wrap it all up by allowing the virtual machine to start without the SDL-based console by removing the # from VNC and OTHERARGS. This will run kvm daemonized (detaching it from the tty) and with the console output redirected to a VNC server on display :1.

Enabling Terminal Services

Terminal Services is called Remote Access in Windows XP – enable it in Start -> Control Panel -> System -> Remote Access.

One downside is that someone needs to log on before XP punches a hole in the firewall. To circumvent this either manually add an exception for the RDP service or simply turn of the firewall (that’s what I did since the host will be protected by the host’s firewall as well as the NAT feature of VirtualBox).

Tuning Terminal Services

One of the more annoying limitations in Windows XP is that the color depth by default is limited to 16 bits.

To change this open the Group Policy Editor (Start -> Run -> gpedit.msc) and navigate to Administrative Template -> Windows Components -> Terminal Services and change the limit:

Setting connection limit in Terminal Services

Setting connection limit in Terminal Services

There are a few other parameters one can change, feel free to poke around.

SeamlessRDP

The main component in this setup is SeamlessRDP which allows one to launch a single application using RDP (remote desktop) and open only the window of that application. The drawback (with Windows XP) is that you are only allowed to open one session which means you can only launch one application at the same time.

Luckily someone grew tired of this and has made a patch to both rdesktop and SeamlessRDP that makes it possible to launch more than one application over the same SeamlessRDP session.

Installing rdesktop from CVS

First make sure that you have all the required packages for building

$ sudo apt-get build-dep rdesktop

Download rdesktop from CVS

$ cvs -d:pserver:[email protected]:/cvsroot/rdesktop login
$ cvs -z3 -d:pserver:[email protected]:/cvsroot/rdesktop co -P rdesktop

Download the patch to the checked out source

$ cd rdesktop
$ wget http://www.fontis.com.au/system/files/rdesktop.patch

Patch the source

$ patch -p2 < rdesktop.patch

Compile the source and install (install it as rdesktop-cvs to not interfere with the Ubuntu package)

$ ./bootstrap
$ ./configure
$ make
$ sudo make install
$ sudo mv /usr/local/bin/rdesktop /usr/local/bin/rdesktop-cvs

Now download the updated SeamlessRDP program and unpack it to c:\seamlessrdp on the virtual machine.

Making it all come together

winrun

Used to run any application on you Windows machine.

Create a script in $HOME/bin called winrun (requires that you have added $HOME/bin to your $PATH).

RDESKTOP="/usr/local/bin/rdesktop-cvs"
SRDP="c:\seamlessrdp\seamlessrdpshell.exe"
SOCKET="$HOME/.rdesktop/socket"
RDESKTOP_ARGS="-k da -u  -p   -z -x l -M $SOCKET -A"
RHOST=""
RUNNING=$(pgrep -c -U $USER -x rdesktop-cvs)
if [ -e $SOCKET -a $RUNNING -ge 1 ]
then
$RDESKTOP $RDESKTOP_ARGS -l "$*"
else
$RDESKTOP $RDESKTOP_ARGS -s "$SRDP $*" $RHOST
fi

Run as winrun c:pathtoprogram.exe

Sharing data between host and VM

There are (at least) three ways of sharing data between the host and the virtual machine

Remote Desktop resource redirection

This is the easiest way of sharing data but it has some drawbacks.

Enable it by adding this to RDESKTOP_ARGS in winrun:

-r disk:Home=$HOME

This will make your entire home directory available to your virtual machine but only when you are connected and not with an assigned drive letter.

Redirected local resource in RDP

Redirected local resource in RDP

Samba

Last but not least one could use a Samba server on the host

$ sudo apt-get install samba

By default the section in /etc/samba/smb.conf concerning home directories is commented out

[homes]
comment = Home Directories
browseable = no
read only = no
create mask = 0700
directory mask = 0700
valid users = %S