Skip to content

TFTP Server

For the impatient: serve files via TFTP for PXE boot.

# Upload boot file to router (via Winbox Files or fetch)
/tool fetch url="https://boot.netboot.xyz/ipxe/netboot.xyz.kpxe"
# Create TFTP rule to serve the file
/ip tftp add req-filename="netboot.xyz.kpxe" real-filename="netboot.xyz.kpxe" \
ip-addresses=192.168.88.0/24 read-only=yes
# Configure DHCP for PXE boot
/ip dhcp-server network set [find] next-server=192.168.88.1 boot-file-name="netboot.xyz.kpxe"

Verify:

/ip tftp print
/log print where topics~"tftp"

What this does: TFTP (Trivial File Transfer Protocol) provides simple, unauthenticated file transfers primarily used for network booting (PXE), IP phone provisioning, and firmware updates on network devices.

When to use this:

  • PXE/network boot for diskless systems or installers
  • IP phone configuration file provisioning
  • Switch/router firmware distribution
  • Thin client boot environments

Key Concepts:

  • TFTP server only starts if at least one rule exists
  • Rules map requested filenames (regex) to actual files
  • No authentication - control access via IP ranges and firewall
  • Maximum ~32MB file size without allow-rollover

Prerequisites:

  • Files uploaded to router storage
  • DHCP server (for PXE boot integration)
  • Firewall allowing UDP port 69
Configuration Steps diagram

Upload boot files or configs via Winbox Files panel, FTP, or fetch:

# Download from URL
/tool fetch url="https://boot.netboot.xyz/ipxe/netboot.xyz.kpxe"
# Verify file exists
/file print where name~"kpxe"

Serve a specific file:

/ip tftp add req-filename="netboot.xyz.kpxe" real-filename="netboot.xyz.kpxe" \
ip-addresses=192.168.88.0/24 read-only=yes

Serve all files from a directory (using regex backreference):

/ip tftp add ip-addresses=192.168.88.0/24 real-filename="flash/tftp/\\0" read-only=yes

The \\0 backreference means “whatever filename the client requested”.

Use next-server and boot-file-name in DHCP network settings:

/ip dhcp-server network set [find address=192.168.88.0/24] \
next-server=192.168.88.1 boot-file-name="netboot.xyz.kpxe"

Common Mistakes

  • Don’t use DHCP options 66/67 when next-server/boot-file-name will work - PXE clients check BOOTP header fields first
  • Don’t forget that TFTP server won’t start without at least one rule configured
  • Don’t set read-only=no unless you specifically need clients to upload files
PropertyDefaultDescription
req-filename.*Requested filename pattern (regex)
real-filename(required)Actual file path; supports \\0, \\1 backreferences
ip-addresses0.0.0.0/0Allowed client IP ranges
read-onlynoPrevent file uploads when yes
allow-rollovernoEnable for files >32MB
allowyesEnable/disable rule
PatternMatches
.*Any filename (wildcard)
netboot.xyz.kpxeExact filename
.*\\.cfg$Files ending in .cfg
.*\\.bin$Files ending in .bin
^pxelinuxFiles starting with “pxelinux”
(pxelinux.0)|(lpxelinux.0)Either filename

Backreferences in real-filename:

  • \\0 - Entire matched filename
  • \\1 - First captured group
  • \\2 - Second captured group
