Friday, November 28, 2014

Set up an LXC Host using Ubuntu and ZFS

Background


I needed a host that manages LXC instances (Linux Kernel Containers) on my local network. I wanted the LXC instances to fetch IP addresses from my already existing, local DHCP server. I also wanted to take advantage of the ZFS snapshot and deduplication features, as I will have lots of LXC instances based on the same root image.

So this manual outlines the steps to install LXC and ZFS on a minimal Ubuntu 14.04 LTS. I pieced the parts relevant for my situation together from various tutorials and sources out there. Enjoy.


Step 1: Install Base OS


Start out with a plain vanilla Ubuntu 14.04 LTS Server installer. The partition layout needs to be done manually, as the installer does not support ZFS partitions. I decided to go with the following, very simple layout. No LUKS, no LVM, just 3 primary partitions. A small OS partition and a decent swap partition. The third partition filling all the available space on the disk, but being marked as "do not use" in the installer, so it will be created, but not mounted. This will become our ZFS pool later. This runs on a hardware RAID, so no need to pool multiple disks in ZFS here.

/dev/sda1     /           10 GB
   /dev/sda2     swap        min(RAM,8GB)
   /dev/sda3     "do not use this partition"


Step 2: Install Packages


Refresh everything and install a few required packages:

# apt-get update
# apt-get dist-upgrade
# apt-get install vim software-properties-common bridge-utils


Step 3: Configure Bridged Network


Since the LXC instances will have IPs in the same subnet as the LXC host itself, the host's primary interface, "eth0", must not be configured with an IP. Instead, a bridge interface with the LXC host's primary IP needs to be created. The following /etc/network/interfaces file will accomplish that. My LXC host's IP will be 192.168.5.50.

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface without IP
iface eth0 inet manual

# The bridge interface for the LXCs and the host itself
auto br0
iface br0 inet static
address 192.168.5.50
netnask 255.255.255.0
gateway 192.168.5.1
dns-nameservers 192.168.5.1
bridge_ports eth0

If you are using the UFW firewall on the LXC host, you need to allow bridged traffic across by adding the following into /etc/ufw/before.rules, before the final COMMIT:

# Allow bridged traffic to be forwarded
-I FORWARD -m physdev --physdev-is-bridged -j ACCEPT


Restart the network (or reboot) to make the new network configuration active.


Step 4: Install and Configure ZFS and zpool


Add the PPA for the ZFS modules, then install the required packages:

# add-apt-repository ppa:zfs-native/stable
# apt-get update
# apt-get install ubuntu-zfs

Create the zpool on the previously created but un-used /dev/sda3 partition:

# zpool create lxc /dev/sda3
# zpool set listsnapshots=on lxc
# zfs create -o dedup=on lxc/containers
# zfs create lxc/tmp
# chmod 1777 /lxc/tmp


Step 5: Install and Configure LXC


Add packages:

# apt-get install lxc
# cp /etc/lxc/default.conf{,.orig}

Optional: if you want to use swap space with cgroups, add this to the GRUB_CMDLINE_LINUX_DEFAULT parameter in /etc/default/grub:

cgroup_enable=memory swapaccount=1

and then run

# update-grub

and reboot.


Tweak the configuration in /etc/lxc/default.conf:

lxc.network.type = veth
lxc.network.link = br0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:3e:xx:xx:xx

Tweak the configuration in /etc/lxc/lxc.conf to use the ZFS backend:

lxc.lxcpath = /lxc/containers
lxc.bdev.zfs.root = lxc/containers

Step 6: Start Creating Containers


You are now ready to start creating LXC instances. They should come up with a DHCP address from the DHCP server in the same subnet.

# lxc-create -t ubuntu -n my_lxc_1 -B zfs

To limit the amount of RAM and swap space for a container, make sure you enabled swap support above. Then add something like this to the container's config file:

lxc.cgroup.memory.limit_in_bytes = 512M
lxc.cgroup.memory.memsw.limit_in_bytes = 1G

Friday, February 14, 2014

Broken Icons with Evince in Ubuntu 13.10

When I upgraded from Ubuntu (or rather: Kubuntu) 13.04 to 13.10, I noticed that the icons in the evince document viewer were all broken. The application window looked like this:




After some research, I narrowed it down to a missing package of Gnome icons. Install this:

# apt-get install gnome-icon-theme-symbolic

Then the icons in evince are fixed:


Saturday, November 9, 2013

Configure a Raspberry Pi as OpenVPN Client

Background

