GRE Setup for Bacula on a Mobile Client

The way Bacula works is:

  • A backup client runs a TCP server process bacula-fd, waiting for a backup server process bacula-dir to connect and perform backup and restore jobs.
  • There is a simple authentication mechanism, where bacula-dir presents a shared secret to bacula-fd to be granted access.

Opening the bacula-fd TCP server on an exposed network interface may be fine for static backup clients with dedicated storage networking towards the backup server, but on a mobile computer bacula-fd should be reachable by bacula-dir only if the computer is connected by Ethernet to the home network. Specifically, the TCP server port of bacula-fd should not be exposed on the Ethernet NIC.

To implement this, i have defined a GRE tunnel between mobile backup client and home network backup server.

Overview

A GRE interface is essentially defined by stating two IP addresses:

  • a local IP address that may be assigned to a network interface of the local node, and
  • a remote IP address assigned to a network interface of a remote node, routable via the local IP address.
Diagram

Example GRE tunnel setup

If GRE devices are defined with matching local and remote addresses on both peers, the result is a GRE network interface on each peer that in turn can be assigned addresses from some virtual network range, for example a /30 or /31 subnet.

IP traffic sent to the GRE interface IP address of the peer will be routed over the local GRE interface, and IP packages will be encapsulated as GRE packages (internet protocol 47), which means that the payload will be preprended with a GRE header when sending it from the local to the remote network interface. The GRE link has an MTU at least 24 bytes lower than the encapsulating network link: 4 bytes GRE header plus at least 20 bytes additional IP header minimum length.

Configure the GRE Tunnel

I use systemd-networkd to define the GRE link. On client and server, two files are required:

/etc/systemd/network/gre1.netdev: GRE interface definition, i.e. local and remote network IP address to use for encapsulation. The manpage systemd.netdev(5) describes all possible settings.

Client:

[NetDev]
Name=gre1
Description=GRE tunnel to backup server
Kind=gre
[Tunnel]
Local=192.168.1.2
Remote=192.168.1.1
TTL=255
Independent=true

Server:

[NetDev]
Name=gre1
Description=GRE tunnel to mobile backup client
Kind=gre
[Tunnel]
Local=192.168.1.1
Remote=192.168.1.2
TTL=255

A notable setting in the [Tunnel] section: On the client, i need to set Independent to true, because the network device is not managed by systemd-networkd but instead by NetworkManager, and if systemd-networkd does not manage the encapsulating interface, it will not configure the GRE interface automatically when the network interface becomes routable. With Independent=true, systemd-networkd will always configure the GRE interface, no matter if the local network IP address is currently assigned and/or routable or not.

/etc/systemd/network/gre1.network: Assigns IP address and netmask to the GRE interface, once it is configured. The manpage systemd.network(5) describes all possible settings.

Client:

[Match]
Type=ipgre
Name=gre1
[Network]
Address=10.0.0.2/30

Server:

[Match]
Type=ipgre
Name=gre1
[Network]
Address=10.0.0.1/30

Enable the GRE Tunnel

To make the configuration effective on client and server, make sure that systemd-networkd is enabled, running and has reloaded its configuration:

systemctl enable --now systemd-networkd
networkctl reload

To test if the setup is working:

1. On client and server, check the network link, for example with this command:

ip link show dev gre1

The output should be similar to:

6: gre1@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1476 qdisc ...
   link/gre 192.168.1.2 peer 192.168.1.1

(Note the GRE link’s MTU of 1476 bytes)

2. On client and server, check if the tunnel IP addresses have been assigned correctly, for example with this command:

ip --brief address show dev gre1

The output should be like this:

gre1@NONE UNKNOWN 10.0.0.2/30

3. Check if IP traffic is routable across the GRE interface. For example, on the client:

ping 10.0.0.1

If these tests are successful, try rebooting client and/or server to check if the setup is permanent.

Configure bacula-fd

On the backup client, in /etc/bacula/bacula-fd.conf, find the FileDaemon section and set FDAddress to the tunnel IP address:

FileDaemon {
  Name = my-client.my-network-fd
  FDport = 9102
  FDAddress = 10.0.0.2
  ...

Restart bacula-fd.service:

systemctl restart bacula-fd.service

Check that bacula-fd has opened the TCP server socket on the tunnel interface:

ss -ap 'sport 9102'

The output should be similar to:

Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp   LISTEN 0      50     10.0.0.2:bacula-fd 0.0.0.0:*         users:(("bacula-fd",pid=12345,fd=3))

Configure bacula-dir

On the backup server, edit /etc/bacula/bacula-dir.conf. Find the Client section of the backup client and change Address to the tunnel IP address of the client:

Client {
  Name = my-client.my-network-fd
  Address = 10.0.0.2
  FDPort = 9102
  ...

Restart bacula-dir.service:

systemctl restart bacula-dir.service

Facit

Subsequent backup jobs for the backup client should now automatically be performed over the GRE tunnel if it is connected.

Access by incoming traffic to 10.0.0.2 could additionally be restricted using iptables, nftables etc.

A GRE tunnel does not encrypt traffic. If encryption between backup client and server is required, using a VPN technology such as IPSEC, OpenVPN or Wireguard could be more suitable. The GRE tunnel could also be used to establish an ssh port redirection, an stunnel connection or something similar.

The GRE device gre1 stays configured on the client even if the client is not connected to the Ethernet. I find this acceptable, because my primary goal, to not have the bacula-fd port opened on an exposed network interface, is reached.