Skip to content

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.


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.

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
  • Inbox (raw uploads): /srv/xftp/
  • Processed device storage (moved files):
Terminal window
/var/www/html/rconfig8/storage/app/rconfig/data/<Category>/<device-name>/xftpuploads/

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.

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.

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:

Terminal window
php artisan rconfig:sweep-xftp-dir

To trigger a sweep manually, run it as the web server user so the moved files stay owned by that user:

Terminal window
cd /var/www/html/rconfig8/current
sudo -u apache php artisan rconfig:sweep-xftp-dir # Ubuntu: sudo -u www-data

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.


  • Docker installed on the rConfig server, with the docker command at /usr/bin/docker or /usr/local/bin/docker (the setup wizard can install it automatically)
  • Shell access with sudo. rconfig:xftp-toggle and rconfig:xftp-install-helper must 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

Manage xFTP Docker microservices through the UI or CLI.

Web interface: Navigate to Platform → Network Services → XFTP

rConfig V8 xFTP Services settings dashboard displaying service status and configuration options

The page reads container status through the Docker helper. Starting and stopping services is done on the server, with sudo.

CLI:

Terminal window
cd /var/www/html/rconfig8/current
sudo php artisan rconfig:xftp-toggle

From 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-toggle

Check service status at any time:

Terminal window
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.
rConfig V8 xFTP Services management dashboard showing Docker container running status rConfig V8 CLI terminal output displaying xFTP service status and Docker container information

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:

Terminal window
cd /var/www/html/rconfig8/current
sudo php artisan rconfig:xftp-install-helper

It is safe to run again. In order, it:

  1. Installs the helper and the container entrypoints.
  2. Writes the sudo rule, checks it with visudo -c first, and installs nothing if visudo rejects it.
  3. Creates the rconfigxftp group with gid 2000 if no group has that gid, and adds the web user to the gid 2000 group.
  4. Puts the Docker socket back to 0660 if any local user could reach it: Docker socket was 0666 (accessible to every local user). Reset it to 0660.
  5. Warns if the web user is in the docker group. It does not remove it.
  6. Removes world-write from the legacy TFTP folders /srv/tftp and /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.

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:

Terminal window
# RHEL, Rocky, Alma
sudo gpasswd -d apache docker
# Ubuntu
sudo gpasswd -d www-data docker

Check the result with id apache (or id www-data): docker should no longer be listed.


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-permissions

The 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:

  1. 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/current
    sudo php artisan rconfig:xftp-toggle

    To 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.

  2. Lock the folder down.

    Terminal window
    sudo php artisan rconfig:xftp-toggle --fix-permissions

    It runs the Docker helper install first, then sets the folder to root:<group> 2770 and 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.

  3. Restart the web server, php-fpm and 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-permissions

It still runs the install helper first, so the helper, sudo rule, group and Docker socket are fixed even when the folder is not.

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:

Terminal window
sudo php artisan rconfig:xftp-install-helper
sudo php artisan rconfig:xftp-toggle --fix-permissions

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:

Terminal window
sudo php artisan rconfig:tftp-server off

The 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.


Run the interactive toggle command and choose which protocol to deploy:

Terminal window
sudo php artisan rconfig:xftp-toggle

TFTP provides basic file transfer without authentication. Suitable for legacy devices and isolated environments.

  1. Run sudo php artisan rconfig:xftp-toggle and choose TFTP from the protocol list.

    rConfig V8 xFTP setup wizard TFTP service selection interface
  2. Docker pulls the TFTP image on first deployment.

  3. The TFTP container starts automatically.

  4. Verify the service shows TFTP running on port 69.

    rConfig V8 CLI terminal output confirming TFTP service 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 provides authenticated file transfer with credential-based access.

  1. Run sudo php artisan rconfig:xftp-toggle and choose FTP.

    rConfig V8 xFTP setup wizard FTP service selection interface
  2. Enter the FTP username and password when prompted.

  3. Docker pulls the FTP image on first deployment.

  4. The FTP container starts with the configured credentials.

  5. Verify the service shows FTP running on port 21.

    rConfig V8 FTP service running confirmation showing active status 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 provides encrypted, authenticated file transfer over SSH. Use for production environments and sensitive data.

  1. Run sudo php artisan rconfig:xftp-toggle and choose SFTP.

    rConfig V8 xFTP setup wizard SFTP service selection for secure encrypted file transfers
  2. Enter the SFTP port. It must not conflict with host SSH on port 22; 2222 is a common choice.

  3. Enter the SFTP username and password.

  4. Docker pulls the SFTP image on first deployment.

  5. The SFTP container starts with the configured port and credentials.

  6. Verify the service shows SFTP running on your chosen port.

    rConfig V8 CLI terminal output confirming SFTP service running on the configured custom 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:

