{"id":37175211,"url":"https://github.com/feederco/really-simple-db-backup","last_synced_at":"2026-01-14T20:27:49.354Z","repository":{"id":58419817,"uuid":"167167277","full_name":"feederco/really-simple-db-backup","owner":"feederco","description":"Automated MySQL backups on DigitalOcean made simple and intuitive (with built-in alerts to Slack)","archived":false,"fork":false,"pushed_at":"2020-12-16T08:22:54.000Z","size":79,"stargazers_count":5,"open_issues_count":13,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-03-19T04:00:58.987Z","etag":null,"topics":["digitalocean","digitalocean-spaces","digitalocean-volumes","go","golang","mysql","percona-xtrabackup","slack"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/feederco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-23T10:52:20.000Z","updated_at":"2023-07-08T03:16:55.000Z","dependencies_parsed_at":"2022-09-10T14:11:32.311Z","dependency_job_id":null,"html_url":"https://github.com/feederco/really-simple-db-backup","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/feederco/really-simple-db-backup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feederco%2Freally-simple-db-backup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feederco%2Freally-simple-db-backup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feederco%2Freally-simple-db-backup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feederco%2Freally-simple-db-backup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/feederco","download_url":"https://codeload.github.com/feederco/really-simple-db-backup/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/feederco%2Freally-simple-db-backup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["digitalocean","digitalocean-spaces","digitalocean-volumes","go","golang","mysql","percona-xtrabackup","slack"],"created_at":"2026-01-14T20:27:48.191Z","updated_at":"2026-01-14T20:27:49.339Z","avatar_url":"https://github.com/feederco.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# really-simple-db-backup\n\nThe goal of this project is to be a really simple backup solution where you can just drop a binary on your database server, setup a cronjob to run at regular intervals, and it will take care of performing full and incremental backups at a regular intervals and uploading them to a cloud bucket.\n\nThis project also aims to simplify restoring backups. The goal is for it to be hassle free and require little mental overhead in the greatest time of needs.\n\nCurrently this project is built to perform backups of MySQL 8.0 and store them on a [DigitalOcean Space](https://www.digitalocean.com/products/spaces/). The software for actually generating the backup file is the amazing [Percona Xtrabackup](https://www.percona.com/software/mysql-database/percona-xtrabackup).\n\n## Usage\n\n### Download release\n\nLatest release can be found on [releases page](https://github.com/feederco/really-simple-db-backup/releases).\n\n```\nssh your-server\nwget https://github.com/feederco/really-simple-db-backup/releases/download/$VERSION/really-simple-db-backup_$VERSION_$PLATFORM_$ARCH.tar.gz -O really-simple-db-backup.tar.gz\ntar xvf really-simple-db-backup.tar.gz\nsudo mv really-simple-db-backup /usr/bin/really-simple-db-backup\n```\n\n### Build \u0026 upload binary\n\n```\ngit clone git@github.com:feederco/really-simple-db-backup.git\ncd really-simple-db-backup\nGOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/really-simple-db-backup main.go\nscp build/really-simple-db-backup my-db-host:/usr/bin/really-simple-db-backup\n```\n\n### Setup Cronjob\n\n```shell\ncrontab -e\n```\n\nAnd add the following:\n\n#### For daily backups\n\nSet to run 05:00 AM every day.\n\n```\nSHELL=/bin/sh\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n0 5 * * * /usr/bin/really-simple-db-backup perform \u003e\u003e /var/log/really-simple-db-backup.log 2\u003e\u00261\n```\n\n#### For hourly backups\n\n```\nSHELL=/bin/sh\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n1 * * * * /usr/bin/really-simple-db-backup perform \u003e\u003e /var/log/really-simple-db-backup.log 2\u003e\u00261\n```\n\n### Available commands\n\n```shell\nreally-simple-db-backup THE_COMMAND\n```\n\n- [`perform`](#perform)\n- [`perform-full`](#perform-full)\n- [`perform-incremental`](#perform-incremental)\n- [`restore`](#restore)\n- [`upload`](#upload)\n- [`download`](#download)\n- [`finalize-restore`](#finalize-restore)\n- [`test-alert`](#test-alert)\n- [`list-backups`](#list-backups)\n- [`prune`](#prune)\n\n### Perform backup\n\nPerforms either a full or incremental backup by checking for previous runs.\n\n```shell\nreally-simple-db-backup perform\n```\n\n`/etc/really-simple-db-backup.json`\n\n```json\n{\n  \"digitalocean\": {\n    \"key\": \"digitalocean-app-token\",\n    \"space_endpoint\": \"fra1.digitaloceanspaces.com\",\n    \"space_name\": \"my-backups\",\n    \"space_key\": \"auth-key-for-space\",\n    \"space_secret\": \"auth-secret-for-space\"\n  },\n  \"mysql\": {\n    \"data_path\": \"(optional)\"\n  },\n  \"persistent_storage\": \"(optional)\",\n  \"alerting\": {\n    \"slack\": {\n      \"webhook_url\": \"https://hooks.slack.com/services/\u003cyour-webhook-url\u003e\"\n    }\n  },\n  \"retention\": {\n    \"automatically_remove_old\": true,\n    \"retention_in_days\": 7,\n    \"hours_between_full_backups\": 24\n  }\n}\n```\n\n#### Perform without config file\n\n```shell\nreally-simple-db-backup perform \\\n  -do-key=digitalocean-app-token \\\n  -do-space-endpoint=fra1.digitaloceanspaces.com \\\n  -do-space-name=my-backups \\\n  -do-space-key=auth-key-for-space \\\n  -do-space-secret=auth-secret-for-space\n```\n\n### Force a full backup (or incremental backup)\n\nTo force a full backup you can use the `perform-full` command.\n\n```shell\nreally-simple-db-backup perform-full\n```\n\nTo force an incremental backup you can use the `perform-incremental` command.\n\n```shell\nreally-simple-db-backup perform-incremental\n```\n\n### Force upload\n\nIf for some reason a backup failed and you were successfully able to retrieve a backup yourself, you can use the `upload` command to upload this to your DigitalOcean Space.\n\n```shell\nreally-simple-db-backup upload -file /path/to/backup.xbstream\n```\n\n### Download and prepare backup without moving it back\n\n`restore` will download a backup to a new volume, extract it, decompress it, run [Xtrabackup's prepare](https://www.percona.com/doc/percona-xtrabackup/8.0/backup_scenarios/full_backup.html#preparing-a-backup) command. When these steps are completed the backup is ready to be moved to the MySQL `datadir` and after that MySQL is ready to start again.\n\nIf you just want to download and prepare a backup, you can use the `download` command. This is good if you just want to\n\n```shell\nreally-simple-db-backup download -hostname my-other-host\n```\n\n### Put back after `download`\n\nIf you have run the `download` command and have a fully prepared backup that you now wish to use, you can run the `finalize-restore` command which will run the second half of steps that are run by the `restore` command.\n\n```shell\nreally-simple-db-backup finalize-restore -existing-restore-directory=/mnt/my_restore_volume/really-simple-db-restore\n```\n\n**Note**\n\n### Remove old backups\n\nIf the config-option `retention.automatically_remove_old` is set to `true`, an automatic prune will be run on each full backup. Backup lineages older than `retention.retention_in_days` (or `retention.retention_in_hours`).\n\nTo force a prune the `prune` command can be run:\n\n```\nreally-simple-db-backup prune\n```\n\nTo prune on another host the `-hostname` flag can be passed in:\n\n```\nreally-simple-db-backup prune -hostname other-host\n```\n\n### Test alert\n\nTo make sure the Slack integration is setup correctly you can use the `test-alert` command to run the same code path that will be executed on a critical error.\n\n```shell\nreally-simple-db-backup test-alert\n```\n\n### Listing existing backups\n\nTo list all backups for the current host you can run the `list-backups` command. This is also a good way to test that your access tokens for cloud storage is correct.\n\n```shell\nreally-simple-db-backup list-backups\n```\n\nYou can also run this on another host to check the backups of a specific host:\n\n```shell\nreally-simple-db-backup list-backups -hostname my-other-host\n```\n\nTo see if there are any backups since a certain timestamp simply pass in the timestamp (as formatted in the backup filenames: `YYYYMMDDHHII`)\n\n```shell\nreally-simple-db-backup list-backups -timestamp 201901050000\n```\n\n## Configuration\n\nBy default the script checks for the existence of a config file at `/etc/really-simple-db-backup.json`. If this is found the defaults are loaded from that file and can be overriden by command line options.\n\nIf this config file is located somewhere else you can pass that in with the `-config` option.\n\n```shell\nreally-simple-db-backup perform -config ./my-other-config.json\n```\n\nThe following format is expected:\n\n```json\n{\n  \"digitalocean\": {\n    \"key\": \"digitalocean-app-token\",\n    \"space_endpoint\": \"fra1.digitaloceanspaces.com\",\n    \"space_name\": \"my-backups\",\n    \"space_key\": \"auth-key-for-space\",\n    \"space_secret\": \"auth-secret-for-space\"\n  },\n  \"mysql\": {\n    \"data_path\": \"(optional)\"\n  },\n  \"persistent_storage\": \"(optional)\",\n  \"alerting\": {\n    \"slack\": {\n      \"webhook_url\": \"https://hooks.slack.com/services/\u003cyour-webhook-url\u003e\"\n    }\n  },\n  \"retention\": {\n    \"automatically_remove_old\": true,\n    \"retention_in_days\": 7,\n    \"hours_between_full_backups\": 24\n  }\n}\n```\n\n#### `retention`\n\nIf the `retention` option is left empty (or `null`) no pruning is done.\n\n#### `automatically_remove_old`\n\nSet this to `true` for the pruning to be run on each full backup. If it is set to `false` (or not set at all) you need to manually run `really-simple-db-backup prune` to remove old backups.\n\n#### `retention_in_days`\n\nSet to the number of days a backup is kept before being considered for removal.\n\n#### `retention_in_hours`\n\nIf you want more fine-grained control of how old backups are kept, use the `retention_in_hours` option instead. If any of the above values are set to `0` (or not included in the config JSON), the other value is used.\n\n#### `hours_between_full_backups`\n\nSet to number of hours between full backups. Note: This does perform the actually scheduling of this command. You need to do that separately in a cronjob or similar. See the section\n\n### Different MySQL data directory\n\nThe default directory for MySQL is normally `/var/lib/mysql`. If you have mounted a volume for your data and set different [`datadir`](https://dev.mysql.com/doc/refman/8.0/en/data-directory.html) you can pass in the following option: `-mysql-data-path=/mnt/my_mysql_volume/mysql` or set the `\"mysql.data_path\"` config property in the JSON config.\n\n### Persistent storage directory\n\nTo save state between runs a persistent storage directory is created to store information about the last backup. By default this is: `/var/lib/backup-mysql`. To change this the flag `-persistent-storage=/my/alternate/directory` can be passed in or set the `\"persistent_storage\"` config property in the JSON config.\n\n## Process\n\nBelow is a short run-through of what this script does.\n\nThe process and code is based on the excellent guide from DigitalOcean Docs: [How To Back Up MySQL Databases to Object Storage with Percona](https://www.digitalocean.com/community/tutorials/how-to-back-up-mysql-databases-to-object-storage-with-percona-on-ubuntu-16-04#creating-the-remote-backup-scripts)\n\n### Backups\n\nWhen running the following things happen:\n\n1. Check to see if MySQL is installed with the expected version (8.0)\n2. Check to see that all necessary software installed (Percona Xtrabackup 8.0)\n3. Decide wether a full or an incremental backup is needed by checking for previous runs of this software\n4. A [DigitalOcean Block Storage volume](https://www.digitalocean.com/products/block-storage/) is created and mounted. The volume size depends on the MySQL data directory\n5. Percona Xtrabackup is run and a compressed backup file is created onto the volume\n6. The backup file is uploaded to a DigitalOcean Space for safe storage\n\n### Restoring\n\n1. Fetch all backups for the given host on the [DigitalOcean Space](https://www.digitalocean.com/products/spaces/)\n2. Find the one that is a best match for the passed in timestamp\n4. A [DigitalOcean Block Storage volume](https://www.digitalocean.com/products/block-storage/) is created and mounted. The volume size depends on the file found in the\n5. Download \u0026 extract all pieces for the backup to this volume\n6. Decompress the backup\n7. Perform `Xtrabackup`'s prepare command which prepares it for use\n8. Move all files back to the MySQL data path\n\nStarting MySQL is up to you when the process is finished.\n\n## Alerting\n\nBackup failures should not be happen silently. Therefor alerting to Slack is built-in to this project.\n\n### Slack\n\nYou need to create a `Custom Integration` in your Slack channel with the type `Incoming WebHook`. We recommend creating a separate channel with must-action messages.\n\n![](https://i.imgur.com/tkYCqSW.png?1)\n\n#### Config options\n\nThe `slack` entry in the config file can have the following options:\n\n```\n{\n  \"webhook_url\": \"webhook URL\",\n  \"channel\": \"Override default channel to share to\",\n  \"username\": \"Override username (default: BackupsBot)\",\n  \"icon_emoji\": \"Override avatar of bot (default: :card_file_box: 🗃)\",\n}\n```\n\n## Manual restore \n\nPanic mode. 2 minutes ago you accidentally ran `rm -rf /var/lib/mysql` on the production database. For some reason you decide to do this manually, instead of using `really-simple-db-backup restore`.\n\nNow, you are reading this guide. What do I need to do? \n\nHere are the steps:\n\n1. Boot up a new server. *Note* Decompressing takes up a lot of extra space, so add extra margin to the server.\n\n2. SSH into the server, open a new `screen` session.\n\n```shell\nscreen\n```\n\n3. Install the right version of MySQL (the same version as the backup was made on) This can be super tricky. This is what I did for Ubuntu 18:\n\nChose the right version here:\n\n[https://downloads.mysql.com/archives/community/](https://downloads.mysql.com/archives/community/)\n\nUsed `wget` to download each file matching the right version of the platform. Then ran `dpkg -i` in the correct order:\n\n```shell\ndpkg -i mysql-common_*\ndpkg -i mysql-community-client-core_*\ndpkg -i mysql-community-client_*\ndpkg -i mysql-client_*\ndpkg -i mysql-community-server-core_*\ndpkg -i mysql-server_*\n```\n\n4. Stop mysql\n\n```shell\nservice mysql stop\n```\n\n5. Install percona-xtrabackup:\n\n```shell\nwget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb\ndpkg -i percona-release_latest.$(lsb_release -sc)_all.deb\napt update\npercona-release enable-only tools release\napt update\napt install percona-xtrabackup-80 qpress\n```\n\n6. Download your backup\n\n```shell\nwget -o backup.xbstream https://secure-link-to-backup/backup.xbstream\n```\n\n6. Extract and decompress the backup into a temporary directory.\n\n```shell\nmkdir backup;\nxbstream -x \u003c backup.xbstream -C backup/;\nfor bf in `find backup/ -iname \"*\\.qp\"`; do qpress -d $bf $(dirname $bf) \u0026\u0026 rm $bf; done;\n```\n\n7. Prepare any incremental backups.\n\n**HELP NEEDED** What are the correct steps here?\n\n8. Move the backup to the right place\n\n```shell\nmv /var/lib/mysql /var/lib/mysql-old; # just to be safe :)\nmv backup /var/lib/mysql\nchown mysql:mysql -R /var/lib/mysql\n```\n\n9. Start mysql\n\n```shell\nservice mysql start\n```\n\n## For maintainers\n\nWe use [`goreleaser.com`](https://goreleaser.com) for release management. Install `goreleaser` as defined here: [goreleaser.com/install](https://goreleaser.com/install/)\n\nTo release a new version you need to get a personal access token with the `repo` scope here: [github.com/settings/tokens/new](https://github.com/settings/tokens/new). Remember that token.\n\nTo create a new release tag a version and run `goreleaser`:\n\n```shell\ngit tag 1.0.0\ngit push --tags\nGITHUB_TOKEN=yourtoken goreleaser\n```\n\n### Issues to work on\n\nAll issue management is on our [Github issues](https://github.com/feederco/really-simple-db-backup/issues).\n\nCheck the issues tagged [`help wanted`](https://github.com/feederco/really-simple-db-backup/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) for good tickets to work on.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeederco%2Freally-simple-db-backup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffeederco%2Freally-simple-db-backup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeederco%2Freally-simple-db-backup/lists"}