I’m going to assume you already have a working KVM host, with virsh and a networking bridge setup. If not this is a great how-to to get KVM and virsh setup: http://www.charleslabri.com/installing-and-working-with-centos-7-x64-and-kvm/

First, download the KVM cloud image, go to getfedora.org for the latest image link.

# cd /opt/guests/disk
# wget http://download.fedoraproject.org/pub/fedora/linux/releases/test/22_Beta/Cloud/x86_64/Images/Fedora-Cloud-Base-22_Beta-20150415.x86_64.qcow2

I keep my images in /opt/guests/disk and isos in /opt/guests/iso/, you may keep them elsewhere.

Its a good idea to make a copy of this image for each VM because the VM will read and write to this image.

# cp Fedora-Cloud-Base-22_Beta-20150415.x86_64.qcow2 myf22.qcow2

The image is only 3GB by default, you probably want to expand the disk, so lets do that now (you can skip this step if you’re OK with 3GB):

# qemu-img create -f qcow2 -o preallocation=metadata f22tmp.qcow2 20G
# virt-resize –expand /dev/sda1 myf22.qcow2 f22tmp.qcow2
# mv f22tmp.qcow2 myf22.qcow2

Now you’ll need to create an iso for cloud-init. cloud-init will setup your ssh user and networking.

First create the user-data and meta-data files for the iso, update the configuration accordingly.

# cat meta-data
instance-id: myfedora22
local-hostname: myfedora22.domain.tld
network-interfaces: |
iface eth0 inet static

# cat user-data
– name: travis
shell: /bin/bash
–   (insert ssh public key here)

Now generate the iso:

# genisoimage -output /opt/guests/iso/myf22.iso -volid cidata -joliet -rock user-data meta-data
# chown qemu:qemu /opt/guests/iso/myf22.iso

And create the VM:

virt-install –name MyF22 \
–ram 2048 \
–disk /opt/guests/disk/myf22.qcow2 \
–vcpus 2 \
–os-variant fedora21 \
–connect qemu:///system \
–network bridge:br0,model=virtio \
–cdrom /opt/guests/iso/myf22.iso \
–boot hd

After the VM boots you can press ^] to exit the console.

Now you can log into the VM:

ssh travis@

Now the only issue is that on reboot, the cloud-init iso won’t be mounted and your networking settings won’t be provided to the guest. You will need to launch virsh and edit the XML description for the vm and add the source manually.

# virsh

virsh # edit MyF22

Find the disk section that describes the cdrom , it will look like this:

<disk type=’block’ device=’cdrom’>
<driver name=’qemu’ type=’raw’/>
<target dev=’hda’ bus=’ide’/>
<address type=’drive’ controller=’0′ bus=’0′ target=’0′ unit=’0’/>

Change the disk type to “file” and add a source tag with your cloud-init iso as the source:

<disk type=’file‘ device=’cdrom’>
<driver name=’qemu’ type=’raw’/>
  <source file=’/opt/guests/iso/myf22.iso’/>
<target dev=’hda’ bus=’ide’/>
<address type=’drive’ controller=’0′ bus=’0′ target=’0′ unit=’0’/>

This information was gathered from the following sources:


Since as long as I have used Php, I have carried around some code that I use for quick shell scripts and the occasional data mangling. It’s not particularly great code, in fact I would say its pretty bad but it was never really used for anything other than the occasional quick hack (I use Propel, RedBean, or PDO for other Php projects). I have been using this code copy+paste style for over 5 years and it has remain mostly unchanged:

