Agentless backup over SFTP/SSH, zero deployment on the remote host, support for network equipment (Cisco/Juniper/MikroTik/…), NAS (Synology/QNAP/TrueNAS), cloud SFTP (AWS Transfer, Hetzner Storage Box), and cloud VMs. Replaces fragile SSHFS/NFS/CIFS mountpoints with stateless per-job SFTP connections.
Companion document to the PodHeitor SFTP plugin page.
1. The problem: SSHFS/NFS/CIFS mountpoints are fragile
The traditional “remote backup without a Bacula agent” pattern is to mount the remote filesystem via SSHFS/NFS/CIFS on the FD host. That sounds simple but fails in the field in many ways:
| Mountpoint problem | SFTP advantage |
|---|---|
| SSHFS/NFS/CIFS mounts go stale → backups fail silently | SFTP opens a fresh connection per job — no stale state |
| Mount requires FUSE or a kernel module on the FD host | SFTP/SSH is pure userspace (Rust ssh2 / libssh2) — no kernel deps |
Credentials stored in /etc/fstab or systemd mount files |
Credentials live in Bacula config, encrypted at rest |
| Mount exposes the entire filesystem to the FD host | SFTP scopes access to path — no local mount surface |
| NFS/CIFS firewalling is complex (portmapper, SMB ports) | SFTP/SSH = single TCP port (22), easily firewalled |
| Stale mounts block the FD process (hung stat calls) | SFTP timeout is per-operation — never blocks the daemon |
| Network devices (switches, routers, firewalls) can’t be mounted | SFTP/SSH is native on network equipment |
| Cloud SFTP services (AWS Transfer, Hetzner Storage Box) | Direct SFTP connection — no mount layer |
2. Architectural model
┌──────────────┐ PTCOMM protocol ┌──────────────────────────┐
│ Bacula FD │◄═══════════════════════► │ podheitor-sftp-backend │
│ │ (stdin/stdout) │ (Rust + libssh2) │
│ loads .so: │ │ │
│ podheitor- │ Handshake → Job Info │ connect() → walk() → │
│ sftp-fd.so │ → Params → Start → │ FNAME/STAT/DATA → │
│ (Rust cdylib,│ ← file data ← │ include/exclude filter │
│ metaplugin- │ │ │
│ rs) │ │ │
└──────────────┘ └──────────────────────────┘
Same PodHeitor cdylib + backend architecture. The backend hosts the SFTP client (libssh2 via Rust ssh2), recursively walks the remote path, and streams metadata + data over PTCOMM. No intermediate disk; the FD receives bytes directly.
3. Features
- Agentless — SFTP/SSH only, no software on remote hosts
- Full / Incremental / Differential — native Bacula levels via mtime comparison
- Include/exclude filters — glob-based (
*.pdf,*.tmp) for files and directories - Metadata preserved — permissions, UID/GID, timestamps, symlinks
- Authentication — SSH key (ed25519, RSA, ECDSA), agent forwarding, password
- Host key verification — MITM protection via known_hosts
- File listing —
estimate(pre-backup), catalog queries, restore tree browsing - Multiple sources — N SFTP servers in a single FileSet
- Compression & Encryption — Bacula’s native LZ4/GZIP + AES
4. Documented use cases
4.1 Network equipment
| Vendor | Models / OS |
|---|---|
| Cisco | Catalyst 9000 (IOS-XE), Nexus (NX-OS), ISR/ASR |
| Juniper | EX, QFX, SRX, MX (Junos) |
| MikroTik | All RouterOS devices |
| Arista | 7000, 7500 series (EOS) |
| HPE Aruba | CX switches, Instant AP |
| Dell | PowerSwitch (OS10) |
| Fortinet | FortiGate (FortiOS) |
| Palo Alto | PA series (PAN-OS) |
| Ubiquiti | UniFi, EdgeRouter |
| Others | VyOS, OPNsense, pfSense |
4.2 NAS and Storage
| Synology DiskStation | SFTP/SSH built-in (DSM) |
| QNAP | SFTP/SSH built-in (QTS) |
| TrueNAS / FreeNAS | SFTP/SSH built-in |
| Asustor, TerraMaster | SFTP/SSH available |
4.3 Cloud SFTP services
| AWS Transfer Family | Managed SFTP endpoint |
| Azure Blob Storage | SFTP access (preview/GA) |
| Hetzner Storage Box | Native SFTP/SSH (port 23) |
| Files.com, ExaVault, GoAnywhere MFT | Enterprise SFTP |
4.4 Cloud VMs and hosting
AWS EC2, GCP Compute, Azure VMs, DigitalOcean, Linode, Vultr, Hetzner Cloud, OVH; cPanel/WHM, Plesk, DirectAdmin — any hosting with SFTP/SSH.
4.5 Embedded and IoT
Raspberry Pi, IoT gateways — lightweight backup without mount overhead. Devices with limited storage — no FUSE/mount layer required.
5. Plugin parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
host |
yes | — | SFTP server hostname or IP |
port |
no | 22 |
SFTP port |
user |
yes | — | SFTP username |
password |
no | — | SFTP password (prefer keyfile) |
keyfile |
no | — | Path to private key |
passphrase |
no | — | Key passphrase |
path |
yes | / |
Remote base directory |
known_hosts |
no | — | Path to known_hosts |
verify_host |
no | yes |
Verify host key |
timeout |
no | 30 |
Connection timeout (seconds) |
include |
no | — | Include glob patterns (e.g. *.pdf,*.doc) |
exclude |
no | — | Exclude glob patterns (e.g. *.tmp,*.log) |
abort_on_error |
no | no |
Abort job on read error |
6. Quick start
# 1. Prepare key for SFTP access
sudo mkdir -p /etc/bacula/.ssh
sudo ssh-keygen -t ed25519 -f /etc/bacula/.ssh/id_ed25519 -N ""
sudo ssh-copy-id -i /etc/bacula/.ssh/id_ed25519.pub [email protected]
# 2. Configure FileSet
FileSet {
Name = "SFTP-Backup"
Include {
Options { Signature = SHA256; Compression = LZ4 }
Plugin = "podheitor-sftp: host=server.local user=backup keyfile=/etc/bacula/.ssh/id_ed25519 path=/data"
}
}
Job {
Name = "SFTP-Daily"
Type = Backup
Level = Incremental
FileSet = "SFTP-Backup"
Client = myserver-fd
Storage = File1
Pool = Default
Schedule = "WeeklyCycle"
}
7. Include/exclude examples and multi-source
# PDFs and Office docs only
Plugin = "podheitor-sftp: host=server user=backup path=/data include=*.pdf,*.docx,*.xlsx"
# Skip temp and cache
Plugin = "podheitor-sftp: host=server user=backup path=/data exclude=*.tmp,*.cache,*.log"
# Network switch — configs only
Plugin = "podheitor-sftp: host=10.0.0.1 user=admin path=/ include=*.conf,*.cfg verify_host=no"
# MikroTik — backup and export files
Plugin = "podheitor-sftp: host=10.0.0.3 user=admin path=/ include=*.backup,*.rsc verify_host=no"
Multi-source in a single FileSet:
FileSet {
Name = "AllServers"
Include {
Options { Signature = SHA256; Compression = LZ4 }
Plugin = "podheitor-sftp: host=web1.prod user=deploy keyfile=/etc/bacula/.ssh/key path=/var/www exclude=*.log"
Plugin = "podheitor-sftp: host=web2.prod user=deploy keyfile=/etc/bacula/.ssh/key path=/var/www exclude=*.log"
Plugin = "podheitor-sftp: host=nas.local user=admin keyfile=/etc/bacula/.ssh/key path=/volume1/shared"
Plugin = "podheitor-sftp: host=switch-core user=admin keyfile=/etc/bacula/.ssh/key path=/ include=*.conf verify_host=no"
}
}
8. Restore
Restore operates in the @sftp/host:port/path namespace:
bconsole
* restore where=/tmp/sftp-restore select all done yes
9. Requirements
| Component | Minimum | Notes |
|---|---|---|
| Bacula Community | 13.0.0+ | Metaplugin framework required |
| libssh2 / openssl | system | Runtime libs (system packages) |
| Remote host | SFTP/SSH access | No agent |
10. License posture
Proprietary — LicenseRef-PodHeitor-Proprietary (both the FD-side .so and the backend binary). No statically-linked third-party code in this product is AGPL or any other copyleft. Transitive Rust dependencies (ssh2, libssh2-sys, libc, parking_lot, openssl-sys) are all MIT / Apache-2.0.
Ready to evaluate?
30-day free trial for qualified SFTP deployments (network equipment, NAS, cloud, embedded). We guarantee at least 50% off vs Bacula Enterprise, Veeam, or Commvault, with more features — including pure agentless without the fragile mountpoint the competitor forces.
Heitor Faria — Founder, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 PodHeitor SFTP plugin page
Disponível em:
Português (Portuguese (Brazil))
English
Español (Spanish)