Update #4 - Automated Backups for BookStack on VPS - Secure & Scheduled
Update #4
As part of hardening and maintaining my public BookStack instance hosted on a VPS, I implemented a secure, automated backup system using shell scripting and cron. This ensures my database and uploaded files are regularly archived and protected against data loss - without exposing sensitive information in scripts.
The Setup
- 
VPS: Ubuntu 22.04 LTS (Hostinger) 
- 
Web Stack: Apache, MySQL, PHP 8.2 (LAMP stack) 
- 
Application: BookStack (latest stable) 
- 
Backup Destination: /opt/bookstack_backups/on the VPS
- 
Security Enhancements: - 
fail2banactive
- 
SSH hardening complete 
- 
UFW configured to allow only necessary services 
 
- 
The Process
- 
Created a Shell Script - 
A custom script ( /usr/local/bin/bookstack-backup.sh) was written to:- 
Dump the MySQL bookstackdatabase
- 
Archive important BookStack directories (such as /var/www/bookstack/public/uploadsand/var/www/bookstack/storage/uploads)
- 
Rotate old backups by removing any older than 7 days 
 
- 
 
- 
- 
Secured MySQL Credentials - 
Rather than placing the database password in the script (which is insecure), credentials were stored securely in the root user's ~/.my.cnffile:[client] user=bookstack password=your_db_password
 
- 
- 
Tested the Script - 
Verified manual execution of the script: - 
Confirmed .sqldumps and.tar.gzfiles were created correctly
- 
Ensured proper permissions and ownership of backup files 
 
- 
 
- 
- 
Scheduled Daily Cron Job - 
Added the script to root’s crontab to run automatically at 2:00 AM each day: 0 2 * * * /usr/local/bin/bookstack-backup.sh
 
- 
Sample Output
Backup files generated daily look like:
- 
/opt/bookstack_backups/bookstack_2025-05-09.sql
- 
/opt/bookstack_backups/bookstack_files_2025-05-09.tar.gz
What I Learned
- 
Avoid using mysqldumppasswords in scripts —~/.my.cnfis a secure alternative.
- 
Giving the database user PROCESSprivilege was necessary to prevent dump errors.
- 
Always verify permissions and script execution manually before automating via cron. 
- 
Storing backups under /opt/keeps them cleanly separated from web content.
 
                
1 Comment
Love it.