diff --git a/README.rst b/README.rst
index 7ed6e78d52d5db7f7c500745f9f7d1a6b6f5d0bd..3923e54bcf3bf8ddc409ed3ed4456c9773c70fd9 100644
--- a/README.rst
+++ b/README.rst
@@ -155,6 +155,22 @@ with data on its own memory usage), in JSON format at the
 ``/debug/vars`` URL.
 
 
+Testing
+-------
+
+There's a Vagrant_ configuration in the ``vagrant-test`` subdirectory
+that will turn up a test three-node cluster (with Debian) using
+pre-packaged binaries. To run it::
+
+    $ cd vagrant-test
+    $ vagrant up
+
+It will take a while to download the base image the first time, then
+it will turn up three nodes called **node1**, **node2** and **node3**.
+Use ``vagrant ssh`` to inspect them.
+
 
 .. _etcd: https://github.com/coreos/etcd
 .. _autoca: https://git.autistici.org/ai/autoca
+.. _Vagrant: http://www.vagrantup.com/
+
diff --git a/vagrant-test/Vagrantfile b/vagrant-test/Vagrantfile
new file mode 100644
index 0000000000000000000000000000000000000000..9b3e4da7a53e9258674caa690b2d73e27be82acf
--- /dev/null
+++ b/vagrant-test/Vagrantfile
@@ -0,0 +1,51 @@
+
+API_VERSION = "2"
+
+# Note: we shouldn't need to create a host entry for 'etcd', but
+# 'test.net' is a real domain with a catch-all...
+$setup_host_file = <<SCRIPT
+cat >/etc/hosts <<EOF
+127.0.0.1 localhost
+192.168.50.2 node1.test.net etcd.test.net node1
+192.168.50.3 node2.test.net node2
+192.168.50.4 node3.test.net node3
+EOF
+SCRIPT
+
+Vagrant.configure(API_VERSION) do |config|
+  config.vm.box = "wheezy"
+  config.vm.box_url = "http://www.incal.net/ale/debian-wheezy-64.box"
+
+  config.vm.provision "shell", inline: $setup_host_file
+
+  config.vm.provision "shell" do |s|
+    s.path = "bootstrap.sh"
+    s.args = "test.net"
+  end
+
+  config.vm.define "node1" do |m|
+    m.vm.hostname = "node1"
+    m.vm.network "private_network", ip: "192.168.50.2"
+    m.vm.provision "shell",
+      inline: "echo BOOTSTRAP=1 > /etc/default/etcd"
+  end
+
+  config.vm.define "node2" do |m|
+    m.vm.hostname = "node2"
+    m.vm.network "private_network", ip: "192.168.50.3"
+    #m.vm.provision "shell", inline: "hostname node2"
+    m.vm.provision "shell",
+      inline: "echo ETCD_SERVER=node1 > /etc/default/etcd"
+  end
+
+  config.vm.define "node3" do |m|
+    m.vm.hostname = "node3"
+    m.vm.network "private_network", ip: "192.168.50.4"
+    m.vm.provision "shell",
+      inline: "echo ETCD_SERVER=node1 > /etc/default/etcd"
+    m.vm.provision "shell",
+      inline: "sleep 3 && radioctl create-mount sample.ogg"
+  end
+
+end
+
diff --git a/vagrant-test/bootstrap.sh b/vagrant-test/bootstrap.sh
new file mode 100644
index 0000000000000000000000000000000000000000..02e3dd66e83babde0fd729041951f84a91ebe0db
--- /dev/null
+++ b/vagrant-test/bootstrap.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+
+# Install our Debian apt repository.
+echo 'deb http://www.incal.net/ale/debian autoradio/' > \
+	/etc/apt/sources.list.d/autoradio.list
+
+cat >/etc/default/icecast2 <<EOF
+CONFIGFILE="/etc/icecast2/icecast.xml"
+USERID=icecast2
+GROUPID=icecast
+ENABLE=true
+EOF
+
+# Install the required packages.
+export DEBIAN_FRONTEND=noninteractive
+apt-get update -q
+yes n | apt-get install -q -y --force-yes etcd autoradio
+
+# Install the configuration.
+DOMAIN="${DOMAIN:-$1}"
+if [ -n "${DOMAIN}" ]; then
+  echo "Autoconfigured with domain: ${DOMAIN}" 1>&2
+  echo "DOMAIN=${DOMAIN}" > /etc/default/autoradio
+fi
+
+echo "All done (?)" 1>&2
+exit 0
+