Skip to content

TFTP

Trivial File Transfer Protocol (TFTP) is a simple protocol used to transfer files between devices on a network. Unlike FTP, TFTP provides no authentication and uses UDP for transport, making it lightweight and suitable for embedded systems, network device configuration transfers, and PXE boot scenarios. Each data packet is acknowledged separately, ensuring reliable delivery even on lossy networks.

The TFTP implementation in RouterOS allows you to define access rules that control which files can be requested, from which clients, and from what storage locations. The server is not started by default—access rules must be configured under /ip/tftp to enable the service.

TFTP serves as a fundamental file transfer mechanism in network environments where simplicity and minimal overhead are priorities. Common use cases include transferring router configuration files, deploying firmware updates to network devices, serving boot images for PXE (Preboot Execution Environment) installations, and exchanging files with embedded systems that lack full FTP or SCP capabilities.

The protocol operates on UDP port 69 and uses a lock-step exchange where each data block (typically 512 bytes) must be acknowledged before the next block is sent. This design provides inherent reliability on reliable networks while minimizing protocol overhead. However, the lack of authentication means TFTP should only be deployed in trusted networks or behind proper access controls.

RouterOS TFTP server features include support for regex-based filename matching, real-filename redirection for serving files under different names, IP address filtering for access control, read-only mode to prevent unauthorized writes, and configurable maximum block sizes for compatibility with various clients.

The TFTP server configuration in RouterOS consists of two main components: access rules that define what files can be served and to whom, and global settings that control server behavior.

Access rules define the parameters under which the TFTP server will fulfill file requests. Each rule specifies client IP address constraints, filename matching patterns, and the actual file location to serve.

/ip/tftp add ip-addresses=192.168.1.0/24 req-filename="*.routeros" real-filename=/flash/routeros.bin allow=yes read-only=yes

The access rules are evaluated in order when a request arrives. The first matching rule determines whether the request is allowed and which file is served. This allows for hierarchical configurations where specific files can have dedicated rules while catch-all patterns handle remaining requests.

Each TFTP access rule requires and supports several properties that control access behavior.

PropertyDescription
ip-addressesIP address or range that clients must match. If empty, all clients (0.0.0.0/0) are accepted
req-filenameRegular expression pattern that requested filenames must match. Defaults to .* if empty
real-filenameActual file path to serve when the req-filename pattern matches. Required if allow=yes
allowEnable (yes) or disable (no) this rule. When no, matching requests are rejected
read-onlyPrevent write attempts when yes. Write requests receive an error response
hitsCounter showing how many times this rule has been matched (read-only)
allow-rolloverEnable sequence number rollover for large downloads beyond 65535 blocks

Use a static real-filename value for each rule. RouterOS does not support \0, \1, and similar backreferences in real-filename, so redirects must point to an explicit path.

/ip/tftp add req-filename="v(7|8)-(r[0-9]+).routeros" real-filename="/flash/routeros.bin" allow=yes

The TFTP server does not start automatically when RouterOS boots. At least one access rule must exist in /ip/tftp for the server to begin listening for requests. This design prevents unintended exposure of TFTP services and ensures administrators explicitly enable file transfers.

When the server starts, it binds to all interfaces and listens on UDP port 69. Clients initiate transfers by sending RRQ (Read Request) or WRQ (Write Request) packets to this port. The server responds from a dynamically allocated ephemeral port for each session.

Global TFTP server settings control protocol-level parameters that affect all transfers.

/ip/tftp/settings set max-block-size=4096
PropertyDescription
max-block-sizeMaximum block size the server will negotiate. Default is 4096 bytes. Range is 512-65535

The max-block-size parameter controls the largest data block the server will accept during transfer negotiation. Standard TFTP uses 512-byte blocks, but many clients support larger blocks for improved throughput on high-latency networks. Setting this value too high may cause issues with clients that cannot handle fragmented packets.

Some embedded TFTP clients request large block sizes but fail to handle fragmented IP packets correctly. If transfers timeout with such clients, reduce max-block-size to 512 or set it to the smallest MTU on your network minus 32 bytes.

The req-filename field uses regular expressions to filter which files clients may request. Understanding regex syntax is essential for creating precise access controls.

TFTP regex supports common pattern matching constructs that allow precise control over allowed filenames.

/ip/tftp add req-filename="routeros-.*.npk" real-filename=/flash/routeros.npk allow=yes
/ip/tftp add req-filename="config-(backup|current).txt" real-filename=/files/config.txt allow=yes
/ip/tftp add req-filename="firmware-v[0-9]+.[0-9]+" real-filename=/flash/firmware.bin allow=yes

Alternation and Grouping: Parentheses create subgroups that can be matched as a unit or used for backreferences. The pipe character (|) acts as OR between alternatives.

req-filename="(config|boot|system).bin" # Matches config.bin, boot.bin, or system.bin

Quantifiers: The asterisk (*) matches zero or more of the preceding element, plus (+) matches one or more, and question mark (?) matches zero or one.

req-filename="log-.*.txt" # Matches log-anything.txt including log-.txt
req-filename="backup-[0-9]+.tgz" # Matches backup-1.tgz, backup-123.tgz, etc.
req-filename="config.txt?" # Matches config.txt or config.txtt (rare)

Character Classes: Square brackets specify a set of characters to match at a single position.

req-filename="interface-[a-z0-9]+.cfg" # Lowercase letters and digits only
req-filename="[A-Z][a-z]+" # Capitalized words
req-filename="file-[0-9A-F]{8}.bin" # 8-character hex filename

