diff --git a/backup-Wordpress.sh b/backup-Wordpress.sh deleted file mode 100755 index 94480f9..0000000 --- a/backup-Wordpress.sh +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/bash - -# TODO - # Display the archive name at the end - # Display the log location at start AND at end - # Check if we can avoid sudo - passphrase in user's .config dir - # Keyshortcuts for - # easily list the archives - # Mount an archive - # Health check - # Put the temp DB backup file in some other location - -# TODO - Accept the following mandatory parameters - # --project-name | -pname - # --wp-source-dir | -wp_src - # --backup-dir - ## Will be created if it does not exists -# And the following optional parameters - # --storage-quota | -quota - - -# TODO - Check on other OSes - # Ubuntu 16, 18, 18.08 - # Debian 8, 9, 10 - -# So root - no good -[[ "$(id -u)" != "0" ]] && { - echo -e "ERROR: You must be root to run this script.\nPlease login as root and execute the script again." - exit 1 -} - -SCRIPT_NAME=wp_borg_backup -SCRIPT_VERSION=0.1 - - -project_name="$1" -wp_src_dir="$2" -backup_dst_dir="$3" - -storage_quota="5G" #if user provided - update this - -# Create the backup directory if it does not exist -mkdir -pv "${backup_dst_dir}"/{bkp_log,DB,WP} > /dev/null -bkp_log_dir="${backup_dst_dir}/bkp_log" -bkp_final_dir="${backup_dst_dir}/WP" -bkp_DB_dir="${backup_dst_dir}/DB" -TS=$(date '+%d_%m_%Y-%H_%M_%S') - -LOGFILE="${bkp_log_dir}"/"$SCRIPT_NAME"_v"$SCRIPT_VERSION"_"$TS".log -touch "${LOGFILE}" - - -# Install "borgbackup" if NOT installed -if ! (type borg > /dev/null 2>&1); then - apt-get install -y borgbackup >> "$LOGFILE" 2>&1 -fi - -#If borg is running the same backup - quit -if (pidof -x borg > /dev/null) && $(pgrep -ac "$wp_src_dir") -gt 0 ; then - echo "${wp_src_dir} is being backed up from another process" | tee -a "$LOGFILE" - echo "This process will now exit" | tee -a "$LOGFILE" - exit 11 -fi - -# Install wp-cli if not installed -if ! (type wp > /dev/null 2>&1); then - echo -e "wp-cli not found on system. \nInstalling wp-cli" >> "$LOGFILE" 2>&1 - wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -O /usr/local/bin/wp >> "$LOGFILE" 2>&1 - chmod +x /usr/local/bin/wp >> "$LOGFILE" 2>&1 -fi - -# Backup WP database -directory_owner=$(ls -ld "${wp_src_dir}" | awk '{print $3}') -sudo -u "${directory_owner}" wp db --quiet export "${wp_src_dir}"/"$TS"_database.sql --add-drop-table --path="${wp_src_dir}" - -if mv "${wp_src_dir}"/"${TS}"_database.sql "${bkp_DB_dir}"/"${TS}"_database.sql >> "$LOGFILE" 2>&1; then - echo "DB backed up successfully" | tee -a "$LOGFILE" -else - echo "ERROR: DB Backup Failed. Check log for more details." | tee -a "$LOGFILE" -fi - -# Try reading the passphrase from the BORG_PASSCOMMAND exported variable -if [[ -n "$BORG_PASSCOMMAND" ]]; then - borg_passphrase="$BORG_PASSCOMMAND" -# Else - try finding it from our designated password file -elif [[ -f /root/.config/borg/."$project_name" && -s /root/.config/borg/."$project_name" ]]; then - borg_passphrase=$(cat /root/.config/borg/."$project_name") -fi - -# If no passphrase found and repo EXISTS at the destination - Exit -if [[ ( -z "$borg_passphrase" ) && ( -f "$backup_dst_dir"/config || -f "$bkp_final_dir"/config ) ]]; then - echo "Could not find a passphrase" | tee -a "$LOGFILE" - echo -e "Either do a (EXPORT BORG_PASSCOMMAND=[your-passphrase] \n\t\t OR \nAdd the passphrase to /root/.config/borg/.${project_name} file." | tee -a "$LOGFILE" - exit 12 -fi - -# Auto generate passphrase if no repo exists -if [[ ( ! -f "$backup_dst_dir"/config ) && ( ! -f "$bkp_final_dir"/config ) ]]; then - borg_passphrase=$(< /dev/urandom tr -cd 'a-zA-Z0-9@&_' | head -c 20) # 20-character - - mkdir "$backup_dst_dir"/WP >> "$LOGFILE" 2>&1 - - export BORG_NEW_PASSPHRASE="$borg_passphrase" - - # Backup any recidual passphrase keys - if [[ -f /root/.config/borg/."$project_name" ]]; then - mv /root/.config/borg/."$project_name" /root/.config/borg/."$project_name"_old_"${TS}" - fi - - # chmod 400 the passphrase file - touch /root/.config/borg/."$project_name" >> "$LOGFILE" 2>&1 && chmod 440 /root/.config/borg/."$project_name" >> "$LOGFILE" 2>&1 && { - # Display the passphrase on screen - echo "############### BACKUP PASSPHRASE ###############" | tee -a "$LOGFILE" - echo "$borg_passphrase" | tee /root/.config/borg/."$project_name" | tee -a "$LOGFILE" - echo "############### BACKUP PASSPHRASE ###############" | tee -a "$LOGFILE" - echo "You CANNOT access your backup without the above passphrase" | tee -a "$LOGFILE" - echo "" | tee -a "$LOGFILE" - } - - # Initalize the repo - if (borg init -v --encryption=repokey-blake2 --storage-quota "$storage_quota" "$bkp_final_dir" >> "$LOGFILE" 2>&1); then - echo "Repository initialized successfully" | tee -a "$LOGFILE" - else - echo "ERROR: Backup initialization failed. Check the logfile for more details." | tee -a "$LOGFILE" - fi -fi - -# This is required again - if passphrase was generated in the above step -export BORG_PASSPHRASE="$borg_passphrase" - -# Do the actual backup -# We run it on a lower priority so it does not disturb others -if ionice -c 2 -n 7 borg create \ - --verbose \ - --filter AMEsd \ - --list \ - --json \ - --stats \ - --show-rc \ - --compression zstd \ - --exclude-caches \ - "$bkp_final_dir"::{hostname}_"$project_name"_"$TS" \ - "$wp_src_dir" \ - "${bkp_DB_dir}" \ - >> "$LOGFILE" 2>&1; then - echo "Backup Completed Successfully" | tee -a "$LOGFILE" -else - echo "ERROR: Backup failed. Check the logfile for more details" | tee -a "$LOGFILE" -fi \ No newline at end of file diff --git a/note-to-self.txt b/note-to-self.txt index 9b1a903..1e16c1d 100644 --- a/note-to-self.txt +++ b/note-to-self.txt @@ -64,4 +64,5 @@ ## How to restore - for a particular date? ## Point to rclone to sync these backups to remote locations ## Point to init linux hardening for hardening linux servers - ## Point to WordOps for easier wordpress installations \ No newline at end of file + ## Point to WordOps for easier wordpress installations + ## MUST have a passphrase for your existing backup \ No newline at end of file diff --git a/wp_borg_backup.sh b/wp_borg_backup.sh new file mode 100755 index 0000000..ff25f96 --- /dev/null +++ b/wp_borg_backup.sh @@ -0,0 +1,288 @@ +#!/usr/bin/env bash + +# TODO + # Keyshortcuts for + # easily list the archives + # Mount an archive + # Health check + # A usage() + + # Best Practice -> https://google.github.io/styleguide/shell.xml + # Send error messages to STDERR + # Comment at top of the file explaining what it does + # Split pipes across multiple lines for readability + # Make argument variables READONLY after they are set + # Put everything in a function called main() + # Call the function at the very end of the file - main "$@" + # Where-ever we have pipes + # Check the status of the entire pipe by checking on ${PIPESTATUS[*]} + # Use long options (logger --priority vs logger -p) -> for readability + +# TODO - Check on other OSes + # Ubuntu 16, 18, 18.08 + # Debian 8, 9, 10 + +# No root - no good +[[ "$(id -u)" != "0" ]] && { + echo -e "ERROR: You must be root to run this script.\nUse sudo and execute the script again." + exit 1 +} + +# No apt - no good +! (type apt-get > /dev/null 2>&1) && { + echo -e "ERROR: This script works only on Debian and Debian-derivatives that use 'apt'" + exit 2 +} + +SCRIPT_NAME=wp_borg_backup +SCRIPT_VERSION=0.9 + +################################# Parse Script Arguments ################################# +usage() { + cat < --wp-source-dir --backup-dir [--storage-quota ] [--passphrase-dir ]" + -u, --username Username for your server (If omitted script will choose an username for you) + -r, --resetrootpwd Reset current root password + -hide, --hide-credentials Credentials will hidden from screen and can ONLY be found in the logfile + eg: tail -n 20 logfile + -d, --defaultsourcelist Updates /etc/apt/sources.list to download software from debian.org + -ou, --only-user Only creates the user and its SSH authorizations + NOTE: -r, -d would be ignored + + export BORG_PASSPHRASE= + Example: bash ./$SCRIPT_NAME.sh --username myuseraccount --resetrootpwd + +USAGE + exit 0 +} + +# defaults +passphrase_dir="/home/$(who am i | cut -f1 -d " ")/.config/borg" #cause I don't want to pollute root user's home + +while [[ "${#}" -gt 0 ]]; do + case $1 in + --project-name | -pname) + project_name="$2" + shift + shift + ;; + --wp-source-dir | -wp_src) + wp_src_dir="$2" + if [[ ! -d "$wp_src_dir" ]]; then + echo "Directory ${wp_src_dir} does NOT exist. Please provide a valid source directory." + exit 3 + fi + shift + shift + ;; + --backup-dir) + backup_dst_dir="$2" + if [[ ! -d "$backup_dst_dir" ]]; then + echo "Directory ${backup_dst_dir} does NOT exist. Please provide a valid backup directory." + exit 4 + fi + shift + shift + ;; + --storage-quota | -quota) + storage_quota="$2" + shift + shift + ;; + --passphrase-dir | -passdir) + passphrase_dir="$2" + if [[ ! -d "$passphrase_dir" ]]; then + echo "Directory ${passphrase_dir} does NOT exist. Please provide a valid directory where passphrases can be saved." + exit 5 + fi + shift + shift + ;; + -h|--help) + echo + #TODO - implement the "usage" function + usage + echo + exit 0 + ;; + *) + echo "Unknown parameter encounted : $1 - this will be ignored" + ;; + esac +done + +# Check if mandatory items were provided or not +if [[ -z "$project_name" ]]; then + echo "ERROR: Script requires a project name (--project-name | -pname) parameter" + usage + exit 6 +fi + +if [[ -z "$wp_src_dir" ]]; then + echo "ERROR: Script requires a source directory (--wp-source-dir | -wp_src) parameter" + usage + exit 7 +fi + +if [[ -z "$backup_dst_dir" ]]; then + echo "ERROR: Script requires a backup directory (--backup-dir) parameter" + usage + exit 8 +fi + +# if blank - do something +if [[ -n "${storage_quota}" ]]; then + storage_quota="--storage-quota ${storage_quota}" +fi + +################################# Parse Script Arguments ################################# + + + + +######################################### Set up ######################################### + +# Create the backup directory structure +mkdir -pv "${backup_dst_dir}"/{bkp_log,DB,WP} > /dev/null +readonly bkp_log_dir="${backup_dst_dir}/bkp_log" +readonly bkp_final_dir="${backup_dst_dir}/WP" +readonly bkp_DB_dir="${backup_dst_dir}/DB" +readonly TS=$(date '+%d_%m_%Y-%H_%M_%S') +readonly LOGFILE="${bkp_log_dir}"/"$SCRIPT_NAME"_v"$SCRIPT_VERSION"_"$TS".log +touch "${LOGFILE}" +echo "You can find the log at ${LOGFILE}" + +######################################### Set up ######################################### + + + + +################################### Prepare the System ################################### + +# Install "borgbackup" if NOT installed +if ! (type borg > /dev/null 2>&1); then + if apt-get install -y borgbackup >> "$LOGFILE" 2>&1; then + echo "borg installed successfully" | tee -a "$LOGFILE" + else + echo "ERROR: installing borgbackup. Check the log for more details" | tee -a "$LOGFILE" + exit 11 + fi +fi + +#If borg is currently backing up the same website - quit +if (pidof -x borg > /dev/null) && $(pgrep -ac "$wp_src_dir") -gt 0 ; then + echo "${wp_src_dir} is being backed up from another process" | tee -a "$LOGFILE" + echo "This process will now exit" | tee -a "$LOGFILE" + exit 11 +fi + +# Download and Install wp-cli if not installed +if ! (type wp > /dev/null 2>&1); then + echo -e "wp-cli not found on system. \nInstalling wp-cli" >> "$LOGFILE" 2>&1 + wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -O /usr/local/bin/wp >> "$LOGFILE" 2>&1 + if chmod +x /usr/local/bin/wp >> "$LOGFILE" 2>&1; then + echo "Successfully Installed wp-cli" | tee -a "$LOGFILE" + else + wp_cli_installed="$?" + echo "ERROR: Could not install wp-cli. Program will continue to backup the site data..." | tee -a "$LOGFILE" + fi +fi + +################################### Prepare the System ################################### + + + + +################################### Wordpress DB Backup ################################### + +# Backup WP database only if wp-cli is installed +if [[ -z "$wp_cli_installed" || "$wp_cli_installed" == 0 ]]; then + directory_owner=$(stat -c '%U' "${wp_src_dir}") + sudo -u "${directory_owner}" wp db --quiet export "/tmp/${TS}_database.sql" --add-drop-table --path="${wp_src_dir}" + + if mv "/tmp/${TS}"_database.sql "${bkp_DB_dir}/${TS}_database.sql" >> "$LOGFILE" 2>&1; then + echo "DB backed up successfully" | tee -a "$LOGFILE" + else + echo "ERROR: DB Backup Failed. Check log for more details." | tee -a "$LOGFILE" + fi +fi + +################################### Wordpress DB Backup ################################### + + + + +################################## Wordpress Site Backup ################################## + +# Try reading the passphrase from the BORG_PASSCOMMAND exported variable +if [[ -n "$BORG_PASSCOMMAND" ]]; then + borg_passphrase="$BORG_PASSCOMMAND" +# Else - try finding it from our designated password file +elif [[ -f "${passphrase_dir}/.$project_name" && -s "${passphrase_dir}/.$project_name" ]]; then + borg_passphrase=$(cat "${passphrase_dir}"/."$project_name") +fi + +# If no passphrase found and repo EXISTS at the destination - Exit +if [[ ( -z "$borg_passphrase" ) && ( -f "$backup_dst_dir"/config || -f "$bkp_final_dir"/config ) ]]; then + echo "ERROR: Could not find a passphrase" | tee -a "$LOGFILE" + echo -e "Either do a (EXPORT BORG_PASSCOMMAND=[your-passphrase] \n\t\t OR \nAdd the passphrase to ${passphrase_dir}/.${project_name} file." | tee -a "$LOGFILE" + exit 12 +fi + +# Auto generate passphrase if no repo exists +if [[ ( ! -f "$backup_dst_dir"/config ) && ( ! -f "$bkp_final_dir"/config ) ]]; then + borg_passphrase=$(< /dev/urandom tr -cd 'a-zA-Z0-9@&_' | head -c 20) # 20-character + + mkdir "$backup_dst_dir"/WP >> "$LOGFILE" 2>&1 + + export BORG_NEW_PASSPHRASE="$borg_passphrase" + + # Backup any recidual passphrase keys + if [[ -f "${passphrase_dir}/.${project_name}" ]]; then + mv "${passphrase_dir}/.${project_name}" "${passphrase_dir}/.${project_name}_old_${TS}" + fi + + # chmod 400 the passphrase file + mkdir -p "${passphrase_dir}" >> "$LOGFILE" 2>&1 && touch "${passphrase_dir}/.${project_name}" >> "$LOGFILE" 2>&1 && chmod 440 "${passphrase_dir}/.${project_name}" >> "$LOGFILE" 2>&1 && { + # Display the passphrase on screen + echo -e "\n############### BACKUP PASSPHRASE ###############" | tee -a "$LOGFILE" + echo "$borg_passphrase" | tee "${passphrase_dir}/.${project_name}" | tee -a "$LOGFILE" + echo "############### BACKUP PASSPHRASE ###############" | tee -a "$LOGFILE" + echo -e "You CANNOT access your backup without the above passphrase\n" | tee -a "$LOGFILE" + } + + # Initalize the repo + if (borg init -v --encryption=repokey-blake2 --storage-quota "$storage_quota" "$bkp_final_dir" >> "$LOGFILE" 2>&1); then + echo "Repository initialized successfully" | tee -a "$LOGFILE" + else + echo "ERROR: Backup initialization failed. Check the logfile for more details." | tee -a "$LOGFILE" + fi +fi + +# This is required again - if passphrase was generated in the above step +export BORG_PASSPHRASE="$borg_passphrase" + +# Do the actual backup +# We run it on a lower priority so it does not disturb others +if ionice -c 2 -n 7 borg create \ + --verbose \ + --filter AMEsd \ + --list \ + --json \ + --stats \ + --show-rc \ + --compression zstd \ + --exclude-caches \ + "$bkp_final_dir"::{hostname}_"$project_name"_"$TS" \ + "$wp_src_dir" \ + "${bkp_DB_dir}" \ + >> "$LOGFILE" 2>&1; then + echo "Backup Completed Successfully" | tee -a "$LOGFILE" +else + echo "ERROR: Backup failed. Check the logfile for more details" | tee -a "$LOGFILE" +fi + +echo "You can find the log at ${LOGFILE}" + +################################## Wordpress Site Backup ##################################