Terminal window
# SFTP
sftp -P 2222 username@rconfig-server-ip
# SCP
scp -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.


For rConfig to associate an uploaded file with a device, the filename must include the device ID before a dash:

{deviceid}-filename.ext

Valid patterns:

  • tftp://192.168.1.131/{deviceid}-vlan.dat
  • ftp://server/{deviceid}-config.log
  • sftp://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.

TFTP (Cisco IOS):

Terminal window
Router(config)#file prompt quiet
Router#copy vlan.dat tftp://192.168.1.131/1234-vlan.dat

FTP (Cisco IOS):

Terminal window
Router#copy vlan.dat ftp://ftpuser:ftppass@192.168.1.131/1234-vlan.dat

Using credential variables (recommended):

Terminal window
Router#copy vlan.dat ftp://{ftpusername}:{ftppassword}@192.168.1.131/{deviceid}-vlan.dat

SFTP (Cisco IOS):

Terminal window
Router#copy vlan.dat sftp://sftpuser:sftppass@192.168.1.131:2222/1234-vlan.dat

Using credential variables:

Terminal window
Router#copy vlan.dat sftp://{sftpusername}:{sftppassword}@192.168.1.131:2222/{deviceid}-vlan.dat

Incorporate upload commands into rConfig command categories so files transfer automatically during device polling.

  1. Navigate to Settings → Commands in the rConfig UI.

  2. Create or open the command category used by the target devices.

  3. Add the upload command with variables:

    Terminal window
    copy vlan.dat tftp://192.168.1.131/{deviceid}-vlan.dat
  4. Assign the category to the relevant devices.

  5. 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.

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:

  1. 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:

    # 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 xFTP
    desc: '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 entirely
    port: 21 # Unused: no outbound connection is ever attempted for this protocol
    This template also ships ready-made in the xFTP templates folder in our templates repository.
  2. Save the template and assign it to the device through the normal template assignment workflow.

  3. 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.

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.

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.


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

rConfig V8 xFTP File Matching patterns configuration page

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+)”

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.

rConfig V8 xFTP Services dashboard displaying unprocessed files in the inbox directory

Navigate to Devices → [Device Name] and scroll to the uploaded files section.

rConfig V8 device page showing processed xFTP uploads table with file metadata and action buttons

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.

rConfig V8 full file listing interface with view, download, and delete management actions

Click View All to access the full file management interface.


If you upgraded and already have files on disk without tracking rows, populate xftp_uploads from the filesystem:

Terminal window
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=1000

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:

Terminal window
# Run all purge targets
php artisan rconfig:data-purge
# Run only xFTP targets
php artisan rconfig:data-purge --table=xftp_root
php artisan rconfig:data-purge --table=xftp_device_uploads
# Dry run
php artisan rconfig:data-purge --table=xftp_root --dry-run

Organisations can move the xFTP inbox, or deploy their own FTP/SFTP services and have rConfig process files from a custom directory.

  1. Edit .env to set the custom path:

    Terminal window
    XFTP_ROOT_DIR=/path/to/custom/upload/directory
  2. Clear the config cache so rConfig reads the new path:

    Terminal window
    cd /var/www/html/rconfig8/current
    sudo -u apache php artisan config:clear # Ubuntu: sudo -u www-data
  3. 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.

  4. Lock the new folder down with the same layout as /srv/xftp:

    Terminal window
    sudo php artisan rconfig:xftp-toggle --fix-permissions

    If the folder does not exist yet, the command does nothing; starting a service creates it as root:<group> 2770.

  5. Run a manual sweep as the web user to confirm rConfig can read it.

  6. If you run your own FTP or SFTP service, have it write as gid 2000 with umask 007 so uploads land as 0660 in the shared group.

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)

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:

