Site Overlay

Bacularis Installation and Configuration Notes

Bacularis is a fully loaded Bacula CE suite that comes with a successor of highly popular Baculum GUI. It can be installed by a one-liner Docker command thereby short-cutting hours of tedious installation steps like the ones I described in one of my previous posts.

1 Creating the container

1.1 with docker run

By default, the docker container mounts six volumes that it labels with non-intuitive random alphanumeric uuids. To get meaningful volumes that we can later identify on the host machine, we add a set of --mount options so that volumes are not created with anonymous uuid labels.

Furthermore, we open not only the Bacularis port 9097 but also ports 9101-9103 which are needed for communication between the director, the file daemons and the storage daemons.

ilek@q556:~$ docker run -d -p 9097:9097 -p 9101-9103:9101-9103 \
           --name bacuprod \
           --mount source=bacuprod_etc,destination=/etc/bacula \
           --mount source=bacuprod_archive,destination=/var/lib/bacula \
           --mount source=bacuprod_postgre,destination=/var/lib/postgresql/data \
           --mount source=bacuprod_api_conf,destination=/var/www/bacularis/protected/vendor/bacularis/bacularis-api/API/Config \
           --mount source=bacuprod_api_log,destination=/var/www/bacularis/protected/vendor/bacularis/bacularis-api/API/Logs \
           --mount source=bacuprod_web_conf,destination=/var/www/bacularis/protected/vendor/bacularis/bacularis-web/Web/Config \
           --mount source=bacuprod_web_log,destination=/var/www/bacularis/protected/vendor/bacularis/bacularis-web/Web/Logs \
           bacularis/bacularis-standalone

1.2 with docker compose

From my experience, it is more convenient to keep the container configuration in a docker-compose.yml file: The complete configuration is stored readily available on disk, so there is no need to look it up. Besides having to enter multi-line commands with dozens of parameters at the console is cumbersome and prone to syntax errors.

  • Save the docker-compose.yml file below in a directory like ~/docker/bacuprod
  • Launch by issuing the command docker compose up --detach from the directory
  • Stop by issuing the command docker compose down
name: bacuprod
services:
  bacuprod:
    image: 'bacularis/bacularis-standalone:2.1.0-alpine'
    container_name: 'bacuprod'
    hostname: 'q556.fritz.box'
    ports:
      - '9097:9097'
      - '9101:9101'
      - '9102:9102'
      - '9103:9103'
    volumes:
      - etc:/etc/bacula
      - archive:/var/lib/bacula
      - postgre:/var/lib/postgresql/data
      - api_conf:/var/www/bacularis/protected/vendor/bacularis/bacularis-api/API/Config
      - api_log:/var/www/bacularis/protected/vendor/bacularis/bacularis-api/API/Logs
      - web_conf:/var/www/bacularis/protected/vendor/bacularis/bacularis-web/Web/Config
      - web_log:/var/www/bacularis/protected/vendor/bacularis/bacularis-web/Web/Logs

volumes:
  etc:
  archive:
  postgre:
  api_conf:
  api_log:
  web_conf:
  web_log:

2 Set meaningful daemon names

The default name of the director is simply the host name of the docker container’s Alpine Linux OS plus an appended -dir. So you get unintuitive names like build-3-16-x86_64-dir. To better identify the machine, …

… stop the Bacularis container, as sudo change to the host machine’s local bacula_etc volume (the path may differ on your machine, depending on the docker installation it might be /var/lib/docker/volumes while in my case it’s ~/.local/share/docker/volumes).

ilek@q556:~/bacuprod$ docker stop bacuprod 
bacuprod
ilek@q556:~/bacuprod$ sudo su
[sudo] password for ilek: 
root@q556:/home/ilek/bacuprod# cd /home/ilek/.local/share/docker/volumes/bacuprod_etc/_data
root@q556:/home/ilek/.local/share/docker/volumes/bacuprod_etc/_data# ls
bacula-dir.conf  bacula-fd.conf  bacula-sd.conf  bconsole.conf  scripts
root@q556:/home/ilek/.local/share/docker/volumes/bacuprod_etc/_data# vim bacula-dir.conf 

First thing we have to edit is the bconsole.conf file. Replace Name and address directives as follows:

