{"id":15129860,"url":"https://github.com/bearlike/portainer-compose-backup","last_synced_at":"2026-01-18T00:23:33.088Z","repository":{"id":256288891,"uuid":"854842715","full_name":"bearlike/portainer-compose-backup","owner":"bearlike","description":"Periodic Snapshots of all compose stacks stored specifically in Portainer","archived":false,"fork":false,"pushed_at":"2024-09-09T22:12:05.000Z","size":12,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"current","last_synced_at":"2025-02-11T17:14:00.175Z","etag":null,"topics":["backup","docker-compose","portainer","template-repository"],"latest_commit_sha":null,"homepage":"","language":"Python","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/bearlike.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-09T21:41:41.000Z","updated_at":"2024-09-09T23:29:38.000Z","dependencies_parsed_at":"2024-09-10T02:42:27.031Z","dependency_job_id":"eb47a422-08c7-428f-8012-0ae80023dc29","html_url":"https://github.com/bearlike/portainer-compose-backup","commit_stats":null,"previous_names":["bearlike/portainer-compose-backup"],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bearlike%2Fportainer-compose-backup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bearlike%2Fportainer-compose-backup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bearlike%2Fportainer-compose-backup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bearlike%2Fportainer-compose-backup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bearlike","download_url":"https://codeload.github.com/bearlike/portainer-compose-backup/tar.gz/refs/heads/current","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247386892,"owners_count":20930730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["backup","docker-compose","portainer","template-repository"],"created_at":"2024-09-26T02:21:56.191Z","updated_at":"2026-01-18T00:23:33.058Z","avatar_url":"https://github.com/bearlike.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Portainer Compose Backup 🐳\n\nPortainer centralizes your Compose projects, but that also means there's a single point of failure - losing access to all your stacks with just one accidental deletion or daemon crash! Since Portainer doesn't have a native backup solution, this project helps you securely store \u0026 track your compose files from multiple endpoints into a Git repository. It's saved my sanity (and data) on more than one occasion!\n\n**You may use this as a template repository to begin with.**\n\n## Overview 📋\n\n- This Python script is used to backup Docker compose scripts created within Portainer to our project directory. The copies will be saved in a directory structure of the following format: `backups/[current year]/[current month]/[current date]/[endpoint]/[docker stack name]`. Once the copying operation is complete, the changes will be committed and pushed to Git.\n- `db-exporter/` is a small Docker image (may need to be built) to export few necessary buckets from Portainer's BoltDB. This janky combination of using this `compose_backup.py` with `db-exporter\\docker-compose.yml` is because there isn't a reliable BoltDB client for Python.\n- Automatically maps `docker-compose.yml` files to their respective Portainer endpoints.\n- Rename `sample.env` to `.env` and fill in with appropriate values.\n- **All `*.env` files will be stored to an encrypted TinyDB (`stack.encrypted.json`)**\n    - Once the `DB_PASSWORD` is set, do not change the password until the `*.env` files are completely restored.\n    - Make sure that the `stack.encrypted.json` doesn't contain values encrypted with multiple passwords.\n- Last tested to work with Portainer [2.21.0](https://github.com/portainer/portainer/releases/tag/2.21.0).\n\n## Backup Calendar 📅\n\n\u003e [!NOTE]\n\u003e This example comes from our `calendar_md.py` script. Consider running it together with `compose_backup.py` to keep the documentation updated.\n\n\u003cdetails\u003e\n  \u003csummary\u003eOctober 2023\u003c/summary\u003e\n\n   | Mon                       | Tue                       | Wed                       | Thu                       | Fri                       | Sat                       | Sun                       |\n   | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- |\n   |                           |                           |                           |                           |                           |                           | [01](/backups/2023/10/01) |\n   | [02](/backups/2023/10/02) | [03](/backups/2023/10/03) | [04](/backups/2023/10/04) | [05](/backups/2023/10/05) | [06](/backups/2023/10/06) | [07](/backups/2023/10/07) | [08](/backups/2023/10/08) |\n   | [09](/backups/2023/10/09) | [10](/backups/2023/10/10) | [11](/backups/2023/10/11) | [12](/backups/2023/10/12) | [13](/backups/2023/10/13) | [14](/backups/2023/10/14) | [15](/backups/2023/10/15) |\n   | [16](/backups/2023/10/16) | [17](/backups/2023/10/17) | [18](/backups/2023/10/18) | [19](/backups/2023/10/19) | [20](/backups/2023/10/20) | [21](/backups/2023/10/21) | [22](/backups/2023/10/22) |\n   | [23](/backups/2023/10/23) | [24](/backups/2023/10/24) | [25](/backups/2023/10/25) | [26](/backups/2023/10/26) | [27](/backups/2023/10/27) | [28](/backups/2023/10/28) | [29](/backups/2023/10/29) |\n   | [30](/backups/2023/10/30) | [31](/backups/2023/10/31) |                           |                           |                           |                           |                           |\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eNovember 2023\u003c/summary\u003e\n\n   | Mon                       | Tue                       | Wed                       | Thu                       | Fri                       | Sat                       | Sun                       |\n   | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- |\n   |                           |                           | [01](/backups/2023/11/01) | [02](/backups/2023/11/02) | [03](/backups/2023/11/03) | [04](/backups/2023/11/04) | [05](/backups/2023/11/05) |\n   | [06](/backups/2023/11/06) | [07](/backups/2023/11/07) | [08](/backups/2023/11/08) | [09](/backups/2023/11/09) | [10](/backups/2023/11/10) | [11](/backups/2023/11/11) | [12](/backups/2023/11/12) |\n   | [13](/backups/2023/11/13) | [14](/backups/2023/11/14) | [15](/backups/2023/11/15) | [16](/backups/2023/11/16) | [17](/backups/2023/11/17) | [18](/backups/2023/11/18) | [19](/backups/2023/11/19) |\n   | [20](/backups/2023/11/20) | [21](/backups/2023/11/21) | [22](/backups/2023/11/22) | [23](/backups/2023/11/23) | [24](/backups/2023/11/24) | [25](/backups/2023/11/25) | [26](/backups/2023/11/26) |\n   | [27](/backups/2023/11/27) | [28](/backups/2023/11/28) | [29](/backups/2023/11/29) | [30](/backups/2023/11/30) |                           |                           |                           |\n\u003c/details\u003e\n\n## How to Use? 🚀\n\n1. **Setup and Configuration 🛠️**\n   - Clone the repository.\n   - Make sure you have `root` access or you are a `sudoers`. We need this to access `/var/lib/docker/volumes/portainer_data/_data`, so, we can export the `docker-compose.yml` files.\n   - For the script to commit and push to Git, you need to have configured your Git repo with SSH keys or stored the credentials in the cache.\n   - As the user you'll be running the script, run `git config --global --add safe.directory /path/to/compose-backups` to resolve `git` ownership/permission issues.\n   - Modify the credentials and paths to your needs.\n   - **Git Configurations**\n\n     ```bash\n     git config --global user.name \"Krishna Alagiri [bot]\"\n     git config --global user.email \"92169357+kalagiri-bot@users.noreply.github.com\"\n     git config --global --add safe.directory /path/to/compose-backups\n     ```\n\n2. **Dependencies 📦**\n   - You obviously need `python3` and `git` installed (duh!)\n   - The script has several dependencies. To install it, use `sudo pip install -r requirements.txt`.\n   - Build the `db-exporter\\Dockerfile` to create the `bearlike/portainer-db-exporter:latest` image using:\n\n   ```bash\n   cd db-exporter\n   docker build -t bearlike/portainer-db-exporter:latest .\n   ```\n\n3. **Execution 🚀**\n   - Run the script using `python3` in the terminal. For example:\n\n   ```bash\n   sudo python3 compose_backup.py\n   ```\n\n4. **Logging**\n   The script uses basic logging to keep track of its operation. Each logs are stored as `backup.log` in the each backup directories. There is also a `metadata.json` with `docker-compose` stack information(s) exported from portainer.\n\n## Setting Up Daily Cronjob 🕒\n\n1. Open the cron configuration file using your favorite text editor:\n\n   ```bash\n   sudo crontab -e\n   ```\n\n2. Add a new line at the end of the file using the following format to run the script daily at a specific time (e.g., midnight):\n\n   ```cron\n   0 0 * * * /usr/bin/python3 /path/to/compose-backups/compose_backup.py\n   ```\n\n3. Save and close the file. The cron daemon will now execute the `compose_backup.py` script every day at the specified time.\n\n## Restore Encrypted `.env` Files 🔄\n\nThe `load_env_to_db.py` script provides functionality to backup and restore encrypted `.env` files.\n\n**To restore all `stack.env` files from the backup:**\n\n```bash\npython load_env_to_db.py --restore-all --db-password \u003cyour_db_password\u003e\n```\n\nThis command will retrieve all backup entries from the database, decrypt each entry, and write the decrypted content back to its original location.\n\n**To restore a single `stack.env` file from the backup:**\n\n```sh\npython load_env_to_db.py --restore \u003cbackup_key\u003e --db-password \u003cyour_db_password\u003e\n```\n\n**Example:**\n\n```sh\npython load_env_to_db.py --restore backups/2023/10/16/Hurricane/nextcloud/stack.env --db-password MySecurePassword\n```\nThis command will retrieve the specified backup entry from the database, decrypt it, and write the decrypted content back to its original location.\n\n## Issues? 💬\n\nHaving trouble with the script? 💔\nFound a bug? 🐞\nDo you have an idea for a new featur? 🪄\nLet everybody know!\n\n[Create an issue](https://github.com/bearlike/portainer-compose-backup/issues/new)\n\n## Contributions 🎉\n\nWant to help make this project even better? 🤝 Contributions are welcome! ✨\n[Fork and submit a pull request](https://github.com/bearlike/portainer-compose-backup/compare/)\n\n## License 📝\n\nThis project is released under the MIT License. See [`LICENSE`](LICENSE) for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbearlike%2Fportainer-compose-backup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbearlike%2Fportainer-compose-backup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbearlike%2Fportainer-compose-backup/lists"}