FTP clients connecting to a ProFTPD server on Debian that authenticate successfully but fail during directory listing with "Unable to build data connection: No route to host" are experiencing a fundamental mismatch between the server's advertised IP address and the client's network routing capabilities. This error typically occurs because ProFTPD is broadcasting its internal private IP address (such as 192.168.x.x or 10.x.x.x) in the FTP PASV response, which the remote client cannot reach directly through the public internet or across different subnets. The solution requires configuring ProFTPD to explicitly define the external IP address it should advertise to clients, ensuring that the data channel establishment uses a routable address rather than an internal one.
Understanding the Passive Mode Connection Failure
FTP operates using two separate connections: a control connection for commands and a data connection for file transfers and directory listings. When a client issues a LIST command, the server enters passive mode by default and responds with a PASV reply containing an IP address and a port range. If the server is behind a NAT gateway or firewall, it often defaults to using its local interface IP in this response. For a remote client, this IP is unreachable, resulting in the "No route to host" error even though the initial login succeeded over the control connection.
This issue is distinct from simple firewall blocking, where the connection would time out or be refused entirely. Here, the client receives a valid IP but simply has no path to it. To resolve this, we must ensure the server communicates its true public identity to the client. You can compare this configuration challenge with
Troubleshooting FTP Access on a Debian VSFTPD Server, as similar NAT handling principles apply across different FTP daemons.
Determining the Correct External IP
Before modifying configuration files, identify the exact public IP address assigned to your Debian server by your ISP or cloud provider. This is the address that remote clients use to establish the initial control connection. Ensure that this IP is static or that you have a dynamic DNS service configured if it changes frequently, as hardcoding a changing IP will lead to intermittent failures.
Configuring ProFTPD for External IP Advertisement
The primary fix involves editing the ProFTPD configuration file, typically located at
/etc/proftpd/proftpd.conf or within the
/etc/proftpd/conf.d/ directory depending on your Debian version and installation method. You need to add or modify the
MasqueradeAddress directive. This directive tells ProFTPD to replace its internal hostname or IP address with the specified external address in all PASV responses.
Add the following line to your main configuration file, replacing
YOUR_PUBLIC_IP with the actual IP address identified earlier:
MasqueradeAddress YOUR_PUBLIC_IP
If your server is behind a NAT device that performs port translation, you may also need to specify the range of ports used for passive connections. ProFTPD needs to know which ports are being forwarded so it can include them correctly in the PASV response. Use the
PassivePorts directive to define this range:
PassivePorts 60000 60100
Ensure that your firewall rules allow inbound traffic on this specific port range. Without these ports open, the client will connect to the correct IP but fail to establish the data stream, leading to timeouts rather than routing errors.
Verifying Firewall and NAT Settings
After updating the ProFTPD configuration, verify that your system firewall (such as
ufw or
iptables) permits traffic on the passive port range. On Debian, you can check current rules using
sudo ufw status. If you are using UFW, allow the range with:
sudo ufw allow 60000:60100/tcp
If you are using iptables directly, ensure your INPUT chain accepts TCP packets destined for these ports. Additionally, if your server is behind a hardware router or cloud security group, confirm that port forwarding is configured to direct incoming traffic on the passive port range to the Debian machine's internal IP.
Restart the ProFTPD service to apply changes:
sudo systemctl restart proftpd
Test the connection again. If the issue persists, enable ProFTPD logging to debug the PASV response. Edit
/etc/proftpd/proftpd.conf to set
SystemLog /var/log/proftpd/proftpd.log and review the logs after a failed attempt to see what IP address is actually being sent.
Alternative Considerations for Complex Networks
In some enterprise environments, using explicit IP masking might not be sufficient due to strict stateful inspection firewalls. In such cases, switching to SFTP (SSH File Transfer Protocol) is highly recommended. SFTP runs over a single encrypted SSH connection, eliminating the need for separate data channels and passive port ranges entirely. While this article focuses on fixing FTP, migrating to SFTP resolves many of these architectural complexities permanently.
For users managing multiple services on Debian, understanding network interfaces is crucial. Network misconfigurations affecting Ethernet can sometimes mimic application-level errors, as seen in
Fixing Debian KDE: Internet Breaks When Wired Ethernet Connects, though the symptoms here are more specific to FTP protocol behavior.
Frequently Asked Questions
Why does the login succeed but the list command fail?
Login occurs over the control connection, which uses a single port and establishes a session. Directory listing requires a second, separate data connection. If the server advertises an unreachable IP for this second connection, the client authenticates fine but fails when trying to transfer data.
Can I use a domain name instead of an IP address?
Yes, you can use the
MasqueradeAddress directive with a fully qualified domain name (FQDN) like
ftp.example.com. The client will resolve this name to an IP address. Ensure that DNS records point to the correct public IP and that TTL values are low enough to update quickly if the IP changes.
What if my server has multiple network interfaces?
ProFTPD might bind to the wrong interface by default. Using
MasqueradeAddress overrides this behavior regardless of which interface handles the traffic. However, ensure that the external IP you specify is actually reachable from the client's network and not blocked by intermediate routers.
How do I check if passive ports are open?
Use tools like
nmap from an external machine to scan the specific port range defined in
PassivePorts. For example, run
nmap -p 60000-60100 YOUR_PUBLIC_IP. If the ports show as filtered or closed, your firewall is blocking the data connection.
Is there a performance impact when using MasqueradeAddress?
There is negligible performance impact. The directive simply modifies the text string sent in the FTP response packet. It does not involve additional processing overhead for data transfer itself. The only requirement is that the specified IP is correctly routed back to your server.