Director {
  Name = q556_d-dir
  DIRport = 9101
  address = q556 # was localhost

Save and continue editing bacula-dir.conf as follows:

Director {                            # define myself
  Name = q556_d-dir
  DIRport = 9101                # where we listen for UA connections
  QueryFile = "/etc/bacula/scripts/query.sql"
  WorkingDirectory = "/var/lib/bacula"
  PidDirectory = "/run/bacula"
  Maximum Concurrent Jobs = 20
  Password = "yRtfeKlgyBI7lXuDRXJJ3XuE718Nz/M7cg2zeuSgUNuy"         # Console password
  Messages = Daemon
}

In the same file, we can already change the name of the local client (file daemon) in the JobDef Resource:

JobDefs {
  Name = "DefaultJob"
  Type = Backup
  Level = Incremental
  Client = q556_d-fd
  FileSet = "Full Set"
  Schedule = "WeeklyCycle"
  Storage = File1
  Messages = Standard
  Pool = File
  SpoolAttributes = yes
  Priority = 10
  Write Bootstrap = "/var/lib/bacula/%c.bsr"
}

Still in bacula-dir.conf we change the client name in the Job Resource for the Restore operation:

Job {
  Name = "RestoreFiles"
  Type = Restore
  Client = q556_d-fd
  Storage = File1
# The FileSet and Pool directives are not used by Restore Jobs
# but must not be removed
  FileSet="Full Set"
  Pool = File
  Messages = Standard
  Where = /var/lib/bacula/archive/bacula-restores
}

And, still in bacula-dir.conf we change the client name in the Client Ressource:

# Client (File Services) to backup
Client {
  Name = q556_d-fd
  Address = localhost
  FDPort = 9102
  Catalog = MyCatalog
  Password = "9jTOS+av7cVucWfwyVKSxKVFWF45xgArseso98h6EBO1"          # password for FileDaemon
  File Retention = 60 days            # 60 days
  Job Retention = 6 months            # six months
  AutoPrune = yes                     # Prune expired Jobs/Files
}

For the sake of house-keeping, we also amend the Name directive of the Console resource in bacula-conf.dir:

Console {
  Name = q556_d-mon
  Password = "W2lr7PKwCsd2WRAXN8/rAGFXMGB6XplIyMXlamqfYwaU"
  CommandACL = status, .status
}

Don’t forget that director name also needs to be set for any daemon which the director should talk to. In our default installation, this should be the local file daemon and the storage daemon.

Save the changes in bacula-dir.conf and continue with editing bacula-fd.conf:

Director {
  Name = q556_d-dir
  Password = "9jTOS+av7cVucWfwyVKSxKVFWF45xgArseso98h6EBO1"
}
[...]
Director {
  Name = q556_d-mon
  Password = "G+UhGCVuxrajBJAU0yyIDFY+KiUBlA/9n2u/qfJq84NW"
  Monitor = yes
}
[...]
# Send all messages except skipped files back to Director
Messages {
  Name = Standard
  director = q556_d-dir = all, !skipped, !restored, !saved
}

Save and continue with editing bacula-sd.conf:

Storage {                             # definition of myself
  Name = q556_d-sd
  SDPort = 9103                  # Director's port
  WorkingDirectory = "/var/lib/bacula"
  Pid Directory = "/run/bacula"
  Plugin Directory = "/usr/lib"
  Maximum Concurrent Jobs = 20
}
[...]
# List Directors who are permitted to contact Storage daemon
#
Director {
  Name = q556_d-dir
  Password = "X2FRyPJvCMGw8phX2/GkvkTOUxcgfAkTjfILgYFWbIhP"
}
[...]
# Restricted Director, used by tray-monitor to get the
#   status of the storage daemon
#
Director {
  Name = q556_d-mon
  Password = "V/dvYvy+gzV5dAiA7a8wptnVP/zfDFIejzoCkpMB2Ett"
  Monitor = yes
}

Save and exit.

3 Further amendments

3.1 Add host ip and name to /etc/hosts

As we use host names instead of IP addresses we make sure that the q556 host’s IP address is known to bacularis. We therefore have to edit /etc/hosts inside the bacularis container.

For convenience we first install vim inside the bacularis container.

root@q556:/var/lib/docker/volumes/bacuprod_etc/_data# docker exec -it bacuprod bash
bash-5.1# apk add vim
fetch https://dl-cdn.alpinelinux.org/alpine/v3.16/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.16/community/x86_64/APKINDEX.tar.gz
OK: 114 MiB in 95 packages

We can then invoke vim /etc/hosts and add the host machine’s name and IP:

127.0.0.1	localhost

192.168.4.64	q556

::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	7abceb86cb26

3.2 Wrong database name in script of BackupCatalog job

In my case the default BackupCatalog failed when I tried to run it from the console:

ilek@q556:~/docker/bacudock$ docker exec -it bacutest bconsole
Connecting to Director localhost:9101
1000 OK: 10002 build-3-16-x86_64-dir Version: 11.0.6 (10 March 2022)
Enter a period to cancel a command.
*run
Automatically selected Catalog: MyCatalog
Using Catalog "MyCatalog"
A job name must be specified.
The defined Job resources are:
     1: BackupClient1
     2: BackupCatalog
     3: RestoreFiles
Select Job resource (1-3): 2
Run Backup job
JobName:  BackupCatalog
Level:    Full
Client:   build-3-16-x86_64-fd
FileSet:  Catalog
Pool:     File (From Job resource)
Storage:  File1 (From Job resource)
When:     2022-09-19 15:46:09
Priority: 11
OK to run? (yes/mod/no): yes
Job queued. JobId=1
*messages
19-Sep 15:46 build-3-16-x86_64-dir JobId 1: shell command: run BeforeJob "/etc/bacula/scripts/make_catalog_backup MyCatalog"
19-Sep 15:46 build-3-16-x86_64-dir JobId 1: BeforeJob: pg_dump: error: connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: FATAL:  database "MyCatalog" does not exist

For me the term ‘catalog’ is somewhat confusing. According to the Bacula MRG (Section 22.17), the terms catalog and database are apparently used as synonyms. The error message above FATAL: datatbase "MyCatalog" does not exist corroborates such an assumption.

This leads to two questions:

  1. What is the actual name of the Bacula database as set up by the Docker container? – Answer: The name of the Bacula PostgreSQL database is (unsurprisingly) bacula.
  2. In which Ressource(s) of which config file(s) has this ressource been incorrectly referred to as MyCatalog?

Looking at /etc/bacula-dir.conf, we realize that the Job Ressource BackupCatalog contains a directive that is passed MyCatalog as a command line argument.

# Backup the catalog database (after the nightly save)
Job {
  Name = "BackupCatalog"
  JobDefs = "DefaultJob"
  Level = Full
  FileSet="Catalog"
  Schedule = "WeeklyCycleAfterBackup"
  # This creates an ASCII copy of the catalog
  # Arguments to make_catalog_backup are:
  #  make_catalog_backup <catalog-name>
  RunBeforeJob = "/etc/bacula/scripts/make_catalog_backup MyCatalog"
  # This deletes the copy of the catalog
  RunAfterJob  = "/etc/bacula/scripts/delete_catalog_backup"
  Write Bootstrap = "/var/lib/bacula/%n.bsr"
  Priority = 11                   # run after main backup
}

Let’s check the content of the script that is called with MyCatalog. And here’s the relevant line:

    # you could also add --compress for compression.  See man pg_dump
    exec ${BINDIR}/pg_dump -c $PGHOST -U $user $1 >$1.sql
    ;;
esac

Clearly, the pg_dump command expects the database name – which by default is bacula – and not some externally assigned label or alias from a config file.

So to fix the problem, we simply have to replace MyCatalog by bacula in the RunBeforeJob Directive of the Job Resource for BackupCatalog in bacula-dir.conf:

RunBeforeJob = "/etc/bacula/scripts/make_catalog_backup bacula"

3.3 No contact to SD when backing up external clients

bacula-dir.conf of the Bacularis host features two Storage resources with an Address directive pointing to localhost. If you try to connect a client from outside the Docker container the job will stall / spin forever and can only be stopped by cancelling it. You will then get an error message that looks as follows:

q556_d-dir JobId 73: Fatal error: Bad response to Storage command: wanted 2000 OK storage
, got Jmsg JobId=73 type=4 level=1664154685 x220-fd JobId 73: Fatal error: job.c:2720 Failed to connect to Storage daemon: localhost:9103

The solution is to replace the localhost Address directive in the Storage resource of bacula-dir.conf on host q556 by the host’s hostname – which is q556.

Storage {
  Name = "File1"
  SdPort = 9103
  Address = q556
  Password = "X2FRyPJvCMGw8phX2/GkvkTOUxcgfAkTjfILgYFWbIhP"
  Device = "FileChgr1"
  MediaType = "File1"
  Autochanger = "File1"
  MaximumConcurrentJobs = 10
}
Storage {
  Name = "File2"
  SdPort = 9103
  Address = q556
  Password = "X2FRyPJvCMGw8phX2/GkvkTOUxcgfAkTjfILgYFWbIhP"
  Device = "FileChgr2"
  MediaType = "File2"
  Autochanger = "File2"
  MaximumConcurrentJobs = 10
}

4 First test: running local jobs

We now access the Bacula director from the Docker host machine to start with local backups:

ilek@q556:~$ docker exec -it bacuprod bconsole

4.1 Catalog backup

Connecting to Director localhost:9101
1000 OK: 10002 q556_d-dir Version: 11.0.6 (10 March 2022)
Enter a period to cancel a command.
*run
Automatically selected Catalog: MyCatalog
Using Catalog "MyCatalog"
A job name must be specified.
The defined Job resources are:
     1: BackupClient1
     2: BackupCatalog
     3: RestoreFiles
Select Job resource (1-3): 2
Run Backup job
JobName:  BackupCatalog
Level:    Full
Client:   q556_d-fd
FileSet:  Catalog
Pool:     File (From Job resource)
Storage:  File1 (From Job resource)
When:     2022-09-22 13:09:43
Priority: 11
OK to run? (yes/mod/no): yes
Job queued. JobId=2
*message
22-Sep 13:09 q556_d-dir JobId 2: shell command: run BeforeJob "/etc/bacula/scripts/make_catalog_backup bacula"
*messages
22-Sep 13:09 q556_d-dir JobId 2: Start Backup JobId 2, Job=BackupCatalog.2022-09-22_13.09.45_03
22-Sep 13:09 q556_d-dir JobId 2: Using Device "FileChgr1-Dev1" to write.
22-Sep 13:09 q556_d-sd JobId 2: Volume "Vol-0001" previously written, moving to end of data.
22-Sep 13:09 q556_d-sd JobId 2: Ready to append to end of Volume "Vol-0001" size=61,640
22-Sep 13:09 q556_d-sd JobId 2: Elapsed time=00:00:01, Transfer rate=64.64 K Bytes/second
22-Sep 13:09 q556_d-sd JobId 2: Sending spooled attrs to the Director. Despooling 219 bytes ...
22-Sep 13:09 q556_d-dir JobId 2: Bacula q556_d-dir 11.0.6 (10Mar22):
  Build OS:               x86_64-alpine-linux-musl unknown unknown
  JobId:                  2
  Job:                    BackupCatalog.2022-09-22_13.09.45_03
  Backup Level:           Full
  Client:                 "q556_d-fd" 11.0.6 (10Mar22) x86_64-alpine-linux-musl,unknown,unknown
  FileSet:                "Catalog" 2022-09-22 11:50:13
  Pool:                   "File" (From Job resource)
  Catalog:                "MyCatalog" (From Client resource)
  Storage:                "File1" (From Job resource)
  Scheduled time:         22-Sep-2022 13:09:43
  Start time:             22-Sep-2022 13:09:50
  End time:               22-Sep-2022 13:09:51
  Elapsed time:           1 sec
  Priority:               11
  FD Files Written:       1
  SD Files Written:       1
  FD Bytes Written:       64,532 (64.53 KB)
  SD Bytes Written:       64,643 (64.64 KB)
  Rate:                   64.5 KB/s
  Software Compression:   None
  Comm Line Compression:  76.1% 4.2:1
  Snapshot/VSS:           no
  Encryption:             no
  Accurate:               no
  Volume name(s):         Vol-0001
  Volume Session Id:      1
  Volume Session Time:    1663852175
  Last Volume Bytes:      126,753 (126.7 KB)
  Non-fatal FD errors:    0
  SD Errors:              0
  FD termination status:  OK
  SD termination status:  OK
  Termination:            Backup OK

22-Sep 13:09 q556_d-dir JobId 2: Begin pruning Jobs older than 6 months .
22-Sep 13:09 q556_d-dir JobId 2: No Jobs found to prune.
22-Sep 13:09 q556_d-dir JobId 2: Begin pruning Files.
22-Sep 13:09 q556_d-dir JobId 2: No Files found to prune.
22-Sep 13:09 q556_d-dir JobId 2: End auto prune.

22-Sep 13:09 q556_d-dir JobId 2: shell command: run AfterJob "/etc/bacula/scripts/delete_catalog_backup"

4.2 Local FileSet backup

We now try to run a file backup job of the local client. Still in bconsole proceed as follows:

*run
A job name must be specified.
The defined Job resources are:
     1: BackupClient1
     2: BackupCatalog
     3: RestoreFiles
Select Job resource (1-3): 1
Run Backup job
JobName:  BackupClient1
Level:    Incremental
Client:   q556_d-fd
FileSet:  Full Set
Pool:     File (From Job resource)
Storage:  File1 (From Job resource)
When:     2022-09-22 13:25:19
Priority: 10
OK to run? (yes/mod/no): yes
Job queued. JobId=3
You have messages.
*messages
22-Sep 13:25 q556_d-dir JobId 3: No prior or suitable Full backup found in catalog. Doing FULL backup.
22-Sep 13:25 q556_d-dir JobId 3: Start Backup JobId 3, Job=BackupClient1.2022-09-22_13.25.48_43
22-Sep 13:25 q556_d-dir JobId 3: Using Device "FileChgr1-Dev2" to write.
22-Sep 13:25 q556_d-sd JobId 3: Volume "Vol-0001" previously written, moving to end of data.
22-Sep 13:25 q556_d-sd JobId 3: Ready to append to end of Volume "Vol-0001" size=126,753
22-Sep 13:25 q556_d-sd JobId 3: Elapsed time=00:00:01, Transfer rate=12.04 M Bytes/second
22-Sep 13:25 q556_d-sd JobId 3: Sending spooled attrs to the Director. Despooling 9,909 bytes ...
22-Sep 13:25 q556_d-dir JobId 3: Bacula q556_d-dir 11.0.6 (10Mar22):
  Build OS:               x86_64-alpine-linux-musl unknown unknown
  JobId:                  3
  Job:                    BackupClient1.2022-09-22_13.25.48_43
  Backup Level:           Full (upgraded from Incremental)
  Client:                 "q556_d-fd" 11.0.6 (10Mar22) x86_64-alpine-linux-musl,unknown,unknown
  FileSet:                "Full Set" 2022-09-22 13:25:49
  Pool:                   "File" (From Job resource)
  Catalog:                "MyCatalog" (From Client resource)
  Storage:                "File1" (From Job resource)
  Scheduled time:         22-Sep-2022 13:25:19
  Start time:             22-Sep-2022 13:25:52
  End time:               22-Sep-2022 13:25:53
  Elapsed time:           1 sec
  Priority:               10
  FD Files Written:       56
  SD Files Written:       56
  FD Bytes Written:       12,044,152 (12.04 MB)
  SD Bytes Written:       12,049,525 (12.04 MB)
  Rate:                   12044.2 KB/s
  Software Compression:   None
  Comm Line Compression:  57.8% 2.4:1
  Snapshot/VSS:           no
  Encryption:             no
  Accurate:               no
  Volume name(s):         Vol-0001
  Volume Session Id:      2
  Volume Session Time:    1663852175
  Last Volume Bytes:      12,186,782 (12.18 MB)
  Non-fatal FD errors:    0
  SD Errors:              0
  FD termination status:  OK
  SD termination status:  OK
  Termination:            Backup OK

22-Sep 13:25 q556_d-dir JobId 3: Begin pruning Jobs older than 6 months .
22-Sep 13:25 q556_d-dir JobId 3: No Jobs found to prune.
22-Sep 13:25 q556_d-dir JobId 3: Begin pruning Files.
22-Sep 13:25 q556_d-dir JobId 3: No Files found to prune.
22-Sep 13:25 q556_d-dir JobId 3: End auto prune.

5 Adding an (external) client

Any client must have a Bacula File Daemon running on the system which allows to the machine to connect with the Bacula Director and the Storage Daemon.

5.1 Installing bacula-fd on a client machine

Why not Docker for external file daemons?

The fastest way to install bacula-fd on a client machine is to pull the bacularis-api-fd from Docker and run a container with the file daemon.

The disadvantage is though, that by default, such a file daemon can only see what is inside the container while we are typically interested in the data on the host which runs the container. Granting the container access to the host data comes with a lot of problems:

  • We would need to come up with some NFS stunt to (ideally) mount the client’s complete file system as a volume into the container – but exclude the Docker container files it would produce some kind of “circular reference”.
  • Even if this would work, we would have to worry about file ownership and access privileges in the backup process
  • There may be older client machines that run a 32 bit OS, while Docker generally requires 64 bit architectures. (Still, Bacula’s deb packages are only provided for 64 bit machines, too).

Direct deployment

All this looks pretty nasty, so installing the file daemon on the client machine in a direct deployment from some deb packages (or whatever installs on the client machine’s OS) looks more suitable.

The first thing is to arm the GPG key and set up the repo information on the client machine. proceed as in section 2 of my post Bacula testing installation. Once you have pulled the apt update from the new repositories, you can install bacula-fd:

ilek@x220:/media/ramdisk$ sudo apt install bacula-client

Check if the client is already running:

ilek@x220:/media/ramdisk$ sudo service bacula-fd status
● bacula-fd.service - Bacula File Daemon service
     Loaded: loaded (/lib/systemd/system/bacula-fd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-09-18 12:27:03 CEST; 1 day 13h ago
   Main PID: 1088 (bacula-fd)
      Tasks: 3 (limit: 4484)
     Memory: 960.0K
        CPU: 501ms
     CGroup: /system.slice/bacula-fd.service
             └─1088 /opt/bacula/bin/bacula-fd -fP -c /opt/bacula/etc/bacula-fd.conf

Sep 18 12:27:03 x220 systemd[1]: Started Bacula File Daemon service.

5.2 Configuration of the client

We first make sure that the client has the bacula director machine’s IP address mapped to the director machine’s host name, so we check if /etc/hosts on the client has an entry with q556 192.196.4.64.

Next, edit the config file in /opt/bacula/etc/bacula-fd.conf (you need to be root to get access to that file).

In the Director Resource, set the correct Name directive by putting in the Name of the director that runs inside the Bacularis Docker container on our main Bacula Server (which is q556 in my case).

# List Directors who are permitted to contact this File daemon
#
Director {
  Name = q556_d-dir
  Password = "YSJfJkw_X9kfEOT8oFd0LvDgdjT-VoQjo"
}

[...]

# Send all messages except skipped files back to Director
Messages {
  Name = Standard
  director = q556_d-dir = all, !skipped, !restored, !verified, !saved
}

Save and restart the client machine’s file daemon:

ilek@x220:/media/ramdisk$ sudo service bacula-fd restart
ilek@x220:/media/ramdisk$ sudo service bacula-fd status

5.3 Amending bacula-dir.conf on the Bacula director machine

Now change to the machine running the Bacula Director (our Bacularis container) and amend bacula-dir.conf as shown below. The Password directive must match the Password directive we set on the external client machine in the previous step.

# Second Client (File Services) to backup
#  You should change Name, Address, and Password before using
#
Client {
  Name = x220-fd
  Address = x220
  FDPort = 9102
  Catalog = MyCatalog
  Password = "YSJfJkw_X9kfEOT8oFd0LvDgdjT-VoQjo"        # password for FileDaemon 2
  File Retention = 60 days           # 60 days
  Job Retention = 6 months           # six months
  AutoPrune = yes                    # Prune expired Jobs/Files
}

Restart the Bacula director in the Docker container to activate the amendments:

ilek@q556:~$ docker restart bacuprod 
bacuprod
ilek@q556:~$ docker exec -it bacuprod bconsole
Connecting to Director localhost:9101
1000 OK: 10002 q556_d-dir Version: 11.0.6 (10 March 2022)
Enter a period to cancel a command.
*status client
The defined Client resources are:
     1: q556_d-fd
     2: x220-fd
Select Client (File daemon) resource (1-2): 2
Connecting to Client x220-fd at x220:9102

x220-fd Version: 13.0.1 (05 August 2022)  x86_64-pc-linux-gnu-bacula-enterprise ubuntu 22.04
Daemon started 22-Sep-22 15:58. Jobs: run=0 running=0.
 Heap: heap=966,656 smbytes=197,860 max_bytes=197,877 bufs=101 max_bufs=101
 Sizes: boffset_t=8 size_t=8 debug=0 trace=0 mode=0,0 bwlimit=0kB/s
 Crypto: fips=N/A crypto=OpenSSL 3.0.2 15 Mar 2022
 Plugin: bpipe-fd.so(2) 

Running Jobs:
Director connected using TLS at: 22-Sep-22 16:13
No Jobs running.
====

5.4 Opening and forwarding ports

Client side

On the client side, we the Bacula file daemon we installed will listen on port 9102. Use the netstat command to confirm that this port has already been opened when we installed the bacula-client package from the repository.

ilek@x220:~$ netstat -an | grep LISTEN
[..]
tcp        0      0 0.0.0.0:43457           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:43283           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:9102            0.0.0.0:*               LISTEN     
tcp        0      0 10.126.44.1:53          0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:631             0.0.0.0:*               LISTEN     
[...]

Docker host side

While Docker usually takes care of opening and forwarding all necessary ports between a container and its host, we also have to make sure that the host machine for the docker container has ports 9101-9103 opened for traffic from and to file and storage daemons.

ilek@q556:~$ sudo netstat -tulpn | grep LISTEN
[...]
tcp        0      0 0.0.0.0:9101            0.0.0.0:*               LISTEN      17542/rootlesskit   
tcp        0      0 0.0.0.0:9103            0.0.0.0:*               LISTEN      17542/rootlesskit   
tcp        0      0 0.0.0.0:9102            0.0.0.0:*               LISTEN      17542/rootlesskit   
tcp        0      0 0.0.0.0:9097            0.0.0.0:*               LISTEN      17542/rootlesskit  
[...]
tcp6       0      0 :::9101                 :::*                    LISTEN      17542/rootlesskit   
tcp6       0      0 :::9103                 :::*                    LISTEN      17542/rootlesskit   
tcp6       0      0 :::9102                 :::*                    LISTEN      17542/rootlesskit   
tcp6       0      0 :::9097                 :::*                    LISTEN      17542/rootlesskit   

After making sure that the host machine is actually accepting traffic on ports 9101-9103, we have to ensure that this traffic is actually forwarded to the Docker container.

First we check if the host machine has activated port forwarding per se. Check if the file /etc/sysctl.conf on the Docker host has the following line uncommented. Detailed instructions on principally allowing port forwarding can be found in my Bacula testing installation post.

Next we check the ufw status:

ilek@q556:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
9096                       ALLOW       Anywhere                  
9095                       ALLOW       Anywhere                  
22/tcp                     LIMIT       Anywhere                  
9097                       ALLOW       Anywhere                  
9096 (v6)                  ALLOW       Anywhere (v6)             
9095 (v6)                  ALLOW       Anywhere (v6)             
22/tcp (v6)                LIMIT       Anywhere (v6)             
9097 (v6)                  ALLOW       Anywhere (v6)             

Surprisingly, although the previous iptables command showed that the host is listening on ports 9101-9103, ufw does not list these ports under the allowed ports. We therefore allow these ports explicitly under ufw and remove ports 9095 and 9096 as these look like leftovers from a previous legacy Baculum installation:

ilek@q556:~$ sudo ufw delete allow 9095
Rule deleted
Rule deleted (v6)
ilek@q556:~$ sudo ufw delete allow 9096
Rule deleted
Rule deleted (v6)
ilek@q556:~$ sudo ufw allow 9101
Rule added
Rule added (v6)
ilek@q556:~$ sudo ufw allow 9102
Rule added
Rule added (v6)
ilek@q556:~$ sudo ufw allow 9103
Rule added
Rule added (v6)