I wanted to turn a Raspberry Pi into an OpenVPN gateway on my local network at home, so a SIP-based IP phone can talk to my Asterisk server via an encrypted tunnel. This was a quick-and-dirty setup that works. I am sure it can be improved or made more elegant (send me comments if you have suggestions). I wrote this mostly for my own safekeeping.

This document does not describe the setup of the OpenVPN server or how to generate SSL certificates for the client. There is plenty of documentation on that elsewhere. I also will not describe the Asterisk setup here (I might document that separately later).

Network situation


My home LAN is connected to the Internet via a standard router. The hardware SIP phone does not support any kind of VPN natively, so I will route the SIP traffic through the Raspbery Pi, which will be configured as an OpenVPN client to the OpenVPN server running on my Asterisk server.

  • Home LAN: 192.168.1.0/255.255.255.0
  • VPN Network: 192.168.7.0/255.255.255.0

Installation / Configuration


1. Install Raspbian


This document is based on Raspbian. Whether you install it via the NOOBS installer or the Raspbian image does not matter. Install Raspbian on your SD card and go through the initial setup at first boot; set the password of the pi user, etc.

2. Install Software Packages


We need the openvpn package, but it does not hurt to refresh all other packages as well before we start. Log in as pi and become root for these steps.

$> sudo su -
#> apt-get update
#> apt-get dist-upgrade
#> apt-get install openvpn


3. Configure OpenVPN Client


Copy the OpenVPN SSL client certs and the CA cert into /etc/openvpn.

Then create the /etc/openvpn/client.conf file, similar to this example:
# OpenVPN CLient Configuration

client
dev tun

proto udp
remote myserver.com 6666

resolv-retry infinite
nobind

user nobody
group nogroup

persist-key
persist-tun

ca ca.crt
cert mycert.crt
key mycert.key

ns-cert-type server
comp-lzo
verb 3

Launch the VPN by starting the OpenVPN init script and make sure it connects:
$> /etc/init.d/openvpn start

On success, the output of ifconfig should show you a tun0 interface with the IP information of your VPN subnet:
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:192.168.7.10  P-t-P:192.168.7.9  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

4. Configure sysctl


In order to allow network traffic to be forwarded, you need to enable this via sysctl.

First, set this in the running system:

#> sysctl net.ipv4.ip_forward=1

Then update /etc/sysctl.conf, so this gets set at boot time. Find the following lines and uncomment the forward setting:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

5. Configure iptables


We will configure iptables to masquerade local IPs into the VPN subnet. Create /etc/iptables.conf with the following content, adjusting the masquerading subnet accordingly. The subnet of my VPN is 192.168.7.0/255.255.255.0, so we will masquerade anything that hits the Raspberry Pi for that subnet.

# Generated by iptables-save
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Generated by iptables-save
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o tun0 -d 192.168.7.0/24 -j MASQUERADE
COMMIT

Make sure these rules are loaded whenever the Raspberry Pi boots. You could write a fancy init script, or be lazy like I am and simply restore the rules by adding this to /etc/rc.local:

# Load iptables for VPN masquerading
echo "Loading iptables for OpenVPN masquerading"
/sbin/iptables-restore < /etc/iptables.conf

6. Route to the Pi


The last step is to configure the SIP phone to use the IP of the Raspberry Pi as its default gateway. I have my Pi running on DHCP with a permanent DHCP lease. You could also configure a static IP in your Pi.

Friday, August 30, 2013

Running a Stripes application in WildFly

When I tried to deploy a minimal web application that uses the Stripes Framework to the WildFly-8.0.0 application server, using the instructions given in the Stripes Wiki, I would always get this exception as soon as the first Strips action was requested:

17:23:17,452 ERROR [net.sourceforge.stripes.controller.StripesFilter] (default task-35) : net.sourceforge.stripes.exception.StripesRuntimeException: Something is trying to access the current Stripes configuration but the current request was never routed through the StripesFilter! As a result the appropriate Configuration object cannot be located. Please take a look at the exact URL in your browser's address bar and ensure that any requests to that URL will be filtered through the StripesFilter according to the filter mappings in your web.xml.


After spending quite some time trying to make it work, even going through the StripesFilter source code, the answer was surprisingly simple:

Edit web.xml and change the servlet filter's mapping from
    <filter-mapping>
        <filter-name>StripesFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>StripesFilter</filter-name>
        <servlet-name>StripesDispatcher</servlet-name>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
to
    <filter-mapping>
        <filter-name>StripesFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>StripesFilter</filter-name>
        <url-pattern>*.action</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

