FTP backup uploads failing with “Permission denied”?
Searched every forum and almost given up? If your Hestia FTP
backup uploads keep failing with “Permission denied,” this guide covers the
AppArmor fix that finally worked for us.
The backup archive was created correctly. The remote FTP upload failed.
The missing piece was a capability permission in AppArmor’s
tnftp profile.
The error we found
The kernel log showed these AppArmor denials:
apparmor="DENIED" operation="capable" profile="tnftp"
comm="ftp" capname="dac_read_search"
apparmor="DENIED" operation="capable" profile="tnftp"
comm="ftp" capname="dac_override"
The local backup file looked like this:
drwxr-xr-x root root /backup
-rw-r----- hestiaweb backupgroup /backup/example.2026-11-08_03-40-24.tar
AppArmor already allowed reading the backup directory:
/backup/ r,
/backup/** r,
Yet the upload still failed. Adding
capability dac_read_search, to the local profile override solved
the problem with AppArmor enabled.
Why a read rule wasn’t enough
| Permission | What it does |
|---|---|
/backup/** r, |
Allows reading those paths under AppArmor’s file policy. |
capability dac_read_search, |
Allows the process to use an existing Linux capability to bypass ordinary file-read and directory-search restrictions. |
The archive’s 640 permissions normally allow reads only by
its owner and group. A privileged uploader running under another identity
may need a capability to read it. AppArmor can block that capability even
when the file path itself is allowed.
An AppArmor rule does not grant a Linux capability that the process lacks.
This fix addresses AppArmor blocking an otherwise available capability.
1. Confirm the AppArmor denial
Keep AppArmor enabled, retry one failed backup upload, then inspect recent events:
sudo journalctl -k --since "5 minutes ago" --no-pager | grep 'profile="tnftp"'
Check the actual archive path and permissions:
sudo namei -l /backup/example.2026-11-08_03-40-24.tar
Replace the example filename with your backup. The relevant events must
name profile="tnftp". Denials for Exim or another program need
their own investigation.
2. Check the profile’s local include
sudo grep -n 'local/tnftp' /etc/apparmor.d/tnftp
In our installed profile, the following line appears inside the main
tnftp profile:
include if exists <local/tnftp>
This means we can put the fix in
/etc/apparmor.d/local/tnftp without editing the packaged profile.
If your profile lacks this include, inspect its structure before proceeding.
3. Update the local override
If the local file already exists, make a timestamped backup:
sudo cp -a /etc/apparmor.d/local/tnftp "/etc/apparmor.d/local/tnftp.bak.$(date +%Y%m%d-%H%M%S)"
Open or create the local override:
sudo nano /etc/apparmor.d/local/tnftp
Preserve existing rules. Ensure these entries appear once:
# Allow the privileged FTP backup uploader to read local archives.
capability dac_read_search,
/backup/ r,
/backup/** r,
If archives are always directly inside /backup/ and end in
.tar, you can narrow the recursive rule to:
/backup/*.tar r,
4. Reload the profile
Reload the parent profile so it reads the local override:
sudo apparmor_parser -r /etc/apparmor.d/tnftp
sudo aa-status
Check for reload errors and confirm tnftp is in enforce mode.
If you previously unloaded all AppArmor profiles during testing, restore them:
sudo systemctl restart apparmor
sudo aa-status
5. Retry and verify the backup
Run another backup upload. Confirm that the remote archive exists and its
size matches the local archive. Where possible, compare checksums or test
the downloaded archive as well.
If it fails, inspect fresh events:
sudo journalctl -k --since "5 minutes ago" --no-pager | grep 'profile="tnftp"'
Old denials remain in the logs after the fix. Check timestamps against
your new attempt.
If the upload still fails
- A file-access denial appears: inspect the exact path and requested access before adding another rule.
- A capability denial remains: verify the profile reload succeeded, then check the uploader’s effective user and capabilities.
- An explicit deny matches: inspect the profile and its abstractions; an ordinary allow rule may not override it.
- No relevant denial appears: investigate the FTP response, credentials, remote permissions, quota, and connection.
How to undo the change
Edit the local override and remove only the lines added for this fix.
Preserve any pre-existing rules, then reload:
sudo nano /etc/apparmor.d/local/tnftp
sudo apparmor_parser -r /etc/apparmor.d/tnftp
Alternatively, restore the timestamped backup you created before editing
and reload the parent profile.
Why wasn’t this allowed by default?
The supplied profile primarily covers an FTP client accessing user-owned
files. Hestia’s privileged backup uploader reading archives owned by
hestiaweb is a different workflow. Our results point to a mismatch
between that workflow and the installed policy.
The local override resolved the upload failure without making the archives
publicly readable or leaving AppArmor disabled.

