xFTP Server - TFTP, FTP, and SFTP for Network Device File Transfers
xFTP Server: Secure File Transfer for Network Devices
Section titled “xFTP Server: Secure File Transfer for Network Devices”After reading this page, I can deploy and configure the rConfig xFTP server, choose the right protocol (TFTP, FTP, or SFTP) for my devices, and set up automated file uploads with device-matched processing and retention policies.
How xFTP works
Section titled “How xFTP works”Network devices upload files via TFTP, FTP, or SFTP into a shared inbox directory (/srv/xftp/). A scheduled sweeper then moves matched files into each device’s xftpuploads/ directory and records the lifecycle in the xftp_uploads database table.
Protocols
Section titled “Protocols”| Protocol | Port | Auth | Encryption | When to use |
|---|---|---|---|---|
| TFTP | 69 (UDP) | None | None | Legacy or isolated environments |
| FTP | 21 (TCP) | Username + password | None | Devices lacking SFTP support |
| SFTP/SCP | Configurable (e.g. 2222) | Username + password | SSH | Production and sensitive data |
Directory layout
Section titled “Directory layout”- Inbox (raw uploads):
/srv/xftp/ - Processed device storage (moved files):
/var/www/html/rconfig8/storage/app/rconfig/data/<Category>/<device-name>/xftpuploads/Stored file names
Section titled “Stored file names”The sweep adds the time of the move (hour and minute) to each file name, before the extension. Characters other than letters, digits, dots, hyphens and underscores are removed. If that name already exists in the device folder, a full date and time is added as well:
| Uploaded file | Stored as |
|---|---|
router1-confg.cfg |
router1-confg-1527.cfg |
router1-confg.cfg again, same minute |
router1-confg-1527.20261103152744.cfg |
EDF-GRID_2026_10_29_00_35.tar.gz |
EDF-GRID_2026_10_29_00_35-1527.tar.gz |
From V8.4.1, compound extensions (.tar.gz, .tar.bz2, .tar.xz, .tar.zst) are kept whole and underscores are kept. Earlier versions stored the last example as EDF-GRID202610290035.tar-1527.gz, which appliances such as Infoblox NIOS refuse to restore. The file content was never changed: rename an older file to end in .tar.gz and it restores normally.
Folder permissions
Section titled “Folder permissions”From V8.4.1 the inbox is not open to every local user. The folder (/srv/xftp by default) belongs to root and a shared group with gid 2000, with mode 2770:
| Item | Value |
|---|---|
| Folder owner and group | root, and the gid 2000 group: rconfigxftp, or rconfigxftpusr on older installs |
| Folder mode | 2770 (drwxrws---). The setgid bit gives new files and folders the same group. |
| How the containers write | As uid and gid 2000 with umask 007, so uploads are 0660 and new folders 2770 |
| Who can read the uploads | Members of the group. The rConfig web user (apache on RHEL, Rocky and Alma, www-data on Ubuntu) is added to it, so the sweep can read, move and delete uploads. Other local users cannot see into the folder. |
| Container entrypoints | Root-owned scripts in /usr/local/libexec/rconfig/xftp/, mounted read-only into each container |
A few things follow from this layout:
- TFTP only serves world-readable files. Uploads are
0660, so a TFTP client can never download a config another device uploaded. - Symlinks are never followed. The sweep skips a symlinked file, or a file under a symlinked folder, and logs a warning. The File Directory viewer refuses to open one. An SFTP user can create a symlink, so remove any you did not make.
- Files keep owner uid 2000. If uid 2000 belongs to a real user on the host, that user owns the uploads. Check with
getent passwd 2000.
Installs upgraded from an earlier version keep the old, world-writable folder until the containers are recreated. See Upgrading from an earlier version.
Scheduled sweep
Section titled “Scheduled sweep”The xFTP Directory Sweep scheduled task runs at minute 0 and 15 of every hour and moves matched inbox files to device storage. It runs this command:
php artisan rconfig:sweep-xftp-dirTo trigger a sweep manually, run it as the web server user so the moved files stay owned by that user:
cd /var/www/html/rconfig8/currentsudo -u apache php artisan rconfig:sweep-xftp-dir # Ubuntu: sudo -u www-dataWhen to use xFTP
Section titled “When to use xFTP”Use xFTP when devices need to push non-configuration files, binary data, firmware images, or archive content to rConfig for centralised storage. If you need only configuration backups, use the standard backup workflow instead.
Prerequisites
Section titled “Prerequisites”- Docker installed on the rConfig server, with the
dockercommand at/usr/bin/dockeror/usr/local/bin/docker(the setup wizard can install it automatically) - Shell access with
sudo.rconfig:xftp-toggleandrconfig:xftp-install-helpermust run as root. - Network firewall rules open for the protocol ports you plan to use (69/UDP, 21/TCP, and/or your chosen SFTP port)
- rConfig V8 installed on bare metal or a VM. When rConfig itself runs in Docker, the xFTP page shows a Docker warning instead.
- Admin access to Settings in the rConfig UI
Managing xFTP services
Section titled “Managing xFTP services”Manage xFTP Docker microservices through the UI or CLI.
Web interface: Navigate to Platform → Network Services → XFTP
The page reads container status through the Docker helper. Starting and stopping services is done on the server, with sudo.
CLI:
cd /var/www/html/rconfig8/currentsudo php artisan rconfig:xftp-toggleFrom V8.4.1 the command refuses to run without root:
❕ rconfig:xftp-toggle manages Docker containers and must run as root. Run: sudo php artisan rconfig:xftp-toggleCheck service status at any time:
sudo php artisan rconfig:xftp-toggle --status--status creates the xFTP folder if it is missing, makes sure the xFTP Directory Sweep scheduled task exists, then lists every container with docker ps -a.
| Option | What it does |
|---|---|
| (none) | Interactive menu: add, update or remove the FTP, SFTP/SCP or TFTP service, or view containers |
--status |
Creates the folder and sweep task if missing, then lists the containers |
--fix-permissions |
Locks the xFTP folder down and fixes the group and modes of existing files. See Upgrading from an earlier version. |
--dockercommands |
Prints useful Docker commands. The only option that does not need root. |
Docker helper
Section titled “Docker helper”The web server user never talks to Docker directly. From V8.4.1, the xFTP page reads container status through a small root-owned helper, which the web user may run through sudo for two read-only actions:
| Item | Path |
|---|---|
| Helper | /usr/local/libexec/rconfig/rconfig-xftp-docker, root:root 0755 |
| Actions allowed | status (lists the rconfig-ftp, rconfig-sftp and rconfig-tftp containers) and ping (checks that Docker answers). Anything else is refused. |
| Sudo rule | /etc/sudoers.d/rconfig-xftp, root:root 0440, allowing only those two actions |
| Container entrypoints | /usr/local/libexec/rconfig/xftp/ftp-entrypoint.sh, sftp-entrypoint.sh and tftp-entrypoint.sh |
The deploy script installs the helper on every upgrade. To install or repair it by hand:
cd /var/www/html/rconfig8/currentsudo php artisan rconfig:xftp-install-helperIt is safe to run again. In order, it:
- Installs the helper and the container entrypoints.
- Writes the sudo rule, checks it with
visudo -cfirst, and installs nothing ifvisudorejects it. - Creates the
rconfigxftpgroup with gid 2000 if no group has that gid, and adds the web user to the gid 2000 group. - Puts the Docker socket back to
0660if any local user could reach it:Docker socket was 0666 (accessible to every local user). Reset it to 0660. - Warns if the web user is in the
dockergroup. It does not remove it. - Removes world-write from the legacy TFTP folders
/srv/tftpand/var/lib/tftpboot, if they exist.
If Docker is not installed, it prints Docker is not installed, so the xFTP Docker helper was not installed. Run this command again after installing Docker. and installs nothing.
When it adds the web user to the group, restart the web server (httpd or apache2, and php-fpm) and Horizon so they pick up the new group.
Checking the helper on System Optimization
Section titled “Checking the helper on System Optimization”Settings → System Optimization shows two rows for xFTP under Security & privileges, when Docker is installed on the server and rConfig does not run in Docker:
| Row | Message | Fix |
|---|---|---|
| xFTP Docker helper | The xFTP Docker helper /usr/local/libexec/rconfig/rconfig-xftp-docker is not installed, so the xFTP page cannot read the container status. |
sudo php artisan rconfig:xftp-install-helper |
| xFTP Docker helper | The xFTP Docker helper is installed but could not reach Docker. |
Check that Docker is running (sudo systemctl status docker), then run sudo php artisan rconfig:xftp-install-helper |
| xFTP Docker helper | Docker did not answer the helper within 5 seconds. (TIMED OUT) |
Refresh the page. If it keeps timing out, check Docker, then run the install helper |
| Docker socket | /var/run/docker.sock is 0666, so every local user can control Docker, which is the same as root. |
sudo php artisan rconfig:xftp-install-helper |
| Docker socket | The web user apache is in the docker group, which gives it root-equivalent access. rConfig no longer needs this. |
sudo gpasswd -d apache docker (www-data on Ubuntu) |
The xFTP page shows the same helper problem as an alert, with the fix to run.
Remove the web user from the docker group
Section titled “Remove the web user from the docker group”Older guides told admins to add the web user to the docker group so the xFTP page could read container status. Membership of that group is the same as root, and rConfig no longer needs it. If you added it by hand, remove it, then restart the web server, php-fpm and Horizon:
# RHEL, Rocky, Almasudo gpasswd -d apache docker
# Ubuntusudo gpasswd -d www-data dockerCheck the result with id apache (or id www-data): docker should no longer be listed.
Upgrading from an earlier version
Section titled “Upgrading from an earlier version”Containers created before V8.4.1 write as different users and need a world-writable folder, so the upgrade leaves /srv/xftp as it was. Until you recreate them, old containers keep working, and each run of rconfig:xftp-toggle warns:
❕ /srv/xftp is open to every local user. Recreate the running xFTP containers, then run: sudo php artisan rconfig:xftp-toggle --fix-permissionsThe deploy script runs rconfig:xftp-toggle --fix-permissions for you, but while old containers remain it changes nothing and the deploy only warns. To finish the move:
-
Recreate each running service. Run the toggle, choose the service and stop it, then run the toggle again and start it:
Terminal window cd /var/www/html/rconfig8/currentsudo php artisan rconfig:xftp-toggleTo keep the saved FTP or SFTP credentials, answer No to
FTP Creds were previously configured, do you wish to update/ override them??(SFTP shows the same wording). SFTP also asks again for the optional SSH public key path, which is not saved. TFTP has no credentials. -
Lock the folder down.
Terminal window sudo php artisan rconfig:xftp-toggle --fix-permissionsIt runs the Docker helper install first, then sets the folder to
root:<group> 2770and fixes the group and modes of every existing file and folder. It keeps file owners. On success it prints:/srv/xftp is now root:rconfigxftp, mode 2770. Fixed 12 file(s) and 3 folder(s).It skips symlinks and special files and lists each one:
Skipped <path> (a symlink or special file). It was left as it is and the sweep ignores it. Check it and remove it if you did not create it. -
Restart the web server,
php-fpmand Horizon if the web user was only just added to the group.
If any container from an older version remains, running or stopped, --fix-permissions leaves the folder unchanged, lists the containers to recreate, and exits 1:
❕ These xFTP containers were started by an older rConfig version and still need world access to /srv/xftp: rconfig-ftp /srv/xftp was not changed. Recreate each of them, then run this command again: 1. sudo php artisan rconfig:xftp-toggle, pick the service and stop it. 2. Run it again and start the service. The saved credentials are reused. 3. sudo php artisan rconfig:xftp-toggle --fix-permissionsIt still runs the install helper first, so the helper, sudo rule, group and Docker socket are fixed even when the folder is not.
If gid 2000 belongs to another group
Section titled “If gid 2000 belongs to another group”xFTP containers write as gid 2000. If another group on the server already uses that gid, the install helper does not add the web user to it and exits 1:
❕ Host gid 2000 belongs to the group "<name>", which rConfig did not create. The web user was not added to it.xFTP containers write as gid 2000. Move that group to another gid, then run this command again.The deploy script reports this as a warning and carries on. Until it is fixed, --fix-permissions refuses to change the folder, and starting a service fails if the folder does not exist yet. Move the other group to a free gid (sudo groupmod -g <new gid> <name>, then fix any files it owned), and run:
sudo php artisan rconfig:xftp-install-helpersudo php artisan rconfig:xftp-toggle --fix-permissionsLegacy host TFTP
Section titled “Legacy host TFTP”Before the Docker xFTP services, rConfig could install a TFTP server directly on the host (tftpd-hpa on Ubuntu, tftp-server on RHEL family systems). It is deprecated: rconfig:tftp-server on no longer installs anything. If an older install still runs it, turn it off and use the xFTP TFTP service instead:
sudo php artisan rconfig:tftp-server offThe xFTP install helper removes world-write from the legacy folders /srv/tftp and /var/lib/tftpboot and prints The legacy host TFTP service is deprecated.
Deploying xFTP services
Section titled “Deploying xFTP services”Run the interactive toggle command and choose which protocol to deploy:
sudo php artisan rconfig:xftp-toggleTFTP service deployment
Section titled “TFTP service deployment”TFTP provides basic file transfer without authentication. Suitable for legacy devices and isolated environments.
-
Run
sudo php artisan rconfig:xftp-toggleand choose TFTP from the protocol list.
-
Docker pulls the TFTP image on first deployment.
-
The TFTP container starts automatically.
-
Verify the service shows TFTP running on port 69.
Default configuration: port 69 (UDP), no authentication, upload directory /srv/xftp/. Any device with network access to the rConfig server can upload files.
To stop: run sudo php artisan rconfig:xftp-toggle, select TFTP, and confirm removal. Files already in /srv/xftp/ or device storage are not deleted.
FTP service deployment
Section titled “FTP service deployment”FTP provides authenticated file transfer with credential-based access.
-
Run
sudo php artisan rconfig:xftp-toggleand choose FTP.
-
Enter the FTP username and password when prompted.
-
Docker pulls the FTP image on first deployment.
-
The FTP container starts with the configured credentials.
-
Verify the service shows FTP running on port 21.
Default configuration: port 21 (TCP), username and password authentication, active and passive transfer modes, upload directory /srv/xftp/.
Credential storage: FTP credentials are stored in .env (SERVICE_FTP_USER and SERVICE_FTP_PASS) and referenced in device commands using {ftpusername} and {ftppassword}. When redeploying, the wizard asks whether to override the saved credentials; answer No to reuse them.
To stop: run sudo php artisan rconfig:xftp-toggle, select FTP, and confirm removal. Credentials in .env are preserved.
SFTP/SCP service deployment
Section titled “SFTP/SCP service deployment”SFTP provides encrypted, authenticated file transfer over SSH. Use for production environments and sensitive data.
-
Run
sudo php artisan rconfig:xftp-toggleand choose SFTP.
-
Enter the SFTP port. It must not conflict with host SSH on port 22; 2222 is a common choice.
-
Enter the SFTP username and password.
-
Docker pulls the SFTP image on first deployment.
-
The SFTP container starts with the configured port and credentials.
-
Verify the service shows SFTP running on your chosen port.
Default configuration: port configurable (recommended 2222, cannot be 22), SSH/TCP encryption, username and password authentication, upload directory /srv/xftp/. The same container handles both SFTP and SCP connections.
SFTP vs SCP: SFTP is preferred for modern devices and supports directory listing and resumable transfers. SCP is simpler and suits legacy devices and scripting.
Connection syntax:
# SFTPsftp -P 2222 username@rconfig-server-ip
# SCPscp -P 2222 localfile.txt username@rconfig-server-ip:/remote/path/To stop: run sudo php artisan rconfig:xftp-toggle, select SFTP, and confirm removal. Credentials and port settings in .env are preserved.
Uploading files from devices
Section titled “Uploading files from devices”File naming and device ID
Section titled “File naming and device ID”For rConfig to associate an uploaded file with a device, the filename must include the device ID before a dash:
{deviceid}-filename.extValid patterns:
tftp://192.168.1.131/{deviceid}-vlan.datftp://server/{deviceid}-config.logsftp://server/{deviceid}-firmware.bin
Invalid patterns:
tftp://192.168.1.131/vlan-{deviceid}.dat(device ID not before the dash)ftp://server/{deviceid}config.log(no dash separator)
Find the device ID in the rConfig UI on the device list or device detail page. It is also available in the devices table (id column) and is automatically substituted when you use the {deviceid} variable in commands.
Manual upload examples
Section titled “Manual upload examples”TFTP (Cisco IOS):
Router(config)#file prompt quietRouter#copy vlan.dat tftp://192.168.1.131/1234-vlan.datFTP (Cisco IOS):
Router#copy vlan.dat ftp://ftpuser:ftppass@192.168.1.131/1234-vlan.datUsing credential variables (recommended):
Router#copy vlan.dat ftp://{ftpusername}:{ftppassword}@192.168.1.131/{deviceid}-vlan.datSFTP (Cisco IOS):
Router#copy vlan.dat sftp://sftpuser:sftppass@192.168.1.131:2222/1234-vlan.datUsing credential variables:
Router#copy vlan.dat sftp://{sftpusername}:{sftppassword}@192.168.1.131:2222/{deviceid}-vlan.datAutomated uploads via command categories
Section titled “Automated uploads via command categories”Incorporate upload commands into rConfig command categories so files transfer automatically during device polling.
-
Navigate to Settings → Commands in the rConfig UI.
-
Create or open the command category used by the target devices.
-
Add the upload command with variables:
Terminal window copy vlan.dat tftp://192.168.1.131/{deviceid}-vlan.dat -
Assign the category to the relevant devices.
-
When rConfig runs a backup, the upload command executes automatically.
xFTP-only devices (inbound-only connectivity)
Section titled “xFTP-only devices (inbound-only connectivity)”A device can use inbound-only configuration collection: it pushes its configuration to xFTP instead of waiting for rConfig to retrieve it. rConfig skips the normal outbound SSH, Telnet, script, or TL1 download session for that device. This is the opposite direction from the pull-based protocols covered in Device Connectivity & Backup, and it’s useful for devices that only support pushing files out, or that sit somewhere rConfig can’t initiate a session to.
Enabling it
Section titled “Enabling it”There’s no device-level toggle or database flag for this. The connect.protocol value in the assigned connection template is the source of truth:
-
Open Inventory → Templates and use the built-in xFTP Inbound Only - No Outbound Connection template. Alternatively, create or edit a template and set its
connect:block as follows:This template also ships ready-made in the xFTP templates folder in our templates repository.# rConfig connection template## Edition: pro## Status: untested-starter## Tested-on: rConfig V8## Docs: https://docs.rconfig.com/device-management/connection-templates/## Community: https://github.com/rconfig/rConfig-templates## Note: all free-text values must be wrapped in double quotes " "main:name: 'XFTP Inbound Only - No Outbound Connection' # For devices that push their config into rConfig via xFTPdesc: 'Marks a device as XFTP-only (inbound). rConfig never connects out to it; config arrives via an xFTP upload and reachability comes from ping.'connect:timeout: 30 # Unused: no outbound connection is ever attempted for this protocol# xftp is the canonical inbound-only protocol value from rConfig Pro V8.3.2 onwards.# Releases before V8.3.2 accept only ftp, which stays accepted for templates already# in the field.protocol: xftp # Inbound-only device: skips SSH/Telnet/script/tl1 outbound connection entirelyport: 21 # Unused: no outbound connection is ever attempted for this protocol -
Save the template and assign it to the device through the normal template assignment workflow.
-
Configure the device to push its configuration to xFTP. Ensure the uploaded filename contains its rConfig device ID or matches an enabled file matching pattern.
The reference template ships at storage/app/rconfig/templates/xftp-inbound-only.yml, alongside built-in templates such as ios-ssh-noenable.yml. The value must appear under connect:; a template name containing “xFTP” does not make a device inbound-only. Because rConfig does not start a CLI download session for this protocol, SSH/Telnet authentication, prompt, and command settings do not participate in configuration collection.
rConfig flags inbound-only status wherever templates or devices are listed: a small xFTP icon with an “xFTP-only (inbound) device” tooltip appears next to the template in Inventory → Templates and next to the device in the device list and device pickers. Use the xFTP filter button on the device list to show only inbound-only devices.
What happens during download runs
Section titled “What happens during download runs”xFTP-only devices are omitted from task, tag, category, and device outbound-download selections. If an xFTP-only record reaches the download service by another path, rConfig stops before creating the outbound connection.
As a result, a skipped outbound run:
- does not attempt SSH, Telnet, script, or TL1 configuration collection;
- does not change the device to Config Failed (
STATUS_CONFIG_FAILED); and - does not send the database or email connection-failure notifications used for failed outbound downloads.
Changing an existing device to inbound-only requires assigning a template whose connect.protocol is xftp (or ftp). Changing the template back to an outbound protocol restores the normal download behaviour; no device column or UI flag needs to be changed.
Status lifecycle and reachability
Section titled “Status lifecycle and reachability”An xFTP-only device is tracked with two related signals:
- Ping reachability: rConfig queues an ICMP reachability check for enabled xFTP-only devices every 15 minutes. A successful ping sets the device to Reachable; a failed ping sets it to Unreachable. The queue worker and scheduler must be running for these periodic checks to execute.
- Inbound arrival: when the xFTP sweeper successfully matches and moves an uploaded file into the device’s storage, it sets the device to Reachable and updates
last_seen. Use the device’s xFTP upload history to confirm that configuration delivery is current.
No separate xFTP-only status is introduced. The latest completed ping or successful inbound upload determines the displayed reachable/unreachable state, so these signals can appear to disagree with upload history:
- A device can show Reachable (ping succeeds) with no uploads recorded yet, for example before its first scheduled push, or if the push command on the device itself is broken.
- A device can show Unreachable after a successful upload if a later scheduled ping fails because ICMP is blocked. The successful upload remains in its history and its arrival time remains available through
last_seen.
Ping status alone doesn’t confirm the push pipeline is working, and a blocked ping doesn’t mean uploads have stopped. Check the device’s upload history when in doubt. If uploads aren’t appearing at all, work through Files not appearing on the device page below. See Basic Connectivity Verification for general ping diagnostics.
File matching patterns (V8.1.2+)
Section titled “File matching patterns (V8.1.2+)”When filenames do not contain a numeric device ID, use pattern-based routing to map uploads to devices.
Where: Platform → Network Services → XFTP → File Matching Rules tab
Pattern types: regex, prefix, suffix, contains, exact
Rule precedence: First match wins (ordered by pattern ID). If no rule matches, rConfig falls back to legacy ID extraction from the filename.
Viewing and managing uploaded files (V8.1.2+)
Section titled “Viewing and managing uploaded files (V8.1.2+)”File Directory (raw /srv/xftp/ inbox)
Section titled “File Directory (raw /srv/xftp/ inbox)”Navigate to Platform → Network Services → XFTP → File Directory tab to see files physically present in /srv/xftp/ that are awaiting the sweep or were not yet matched to a device.
The table columns are: File name, Type, Device ID, File Size, Created, Action. rConfig infers file type (text, binary, archive) automatically.
Available actions per file: Download, Copy path, Peek (eye icon, text only, capped at 1 MB), Metadata info (info icon), Delete. Symlinks are never opened. A Delete all files button clears the entire inbox.
Device view: processed uploads
Section titled “Device view: processed uploads”Navigate to Devices → [Device Name] and scroll to the uploaded files section.
The table shows a paginated, database-backed history of moved files. Actions are the same as the File Directory: download, copy path, peek (text only), metadata info, and delete.
Click View All to access the full file management interface.
Backfilling upload tracking (V8.1.2+)
Section titled “Backfilling upload tracking (V8.1.2+)”If you upgraded and already have files on disk without tracking rows, populate xftp_uploads from the filesystem:
php artisan rconfig:xftp-backfill-uploads
# Dry run (no changes made)php artisan rconfig:xftp-backfill-uploads --dry-run
# Limit scanned files (0 = unlimited)php artisan rconfig:xftp-backfill-uploads --limit=1000Retention and auto-cleanup (V8.1.2+)
Section titled “Retention and auto-cleanup (V8.1.2+)”xFTP retention integrates with the existing purge framework (settings_purge).
Targets:
| Target | Covers | Default retention |
|---|---|---|
xftp_root |
Tracked inbox files (/srv/xftp/) |
30 days |
xftp_device_uploads |
Tracked moved device uploads | 90 days |
Run via CLI:
# Run all purge targetsphp artisan rconfig:data-purge
# Run only xFTP targetsphp artisan rconfig:data-purge --table=xftp_rootphp artisan rconfig:data-purge --table=xftp_device_uploads
# Dry runphp artisan rconfig:data-purge --table=xftp_root --dry-runAdvanced configuration
Section titled “Advanced configuration”Custom upload directory
Section titled “Custom upload directory”Organisations can move the xFTP inbox, or deploy their own FTP/SFTP services and have rConfig process files from a custom directory.
-
Edit
.envto set the custom path:Terminal window XFTP_ROOT_DIR=/path/to/custom/upload/directory -
Clear the config cache so rConfig reads the new path:
Terminal window cd /var/www/html/rconfig8/currentsudo -u apache php artisan config:clear # Ubuntu: sudo -u www-data -
Recreate each running xFTP service (stop it, then start it with
sudo php artisan rconfig:xftp-toggle). Containers mount the folder when they are created, so a running container keeps writing to the old path until you do. -
Lock the new folder down with the same layout as
/srv/xftp:Terminal window sudo php artisan rconfig:xftp-toggle --fix-permissionsIf the folder does not exist yet, the command does nothing; starting a service creates it as
root:<group> 2770. -
Run a manual sweep as the web user to confirm rConfig can read it.
-
If you run your own FTP or SFTP service, have it write as gid 2000 with umask
007so uploads land as0660in the shared group.
Running multiple services
Section titled “Running multiple services”All three services can run simultaneously on separate ports. Deploy them one at a time using sudo php artisan rconfig:xftp-toggle and selecting each protocol in turn.
Once deployed, assign protocols to device groups based on capability:
- Legacy switches: TFTP (port 69)
- Modern routers: FTP (port 21)
- Security appliances: SFTP (port 2222)
Security
Section titled “Security”Protocol comparison:
| Protocol | Authentication | Encryption | Recommended for |
|---|---|---|---|
| TFTP | None | None | Isolated lab networks only |
| FTP | Username + password | None | Devices without SFTP |
| SFTP | SSH credentials | Full (SSH) | Production and compliance |
Network-level restrictions:
# Limit upload sources to trusted networkssudo firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="10.0.0.0/8" port protocol="tcp" port="21" accept'
sudo firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="10.0.0.0/8" port protocol="tcp" port="2222" accept'
sudo firewall-cmd --reloadCredential management:
# Restrict .env file permissions (apache on RHEL, Rocky and Alma; www-data on Ubuntu)sudo chmod 600 /var/www/html/rconfig8/current/.envsudo chown apache:apache /var/www/html/rconfig8/current/.envTo rotate credentials: update .env, redeploy the affected service, then update device configurations or rely on credential variables for automatic substitution.
Common gotchas
Section titled “Common gotchas”Troubleshooting
Section titled “Troubleshooting”Files not appearing on the device page
Section titled “Files not appearing on the device page”-
Check the inbox for the file. From V8.4.1 only root and the shared group can list it:
Terminal window sudo ls -la /srv/xftp/ -
Verify the filename contains the device ID before a dash (e.g.
1234-vlan.dat). -
Confirm the device ID exists in rConfig:
Terminal window mysql -u rconfig -p rconfig -e "SELECT id, device_name FROM devices WHERE id = 1234;" -
Run a manual sweep as the web user:
Terminal window sudo -u apache php artisan rconfig:sweep-xftp-dir # Ubuntu: sudo -u www-data -
Check sweep logs for errors. A line saying
xFTP sweep skipped a symlink and did not read itmeans the file is a symlink, which the sweep never follows:Terminal window tail -50 /var/www/html/rconfig8/current/storage/logs/laravel.log | grep -i sweep
Uploads not swept, or a container can’t write
Section titled “Uploads not swept, or a container can’t write”Check the folder layout and the web user’s groups first:
ls -ld /srv/xftp # expect drwxrws--- root rconfigxftp (rconfigxftpusr on older installs)id apache # Ubuntu: id www-data. Expect rconfigxftp (or rconfigxftpusr) in the groupsThen let rConfig put the folder and files right:
cd /var/www/html/rconfig8/currentsudo php artisan rconfig:xftp-toggle --fix-permissionsIf it lists containers from an older version, recreate them first (see Upgrading from an earlier version). If the web user was only just added to the group, restart the web server (httpd or apache2), php-fpm and Horizon so they pick up the new group.
Don’t chown the folder to the web user or chmod 755 it. That stops the containers writing and lets every local user read the uploads.
Upload failures
Section titled “Upload failures”Service not running:
sudo php artisan rconfig:xftp-toggle --statussudo php artisan rconfig:xftp-toggle # restart if neededFirewall blocking:
telnet <rconfig-server-ip> 69 # TFTPtelnet <rconfig-server-ip> 21 # FTPtelnet <rconfig-server-ip> 2222 # SFTP
# Open ports if blockedsudo firewall-cmd --add-port=69/udp --permanentsudo firewall-cmd --add-port=21/tcp --permanentsudo firewall-cmd --add-port=2222/tcp --permanentsudo firewall-cmd --reloadAuthentication failure (FTP/SFTP):
sudo grep -E 'SERVICE_S?FTP_(USER|PASS|PORT)' /var/www/html/rconfig8/current/.env
# Test FTP manuallyftp <rconfig-server-ip>
# Test SFTP manuallysftp -P 2222 username@<rconfig-server-ip>Disk space:
df -h /srv/xftp/Container fails to start
Section titled “Container fails to start”-
Check container logs. The web user is not in the
dockergroup, so usesudo:Terminal window sudo docker ps -asudo docker logs rconfig-tftpsudo docker logs rconfig-ftpsudo docker logs rconfig-sftp❕ /usr/local/libexec/rconfig/xftp/<service>-entrypoint.sh is missing.when starting a service means the helper is not installed. Runsudo php artisan rconfig:xftp-install-helper. -
Check for port conflicts:
Terminal window sudo netstat -tulpn | grep :69sudo netstat -tulpn | grep :21sudo netstat -tulpn | grep :2222 -
Check the folder permissions as in Uploads not swept, or a container can’t write, and run
sudo php artisan rconfig:xftp-toggle --fix-permissionsif they are wrong. -
Restart Docker if needed:
Terminal window sudo systemctl restart dockersudo journalctl -u docker -n 50
After resolving the issue, remove the failed container and redeploy:
sudo docker rm rconfig-<service>sudo php artisan rconfig:xftp-toggleSweep task not processing files
Section titled “Sweep task not processing files”-
Navigate to Tasks → Scheduled Tasks and confirm the xFTP Directory Sweep task is enabled. If it is missing,
sudo php artisan rconfig:xftp-toggle --statuscreates it. -
Check the task run history for errors.
-
Run manually as the web user and check output:
Terminal window sudo -u apache php artisan rconfig:sweep-xftp-dir # Ubuntu: sudo -u www-data -
Verify the scheduler runs from the web user’s crontab:
Terminal window # RHEL, Rocky, Almasudo crontab -u apache -l | grep schedule:run# Ubuntusudo crontab -u www-data -l | grep schedule:runIf it is missing, or
schedule:runis in root’s crontab instead, see Worker privilege.
What’s next
Section titled “What’s next”- Configure device backups - Set up automated configuration backups alongside xFTP file uploads
- Manage devices in rConfig - Add and configure the devices that will push files to xFTP
- Set up scheduled tasks - Configure the xFTP sweep frequency and other automated jobs