It appears as if WildFly does not like the <servlet-name>StripesDispatcher</servlet-name> and simply ignores it. When that is replaced by the pattern of the Stripes actions, it works fine: <url-pattern>*.action</url-pattern>

Maybe this saves someone else from hours of head-scratching.

Thursday, September 20, 2012

Generate MD5, SHA-1 or SHA-512 UNIX password hashes in Python

When scripting the installation of an Ubuntu server template, I needed to pre-populate the template with a couple of system users that had specific passwords.

My old method of doing this was using openssl:

$ openssl passwd -1

Password: secretstuff
Verifying - Password: secretstuff
$1$IothUf.l$E/4eCqLD9JLdg2et7FurS1


This generates the standard MD5-based password hashes that work in the /etc/shadow file. The string enclosed in the first and second dollar sign indicates the hash method used. The string enclosed in the second and third dollar sign is the password salt used.

If you need other formats, I ended up using Python's built-in crypt module. It supports MD5, SHA-1 and SHA-256 hashes, depending on the value you provide as the "salt" (second parameter):

Python 2.7.3 (default, Aug 1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
<<< import crypt
<<< crypt.crypt('secret', '$1$somesalt$')
'$1$somesalt$jezmI5TSY7mVTzHLgsK5L.'
<<< crypt.crypt('secret', '$5$somesalt$')
'$5$somesalt$BY2M0Tw/b.yijagFoMZoeHEQSuk9iqvGNX/dBDdRp8A'
<<< crypt.crypt('secret', '$6$somesalt$')
'$6$somesalt$JX0Uhce8rLRHbaqoSQDYsnTxsqcjCNNcrl79ieTwPGzEhxBEeJcsgDUWIOwc3sDvZN34ZJBWQep7.lcAuSesy/'

Thursday, September 6, 2012

Kdenlive with X.264 Support in Ubuntu 12.04

When installing kdenlive in Ubuntu 12.04, I was not able to export videos in H.264 and other formats out-of-the-box. Instead, I would get "output format not supported" errors when trying to render the videos, even though libx264 was installed.

I came across this multiple times already and was scratching my head every time, since enough time had passed since the last time I dealt with this. I could not easily remember what Ubuntu package was missing. Now it goes in my little knowledge base for next time, hehe.

The package needed is libavcodec-extra-53:
$ sudo apt-get install libavcodec-extra-53

Wednesday, September 5, 2012

Run Android SDK in 64-bit Ubuntu 12.04

When installing the Android SDK on a pure 64-bit Ubuntu system, I noticed that the tools and platform toold didn't run:
/opt/android-sdk-linux $ ./platform-tools/adb

bash: ./platform-tools/adb: No such file or directory

The files are executable and binaries, but compiled for 32-bit environments:
/opt/android-sdk-linux $ file ./platform-tools/adb

/opt/android-sdk-linux/platform-tools/adb: ELF 32-bit
LSB executable, Intel 80386, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.8,
stripped

Trying to find out the usual way, which 32-bit libraries it needs, did not work:
/opt/android-sdk-linux $ ldd ./platform-tools/adb

not a dynamic executable

Searching through several posts on the Internet, people recommended to install the whole set of 32-bit compatibility libraries in the form of the ia32-libs-multiarch package. This would have pulled in 230 new packages with all kinds of 32-bit libraries, and I did not care for this all that much.

So I tried to manually install just the lib32stdc++6 package (pulling in 2 more packages and 4 MB worth of data). Then I re-ran the ldd command to find out what else was needed:
/opt/android-sdk-linux $ ldd ./platform-tools/adb

        linux-gate.so.1 =>  (0xf77b2000)
        librt.so.1 => /lib32/librt.so.1 (0xf7795000)
        libncurses.so.5 => not found
        libpthread.so.0 => /lib32/libpthread.so.0 (0xf777a000)
        libstdc++.so.6 => /usr/lib32/libstdc++.so.6 (0xf7695000)
        libm.so.6 => /lib32/libm.so.6 (0xf766a000)
        libgcc_s.so.1 => /usr/lib32/libgcc_s.so.1 (0xf764b000)
        libc.so.6 => /lib32/libc.so.6 (0xf74a9000)
        /lib/ld-linux.so.2 (0xf77b3000)

Only the libncurses.so.5 is still missing! Yaay. After installing lib32ncurses5 (pulling in one dependency and 200 KB), the adb and fastboot tools launched fine:
/opt/android-sdk-linux $ ./platform-tools/adb version

Android Debug Bridge version 1.0.29