--- title: "Ghost multi-blog backup bash script to Minio (S3 Compatible)" description: "Simple bash script to automatic backup multiple Ghost blog on the same server to remote AWS S3 compatible server." date: 2023-01-18T07:20:27+07:00 lastmod: draft: false noindex: false featured: false pinned: false # comments: false series: # - categories: - SysAdmin tags: - Ghost - S3 - Minio - Bash images: # - # menu: # main: # weight: 100 # params: # icon: # vendor: bs # name: book # color: '#e24d0e' authors: - ditatompel --- So, inspired from [Jerry Ng's Ghost backup script](https://jerrynsh.com/backing-up-ghost-blog-in-5-steps/) which can be used to backup single blog site to remote storage using `rclone`, I write this script that can be used to automatic backup multi Ghost blog on the same server to remote **AWS S3 compatible server** (in this case Minio) using Minio-CLI. ## What's backed up? - `config.production.json` and `package-lock.json` file. - Everything under `content/` directory. - MySQL dump database. Structure of generated backup on remote backup location (S3): `[BUCKET_NAME]/ghost/[WEBSITE_NAME]/[YEAR]/[MONTH]/`. ## Requirements - Access to Linux Ghost admin user. - Configured [Minio CLI](https://min.io/docs/minio/linux/reference/minio-mc.html). - S3 Compatible storage server (in this case Minio) ## Script ```bash #!/bin/bash # Backup ghost website(s) to Minio # Inspired from https://jerrynsh.com/backing-up-ghost-blog-in-5-steps/ # # This script also need Minio CLI configured, see: # https://min.io/docs/minio/linux/reference/minio-mc.html # Or edit and adapt with your favorite s3 client on # S3_SECTION below. set -e MINIO_REMOTE_ALIAS="myminio" # your mc `alias` name MINIO_BUCKET="backups" MINIO_FOLDER="ghost/" # Mandatory, don't forget the trailing slash at the end # Array of website, `IFS` property separate by `|` # `IFS[0]` = website shortname, used to organize backuo folder location on S3 # `IFS[1]` = Ghost website directory GHOST_WEBSITES=( "example_blog1|/path/to/blog1" # 1st website "example_blog2|/path/to/blog2" # 2nd website ) ##### End basic config ##### SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) for WEBSITE in "${GHOST_WEBSITES[@]}" do IFS='|' read -ra WEBPARAMS <<< "$WEBSITE" if [ ! -d "${WEBPARAMS[1]}" ]; then echo "Folder not exists.. Skipping ${WEBPARAMS[0]}" else BACKUPDATE=`date +%Y-%m-%d-%H-%M` echo "Performing backup ${WEBPARAMS[0]}" cd ${WEBPARAMS[1]} ### ARCHIVE ### tar -czf $SCRIPT_DIR/$BACKUPDATE-${WEBPARAMS[0]}.tar.gz content/ config.production.json package-lock.json ### DATABASE SECTION ### db_user=$(ghost config get database.connection.user | tail -n1) db_pass=$(ghost config get database.connection.password | tail -n1) db_name=$(ghost config get database.connection.database | tail -n1) mysqldump -u"$db_user" -p"$db_pass" "$db_name" --no-tablespaces | gzip > "$SCRIPT_DIR/$BACKUPDATE-$db_name.sql.gz" ### S3_SECTION ### # adapt to your env mc cp $SCRIPT_DIR/$BACKUPDATE-${WEBPARAMS[0]}.tar.gz $MINIO_REMOTE_ALIAS/$MINIO_BUCKET/$MINIO_FOLDER${WEBPARAMS[0]}/$(date +%Y)/$(date +%m)/$BACKUPDATE-${WEBPARAMS[0]}.tar.gz mc cp $SCRIPT_DIR/$BACKUPDATE-$db_name.sql.gz $MINIO_REMOTE_ALIAS/$MINIO_BUCKET/$MINIO_FOLDER${WEBPARAMS[0]}/$(date +%Y)/$(date +%m)/$BACKUPDATE-$db_name.sql.gz # REMOVE LOCAL BACKUP rm -f $SCRIPT_DIR/$BACKUPDATE-${WEBPARAMS[0]}.tar.gz rm -f $SCRIPT_DIR/$BACKUPDATE-$db_name.sql.gz cd $SCRIPT_DIR fi done exit 0 ``` Or you can find it on [https://gist.github.com/ditatompel/dc1d13259df3b945a633f8c0b789bd80](https://gist.github.com/ditatompel/dc1d13259df3b945a633f8c0b789bd80). ## How to use Edit `MINIO_REMOTE_ALIAS`, `MINIO_BUCKET`, `MINIO_FOLDER` and array of website(s) to `GHOST_WEBSITES` variable. Then you can execute the script using cron.