Automate backups with a Raspberry Pi
In this post I describe a setup where you use a Raspberry Pi to automate the backup of your databases.
We will have to install and configure the Raspberry Pi first. Then we will create a user with limited rights on our server. We will use this user to connect to the server and perform the backups.
Download raspbian
You can download Raspbian on the official website. Unzip the image:
cd Downloads
unzip 2017-04-10-raspbian-jessie-lite.zip
# Output
Archive: 2017-04-10-raspbian-jessie-lite.zip
inflating: 2017-04-10-raspbian-jessie-lite.img
Find the SD card
Plug the SD card and use dmesg
to find it:
dmesg | tail
# Output
[ 138.753330] CIFS VFS: Error connecting to socket. Aborting operation.
[ 138.753386] CIFS VFS: Error connecting to socket. Aborting operation.
[ 138.753690] CIFS VFS: cifs_mount failed w/return code = -113
[ 138.753717] CIFS VFS: cifs_mount failed w/return code = -113
[ 138.753725] CIFS VFS: cifs_mount failed w/return code = -113
[ 138.753769] CIFS VFS: cifs_mount failed w/return code = -113
[ 4170.871943] sd 6:0:0:0: [sde] 125042688 512-byte logical blocks: (64.0 GB/59.6 GiB)
[ 4170.876516] sde: sde1
The card is sde1.
Copy the image to the SD card
cd ~/Downloads
sudo dd bs=4M if=2017-04-10-raspbian-jessie-lite.img of=/dev/sde status=progress conv=fsync
Check the image
We copy the image on the SD card on our computer:
sudo dd bs=4M if=/dev/sde of=from-sd-card.img status=progress
Then we truncate it to the size of the original image since our SD card is probably larger than the original image:
sudo truncate --reference 2017-04-10-raspbian-jessie.img from-sd-card.img
sudo diff -s from-sd-card.img 2017-04-10-raspbian-jessie.img
There should be no difference between the truncated image and the original.
Finally we run sync
. This will ensure the write cache is flushed and that it is
safe to unmount your SD card.
Authorize SSH
For security reasons, SSH is disabled by default on raspbian now.
We can enable it by adding an empty file named ssh
in /mnt/rasp
.
sudo mkdir /mnt/rasp
sudo mount /dev/sde1 /mnt/rasp
sudo touch /mnt/rasp/ssh
umount /dev/sde1 /dev/sde1
Updating the Raspberry Pi
Place the card in the raspberry pi and plug the power.
We connect to the Raspberry Pi with:
ssh pi@raspberrypi
# password is raspberrypi
We start by changing the password:
passwd
Then we change the hostname:
sudo hostnamectl set-hostname backuppi
We perform updates and install useful software
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git tree vim zsh cifs-utils rpi-update
sudo rpi-update
Remove password authentication
We create a SSH key:
ssh-keygen
This might be useful at some point but we will not use it right now.
We add our computer public SSH key to the file ~/.ssh/authorized_keys
.
And we test the authentication with the public SSH key.
Then we remove password authentication by modifying /etc/ssh/sshd_config
sudo vim /etc/ssh/sshd_config
Add a new user
We add a new user backupuser
with:
sudo adduser backupuser
We enter a strong password. And we impersonate the user to perform the configuration:
sudo su - backupuser
We should see that we are now the user backupuser
and that our home directory
is coherent with this.
Add Public Key Authentication
We generate a new key pair with
ssh-keygen
We leave the passphrase blank: this user will have to connect automatically to the servers.
We can display the created public key with:
cat ~/.ssh/id_rsa.pub
backupuser on the server
We create the user backupuser
on our server and configure it so that the user
backupuser
on our Raspberry Pi can SSH to our server.
Add a user backupuser
sudo adduser backupuser
Add the public key
We create the directory /home/backupuser/.ssh
and the file authorized_keys
:
sudo su - backupuser
mkdir ~/.ssh
touch ~/.ssh/authorized_keys
We add the public key generated on our Raspberry Pi to the file /home/backupuser/.ssh/authorized_keys
.
sudo vim ~/.ssh/authorized_keys
And we can stop impersonating backupser
on our server.
exit
Now we can go back to our Raspberry Pi and test the connection to the server:
ssh myserver.net
We should be logged in as backupuser
on our server.
Configure chroot on the server
Install chroot
On the server, as the normal user we install chroot
with:
sudo apt-get install dchroot debootstrap
Add the follwing line in /etc/ssh/sshd_config
. Note that you can have only one configuration line with Subsystem sftp ...
, otherwise your ssh server will fail
starting.
Create a chroot jail
Create a chroot jail by adding the follwing lines at the end of the file /etc/ssh/sshd_config
:
The directory /home/backupuser
must be owned by ROOT
To make the user ROOT the owner of /home/backupuser
we can use:
chown -R root:root /home/backupuser
Now save an restart the SSH server.
sudo service ssh restart
If we try to connect from the Raspberry Pi to the server using SSH the connection will be closed. This is normal.
Copying necessary files
The way chroot
works is that the user is confined to /home/backupuser/
,
which means that the user cannot access /bin/bash
, /bin/ls
, and so on…
To allow the use of bash
we have to :
- copy
/bin/bash
to/home/backupuser/
- copy
/bin/bash
dependencies to/home/backupuser
Copying /bin/bash
We create a directory /home/backupuser/bin
sudo mkdir /home/backupuser/bin
We copy the file to this new directory:
sudo cp /bin/bash /home/backupuser/bin
Copying dependencies
We list the /bin/bash
dependencies with ldd
:
ldd /bin/bash
#Output
linux-vdso.so.1 => (0x00007fff02b45000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f793909a000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7938e96000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7938acc000)
/lib64/ld-linux-x86-64.so.2 (0x00007f79392c3000)
So we create the necessary directories:
sudo mkdir -p /home/backupuser/lib/x86_64-linux-gnu/
sudo mkdir /home/backupuser/lib64
And we copy the libraries to the newly created directories
sudo cp /lib/x86_64-linux-gnu/libtinfo.so.5 /home/backupuser /lib/x86_64-linux-gnu/libtinfo.so.5
sudo cp /lib/x86_64-linux-gnu/libdl.so.2 /home/backpuser/lib/x86_64-linux-gnu/libdl.so.2
sudo cp /lib/x86_64-linux-gnu/libc.so.6 /home/backpuser/lib/x86_64-linux-gnu/libc.so.6
sudo cp /lib64/ld-linux-x86-64.so.2 /home/backpuser/lib64/ld-linux-x86-64.so.2
Now we can try this from our Raspberry Pi:
ssh myserver.net bash --version
We should see the following output:
Copying rsync dependencies
We repeat the operation done with /bin/bash
for /usr/bin/rsync
.
sudo mkdir -p /home/backupser/usr/bin
sudo cp /usr/bin/rsync /home/backupuser/usr/bin/
We list the rsync dependencies:
ldd /usr/bin/rsync
# Output
linux-vdso.so.1 => (0x00007ffd507b3000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f1b11409000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f1b11201000)
libpopt.so.0 => /lib/x86_64-linux-gnu/libpopt.so.0 (0x00007f1b10ff5000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1b10c2b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1b11896000)
And we copy them:
sudo cp /lib/x86_64-linux-gnu/libattr.so.1 /home/backupuser/lib/x86_64-linux-gnu/libattr.so.1
sudo cp /lib/x86_64-linux-gnu/libacl.so.1 /home/backupuser/lib/x86_64-linux-gnu/libacl.so.1
sudo cp /lib/x86_64-linux-gnu/libpopt.so.0 /home/backupuser/lib/x86_64-linux-gnu/libpopt.so.0
sudo cp /lib/x86_64-linux-gnu/libc.so.6 /home/backupuser/lib/x86_64-linux-gnu/libc.so.6
Testing the chroot jail
Now to test the chroot jail we will create a file /home/backupuser/test.txt
on our server, with the following content:
Now from our Raspberry Pi, and as the user backupuser
, we run the following
command:
rsync myserver.net:/test.txt .
We should have the file test.txt
copied on our Raspberry Pi with the correct
contents.
Note that when we connect to the server, the root directory /
for the user
backupuser
is actually the directory /home/backupuser
. This is why in the
rsync command we use myserver.net:/test.txt
.
If we try to ssh into our server, we will have a bash terminal (since we copied
/bin/bash). But we will not have access to commands to given to the user such
as ls
, mkdir
, cat
etc…
Also, the user will only have access to /home/backupuser
which will be its
root directory.
Backing up databases
To backup our database :
- We create a limited read-only user on our databases
- We create a cron job to dump our database in
/home/backupuser/backup
on our server. - We use rsync to retrieve our
backup
folder from our Raspberry Pi. cronjob with normal user.
You can follow these tutorials treating about bullet points 1 and 2:
Once you have followed the tutorials you will only have to create a cron job on your Raspberry Pi.
Use crontab -e
to edit the cron jobs. And add the following job:
# Backup remote databases everyday at 01:00
0 1 * * * rsync -a myserver.net:/backup /home/backupuser/