if (!$link = @mysql_connect('localhost', 'user', 'pass')) {
  die('Could not connect: ' . mysql_error());

@mysql_select_db('database', $link) or die('Could not select database.');

function query($query) {
  $rows = array();
  $result = @mysql_query($query);
  if ($result && mysql_num_rows($result)) {
    while ($row = mysql_fetch_assoc($result)) {
      $rows[] = $row;
  return $rows;

foreach(query("select * from foo") as $row => $record) {

  // do stuff with $record


Yeah… I can see you cringing right now. But for banging out the occasional script it usually worked (as long as the result fit into memory). You may also notice the use of error suppression with @. That’s because I’ve been using this code for so long that the mysql_* functions have been deprecated (as they should be) and they will throw warnings on newer versions of Php when you use them… ouch.

As we all know too well, sometimes our little hacks and kludges work so well that they end up in production, get scheduled as cronjobs, get rolled into internal web pages and the like. Recently this code put me in a bit of a bind. It had found it’s way into a very complex data-mangling cronjob that was needed to generate a table which was used for reporting. The table stopped being generated when the result set had grown too large to fit into memory and the script was crashing.

I realized I had to fix this script but the query function and foreach loops were peppered throughout the code, sometimes nested, sometimes used in recursive functions. I didn’t have time to re-write a large portion of the code so I came up with this backwards compatible version which limited the amount of re-writing I needed to do. I could use it in such a way that when I knew the result set would be small I could use the old in-memory query (no changes were needed), but when I knew it would be large result set, I could use a callback that was called for each row.

function query($query, $callback = FALSE) {
  $rows = array();
  $result = @mysql_query($query);
  if ($result && mysql_num_rows($result)) {
    while ($row = mysql_fetch_assoc($result)) {
      if ($callback === FALSE) {
        $rows[] = $row;
      } else {
        call_user_func($callback, $row);
  return $rows;

// new use, with callback
query("select * from foo", function ($record) {

  // do stuff with each $record


I realize this code is STILL not ideal, but it is a backwards compatible fix and got the job done.

I recently downloaded the Fedora 21 XFCE4 Alpha iso and used the LiveUSB Creator to write the iso to a USB disk. When I tried to boot the USB image I hit an error I haven’t seen before:

vesamenu.c32: not a COM32 image

The quick fix is pretty simple, but not at all obvious: just provide the kernel and arguments manually:

vmlinuz0 initrd=initrd0.img root=live:CDLABEL=LIVE rootfstype=vfat ro rd.live.image quiet  rhgb rd.luks=0 rd.md=0 rd.dm=0 nomodeset

Just type the above in in the “boot:” prompt (all on one line) and it should boot the image to a desktop. Not sure why this happens but it is Alpha.

As if I expected anything else from a beta release. At least the uninitiated have been warned!

This is unstable, pre-release software,

You wake up inside an OS installer in Timbuktu, and it’s six months in the future. But, there are bugs. Bugs everywhere. Bugs you must live with. This OS of the future isn’t a stable OS you can rely on. It’s for testing purposes only.

f20 anaconda

Fedora 20, Anaconda

In this post I am going to outline the steps I took to create an SFTP server with OpenSSH. My SFTP server had the following characteristics:

  • Each SFTP user is chroot’ed into their own private directory.
  • Each chroot has 2 levels: a private, read-only directory and the user’s home directory where the user can upload files.
  • Users do not have shell access.
  • Users can authenticate via password or public rsa key.

The resulting structure looks like:

    user1/    <- User with public key auth
    user2/   <- User with password auth

Note: I put all of my SFTP chroots into a single directory, I chose “/var/sftp” but you are free to use something else. Also this post assumes that SELinux is disabled, this was fine for my use case but it is really not ideal. Perhaps in a future post I will add instructions for making this work with SELinux.

Create a Group for SFTP Users

Create a group called “sftpusers”, all SFTP users that will be chrooted will use this group. You are free to choose a name other than sftpusers.

# groupadd sftpusers

Update SSHD Config

Next, make the following changes to /etc/ssh/sshd_config.

Replace the line:

Subsystem sftp /usr/libexec/openssh/sftp-server

With this:

Subsystem sftp internal-sftp
Match Group sftpusers
 ChrootDirectory /var/sftp/%u
 ForceCommand internal-sftp

This configuration will force all users with the sftpusers group to be chrooted /var/sftp/<username>

You will need to reload the sshd configuration for this change to take effect:

# service sshd reload

Create a user

Create the user:

# useradd -M -g sftpusers -d /upload -s /sbin/nologin myuser

Create the user’s writable home directory:

# mkdir -p /var/sftp/myuser/upload

Make them the owner and give them write permissions:

# chown myuser:sftpusers /var/sftp/myuser/upload/
# chmod o+w /var/sftp/myuser/upload/

If you are adding a lot of SFTP accounts, you will probably want to script these steps.

Password Authentication

If you want password authentication for this user, create their password now:

# passwd myuser

Now you can test out the SFTP account, if you want to use public key authentication, continue to the next section:

Public Key Authentication

Create a ssh directory for the user:

# mkdir -p /var/sftp/myuser/.ssh
# chmod 700 /var/sftp/myuser/.ssh

Add the public key to “”/var/sftp/myuser/.ssh/authorized_keys” and set the correct permissions

# chown -R myuser /var/sftp/myuser/.ssh
# chmod 600 /var/sftp/myuser/.ssh/authorized_keys

We will need to update the sshd_config file again so that the daemon looks in the correct location for .ssh keys

In “/etc/ssh/sshd_config” change this line:

#AuthorizedKeysFile .ssh/authorized_keys

To this:

AuthorizedKeysFile /var/sftp/%u/.ssh/authorized_keys

Reload the service again and you should be all set:

# service sshd reload

I found Munin much more useful than Nagios for monitoring a single server. This guide will show you how to set up a single Munin instance that generates pretty graphs with cron and is accessible via Munin’s web interface.

Get Munin’s dependencies

You will need EPEL, a webserver (I’ll use Apache here) and some Munin packages.

EPEL Repo:

Get the latest EPEL repo from here and install. example:

# rpm -i http://mirrors.ptd.net/epel/6/i386/epel-release-6-8.noarch.rpm

Munin Packages:

# yum install munin munin-node httpd

Start Munin Service and Enable on boot

# service munin-node start
# service httpd start
# chkconfig munin-node on
# chkconfig httpd on

Configure Web Interface

Setup a user and password to access the web interface.

# htpasswd /etc/munin/munin-htpasswd <INSERT A USER NAME HERE>

Navigate to web interface: http://<server ip>/munin

If you don’t see the UI below, but instead see a directory listing, give Munin a few minutes to generate data. By default it will generate graphs every 5 minutes. I usually edit /etc/cron.d/munin such that graphs are generated every hour as I use it more for historical purposes and if I need immediate insight I just use htop.


Some example graphs:


Talks I attended at LinuxCon this year.

Day 1 – Monday, September 16

  • DistCI, Continuos Integration at Scale – Heikki Nousianen, F-Secure
  • LXC, Docker, and the Future of Software Delivery – Jerome Petazzoni, dotCloud
  • A Practical Tutorial to Open Sourcing Proprietary Technology – Guy Martin, Samsung
  • Case Study: Doing a LIve Upgrade on Many Thousands of Servers at Google from an Ancient Redhat Distribution to a Recent Debian-Based One – Marc Merline, Google


Day 2 – Tuesday, September 17

  • Running MySQL Clusters in the cloud – Max Mether, MySQL AB
  • The Enlightened Toolkit: Development Tips and Tricks to Get You Going – Mike Blumenkrantz, Samsung
  • Build Your Own PaaS, Just Like Red Hat’s OpenShift – Diane Mueller, Red Hat
  • (Tutorial) High Availability Solutions for MySQL and MariaDB – Max Mether, MySQL AB


Day 3 – Wednesday, September 18

  • (Tutorial) Cross-Compiling Linux Kernels on x86_64: A Tutorial on How to Get Started – Shuah Khan, Samsung
  • How Platform-as-a-Service Benefits More than Developers – Gordon Haff, Red Hat
  • (Tutorial) Getting Started With OpenStack – Kenneth Hui, Rackspace