LXD now runs my WordPress

Here are some notes on how I used LXD to run a container for WordPress. This is (a lot) more convenient than using Docker, which was my original approach to getting my WordPress site into a container.

Getting LXD onto Debian Stretch

LXD is installed on Debian via a Snap package, so sudo apt-get install snapd if this is not already installed. See https://docs.snapcraft.io/installing-snap-on-debian. Then run snap install lxd (see https://stgraber.org/2017/01/18/lxd-on-debian/) and log in again to get an updated command path to the new snap-installed binaries.

Run lxd init to configure the default environment, the storage type I chose was simply directories, since it’s the most convenient for moving files from the Docker setup that I’m migrating from.

Create and configure our container

When lxd is installed, create a new Debian container with lxc launch 'images:debian/9' susanet-wp.

Use lxc exec susanet-wp passwd to set a root password, then lxc console susanet-wp to log into the console. From here we can install the required packages.

apt-get install apache2 php-curl php-gd php-intl php-mbstring php-soap 
php-xml php-xmlrpc php-zip libapache2-mod-php php-mysql
libphp-phpmailer mariadb-server mariadb-client iputils-ping
exim4-daemon-light curl wget netcat

From here it’s pretty much a normal WordPress installation. Since I was migrating from another database, the commands used to get MariaDB set up were as follows: –

create database wp_db
create user 'wp_user'@'localhost' identified by '<db password>'
grant all privileges on wp_db.* to 'wp_user'@'localhost'
flush privileges

I used this command to install my SQL dump file taken from the old Docker setup: –

zcat kakapo_wordpress_db.gz|lxc exec susanet-wp -- mysql wp_db 

Some notes on LXD

LXD creates containers from locally stored images, though these images might themselves be fetched from a remote server.

There are a number of pre-configured public repositories, which can be viewed with lxc remote list, and if you have another LXD installation elsewhere, then this can be used as a further remote server.

The command to register a new remote server is lxc remote add myremote, where the IP address is that of another server running LXD, and ‘myremote’ is the alias by which I want to refer to the remote server.

Note that the remote server must be exposed on port 8443 (by default) of the specified IP. A password also has to be defined – clients will be prompted for this when adding this remote server. The following commands will configure the remote server.

lxc config unset core.https_address
lxc config set core.https_address [::]:8443
lxc config set core.trust_password <my_remote's password>

A snapshot in LXD refers to the state of a container as at a specific point in time, and can be used to easily restore the state of the container.

An image can be created from a stopped container, or from a snapshot of a running container. The following commands are listed as examples of usage: –

lxc snapshot susanet-wp my-snapshot
lxc publish susanet-wp/my-snapshot --alias my-new-image
lxc delete susanet-wp/my-snapshot

The snapshot command takes a snapshot of the given container. The publish command creates a local image from this snapshot, and the delete command removes the snapshot (assuming you no longer want it).

Putting the above together, this can be used to copy a container to a backup server. The main local server would be configured to bind to an IP address/socket and given a password, and the backup server adds this as a remote. It can then ‘launch’ this image.

Alternatively, it’s even possible to simply push a local image to a backup server: –

lxc launch my-new-image myremote:susanet-backup

In this case, my local image ‘my-new-image’ is created on a remote server I aliased as ‘myremote’, and the new container on the remote server is called ‘susanet-backup’.

Networking to the outside world

A container can be given an interface on the bridge using something like the following: –

lxc config device add susanet-wp eth0 nic name=eth0 nictype=bridged parent=lxdbr0

We can use DNAT to forward host ports (e.g. on an external IP address) to the bridged interface using something like the following: –

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT \

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT \

A possibly simpler and more convenient way to connect the container to an external IP address is to use the ‘proxy’ device. This connects an ip:port address on the host to an ip:port in the container, so: –

kevin@vps1:~$ lxc config device add susanet-wp http proxy \
listen=tcp: connect=tcp:
kevin@vps1:~$ lxc config device add susanet-wp https proxy \
listen=tcp: connect=tcp:

would connect port 80 on all host interfaces to port 80 on the container’s localhost interface.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *