Bash scripts for EC2 web server backup and monitoring

How to automate backups and monitoring on EC2.

Here's a way to perform backups for a LAMP stack and monitor EC2 server.

AWS setup

We first create a bucket on AWS S3 named backups.customer.com and an SNS topic named CustomerEc2WebServerDiskSpaceAlert. There's no need for bucket policy on the S3. On the SNS topic, create the relevant subscriptions.

Once ready, we create an IAM role with the following permissions and attach the role to the target EC2:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowEc2RebootItself",
            "Effect": "Allow",
            "Action": "ec2:RebootInstances",
            "Resource": "arn:aws:ec2:us-east-1:000000000000:instance/i-aaaaaaaaaaaaaaaaa"
        },
        {
            "Sid": "AllowEc2ViewS3Buckets",
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:GetBucketLocation"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowEc2ListS3BucketContent",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketAcl",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": [
                "arn:aws:s3:::backups.customer.com",
                "arn:aws:s3:::backups.customer.com/"
            ]
        },
        {
            "Sid": "AllowEc2BackupToS3",
            "Effect": "Allow",
            "Action": "*",
            "Resource": [
                "arn:aws:s3:::backups.customer.com/*"
            ]
        },
        {
            "Sid": "AllowEc2PublishToSns",
            "Effect": "Allow",
            "Action": "sns:Publish",
            "Resource": "arn:aws:sns:us-east-1:000000000000:CustomerEc2WebServerDiskSpaceAlert"
        }
    ]
}

On EC2, create the following scripts. I usually place them in /home/ec2-user/backups/ directory.

Bash scripts

/home/ec2-users/backups/backup-db.sh

#!/bin/bash

# Database settings.
DB_BACKUP_MYSQL_USER="root"
DB_BACKUP_MYSQL_PASSWORD="password"
DB_BACKUP_MYSQL_HOST="localhost"
DB_BACKUP_MYSQL_DATABASE="database"

# Backup settings.
DB_BACKUP_PATH="/home/ec2-user/backups"
DB_BACKUP_TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
DB_BACKUP_YEAR=$(date +"%Y")
DB_BACKUP_MONTH=$(date +"%m")
DB_BACKUP_FILENAME="customerdb-$DB_BACKUP_TIMESTAMP.sql"

# AWS settings.
DB_BACKUP_AWS_S3_BUCKET="backups.customer.com/db"


### Start backup. ###
# 1. Go to backup folder for easier management.
cd $DB_BACKUP_PATH/

# 2. Dump MySQL database to backup folder.
mysqldump --single-transaction -h $DB_BACKUP_MYSQL_HOST -u $DB_BACKUP_MYSQL_USER -B $DB_BACKUP_MYSQL_DATABASE --password="$DB_BACKUP_MYSQL_PASSWORD" > $DB_BACKUP_PATH/$DB_BACKUP_FILENAME

# 3. Zip up MySQL dump.
tar -czvf $DB_BACKUP_PATH/$DB_BACKUP_FILENAME.tgz $DB_BACKUP_FILENAME

# 4. Push to S3.
aws s3 cp $DB_BACKUP_PATH/$DB_BACKUP_FILENAME.tgz s3://$DB_BACKUP_AWS_S3_BUCKET/$DB_BACKUP_YEAR/$DB_BACKUP_YEAR$DB_BACKUP_MONTH/$DB_BACKUP_FILENAME.tgz

# 5. Delete MySQL dump file.
rm $DB_BACKUP_PATH/$DB_BACKUP_FILENAME
rm $DB_BACKUP_PATH/$DB_BACKUP_FILENAME.tgz

### Done backup. ###

/home/ec2-users/backups/backup-www.sh

#!/bin/bash

# User path settings.
WWW_BACKUP_PATH="/var/www/html/"

# AWS settings.
WWW_BACKUP_AWS_S3_BUCKET="backups.customer.com/www/"

### Start backup. ###
aws s3 sync $WWW_BACKUP_PATH s3://$WWW_BACKUP_AWS_S3_BUCKET

### Done backup. ###

/home/ec2-users/backups/monitor-diskspace.sh

#!/bin/bash

# AWS settings.
DISKSPACEALERT_ARN="arn:aws:sns:us-east-1:000000000000:CustomerEc2WebServerDiskSpaceAlert"
DISKSPACEALERT_REGION="us-east-1"

### Start script. ###
CURRENT=$(df / | grep / | awk '{ print $5}' | sed 's/%//g')
THRESHOLD=80
if [ "$CURRENT" -gt "$THRESHOLD" ] ; then
    aws sns publish --region="$DISKSPACEALERT_REGION" --topic-arn "$DISKSPACEALERT_ARN" --subject "Customer EC2 Disk Space Alert $CURRENT%" --message "The remaining disk space in / is running low. Used: $CURRENT%"
fi

### End script. ###

crontab

Once the scripts are ready, add the following into cron via crontab -e command.

# Backup www daily at 3am (UTC).
0 19 * * * /home/ec2-user/backups/backup-www.sh >> /home/ec2-user/backups/cron.log 2>&1

# Backup db daily at 4am (UTC).
0 20 * * * /home/ec2-user/backups/backup-db.sh >> /home/ec2-user/backups/cron.log 2>&1

# Monitor diskspace daily at 5.30am (UTC).
30 21 * * * /home/ec2-user/backups/monitor-diskspace.sh >> /home/ec2-user/backups/cron.log 2>&1

# Reboot every morning 6am (UTC).
0 22 * * * aws ec2 reboot-instances --region us-east-1 --instance-ids i-aaaaaaaaaaaaaaaaa >> /home/ec2-user/backups/cron.log 2>&1

That's it! Adjust as necessary.