{"id":14069655,"url":"https://github.com/vladgh/backup","last_synced_at":"2025-10-09T07:37:29.543Z","repository":{"id":48084796,"uuid":"228220137","full_name":"vladgh/backup","owner":"vladgh","description":"Vlad's Backup","archived":false,"fork":false,"pushed_at":"2023-12-15T02:39:20.000Z","size":71,"stargazers_count":11,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-12T21:17:02.043Z","etag":null,"topics":["backup","bash","duplicacy","linux","macos","powershell","windows"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vladgh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["vladgh"]}},"created_at":"2019-12-15T17:03:48.000Z","updated_at":"2024-03-02T13:04:23.000Z","dependencies_parsed_at":"2024-08-13T07:15:32.000Z","dependency_job_id":"3c2fcc30-0fc9-4903-975c-6d39e913f0e0","html_url":"https://github.com/vladgh/backup","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vladgh/backup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladgh%2Fbackup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladgh%2Fbackup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladgh%2Fbackup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladgh%2Fbackup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vladgh","download_url":"https://codeload.github.com/vladgh/backup/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladgh%2Fbackup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000961,"owners_count":26082973,"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","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["backup","bash","duplicacy","linux","macos","powershell","windows"],"created_at":"2024-08-13T07:07:07.031Z","updated_at":"2025-10-09T07:37:29.526Z","avatar_url":"https://github.com/vladgh.png","language":"Shell","funding_links":["https://github.com/sponsors/vladgh"],"categories":["Shell"],"sub_categories":[],"readme":"# Vlad's Duplicacy Backup Scripts\n\n![Build Status](https://github.com/vladgh/backup/workflows/CI/badge.svg)\n\n## Install Duplicacy\n\nDownload latest release from \u003chttps://github.com/gilbertchen/duplicacy/releases\u003e and add it to PATH\n\nLinux\n\n```sh\nsudo wget -O /usr/local/bin/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v2.5.2/duplicacy_linux_x64_2.5.2 \u0026\u0026 sudo chmod 755 /usr/local/bin/duplicacy\n```\n\nMacOS\n\n```sh\nwget -O /usr/local/bin/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v2.5.2/duplicacy_osx_x64_2.5.2 \u0026\u0026 chmod 755 /usr/local/bin/duplicacy\n```\n\nWindows\n\n```powershell\n# Requires Administrator rights\nInvoke-WebRequest -Uri \"https://github.com/gilbertchen/duplicacy/releases/download/v2.5.2/duplicacy_win_x64_2.5.2.exe\" -OutFile \"C:\\Windows\\System32\\duplicacy.exe\"\n```\n\n## Initialize the repository\n\nPick the desired location for the .duplicacy folder, this will be your repository root. Defaults to your user's home.\nWhen you initialize the repository, it will ask for the encryption password and the path to the RSA key used by SFTP.\n\n```sh\nduplicacy init -encrypt MyID sftp://user@192.168.1.2//path/to/backup/storage\n```\n\nBy default Duplicacy will follow the first-level symlinks (those under the root of the repository).\nSymlinks located under any subdirectories of the repository will be backed up as symlinks and will not be followed.\n\nFor example, on Windows:\n\n```powershell\nmkdir C:\\backup\ncd C:\\backup\ncmd /c mklink /D myname C:\\Users\\myname\ncmd /c mklink /D docs D:\\DOCs\n```\n\n## Configure the repository\n\n```sh\nduplicacy set -storage default -key password -value 'MyPassword'\nduplicacy set -storage default -key ssh_key_file -value '/path/to/.ssh/duplicacy_rsa'\n```\n\nPlace the appropriate filters file inside the `.duplicacy` folder\n\n```sh\nwget -O ~/.duplicacy/filters https://github.com/vladgh/backup/raw/master/filters/osx\n```\n\nFor Windows\n\n```powershell\nInvoke-WebRequest -Uri \"https://github.com/vladgh/backup/raw/master/filters/windows\" -OutFile \"C:\\backup\\.duplicacy\\filters\"\n```\n\n## Backup\n\n```sh\nduplicacy -log backup -stats -vss\n```\n\n## VBackup Script OSX\n\nDownload the OSX/Linux backup script `vbackup.sh`, add it to PATH and make it executable\n\n```sh\nwget -O /usr/local/bin/vbackup https://github.com/vladgh/backup/raw/master/vbackup.sh\nchmod a+x /usr/local/bin/vbackup\n```\n\nUse a dotenv file for secrets and other settings\n\n```sh\ntee ~/.duplicacy/.env \u003c\u003c CONFIG\nSLACK_ALERTS_WEBHOOK='https://hooks.slack.com/services/xxxxxxxxxx'\nCONFIG\nchmod 600 ~/.duplicacy/.env\n```\n\nUpdate the paths and settings in the sample .plist launch script below, copy it to ~/Library/LaunchAgents and load it (-w enables it at the next boot)\n\n```sh\n# Install launch agent\ntee ~/Library/LaunchAgents/duplicacy.plist \u003c\u003c 'EOF'\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n  \u003cdict\u003e\n    \u003ckey\u003eLabel\u003c/key\u003e\n    \u003cstring\u003eduplicacy.startup\u003c/string\u003e\n    \u003ckey\u003eProgramArguments\u003c/key\u003e\n    \u003carray\u003e\n      \u003cstring\u003e/usr/local/bin/bash\u003c/string\u003e\n      \u003cstring\u003e/usr/local/bin/vbackup\u003c/string\u003e\n    \u003c/array\u003e\n    \u003ckey\u003eRunAtLoad\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003eUserName\u003c/key\u003e\n    \u003cstring\u003evlad\u003c/string\u003e\n    \u003ckey\u003eGroupName\u003c/key\u003e\n    \u003cstring\u003estaff\u003c/string\u003e\n    \u003ckey\u003eWorkingDirectory\u003c/key\u003e\n    \u003cstring\u003e/Users/vlad\u003c/string\u003e\n    \u003ckey\u003eStandardErrorPath\u003c/key\u003e\n    \u003cstring\u003e/dev/null\u003c/string\u003e\n    \u003ckey\u003eStandardOutPath\u003c/key\u003e\n    \u003cstring\u003e/dev/null\u003c/string\u003e\n    \u003ckey\u003eStartInterval\u003c/key\u003e\n    \u003cinteger\u003e3600\u003c/integer\u003e\n  \u003c/dict\u003e\n\u003c/plist\u003e\nEOF\n\n# Load/Unload agent\nlaunchctl load -w ~/Library/LaunchAgents/duplicacy.plist\n```\n\nRestart with\n\n```sh\nlaunchctl unload -w ~/Library/LaunchAgents/duplicacy.plist \u0026\u0026 launchctl load -w ~/Library/LaunchAgents/duplicacy.plist\n```\n\n## VBackup Script Linux\n\nDownload the OSX/Linux backup script `vbackup.sh`, add it to PATH and make it executable\n\n```sh\nsudo wget -O /usr/local/bin/vbackup https://github.com/vladgh/backup/raw/master/vbackup.sh\nsudo chmod a+x /usr/local/bin/vbackup\n```\n\nUse a dotenv file for secrets and other settings\n\n```sh\ntee ~/.duplicacy/.env \u003c\u003c CONFIG\nSLACK_ALERTS_WEBHOOK='https://hooks.slack.com/services/xxxxxxxxxx'\nCONFIG\nchmod 600 ~/.duplicacy/.env\n```\n\nUse SystemD timers to trigger the backup service\n\n```sh\ntee ~/.config/systemd/user/vbackup.service \u003c\u003c 'EOF'\n[Unit]\nDescription=Run VBackup\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nWorkingDirectory=%h\nExecStart=/usr/local/bin/vbackup\nEOF\n\ntee /home/vlad/.config/systemd/user/vbackup.timer  \u003c\u003c 'EOF'\n[Unit]\nDescription=Run VBackup\n\n[Timer]\nOnBootSec=15min\nOnUnitActiveSec=60min\n\n[Install]\nWantedBy=timers.target\nEOF\n\nsystemctl --user --now enable vbackup.timer\nsystemctl --user list-timers --all\n```\n\nAlternatively, create a cronjob to run the script as your user, at some interval\n\n```sh\nsudo tee /etc/cron.d/vbackup \u003c\u003c CONFIG\n10 * * * * vlad /usr/local/bin/vbackup.sh \u003e/dev/null 2\u003e\u00261\nCONFIG\n```\n\n## VBackup Script Windows\n\nDownload the Windows backup script `vbackup.ps1`\n\n```powershell\nInvoke-WebRequest -Uri \"https://github.com/vladgh/backup/raw/master/vbackup.ps1\" -OutFile \"C:\\backup\\vbackup.ps1\"\n```\n\nImport the sample xml below into the Task Scheduler to run the powershell script at some interval with elevated privileges. Modify as needed!\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-16\"?\u003e\n\u003cTask version=\"1.3\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\"\u003e\n  \u003cRegistrationInfo\u003e\n    \u003cAuthor\u003eMyPC\\MyName\u003c/Author\u003e\n    \u003cURI\u003e\\DuplicacyBackup\u003c/URI\u003e\n  \u003c/RegistrationInfo\u003e\n  \u003cTriggers\u003e\n    \u003cTimeTrigger\u003e\n      \u003cRepetition\u003e\n        \u003cInterval\u003ePT1H\u003c/Interval\u003e\n        \u003cDuration\u003eP10000D\u003c/Duration\u003e\n        \u003cStopAtDurationEnd\u003etrue\u003c/StopAtDurationEnd\u003e\n      \u003c/Repetition\u003e\n      \u003cStartBoundary\u003e2019-05-02T06:00:00+02:00\u003c/StartBoundary\u003e\n      \u003cEnabled\u003etrue\u003c/Enabled\u003e\n      \u003cRandomDelay\u003ePT5M\u003c/RandomDelay\u003e\n    \u003c/TimeTrigger\u003e\n  \u003c/Triggers\u003e\n  \u003cPrincipals\u003e\n    \u003cPrincipal id=\"Author\"\u003e\n      \u003cUserId\u003eMyPC\\MyName\u003c/UserId\u003e\n      \u003cLogonType\u003ePassword\u003c/LogonType\u003e\n      \u003cRunLevel\u003eHighestAvailable\u003c/RunLevel\u003e\n    \u003c/Principal\u003e\n  \u003c/Principals\u003e\n  \u003cSettings\u003e\n    \u003cMultipleInstancesPolicy\u003eIgnoreNew\u003c/MultipleInstancesPolicy\u003e\n    \u003cDisallowStartIfOnBatteries\u003etrue\u003c/DisallowStartIfOnBatteries\u003e\n    \u003cStopIfGoingOnBatteries\u003efalse\u003c/StopIfGoingOnBatteries\u003e\n    \u003cAllowHardTerminate\u003etrue\u003c/AllowHardTerminate\u003e\n    \u003cStartWhenAvailable\u003etrue\u003c/StartWhenAvailable\u003e\n    \u003cRunOnlyIfNetworkAvailable\u003efalse\u003c/RunOnlyIfNetworkAvailable\u003e\n    \u003cIdleSettings\u003e\n      \u003cStopOnIdleEnd\u003etrue\u003c/StopOnIdleEnd\u003e\n      \u003cRestartOnIdle\u003efalse\u003c/RestartOnIdle\u003e\n    \u003c/IdleSettings\u003e\n    \u003cAllowStartOnDemand\u003etrue\u003c/AllowStartOnDemand\u003e\n    \u003cEnabled\u003etrue\u003c/Enabled\u003e\n    \u003cHidden\u003efalse\u003c/Hidden\u003e\n    \u003cRunOnlyIfIdle\u003efalse\u003c/RunOnlyIfIdle\u003e\n    \u003cDisallowStartOnRemoteAppSession\u003efalse\u003c/DisallowStartOnRemoteAppSession\u003e\n    \u003cUseUnifiedSchedulingEngine\u003etrue\u003c/UseUnifiedSchedulingEngine\u003e\n    \u003cWakeToRun\u003efalse\u003c/WakeToRun\u003e\n    \u003cExecutionTimeLimit\u003ePT72H\u003c/ExecutionTimeLimit\u003e\n    \u003cPriority\u003e7\u003c/Priority\u003e\n  \u003c/Settings\u003e\n  \u003cActions Context=\"Author\"\u003e\n    \u003cExec\u003e\n      \u003cCommand\u003epowershell.exe\u003c/Command\u003e\n      \u003cArguments\u003e-NoProfile -ExecutionPolicy Bypass -File \"C:\\backup\\vbackup.ps1\" -Verb RunAs; quit\u003c/Arguments\u003e\n    \u003c/Exec\u003e\n  \u003c/Actions\u003e\n\u003c/Task\u003e\n```\n\nManually trigger scheduled task\n\n```powershell\nStart-ScheduledTask -TaskName \"DuplicacyBackup\"\n```\n\n---\n\n## Recovery\n\nCreate a folder to restore files\n\n```sh\nmkdir -p /tmp/restore\ncd /tmp/restore\n```\n\nInitialize with THE SAME ID AND PASSWORD as the one in the storage\n\n```sh\nduplicacy init -encrypt MyID sftp://user@192.168.1.2//path/to/backup/storage\n```\n\nRestore the wanted path from the wanted revision\n\n```sh\nduplicacy -log restore -r 604 -stats 'Dropbox/Projects/*'\n```\n\nLook for files, use the list command and grep\n\n```sh\nduplicacy list -r 12 -files | grep pattern\nduplicacy list -r 1-100 -files | grep pattern\n```\n\nFor Windows\n\n```powershell\nduplicacy list -r 12 -files | Select-String -Pattern myFile\nduplicacy list -r 1-100 -files | Select-String -Pattern myFile\n```\n\n## Restore local default storage from remote\n\n```sh\n# With B2 configured in preferences, copy from B2 to default, with bit-identical and set the id and path\nduplicacy add -e -copy B2 -bit-identical default MyID /path/to/backup/storage\n```\n\n## Fix corrupted snapshot\n\nMake sure no other backups are running and delete the corrupted snapshot\n\n```sh\nduplicacy check -a -tabular  # Check all snapshots (this is better than individual id checks, because of deduplication, when the corrupted chunks could belong to different IDs)\nduplicacy check -tabular -id VDev -r 1510-1520  # OR check a range of snapshots\nduplicacy check -tabular -storage B2 -id VDev -r 1510-1520  # OR check a range of snapshots for a single ID on a remote storage\n\nduplicacy prune -exhaustive -exclusive -id VDev -r 1515  # Remove the corrupted snapshot\n\n# IF `duplicacy check -a -tabular` fails with:\n# All chunks referenced by snapshot VDev at revision 5114 exist\n# Chunk cc86bc8351524fa2d17f65abd38b8609489a20410370965291de881b21b15226 can't be found\n# Go and delete the `snapshots/VDev/5115` file\n# Then run `duplicacy prune -exhaustive -exclusive`\n```\n\n---\n\n## Miscellaneous\n\n### Create log rotation script on Mac OS\n\n```sh\nsudo tee /etc/newsyslog.d/duplicacy.conf \u003c\u003c CONFIG\n# logfilename                            [owner:group]   mode  count  size  when  flags [/pid_file] [sig_num]\n/Users/vlad/.duplicacy/logs/backup.log   vlad:staff      644   10     1000  *     NJ\nCONFIG\n```\n\n### Log rotation in Linux\n\n```sh\nsudo tee /etc/logrotate.d/duplicacy \u003c\u003c CONFIG\n/home/vlad/.duplicacy/logs/backup.log {\n  daily\n  rotate 14\n  compress\n  delaycompress\n  missingok\n  notifempty\n  create 644 vlad vlad\n}\nCONFIG\n```\n\n### Full disk access on Mac OS\n\nThis script needs Full Disk Access so we need to add `/usr/local/bin/bash` to Security \u0026 Privacy - Privacy - Full Disk Access (Use CMD+SHIFT+. to show hidden files in the Open file dialog).\nThe .plist file should run with ProgramArguments, `bash` being the first one (or environment variables).\n\n### Linux tail Logs\n\n```sh\ntail -f ~/.duplicacy/logs/backup.log\ngrep -A 1 -e 'INFO BACKUP_END' ~/.duplicacy/logs/backup.log\n```\n\n### PowerShell tail logs\n\n```powershell\nGet-Content C:\\backup\\.duplicacy\\logs\\backup.log -Tail 20 -Wait\n```\n\n### PowerShell pattern in logs\n\n```powershell\n# All\nGet-Content C:\\backup\\.duplicacy\\logs\\backup.log | Select-String -Pattern 'INFO BACKUP_END' -Context 0,1\n# In the last 1000 lines\nGet-Content C:\\backup\\.duplicacy\\logs\\backup.log -Tail 1000 | Select-String -Pattern 'INFO BACKUP_END' -Context 0,1\n```\n\n### Mount backup drive, and save credentials on Windows\n\nIn Windows 10, the credentials need to include the workgroup (ex: WORKGROUP\\myname)\n\n```powershell\nnet use Z: \\\\192.168.1.2\\PathToBackup /savecred /persistent:yes\n```\n\n### Clone storage on Backblaze B2\n\nCreate a duplicate encrypted storage on Backblaze B2\n\n```sh\nduplicacy add -encrypt -copy default -bit-identical B2 MyID b2://vladgh\n```\n\nAdd keys and passwords to preferences\n\n```sh\nduplicacy set -storage default -key password -value 'mypwd'\nduplicacy set -storage B2 -key b2_id -value 'xxxxx'\nduplicacy set -storage B2 -key b2_key -value 'xxxxx'\nduplicacy set -storage B2 -key password -value 'mypwd'\n```\n\nCopy all snapshots to the new storage\n\n```sh\nduplicacy -log copy -to B2 -threads 10\n```\n\nPrune (run only from the NAS for both storages)\n\n```sh\nduplicacy -log prune -all -keep 0:1825 -keep 30:180 -keep 7:30 -keep 1:7\nduplicacy -log prune -all -keep 0:1825 -keep 30:180 -keep 7:30 -keep 1:7 -storage B2\n```\n\n## Contribute\n\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-007ba7.svg)](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html)\n\nContributions are always welcome! Please read the [contribution guidelines](.github/CONTRIBUTING.md) and the [code of conduct](.github/CODE_OF_CONDUCT.md).\n\n## License\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\nLicensed under the Apache License, Version 2.0.\nSee [LICENSE](LICENSE) file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladgh%2Fbackup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvladgh%2Fbackup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladgh%2Fbackup/lists"}