Using kexec to change the kernel & init system on DigitalOcean
DigitalOcean don't currently allow you to boot one of their "droplets" (virtual machines) with a custom kernel or kernel command line. This opens you to security flaws if you don't remember to change the kernel setting for your Droplet whenever you upgrade your distro's kernel.
You can work around this by replacing /sbin/init with a short script that uses kexec to load a new kernel, appending custom command line arguments. First of all, ensure you have a recent backup of your droplet--if this goes, wrong, and you have no backup, you will have to get DigitalOcean support to fix your droplet. Use the automatic backup feature, or power your dropplet off and take a snapshot manually. Next, prepare your droplet; assuming you are running Debian:
# apt-get install -t wheezy-backports systemd systemd-sysv # apt-get install kexec-tools # dpkg-reconfigure kexec-tools
When prompted whether to use kexec to handle reboots, say no--we don't want to use kexec except manually from our replacement /sbin/init.
Move /sbin/init out of the way so that we can provide the replacement. This file is owned by the package manager, so tell dpkg that you want to move it out of the way:
# dpkg-divert --add --local --rename /sbin/init Adding 'local diversion of /sbin/init to /sbin/init.distrib'
Finally, provide the new /sbin/init:
1 #!/bin/bash
2 set -eu
3
4 function unit {
5 echo "Starting systemd ($1)"
6 if ! exec /lib/systemd/systemd --system --unit="$1.target"; then
7 echo 'Falling back to bash'
8 exec /bin/bash
9 fi
10 }
11
12 if read -t 5 -p 'Hit enter within 5 seconds to abort kexec...'; then
13 unit rescue
14 fi
15
16 if ! (
17 /sbin/kexec --load /vmlinuz \
18 --reuse-cmdline \
19 --initrd=/initrd.img \
20 --append='init=/lib/systemd/systemd cgroup_enable=memory swapaccount=1' \
21 && /sbin/kexec --exec
22 ); then
23 unit rescue
24 fi
25
26 unit emergency
Make sure the file is executable: chmod 755 /sbin/init, then reboot.
I'm using the kernel package's /vmlinuz and /initrd.img symlinks; Debian's kernel packages try to keep these pointing at the latest installed kernel, so I install the latest kernel from wheezy-backports (linux-image-i686-pae since my droplet runs the i386 port) and rely on these symlinks, whose names do not change, to load the latest kernel image.