Terminal window
# Limit upload sources to trusted networks
sudo 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 --reload

Credential management:

Terminal window
# Restrict .env file permissions (apache on RHEL, Rocky and Alma; www-data on Ubuntu)
sudo chmod 600 /var/www/html/rconfig8/current/.env
sudo chown apache:apache /var/www/html/rconfig8/current/.env

To rotate credentials: update .env, redeploy the affected service, then update device configurations or rely on credential variables for automatic substitution.



  1. 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/
  2. Verify the filename contains the device ID before a dash (e.g. 1234-vlan.dat).

  3. Confirm the device ID exists in rConfig:

    Terminal window
    mysql -u rconfig -p rconfig -e "SELECT id, device_name FROM devices WHERE id = 1234;"
  4. Run a manual sweep as the web user:

    Terminal window
    sudo -u apache php artisan rconfig:sweep-xftp-dir # Ubuntu: sudo -u www-data
  5. Check sweep logs for errors. A line saying xFTP sweep skipped a symlink and did not read it means 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:

Terminal window
ls -ld /srv/xftp # expect drwxrws--- root rconfigxftp (rconfigxftpusr on older installs)
id apache # Ubuntu: id www-data. Expect rconfigxftp (or rconfigxftpusr) in the groups

Then let rConfig put the folder and files right:

Terminal window
cd /var/www/html/rconfig8/current
sudo php artisan rconfig:xftp-toggle --fix-permissions

If 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.

Service not running:

Terminal window
sudo php artisan rconfig:xftp-toggle --status
sudo php artisan rconfig:xftp-toggle # restart if needed

Firewall blocking:

Terminal window
telnet <rconfig-server-ip> 69 # TFTP
telnet <rconfig-server-ip> 21 # FTP
telnet <rconfig-server-ip> 2222 # SFTP
# Open ports if blocked
sudo firewall-cmd --add-port=69/udp --permanent
sudo firewall-cmd --add-port=21/tcp --permanent
sudo firewall-cmd --add-port=2222/tcp --permanent
sudo firewall-cmd --reload

Authentication failure (FTP/SFTP):

Terminal window
sudo grep -E 'SERVICE_S?FTP_(USER|PASS|PORT)' /var/www/html/rconfig8/current/.env
# Test FTP manually
ftp <rconfig-server-ip>
# Test SFTP manually
sftp -P 2222 username@<rconfig-server-ip>

Disk space:

Terminal window
df -h /srv/xftp/
  1. Check container logs. The web user is not in the docker group, so use sudo:

    Terminal window
    sudo docker ps -a
    sudo docker logs rconfig-tftp
    sudo docker logs rconfig-ftp
    sudo docker logs rconfig-sftp

    ❕ /usr/local/libexec/rconfig/xftp/<service>-entrypoint.sh is missing. when starting a service means the helper is not installed. Run sudo php artisan rconfig:xftp-install-helper.

  2. Check for port conflicts:

    Terminal window
    sudo netstat -tulpn | grep :69
    sudo netstat -tulpn | grep :21
    sudo netstat -tulpn | grep :2222
  3. Check the folder permissions as in Uploads not swept, or a container can’t write, and run sudo php artisan rconfig:xftp-toggle --fix-permissions if they are wrong.

  4. Restart Docker if needed:

    Terminal window
    sudo systemctl restart docker
    sudo journalctl -u docker -n 50

After resolving the issue, remove the failed container and redeploy:

Terminal window
sudo docker rm rconfig-<service>
sudo php artisan rconfig:xftp-toggle
  1. Navigate to Tasks → Scheduled Tasks and confirm the xFTP Directory Sweep task is enabled. If it is missing, sudo php artisan rconfig:xftp-toggle --status creates it.

  2. Check the task run history for errors.

  3. 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
  4. Verify the scheduler runs from the web user’s crontab:

    Terminal window
    # RHEL, Rocky, Alma
    sudo crontab -u apache -l | grep schedule:run
    # Ubuntu
    sudo crontab -u www-data -l | grep schedule:run

    If it is missing, or schedule:run is in root’s crontab instead, see Worker privilege.