Common Scenarios - PXE Boot Server diagram
# Download boot files
/tool fetch url="https://boot.netboot.xyz/ipxe/netboot.xyz.kpxe"
# Create TFTP rule
/ip tftp add req-filename="netboot.xyz.kpxe" real-filename="netboot.xyz.kpxe" \
ip-addresses=192.168.88.0/24 read-only=yes
# Configure DHCP
/ip dhcp-server network set [find] next-server=192.168.88.1 \
boot-file-name="netboot.xyz.kpxe"
# Upload phone configs to flash/phones/ via Winbox Files
# Create TFTP rule for phone subnet
/ip tftp add ip-addresses=192.168.10.0/24 req-filename=".*" \
real-filename="flash/phones/\\0" read-only=yes
# Configure DHCP option 66 for phone VLAN
/ip dhcp-server option add name=tftp-server code=66 value="'192.168.10.1'"
/ip dhcp-server network set [find address=192.168.10.0/24] dhcp-option=tftp-server
# Create directory for firmware files
# Upload firmware via Winbox to flash/firmware/
# Map by file extension
/ip tftp add req-filename=".*\\.bin$" real-filename="flash/firmware/\\0" \
ip-addresses=10.0.0.0/8 read-only=yes allow-rollover=yes

Scenario: Multiple Boot Files to Single File

Section titled “Scenario: Multiple Boot Files to Single File”

Redirect various PXE loader requests to one file:

/ip tftp add req-filename="(pxelinux.0)|(lpxelinux.0)|(undionly.kpxe)" \
real-filename="flash/boot/pxelinux.0" read-only=yes
DHCP Integration diagram

Populates BOOTP header fields - checked by PXE clients first:

/ip dhcp-server network set [find address=192.168.88.0/24] \
next-server=192.168.88.1 boot-file-name="pxelinux.0"

For specific clients or compatibility:

/ip dhcp-server option add name=opt66-tftp code=66 value="'192.168.88.1'"
/ip dhcp-server option add name=opt67-bootfile code=67 value="'pxelinux.0'"
/ip dhcp-server network set [find] dhcp-option=opt66-tftp,opt67-bootfile

Download files from external TFTP servers:

/tool fetch address=192.168.1.100 src-path=firmware.bin dst-path=firmware.bin mode=tftp

Note: TFTP client mode is download-only - cannot upload files.

Adjust block size for problematic clients:

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

Calculate: MTU (1500) - 32 bytes (20 IP + 8 UDP + 4 TFTP) = 1468

Use smaller block sizes for embedded devices (IP phones, older switches) that can’t handle fragmented packets.

# View rules with hit counters
/ip tftp print
# View settings
/ip tftp settings print
# Check logs
/system logging add topics=tftp action=memory
/log print where topics~"tftp"

Expected log output:

tftp,info sending file firmware.bin to 192.168.88.100
tftp,info file firmware.bin sent to 192.168.88.100

Test from Linux client:

Terminal window
tftp 192.168.88.1 -c get netboot.xyz.kpxe

Allow TFTP access from specific networks:

/ip firewall filter add chain=input protocol=udp dst-port=69 \
src-address=192.168.88.0/24 action=accept comment="Allow TFTP"
SymptomCauseSolution
TFTP requests timeoutNo rules configuredAdd at least one TFTP rule
”Permission denied”No matching ruleCheck req-filename regex, ip-addresses, allow
Transfer fails at ~32MBBlock rollover not enabledSet allow-rollover=yes
Embedded device timeoutBlock size too largeSet max-block-size=1468 or lower
PXE uses wrong serverClient reads BOOTP siaddrUse next-server instead of option 66
Backreference \\0 literalRouterOS version bugUpgrade or use explicit filename rules
Option 67 not sentClient didn’t request itUse boot-file-name in network settings
Cannot upload filesRule is read-onlySet read-only=no for upload rules

Common Mistakes

  • TFTP server only starts if rules exist - first rule may require reboot to activate service
  • \\0 backreference in real-filename must use double backslash in CLI
  • TFTP has no authentication - limit access via IP ranges and firewall
  • Files larger than available RAM cannot be served
  • Maximum ~32MB file size without allow-rollover=yes
  • No authentication (protocol limitation)
  • No encryption (plaintext transfers)
  • TFTP client (/tool fetch mode=tftp) is download-only
  • Regex differs slightly from POSIX
  • Adding first rule may require reboot for service to start
  • DHCP Server - PXE boot integration with next-server option
  • IP Pool - address pools for PXE clients
  • Files - storage management for TFTP content