Bacula: Backing Up Linux Servers
A complete guide to deploying the Bacula backup system for automated Linux server backups, with support for Virtual Full backups and efficient disk space management.
In this article
Bacula is an open-source, enterprise-grade backup system for managing backup, recovery and verification of data across a network. It is modular and consists of several components:
- Director - the central control component that coordinates all backup operations
- Storage Daemon - manages the backup storage (disks, tapes)
- File Daemon - runs on the clients being backed up and sends the data
- Console - the management and monitoring interface
- Catalog - a database (MySQL/PostgreSQL) that stores backup metadata
Installation on Debian/Ubuntu
Installing the Director and Storage Daemon (backup server)
apt update
apt install bacula-director-mysql bacula-sd bacula-console
During installation you will be asked about the database configuration. Choose automatic configuration with dbconfig-common.
Installing the File Daemon (backed-up client)
apt install bacula-fd
Verifying the installation
# Check the configuration syntax
bacula-dir -t -c /etc/bacula/bacula-dir.conf
# Start the services
systemctl enable --now bacula-director bacula-sd bacula-fd
Sample configuration
The following configuration backs up a single server with these properties:
- Daily incremental backups at 01:00
- Virtual Full backups twice a week (Wednesday and Sunday) at 02:00
- Automatic freeing of disk space
- 7-day data retention on disk
- 14-day metadata retention in the catalog
File Daemon configuration (client)
This configuration runs on every server being backed up and is stored in /etc/bacula/bacula-fd.conf.
#
# Bacula File Daemon Configuration
#
FileDaemon {
Name = server-fd
FDport = 9102
WorkingDirectory = /var/lib/bacula
Pid Directory = /run/bacula
Maximum Concurrent Jobs = 10
# Address the FD listens on (0.0.0.0 = all)
FDAddress = 0.0.0.0
}
# Connection from the Director
Director {
Name = backup-dir
Password = "heslo-pro-file-daemon"
}
# Local monitoring (optional)
Director {
Name = backup-mon
Password = "heslo-pro-monitoring"
Monitor = yes
}
Messages {
Name = Standard
director = backup-dir = all, !skipped, !restored
}
Storage Daemon configuration
This configuration runs on the backup server where the data is stored, and it lives in /etc/bacula/bacula-sd.conf.
#
# Bacula Storage Daemon Configuration
#
Storage {
Name = backup-sd
SDPort = 9103
WorkingDirectory = /var/lib/bacula
Pid Directory = /run/bacula
Maximum Concurrent Jobs = 20
SDAddress = 0.0.0.0
}
# Connection from the Director
Director {
Name = backup-dir
Password = "heslo-pro-storage-daemon"
}
# Local monitoring (optional)
Director {
Name = backup-mon
Password = "heslo-pro-monitoring"
Monitor = yes
}
# Autochanger - a virtual "tape changer" for disk storage
Autochanger {
Name = FileChgr1
Device = FileChgr1-Dev1
Device = FileChgr1-Dev2
Device = FileChgr1-Dev3
Changer Command = ""
Changer Device = /dev/null
}
# Device for storing backups
Device {
Name = FileChgr1-Dev1
Media Type = File
Archive Device = /home/backupdb/bacula/backup
LabelMedia = yes
Random Access = yes
AutomaticMount = yes
RemovableMedia = no
AlwaysOpen = no
Maximum Concurrent Jobs = 5
}
Device {
Name = FileChgr1-Dev2
Media Type = File
Archive Device = /home/backupdb/bacula/backup
LabelMedia = yes
Random Access = yes
AutomaticMount = yes
RemovableMedia = no
AlwaysOpen = no
Maximum Concurrent Jobs = 5
}
Device {
Name = FileChgr1-Dev3
Media Type = File
Archive Device = /home/backupdb/bacula/backup
LabelMedia = yes
Random Access = yes
AutomaticMount = yes
RemovableMedia = no
AlwaysOpen = no
Maximum Concurrent Jobs = 5
}
Messages {
Name = Standard
director = backup-dir = all
}
Why 3 devices (Device)? An autochanger with multiple devices allows parallel operations. Each device can serve one volume at a time, which is essential for:
- Virtual Full backups - during consolidation Bacula reads from the source volumes (Dev2) and writes to the target volume (Dev1) at the same time. With a single device this would not be possible.
- Backing up multiple clients in parallel - if you back up several servers at once, each one can write to its own volume through a separate device.
- Restoring during a backup - you can restore data (read) while another client is being backed up (write).
All devices point to the same directory (Archive Device), but Bacula uses them as independent "drives" for accessing different volumes. For a typical deployment we recommend 2-3 devices; larger infrastructures with many clients can use more.
Note: The directory /home/backupdb/bacula/backup must exist and be writable by the bacula user:
Main configuration file
It is stored in /etc/bacula/bacula-dir.conf.
Director {
Name = backup-dir
QueryFile = "/etc/bacula/scripts/query.sql"
WorkingDirectory = "/var/lib/bacula"
PidDirectory = "/run/bacula"
Maximum Concurrent Jobs = 10
Password = "silne-heslo-pro-console"
Messages = Daemon
}
# Defaults for all backup jobs
JobDefs {
Name = "DefaultJob"
Type = Backup
Level = Incremental
Schedule = "WeeklyCycle"
Messages = Standard
SpoolAttributes = yes
Priority = 10
Write Bootstrap = "/var/lib/bacula/%c.bsr"
# Automatic upgrade to VirtualFull after 30 days without a Full
Max Virtual Full Interval = 30 days
Allow Mixed Priority = yes
Cancel Lower Level Duplicates = yes
Cancel Queued Duplicates = yes
}
# Backup job for the server
Job {
Name = "BackupServer"
JobDefs = "DefaultJob"
FileSet = "ServerFileSet"
Pool = ServerPool
Client = "server-fd"
Storage = BackupStorage
# Keep only the latest unconsolidated incremental
Backups To Keep = 1
Delete Consolidated Jobs = Yes
Accurate = Yes
# Maximum wait for a job to start
Max Start Delay = 10h
# Retry on error
Reschedule On Error = yes
Reschedule Times = 3
Reschedule Interval = 30 min
}
# Restore job
Job {
Name = "RestoreFiles"
Type = Restore
Client = server-fd
Storage = BackupStorage
FileSet = "ServerFileSet"
Pool = ServerPool
Messages = Standard
Where = /tmp/bacula-restore
}
# Definition of the files to back up
FileSet {
Name = "ServerFileSet"
Include {
Options {
signature = MD5
compression = GZIP
}
# Exclude unnecessary directories
Options {
exclude = yes
wild = "*/logs/*"
wild = "*/var/log/*"
wild = "*/var/cache/*"
wild = "*/tmp/*"
wild = "*/node_modules/*"
wild = "*/.cache/*"
wild = "*/media/cache/*"
}
File = /root
File = /home
File = /etc
}
}
# Backup schedule
Schedule {
Name = "WeeklyCycle"
# Daily incremental backups
Run = Level=Incremental Priority=10 mon-sun at 01:00
# Virtual Full twice a week (Wednesday and Sunday)
Run = Level=VirtualFull Priority=5 wed,sun at 02:00
}
# Client
Client {
Name = server-fd
Address = server.example.com
FDPort = 9102
Catalog = MyCatalog
Password = "heslo-pro-file-daemon"
File Retention = 14 days
Job Retention = 14 days
AutoPrune = yes
Maximum Concurrent Jobs = 10
}
# Storage with an Autochanger
Autochanger {
Name = BackupStorage
Address = backup.example.com
SDPort = 9103
Password = "heslo-pro-storage-daemon"
Device = FileChgr1
Media Type = File
Maximum Concurrent Jobs = 10
Autochanger = BackupStorage
}
# Catalog (database)
Catalog {
Name = MyCatalog
dbname = "bacula"
DB Address = "127.0.0.1"
DB Port = "3306"
dbuser = "bacula"
dbpassword = "heslo-databaze"
}
# Pool for regular backups
Pool {
Name = ServerPool
Pool Type = Backup
Recycle = yes
AutoPrune = yes
# Data retention on disk
Volume Retention = 7 days
# Free up space automatically after purge
Action On Purge = Truncate
Recycle Oldest Volume = yes
Maximum Volume Bytes = 20G
Maximum Volumes = 50
Label Format = "ServerVol-"
# Target pool for Virtual Full
Next Pool = VFServerPool
}
# Pool for Virtual Full backups
Pool {
Name = VFServerPool
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 7 days
Maximum Volume Bytes = 20G
Maximum Volumes = 70
Action On Purge = Truncate
Recycle Oldest Volume = yes
Label Format = "VFServerVol-"
Storage = BackupStorage
}
# Messages
Messages {
Name = Standard
mailcommand = "/usr/sbin/bsmtp -h localhost -f \"Bacula\" -s \"Bacula: %t %e of %c %l\" %r"
mail = admin@example.com = all, !skipped
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
catalog = all
}
Messages {
Name = Daemon
mailcommand = "/usr/sbin/bsmtp -h localhost -f \"Bacula\" -s \"Bacula daemon message\" %r"
mail = admin@example.com = all, !skipped
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
}
# Maintenance job for automatic cleanup
Schedule {
Name = "MaintenanceNightly"
Run = mon-sun at 09:00
}
Job {
Name = "MaintenancePrune"
Type = Admin
Client = server-fd
FileSet = "ServerFileSet"
Schedule = "MaintenanceNightly"
Priority = 50
Messages = Standard
Pool = ServerPool
Storage = BackupStorage
# Prune expired jobs
RunScript {
Console = "prune jobs client=server-fd yes"
RunsOnClient = no
RunsWhen = Before
}
# Prune expired volumes
RunScript {
Console = "prune expired volume pool=ServerPool yes"
RunsOnClient = no
RunsWhen = Before
}
RunScript {
Console = "prune expired volume pool=VFServerPool yes"
RunsOnClient = no
RunsWhen = Before
}
# Truncate - free up disk space
RunScript {
Console = "truncate volume pool=ServerPool allpools storage=BackupStorage yes"
RunsOnClient = no
RunsWhen = Before
}
RunScript {
Console = "truncate volume pool=VFServerPool allpools storage=BackupStorage yes"
RunsOnClient = no
RunsWhen = Before
}
}
Console {
Name = backup-mon
Password = "heslo-pro-monitoring"
CommandACL = status, .status
}
Key parameters explained
Data retention
Volume Retention- how long to keep data on disk. We recommend at least the duration of the longest backup plus a margin.Job Retention- how long to keep job records in the DB. The recommendation is ≥ Volume Retention.File Retention- how long to keep file lists in the DB. The recommendation is ≤ Job Retention.
Why keep File/Job Retention longer than Volume Retention?
File Retention and Job Retention only affect the metadata in the database (catalog), not the backup files on disk themselves. Longer metadata retention brings several benefits:
1. Protection against losing the baseline for incremental backups
Bacula needs a record of the last Full or Virtual Full backup in the catalog to run an Incremental correctly. If Job Retention expires and the Full backup record disappears, Bacula automatically upgrades the next Incremental to a Full - which means transferring all the data instead of just the changes.
An example of the problem with short retention:
- Monday: Full backup (1 TB, takes 4 days)
- Friday: Full completed, Job Retention = 4 days
- Tuesday next week: the Full backup record expires
- Wednesday: the scheduled Incremental is upgraded to a Full (another 4 days, 1 TB)
2. Faster and more accurate file restores
File Retention determines how long the database keeps a list of all backed-up files with their paths, sizes and checksums. With longer retention:
- You can search for specific files across the backup history
- The restore wizard offers a complete list of files to restore
- You don't have to browse volumes manually and guess what they contain
Without metadata in the catalog, a restore is still possible, but you need to know the exact JobId or browse the volumes manually with the bls utility.
3. Better overview and debugging
Longer Job Retention lets you:
- Analyze backup size trends over time
- Identify problematic jobs and failure patterns
- Plan storage capacity based on historical data
Impact on disk space
- Volume Retention - directly affects the disk, as it determines how long backup files are kept. It has no effect on the database.
- Job Retention - no effect on the disk. It takes up minimal space in the database (a few KB per job).
- File Retention - no effect on the disk. It has a significant impact on the database, because it stores the complete list of all backed-up files with their metadata.
File Retention and database size
For a server with 4 million files, File Retention can amount to:
- 4 days of retention: ~200 MB in the database
- 14 days of retention: ~700 MB in the database
- 30 days of retention: ~1.5 GB in the database
This is negligible compared to the size of the backups themselves (hundreds of GB to TB), but it can affect database query performance. For very large installations, consider tuning MySQL/PostgreSQL.
Recommended settings
# In the client configuration
File Retention = 14 days # Lets you find files up to 2 weeks back
Job Retention = 14 days # Protects the baseline for incrementals
Volume Retention = 7 days # Actual data on disk
These settings ensure that:
- Backup files are recycled after 7 days (saving disk space)
- Metadata is kept for 14 days (protection against an upgrade to Full)
- You have a two-week history for file searches
Virtual Full backups
A Virtual Full is a synthesis of the previous Full backup and all subsequent Incrementals into a new "virtual" Full backup. Benefits:
- No data transfer from the client
- Faster restores (no need to apply increments)
- More efficient use of storage
Parameters:
Backups To Keep = 1- deletes old increments after consolidationDelete Consolidated Jobs = Yes- deletes the records of consolidated jobsNext Pool- the target pool for Virtual Full backups
Maintenance job
The MaintenanceNightly maintenance job performs automatic cleanup - it prunes expired records from the catalog and frees disk space by truncating empty volumes.
When to run maintenance: The maintenance job should run only after all backup jobs have finished. If it ran before or during the backups, it could delete metadata needed for Virtual Full consolidation or release volumes that are still in use. For nightly backups starting at 01:00-02:00, we recommend running maintenance in the morning, e.g. at 09:00.
Schedule {
Name = "MaintenanceNightly"
Run = mon-sun at 09:00
}
Disk space management
Action On Purge = Truncate- after a volume is purged, truncates it to zero, freeing disk space immediatelyRecycle Oldest Volume = yes- when a new volume is needed, automatically recycles the oldest available oneMaximum Volume Bytes- the maximum size of a single volume file (e.g. 20G)Maximum Volumes- the maximum number of volumes in the pool, which limits the total capacity
Job order and priorities
Bacula runs jobs according to their priority - lower number = higher priority. This matters for Virtual Full backups to work correctly.
Why the order matters:
A Virtual Full consolidates the previous Full/VirtualFull and all subsequent Incrementals into a new whole. If the VirtualFull started before an Incremental scheduled for the same day, it would not include that Incremental in the consolidation.
Recommended priority settings:
- Priority = 5 - Virtual Full backups (higher priority)
- Priority = 10 - Incremental and Full backups (standard priority)
- Priority = 50 - maintenance jobs (lowest priority)
Schedule {
Name = "WeeklyCycle"
Run = Level=Incremental Priority=10 mon-sun at 01:00
Run = Level=VirtualFull Priority=5 wed,sun at 02:00
}
How does it work? The correct order is ensured by the time offset in the Schedule - Incrementals start at 01:00, VirtualFull only at 02:00. The key point is that the Incrementals start first.
A VirtualFull consolidates all completed jobs in the catalog. If an Incremental is still running when the VirtualFull starts, it won't be included in this consolidation - it will be included in the next VirtualFull instead. This is expected behavior and not a problem, because the data from the running Incremental remains available on its own.
Virtual Full has a higher priority (lower number) so that it can get ahead of less important jobs when waiting in the queue. Priority only matters for jobs waiting in the queue at the same time.
The Allow Mixed Priority parameter in JobDefs allows jobs with different priorities to run at the same time. Without it, Bacula would wait for all higher-priority jobs to finish before starting lower-priority ones.
Allow Mixed Priority = yes
Working with large backups
If a server backup takes several days (e.g. 1 TB of data over a slow network or HDD), you need to adjust the configuration:
1. Increase Volume Retention
Volume Retention = 14 days # At least 2× the backup period
2. Increase Job/File Retention
Job Retention = 21 days
File Retention = 21 days
3. Temporarily disable the job while it is running
# Disable scheduled runs
bconsole <<< "disable job=BackupServer"
# Re-enable when finished
bconsole <<< "enable job=BackupServer"
4. Optimize the FileSet
Excluding large unnecessary directories speeds up the backup considerably:
Options {
exclude = yes
wild = "*/vendor/*"
wild = "*/node_modules/*"
wild = "*.log"
wild = "*.tmp"
wild = "/var/lib/docker/*"
}
BAT graphical interface
For users who prefer a graphical environment to the command line, Bacula offers BAT (Bacula Administration Tool). It is a Qt application that provides a clear GUI for managing and monitoring backups.
The main advantage of BAT is that you can run it on your local computer and monitor the state of server backups remotely - there's no need to log in to the backup server over SSH.
Installation
# Debian/Ubuntu - on your computer
apt install bacula-console-qt
Connection configuration
BAT requires a configuration file with the details for connecting to the Director. Create a file such as ~/.bacula/bat.conf:
Director {
Name = backup-dir
DIRport = 9101
address = backup.example.com
Password = "silne-heslo-pro-console"
}
Important: The password must match the password defined in the Console resource on the Director side.
Running with a custom configuration
# Run with an explicit path to the configuration
bat -c ~/.bacula/bat.conf
For more convenient startup, you can create an alias in ~/.bashrc:
alias bat='bat -c ~/.bacula/bat.conf'
Firewall and network access
For remote connections, access to the Director's port must be allowed on the backup server:
# On the backup server
ufw allow from 192.168.1.0/24 to any port 9101 proto tcp
Alternatively, restrict which addresses it listens on in the Director's configuration:
Director {
Name = backup-dir
DirAddresses = {
ip = { addr = 127.0.0.1 }
ip = { addr = 192.168.1.10 } # LAN address
}
...
}
Basic bconsole commands
Connecting to the console
bconsole
Monitoring status
# Director status - overview of scheduled and running jobs
status dir
# Detailed status of a specific job
status jobid=1234
# Client status
status client=server-fd
# Storage status
status storage=BackupStorage
Managing jobs
# Run a backup manually
run job=BackupServer level=Incremental yes
# Cancel a running job
cancel jobid=1234
# List recent jobs
list jobs client=server-fd
# Job details
list jobid=1234
Managing volumes
# List volumes in the pool
list volumes pool=ServerPool
# Volume details
list volume=ServerVol-0001
# Purge a volume manually
purge volume=ServerVol-0001 yes
# Truncate - free up space
truncate volume pool=ServerPool allpools storage=BackupStorage yes
Verifying the configuration
# Check the syntax (without starting)
bacula-dir -t -c /etc/bacula/bacula-dir.conf
# Reload the configuration at runtime
bconsole <<< "reload"
# Show the configuration
show job=BackupServer
show pool=ServerPool
show schedule=WeeklyCycle
Troubleshooting
# Show messages
bconsole <<< "messages"
# Log file
tail -f /var/log/bacula/bacula.log
# Check the connection to the client
bconsole <<< "status client=server-fd"
# Check the storage
bconsole <<< "status storage=BackupStorage"
Restoring files from a backup
Interactive restore
bconsole
# Start the restore wizard
restore
# Select the client
> 5 (Select the Client)
> server-fd
# Choose how to select files
> 5 (Select the most recent backup for a client)
# Navigate and select files
cd /home/user/documents
mark important-file.txt
mark another-file.pdf
cd /etc
mark nginx
# Finish the selection
done
# Confirm the restore
yes
Quick restore of the last job
bconsole << 'EOF'
restore client=server-fd where=/tmp/bacula-restore all
5
server-fd
done
yes
EOF
Restoring a specific directory
bconsole << 'EOF'
restore client=server-fd where=/tmp/bacula-restore
5
server-fd
cd /home/user
mark documents
done
yes
EOF
Restoring from a specific job/date
bconsole << 'EOF'
restore client=server-fd where=/tmp/bacula-restore
# Option 3 - Enter list of comma separated JobIds to select
3
6789,6790
cd /etc
mark nginx
done
yes
EOF
Restore parameters
where=Target directory for the restorereplace=What to do with existing files:always,ifnewer,ifolder,neverclient=Target client (can differ from the original)
Restoring to a different server
restore client=original-fd restoreclient=new-fd where=/tmp/restore
Solving common problems
"Cannot find any appendable volumes"
The pool has reached its volume limit. Solution:
# Raise the limit
bconsole <<< "update pool=ServerPool MaxVols=100"
# Or create a new volume manually
bconsole <<< "label storage=BackupStorage pool=ServerPool"
"Only one Job found. Consolidation not needed"
The Virtual Full has nothing to consolidate - a previous Full or Incrementals are missing. Make sure your schedule is set up correctly and that at least one Full + Incremental exists.
Disk filling up
# Manual truncate
bconsole << 'EOF'
truncate volume pool=ServerPool allpools storage=BackupStorage yes
truncate volume pool=VFServerPool allpools storage=BackupStorage yes
EOF
# Check the status of volumes
bconsole <<< "list volumes pool=ServerPool"
Job waiting in the queue
# Show waiting jobs
bconsole <<< "status dir"
# Cancel all waiting jobs
bconsole <<< "cancel all yes"
Documentation
For more information, I recommend the official Bacula documentation.