Repository navigation
Scheduling
GitHub Mirror Backup is designed to run unattended.
Once the first manual backup has been completed successfully, the script can be scheduled using either:
- Linux
cron - Synology DSM Task Scheduler
The recommended interval depends on how frequently the repositories change.
For most personal and small-business repositories, once per day is a reasonable starting point.
Synology DSM provides a built-in Task Scheduler that can run shell scripts automatically.
In DSM:
Control Panel
↓
Task Scheduler
↓
Create
↓
Scheduled Task
↓
User-defined script
Give the task a descriptive name, for example:
GitHub Mirror Backup
Run the task as the same user that was used to configure the backup.
This is important because the user needs access to:
~/.config/github/token~/.ssh/- the backup directory
- the GitHub SSH key
If the task runs as another user, $HOME will be different and the token and SSH configuration may not be available.
Open the Schedule section.
Example daily schedule:
Frequency: Daily
Time: 03:00
A backup can also be run more frequently if required.
Examples:
Every day → 03:00
Every 12 hours → 03:00 / 15:00
Every 6 hours → 00:00 / 06:00 / 12:00 / 18:00
The appropriate interval depends on how much repository activity you need to capture.
In the Task Settings section, use the full path to the script.
For example:
/volume1/scripts/github-mirror-backup/github-backup.shIf necessary, explicitly invoke Bash:
/bin/bash /volume1/scripts/github-mirror-backup/github-backup.shUsing absolute paths is recommended for scheduled tasks.
After creating the task, use Run in Task Scheduler to execute it immediately.
Check the task output and the backup log.
The script should perform:
SYSTEM CHECK
GITHUB API
GITHUB SSH
REPOSITORY DISCOVERY
MIRRORING
SUMMARY
Do not rely solely on the Task Scheduler status. The script's own log contains the repository-level results.
The script uses:
TOKEN_FILE="$HOME/.config/github/token"Therefore the account running the scheduled task matters.
For example:
Interactive shell:
/var/services/homes/csiber
Task Scheduler:
/var/services/homes/backup
The second task would look for the token under the backup user's home directory.
If the token is not there, the backup will fail before repository discovery.
Always verify the task's execution user.
A clean Synology installation could look like:
/volume1/
├── Archivum/
│ ├── project-a.git/
│ ├── project-b.git/
│ └── _logs/
│
└── scripts/
└── github-mirror-backup/
└── github-backup.sh
The backup data and script are kept separately.
The token remains in the user's home directory:
~/.config/github/token
The SSH key remains under:
~/.ssh/
On a standard Linux system, the same script can be scheduled with cron.
Edit the user's crontab:
crontab -eFor a daily 03:00 backup:
0 3 * * * /path/to/github-backup.shMake sure the script is executable:
chmod +x /path/to/github-backup.shUsing the user's own crontab is preferable because the script then runs with the same $HOME, SSH keys and token configuration.
If the script's executable bit is not being used:
0 3 * * * /bin/bash /path/to/github-backup.shThis can also make the execution environment more obvious.
The script already creates its own log files, so additional output redirection is usually unnecessary.
If you still want cron's own output captured:
0 3 * * * /bin/bash /path/to/github-backup.sh >> /path/to/cron-github-backup.log 2>&1However, this creates a second log stream.
The script's _logs/ directory should normally be treated as the primary log source.
For repositories that change frequently, the backup can run several times per day.
Example every 6 hours:
0 */6 * * * /bin/bash /path/to/github-backup.shExample every 12 hours:
0 */12 * * * /bin/bash /path/to/github-backup.shThe mirror update is incremental, so later runs normally transfer only changes.
The script has its own lock:
LOCK_DIR="/tmp/github-backup.lock"If another backup is already running, a second instance exits rather than modifying the same mirrors simultaneously.
This is particularly useful when the initial backup takes a long time.
For example:
03:00 → backup starts
04:15 → still running
04:00 → another scheduled run starts
↓
lock detected
↓
second run exits
The first backup continues normally.
The first execution can be substantially heavier than normal scheduled runs.
125 repositories
↓
125 mirror operations
↓
Large amount of network + disk activity
125 existing mirrors
↓
Fetch changes
↓
Only changed Git objects are transferred
Do not schedule the first full backup at the same time as other heavy NAS jobs if the system has limited resources.
After the initial mirror has completed, daily execution should normally be much lighter.
The most useful indicator is the latest log:
ls -1t /volume1/Archivum/_logs/github-backup-*.log | head -1Check the end of the latest log:
tail -n 30 "$(ls -1t /volume1/Archivum/_logs/github-backup-*.log | head -1)"A successful run ends with:
✓ COMPLETED SUCCESSFULLY
A run with repository-level errors ends with:
✗ COMPLETED WITH X ERROR(S)
The script also returns:
0 = success
1 = repository errors
2 = fatal error
This makes it possible for external monitoring to detect failed backups.
For a typical personal GitHub account:
03:00 every day
is sufficient for a simple offline/local mirror.
For an active development environment:
Every 6–12 hours
may be more appropriate.
The backup frequency determines how much GitHub-side history could be lost between successful backup runs if the remote repository becomes unavailable.
Before enabling an unattended schedule:
- First manual backup completed successfully
- Correct DSM/Linux user selected
- Token is accessible to that user
- SSH authentication works for that user
- Backup directory is writable
- Script uses an absolute path
- Logs are being created
- A manual scheduled-task test succeeds
- No overlapping backup jobs are configured
Once these checks pass, the backup can run unattended.