Anchors: Caret (^) at the start means the pattern must match from the beginning of the filename. Dollar ($) at the end means the pattern must match through the end of the filename.

req-filename="^config.txt$" # Exactly "config.txt", nothing else
req-filename="^firmware.*$" # Anything starting with "firmware"

Capture groups are still useful for matching multiple request patterns, but real-filename must remain a fixed path.

# Serve the same file for either requested name
/ip/tftp add req-filename="(aaa|bbb).bin" real-filename="/sata/ccc.bin" allow=yes
# Match multiple firmware versions while serving one tested image
/ip/tftp add req-filename="firmware-v([0-9]+)" real-filename="/flash/firmware.bin" allow=yes

Serve a single configuration file to any client on the local network.

/ip/tftp add ip-addresses=192.168.88.0/24 req-filename="router-config.txt" real-filename=/flash/router.cfg allow=yes read-only=yes

This configuration allows any client in the 192.168.88.0/24 subnet to download router-config.txt, which is actually served from /flash/router.cfg. The read-only flag prevents clients from attempting to write files.

Serve any file from a specific directory, useful for general-purpose TFTP servers.

/ip/tftp add ip-addresses=0.0.0.0/0 req-filename=".*" real-filename=/tftp-root/test.txt allow=yes read-only=yes

This catch-all rule accepts any requested filename and serves the same file from /tftp-root/test.txt. Adjust the real-filename path to match the file you want to expose.

Configure the router as a PXE boot server for network installations.

/ip/tftp add ip-addresses=0.0.0.0/0 req-filename="pxelinux.0" real-filename=/flash/pxelinux.0 allow=yes
/ip/tftp add ip-addresses=0.0.0.0/0 req-filename="pxelinux.cfg/.*" real-filename=/flash/pxelinux.cfg/default allow=yes
/ip/tftp add ip-addresses=0.0.0.0/0 req-filename="kernel/.*" real-filename=/flash/kernel/default allow=yes
/ip/tftp add ip-addresses=0.0.0.0/0 req-filename="initrd.img" real-filename=/flash/initrd.img allow=yes

This configuration accepts connections from any IP address and serves PXE boot files from organized subdirectories. The hierarchical structure keeps different boot components separate.

Multiple File Types with Different Policies

Section titled “Multiple File Types with Different Policies”

Different file types can have different access levels and storage locations.

/ip/tftp add req-filename="firmware.*.bin" real-filename=/flash/firmware.bin allow=yes read-only=yes
/ip/tftp add req-filename="config.*.txt" real-filename=/configs/config.txt allow=yes read-only=yes
/ip/tftp add req-filename="logs/.*.log" real-filename=/var/log/messages.log allow=yes read-only=yes
/ip/tftp add req-filename="backups/.*" real-filename=/backups/backup.tgz allow=yes read-only=yes

Enable sequence number rollover for transfers larger than 32MB (65535 blocks × 512 bytes).

/ip/tftp add req-filename="large-file.bin" real-filename=/flash/large-file.bin allow=yes allow-rollover=yes

Use capture groups to map multiple requested filenames to a single output file.

# Client requesting aaa.bin or bbb.bin receives ccc.bin
/ip/tftp add req-filename="(aaa|bbb).bin" real-filename="/sata/ccc.bin" allow=yes

If TFTP clients report transfer timeouts, several factors may be responsible.

Network Connectivity: Verify that the client can reach the RouterOS device and that UDP port 69 is not blocked by firewall rules.

/ip/firewall/filter/print where dst-port=69
/ip/firewall/filter/add chain=forward dst-port=69 protocol=udp action=accept comment="Allow TFTP"

Block Size Mismatch: Some clients request large block sizes but cannot handle fragmented packets. Reduce max-block-size on the server or adjust client settings.

/ip/tftp/settings set max-block-size=512

Missing Access Rule: Ensure at least one access rule exists in /ip/tftp. The server does not start without configured rules.

/ip/tftp print

Requests being rejected may indicate IP address, filename, or rule configuration issues.

IP Address Mismatch: Verify the ip-addresses setting matches the client’s actual IP. Use 0.0.0.0/0 to accept all clients for testing.

/ip/tftp set [find] ip-addresses=0.0.0.0/0

Regex Pattern Issues: Test regex patterns for correct matching. Complex patterns may not match as expected.

# Simple test pattern to confirm basic functionality
/ip/tftp add req-filename=".*" real-filename=/flash/test.txt allow=yes

Read-Only Mode: Confirm read-only is not blocking intended operations. Write requests require read-only=no.

Transfers exceeding 32MB may fail without the allow-rollover setting.

/ip/tftp set [find] allow-rollover=yes

Additionally, ensure sufficient memory is available for the transfer buffer. Large transfers consume RAM during operation.

Use these commands to monitor TFTP server activity and diagnose issues.

/ip/tftp/print # Show all access rules with hit counts
/ip/tftp/settings/print # Display current settings
/log print where message~"tftp" # View TFTP-related log messages
  • Files - RouterOS file management and storage
  • SMB - Server Message Block for Windows file sharing
  • FTP - FTP server configuration for more complex file transfers
  • DHCP Server - DHCP options for TFTP server discovery
  • PXE Boot Configuration - Network boot setup and configuration
  • RFC 1350 - TFTP Protocol Revision 2
  • RFC 2347 - TFTP Option Extension
  • RFC 2348 - TFTP Blocksize Option
  • RFC 2349 - TFTP Timeout Interval and Transfer Size Options
  • MikroTik Wiki - TFTP Server: https://wiki.mikrotik.com/wiki/Manual:IP/TFTP