Daily Backup Script
Create a backup script to run every night and backup:
- MySQL database
/var/www/BookStack
folder- Nginx configuration
Prerequisites
Prepare directory structure
Before running anz script, make sure all the directories exist, otherwise the script will fail (it doesn't check nor creates them).
This is the structure of the backup directory:
/var/
├── backup
│ └── bookstack
│ ├── db
│ ├── files
│ └── nginx
This is the structure of the log directory:
/var/
├── log
│ ├── apt
│ ├── bookstack
│ │ └── backup_script
Note that you can create your own directory structure, but make sure to adjust the script accordingly.
Create MySQL configuration file
To backup a MySQL database, you'll utilize mysqldump
tool. You would normally use it with the -p
option to specify a password for a user of a database. This however, passes the password in plain text as an option to a command, therefore will be visible to any user who runs ps aux
. You want to avoid this, because it's a serious security issue.
Here's where my.cnf comes into play. my.cnf is a MariaDB configuration file. MariaDB actually has multiple configuration files in a few directories, my.cnf is usually used for user-specifies settings. By utilizing my.cnf, we can put the password in it, adjust permissions, and then point mysqldump to it. This way, the password is hidden in a well-protected file.
We do this instead of -p to avoid having a password to the database in the script in plain text. It would also be visible to any user running ps aux. By utilizing my.cnf, we can put the password in it and then point mysqldump to it. This way, the password is hidden in a well-protected file.
Create the scripts
Main script
Due to the way I decided to implement logging for this script, I have to divide it in two. It is completely possible to have just one script, so adjust it to your liking. The script will be run as root, because it's writing to privileged directories. You are free to adjust permissions, directories, users etc.
RUN_bookstack_backup.sh
#!/bin/bash
LOG_DIR=/var/log/bookstack/backup_script
CURRENT_DATE=$(date +"%Y-%m-%d")
# Run bookstack_backup_worker.sh with root privileges, pipe it to gawk which puts timestamp before every line and writes to file
source ./bookstack_backup_worker.sh | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S %Z]"), $0 }' > $LOG_DIR/bookstack-backup_$CURRENT_DATE.log
#!/bin/bash
– The so called shebang', every bash script should start with one. Read more about it here.LOG_DIR=/var/log/bookstack/backup_script
– Creates a variableLOG_DIR
specifying the location where to save logs. Simplifies scripts, so you don't have to type out long path multiple times.CURRENT_DATE=$(date +"%Y-%m-%d"
) – Creates a variableCURRENT_DATE
, which runs a commanddate
with options+"%Y-%m-%d"
. This gives you a basic ISO date inYYYY-MM-DD
format, separated with dashes. We will append this to the backup filenames.source ./bookstack_backup_worker.sh
– Run the backup script withsource
. Source runs the other script in a sub-shell and that allows us to share variables likeCURRENT_DATE
with the other script. The entire script is piped (|
) togawk
.gawk '{ print strftime("[%Y-%m-%d %H:%M:%S %Z]"), $0 }'
– This is my timestamp logging solution.gawk
takes the output of the entirebookstack_backup_worker.sh
script and adds a timestamp at the beginning of every line. This timestamping solution is described in more detail in this guide. Aftergawk
adds the timestamp, it sends it to a log file with>
. The log file's path is specified using theLOG_DIR
variable and hasCURRENT_DATE
inserted into its name. The entire path and filename then might look like this:/var/log/bookstack/backup_script/bookstack-backup_2021-09-04.log
- To run this script, simply type
sudo ./RUN_booktack_backup
Slave script
bookstack_backup_worker.sh
#!/bin/bash
BOOKSTACK_DIR=/var/www/BookStack
NGINX_DIR=/etc/nginx
BACKUP_DIR=/var/backup/bookstack
DB_BACKUP_DIR=$BACKUP_DIR/db
WEBROOT_BACKUP_DIR=$BACKUP_DIR/files
NGINX_BACKUP_DIR=$BACKUP_DIR/nginx
exec 2>&1
# MYSQL DATABASE BACKUP
echo "Starting BACKUP SCRIPT..."
echo "Starting MySQL backup..."
echo "Backing up to $DB_BACKUP_DIR..."
mysqldump --defaults-extra-file=/root/.my.cnf -v -u bookstack-admin bookstack | gzip -vc > $DB_BACKUP_DIR/bookstackdb-backup_$CURRENT_DATE.sql.gz
echo "Done..."
# WEBSERVER BACKUP
# Archive and compress BookStack webroot folder and save it to backup location with current date
echo "Backing up BookStack webroot directory to $WEBROOT_BACKUP_DIR..."
tar -czvf $WEBROOT_BACKUP_DIR/bookstack-backup_$CURRENT_DATE.tar.gz $BOOKSTACK_DIR
echo "Done..."
# NGINX CONFIG BACKUP
# Archive and compress Nginx config folder and save it to backup location with current date
echo "Backing up Nginx to $NGINX_BACKUP_DIR..."
tar -czvf $NGINX_BACKUP_DIR/nginx-backup_$CURRENT_DATE.tar.gz $NGINX_DIR
echo "Done..."
echo "Finished..."
- VARIABLE PREPARATION
#!/bin/bash
– See aboveBOOKSTACK_DIR=/var/www/BookStack
– Creates variableBOOKSTACK_DIR
pointing to the directory where BookStack is stored.NGINX_DIR=/etc/nginx
– Points to the Nginx configuration folder.BACKUP_DIR=/var/backup/bookstack
– Points to the directory where all BookStack backups will be saved.DB_BACKUP_DIR=$BACKUP_DIR/db
– Points to the database backup directory inside of the main backup directory. This variable uses the previously createdBACKUP_DIR
to make it shorter.WEBROOT_BACKUP_DIR=$BACKUP_DIR/files
– Backup dir for the BookStack files.NGINX_BACKUP_DIR=$BACKUP_DIR/nginx
– Backup dir for Nginx configuration files.
exec 2>&1
– Redirectstderr (2)
tostdout (1)
. This means all errors and normal messages will be redirected to standart output (stdout), which is what we would normally see in a terminal. All messages generated by this script will then go from stdout to the master script, which then redirects is togawk
using pipe|
(described in the master script).- MYSQL DATABASE BACKUP
- echo – Prints to the stdout
- mysqldump – Utility used to backup a MySQL/MariaDB database
- --defaults-extra-file=/root/.my.cnf – my.cnf is a MariaDB configuration file. MariaDB actually has multiple configuration files in a few directories, my.cnf is usually used for user-specifies settings. We do this instead of -p to avoid having a password to the database in the script in plain text. It would also be visible to any user running ps aux. By utilizing my.cnf, we can put the password in it and then point mysqldump to it. This way, the password is hidden in a well-protected file.