Initial commit
This commit is contained in:
commit
d14d9b8fa7
4 changed files with 209 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
config
|
||||||
|
databases/
|
79
README.md
Normal file
79
README.md
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# About:
|
||||||
|
This is a very basic backup script that:
|
||||||
|
1. Exports databases, stores the md5sums, and then compresses them.
|
||||||
|
2. Uploads the databases, along with specified directories to S3.
|
||||||
|
3. Prunes old backups.
|
||||||
|
|
||||||
|
It will send an email to the specified email if there's an error.
|
||||||
|
|
||||||
|
This is the backup script in use on Woem.men's servers.
|
||||||
|
|
||||||
|
# Prerequisites:
|
||||||
|
**Ubuntu Packages:**
|
||||||
|
```bash
|
||||||
|
sudo apt install restic postgresql-client sendemail
|
||||||
|
```
|
||||||
|
**External Services:**
|
||||||
|
1. An S3 provider. (Amazon S3, Backblaze, etc)
|
||||||
|
1. Email provider which allows SMTP. (Gmail, Fastmail, etc)
|
||||||
|
|
||||||
|
# Setup:
|
||||||
|
You'll need to create the required directory, and pull the files from this repository:
|
||||||
|
```bash
|
||||||
|
sudo mkdir /backups/
|
||||||
|
cd /backups/
|
||||||
|
git clone <repository here>
|
||||||
|
```
|
||||||
|
Copy the `config_example` to `config`, verify permissions, and then edit using your favorite text editor:
|
||||||
|
```bash
|
||||||
|
sudo su
|
||||||
|
cp config_example config
|
||||||
|
chown root:root config
|
||||||
|
chmod 700 config
|
||||||
|
nano config
|
||||||
|
```
|
||||||
|
Next, you'll need to run initial setup on the S3 repository:
|
||||||
|
```bash
|
||||||
|
sudo su # if not already root
|
||||||
|
set -a
|
||||||
|
source config
|
||||||
|
restic -r "$S3_BUCKET" init
|
||||||
|
```
|
||||||
|
And finally, set your crontab file with `sudo crontab -e`:
|
||||||
|
```
|
||||||
|
0 * * * * /backups/backup.sh > /backups/logfile.log
|
||||||
|
```
|
||||||
|
|
||||||
|
# Restoring:
|
||||||
|
You'll need to grab your config variables before restoring:
|
||||||
|
```bash
|
||||||
|
sudo su # if not already root
|
||||||
|
cd /backups/
|
||||||
|
|
||||||
|
set -a
|
||||||
|
source config
|
||||||
|
```
|
||||||
|
After that, fetch a list of backups available to you by running `restic -r "$S3_BUCKET" snapshots`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```
|
||||||
|
root@guilty-spark:/backups# restic -r "$S3_BUCKET" snapshots
|
||||||
|
repository 17b028ae opened (version 2, compression level auto)
|
||||||
|
ID Time Host Tags Paths
|
||||||
|
---------------------------------------------------------------
|
||||||
|
724327bb 2025-01-09 07:10:04 guilty-spark /backups
|
||||||
|
/etc
|
||||||
|
/home
|
||||||
|
/root
|
||||||
|
---------------------------------------------------------------
|
||||||
|
```
|
||||||
|
Select one, and run the following command, making adjustments as needed for your setup:
|
||||||
|
Using one of the snapshots, restore the files you're missing using `restic restore`. I recommend reading the man file for `restic-restore`.
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```
|
||||||
|
root@guilty-spark:/backups# restic -r "$S3_BUCKET" restore 724327bb -i /home/service/example_file.txt -t /tmp/restore/
|
||||||
|
```
|
||||||
|
```
|
||||||
|
root@guilty-spark:/backups# restic -r "$S3_BUCKET" restore 724327bb -t /tmp/restore/
|
||||||
|
```
|
93
backup.sh
Normal file
93
backup.sh
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -a
|
||||||
|
source .config
|
||||||
|
set +a
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$DEBUGGING" -eq 1 ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove lock:
|
||||||
|
remove_lock() {
|
||||||
|
rm /tmp/backup.lock
|
||||||
|
}
|
||||||
|
|
||||||
|
# Error Handling:
|
||||||
|
error_handling() {
|
||||||
|
echo "$(date) -> An error occurred!" >&2
|
||||||
|
|
||||||
|
if [ "$ENABLE_EMAILS" -eq 1 ]; then
|
||||||
|
subject="Backup Error -- $SERVER_NAME"
|
||||||
|
body="An error occurred during backup of $SERVER_NAME!\nThe current time is $(date).\nPlease check server logs!"
|
||||||
|
if [ "$DEBUGGING" -eq 1 ]; then
|
||||||
|
sendemail -f $SMTP_FROM -t $SMTP_RECIPIENT -u "$subject" -s $SMTP_SERVER -m "$body" -xu $SMTP_USER -xp $SMTP_PASSWORD -v -o message-charset=$CHARSET
|
||||||
|
else
|
||||||
|
sendemail -f $SMTP_FROM -t $SMTP_RECIPIENT -u "$subject" -s $SMTP_SERVER -m "$body" -xu $SMTP_USER -xp $SMTP_PASSWORD -q -o message-charset=$CHARSET
|
||||||
|
fi
|
||||||
|
echo "$(date) -> Email sent!"
|
||||||
|
fi
|
||||||
|
remove_lock
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
trap "error_handling" ERR
|
||||||
|
trap "remove_lock" SIGINT
|
||||||
|
|
||||||
|
if [ "$TEST_ERROR_HANDLING" -eq 1 ]; then
|
||||||
|
error_handling
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test, then create Lockfile
|
||||||
|
if [ -e /tmp/backup.lock ]; then
|
||||||
|
echo "Backups are already running! If in error, manually remove the lockfile!"
|
||||||
|
fi
|
||||||
|
touch /tmp/backup.lock
|
||||||
|
|
||||||
|
# Backups:
|
||||||
|
if [ ! -z "$DATABASES" ]; then
|
||||||
|
mkdir -p /backups/databases/
|
||||||
|
touch /backups/databases/delete
|
||||||
|
rm /backups/databases/*
|
||||||
|
|
||||||
|
echo "$(date) -> Dumping databases..."
|
||||||
|
|
||||||
|
for database in "${DATABASES[@]}"; do
|
||||||
|
echo "$(date) -> $database"
|
||||||
|
sudo -u postgres pg_dump -d "$database" -f /home/tmp/"$database".pgdump
|
||||||
|
md5sum /home/tmp/"$database".pgdump > /backups/databases/md5sums
|
||||||
|
zstd /home/tmp/"$database".pgdump -o /backups/databases/"$database".pgdump.zst
|
||||||
|
rm /home/tmp/"$database".pgdump
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$(date) -> Dumped!"
|
||||||
|
else
|
||||||
|
echo "No databases selected! Skipping DB export!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$(date) -> Uploading..."
|
||||||
|
|
||||||
|
if [ ! -z "$BACKUP_EXCLUDE" ]; then
|
||||||
|
for exclude in "${BACKUP_EXCLUDE[@]}"; do
|
||||||
|
exclude_parsed=$exclude_parsed' -e '$exclude
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$exclude_parsed"
|
||||||
|
|
||||||
|
if [ ! "$MAX_SPEED_KILOBYTES_SECOND" -eq 0 ]; then
|
||||||
|
speed_parsed='--limit-upload '$(echo $MAX_SPEED_KILOBYTES_SECOND)
|
||||||
|
fi
|
||||||
|
|
||||||
|
restic -r "$S3_BUCKET" backup $BACKUP_LIST $exclude_parsed $speed_parsed
|
||||||
|
|
||||||
|
echo "$(date) -> Pruning old backups..."
|
||||||
|
|
||||||
|
restic -r "$S3_BUCKET" forget --keep-hourly $HOURLY --keep-daily $DAILY --keep-monthly $MONTHLY --keep-yearly $YEARLY
|
||||||
|
restic -r "$S3_BUCKET" prune
|
||||||
|
restic -r "$S3_BUCKET" unlock
|
||||||
|
|
||||||
|
remove_lock
|
||||||
|
|
||||||
|
echo "$(date) -> Done!"
|
35
config_example
Normal file
35
config_example
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Logging:
|
||||||
|
SERVER_NAME="Example Server"
|
||||||
|
|
||||||
|
# Credentials
|
||||||
|
S3_BUCKET="s3:s3.example.com"
|
||||||
|
AWS_ACCESS_KEY_ID="000000000000"
|
||||||
|
AWS_SECRET_ACCESS_KEY="00000000000000"
|
||||||
|
RESTIC_PASSWORD="Password"
|
||||||
|
|
||||||
|
# Backup Settings:
|
||||||
|
BACKUP_LIST="/etc/ /backups/ /home/ /root/"
|
||||||
|
BACKUP_EXCLUDE=(/home/bad_user/ /home/example_user/cache/)
|
||||||
|
MAX_SPEED_KILOBYTES_SECOND=2500
|
||||||
|
|
||||||
|
# Database Exports:
|
||||||
|
DATABASES=( database1 database2 )
|
||||||
|
|
||||||
|
# Retaining Backups:
|
||||||
|
# For GDPR, set monthly and yearly to 0, daily to 30.
|
||||||
|
HOURLY=48
|
||||||
|
DAILY=30
|
||||||
|
MONTHLY=12
|
||||||
|
YEARLY=5
|
||||||
|
|
||||||
|
# SMTP Settings:
|
||||||
|
ENABLE_EMAILS=0
|
||||||
|
SMTP_SERVER="smtp.example.com:587"
|
||||||
|
SMTP_USER="example@example.com"
|
||||||
|
SMTP_FROM="noreply@example.com"
|
||||||
|
SMTP_PASSWORD="password"
|
||||||
|
SMTP_RECIPIENT="example@example.com"
|
||||||
|
|
||||||
|
# Troubleshooting:
|
||||||
|
DEBUGGING=0
|
||||||
|
TEST_ERROR_HANDLING=0
|
Loading…
Reference in a new issue