SSD Nodes Learn 🎉 VPS desde $5.50/mes
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-21

FTP pasivo: inicia sesión, pero no muestra directorios

Si FTP acepta el acceso pero el listado queda bloqueado, el canal de datos usa otros puertos. Define el rango pasivo y permite esos puertos en el firewall.

Por qué FTP inicia sesión, pero el listado de directorios se bloquea

El modo pasivo de FTP falla en un firewall porque FTP usa dos conexiones TCP, no una. La conexión al puerto 21 transporta el inicio de sesión y los comandos, por lo que el nombre de usuario y la contraseña se aceptan y el firewall parece estar configurado correctamente. A continuación, el ls necesita una segunda conexión en otro puerto. El firewall no permite esa conexión, por lo que el cliente queda esperando hasta que se agota el tiempo de espera.

La solución consiste en fijar un intervalo de puertos para esas conexiones de datos y añadir una regla del firewall que permita el mismo intervalo. Un servidor detrás de NAT (traducción de direcciones de red) necesita un ajuste adicional para anunciar la dirección correcta. Antes, los ayudantes de seguimiento de conexiones realizaban este trabajo automáticamente. Ya no lo hacen, y conviene entender el motivo antes de copiar una guía antigua.

El canal de control y el canal de datos

FTP (protocolo de transferencia de archivos) está especificado en RFC 959 y es anterior tanto a NAT como al firewall con estado. Una sesión abre una conexión de control al puerto TCP 21 y la mantiene abierta durante toda la sesión. Los comandos se envían como texto sin cifrar. Las respuestas contienen un código de tres dígitos y una línea de texto. Esa conexión nunca transporta el contenido de los archivos.

Cada pieza de datos usa su propia conexión TCP: una para el listado de directorio (LIST), una para cada descarga (RETR) y una para cada carga (STOR). Se abre, se usa una vez y se cierra. La autenticación se realiza por completo en el canal de control, por lo que una ruta de datos interrumpida siempre presenta el mismo síntoma: el inicio de sesión se completa y después la conexión queda bloqueada. Si el cliente muestra una respuesta 230 y después se detiene al obtener el listado, el problema está en el canal de datos, no en las credenciales.

Modo activo: el servidor se conecta de vuelta al cliente

En el modo activo, el cliente elige un puerto, se pone a escuchar en él e indica al servidor dónde debe conectarse:

PORT 192,168,1,50,195,80

Los cuatro primeros números son la dirección IP del cliente. Los dos últimos representan el puerto, codificado como dos bytes: 195 * 256 + 80 = 50000. A continuación, el servidor abre la conexión de datos desde su propio puerto 20 al puerto 50000 del cliente.

Desde el punto de vista del cliente, esa conexión es entrante y no solicitada, por lo que el firewall del cliente la descarta. Si el cliente está detrás de un router doméstico, la dirección incluida en el comando PORT es privada y el servidor no puede alcanzarla. El modo activo es la causa de la reputación de FTP de no funcionar.

Modo pasivo: el cliente abre ambas conexiones

El modo pasivo invierte la conexión de datos. El cliente envía PASV y el servidor responde con una dirección y un puerto propios:

227 Entering Passive Mode (203,0,113,10,195,80)

La codificación es la misma, por lo que el cliente se conecta a 203.0.113.10 en el puerto 50000. El cliente abre ahora ambas conexiones. Por eso el modo pasivo funciona a través del NAT del lado del cliente y todos los clientes actuales lo solicitan primero.

El problema cambia de lugar, pero no desaparece. La conexión entrante no solicitada llega ahora a su servidor, a un puerto alto que cambia en cada transferencia. Ese firewall es suyo, por lo que el problema también es suyo.

EPSV (modo pasivo extendido, RFC 2428) aplica la misma idea con una respuesta más limpia:

229 Entering Extended Passive Mode (|||50000|)

La respuesta no contiene ninguna dirección. El cliente reutiliza la dirección que ya tiene para la conexión de control. Esto permite que funcione con IPv6 y elimina una clase completa de errores de NAT. El manual de curl indica que curl normalmente prueba EPSV antes que PASV. El puerto se sigue eligiendo en tiempo de ejecución, por lo que EPSV no cambia nada en las reglas del firewall.

Por qué una regla de firewall normal no puede permitir el canal de datos

Porque el número de puerto todavía no existe cuando se escribe la regla. El servidor lo elige para cada transferencia. Con los valores predeterminados, vsftpd documenta pasv_min_port y pasv_max_port como 0, es decir, «usar cualquier puerto», por lo que la conexión de datos puede llegar a cualquier puerto superior a 1023. sudo ufw allow 21/tcp permite el canal de control y nada más. Esa es exactamente la configuración que produce un inicio de sesión correcto y un listado que no funciona. Si el concepto de un servicio que escucha en un puerto fijo todavía no está claro, cómo funcionan los puertos y los sockets de escucha en Linux proporciona el contexto necesario.

Un firewall con estado realiza un seguimiento de las conexiones. El kernel puede admitir una conexión nueva como RELATED de una conexión existente. En FTP, eso requiere que algo lea el flujo de control y extraiga el puerto de una línea 227 o PORT. Nada hace esto de forma predeterminada.

Por qué el helper de seguimiento de conexiones FTP ya no es la solución

El módulo del kernel nf_conntrack_ftp es el que indican las guías antiguas. Lee el canal de control en texto plano, encuentra el puerto anunciado y registra una expectativa, de modo que la conexión de datos se admite sin ninguna regla que especifique su puerto. Desde que se escribieron esas guías han cambiado cuatro aspectos.

La asignación automática de helpers está desactivada. La documentación del kernel define el sysctl nf_conntrack_helper como «0 - disabled (default)» y añade: «If disabled it is required to set up iptables rules to assign helpers to connections.» Cargar el módulo no consigue nada por sí solo.

En los kernels actuales, ese ajuste ya no existe. Ejecute sysctl net.netfilter.nf_conntrack_helper. Una respuesta sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_helper: No such file or directory significa que el kernel ya no tiene ninguna asignación automática de helpers que se pueda activar. Si recibe un número, el ajuste todavía existe y su valor predeterminado es 0.

Las interfaces de firewall también lo han marcado como obsoleto. man ufw-framework en Ubuntu 24.04 indica sobre la línea IPT_MODULES de /etc/default/ufw: «Unconditional loading of connection tracking modules (nf_conntrack_*) in this manner is deprecated» y añade que las reglas de helpers «must be managed in via the RULES FILES». firewalld documenta AutomaticHelpers en firewalld.conf como «Deprecated. This option is ignored and no longer used.» Asociar un helper ahora requiere escribir manualmente una regla explícita con el destino CT. Esto requiere más trabajo que la solución siguiente y deja de funcionar en cuanto se activa TLS. iptables y nftables en Ubuntu explica dónde se encuentran realmente esas reglas.

TLS pone fin al problema. Un helper funciona leyendo el canal de control como texto. Si cifra ese canal, el helper sólo ve texto cifrado y no puede encontrar el puerto. No existe una solución para esto, y no debería existir: un middlebox capaz de leer su canal de control también puede leer su contraseña.

Declare un rango de puertos pasivos en el servidor

Todos los servidores FTP pueden configurarse para elegir sus puertos pasivos de un rango que usted defina. Los nombres de las opciones varían, así que consulte la documentación del servidor que realmente ejecuta.

vsftpd, en /etc/vsftpd.conf:

pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30099

pasv_enable ya tiene el valor predeterminado YES. Las dos opciones de puertos tienen como valor predeterminado 0, es decir, el comportamiento de «usar cualquier puerto» descrito arriba. Aplique los cambios con sudo systemctl restart vsftpd y confirme después que el servicio se haya iniciado de nuevo con systemctl status vsftpd. vsftpd no omite una línea de configuración que no puede analizar: se niega a iniciar. Si el reinicio falla, lea journalctl -u vsftpd -n 20 para encontrar la línea 500 OOPS: que identifica la opción que acaba de escribir.

ProFTPD, en proftpd.conf:

PassivePorts 30000 30099

ProFTPD no documenta ningún valor predeterminado aquí: sin la directiva, el kernel elige el puerto. Su documentación también indica que, cuando ningún puerto del rango está libre, el servidor vuelve a usar un puerto asignado por el kernel y registra un mensaje. Por tanto, un rango demasiado pequeño falla ocasionalmente en lugar de fallar de forma clara, lo que dificulta mucho más el diagnóstico. Use puertos no privilegiados, 1024 o superiores.

Pure-FTPd utiliza la opción -p first:last, documentada en man pure-ftpd como «Usar sólo puertos del rango entre first y last, ambos inclusive, para las descargas en modo pasivo», lo que «hace que pure-ftpd sea más compatible con los filtros de paquetes». Las compilaciones empaquetadas suelen incluir esa opción en un archivo de configuración, así que consulte la documentación de su distribución para conocer el nombre del archivo en lugar de adivinarlo.

¿Cuántos puertos necesita? Uno por cada conexión de datos activa. Un puerto TCP cerrado permanece en TIME_WAIT durante un par de minutos antes de poder reutilizarse, así que reserve varias veces el número máximo previsto. Cien puertos son suficientes para unos pocos usuarios; un servidor público con mucha carga necesita muchos más.

¿Dónde debe situarse el rango? Ejecute primero sysctl net.ipv4.ip_local_port_range. En una instalación estándar de Ubuntu muestra 32768 60999, los puertos que el kernel asigna a las conexiones salientes. Un rango pasivo dentro de esa ventana puede entrar en conflicto con una conexión saliente que ya tenga el puerto ocupado, así que mantenga el rango por debajo de ella. 30000 a 30099 está libre en una instalación predeterminada. Compruébelo en su propio sistema en lugar de confiar en ese número.

Abra el mismo rango en el firewall

ufw escribe un rango con dos puntos, y su manual indica que también se puede usar un rango o una lista "para especificar varios puertos, en cuyo caso el protocolo es obligatorio":

sudo ufw allow 21/tcp
sudo ufw allow 30000:30099/tcp
sudo ufw status verbose

ufw status verbose ahora debería mostrar ambas entradas. El mismo comando sin /tcp se rechaza con un error que indica que debe especificar tcp o udp, porque ufw no hará suposiciones. sintaxis de reglas de ufw en un VPS cubre el resto.

firewalld escribe el rango con un guion y requiere una recarga:

sudo firewall-cmd --permanent --add-service=ftp
sudo firewall-cmd --permanent --add-port=30000-30099/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

--add-service=ftp abre 21/tcp y solicita el helper ftp que define el archivo de servicio incluido. No abre el rango pasivo, por lo que, por sí solo, deja la situación exactamente como estaba. zonas y servicios de firewalld en un VPS explica el contexto general.

nftables directamente, dentro de la cadena input:

tcp dport { 21, 30000-30099 } accept

Debe tener en cuenta otro firewall: la mayoría de los proveedores ejecutan un firewall de red en el panel de control, fuera del sistema operativo. Si las reglas del servidor parecen correctas y los paquetes siguen sin llegar, abra allí también el mismo rango.

Indique la dirección pública del servidor cuando está detrás de NAT

Ejecute ip -4 addr show en el servidor. Si la dirección de la interfaz es la dirección a la que se conectan los clientes, omita esta sección. Si la interfaz tiene una dirección privada (10.x, 172.16 a 172.31.x, 192.168.x) y la plataforma asigna una dirección pública sobre ella, el servidor no conoce su propia dirección pública. La documentación de vsftpd indica que el valor predeterminado de pasv_address es «la dirección se obtiene del socket conectado entrante», por lo que la respuesta 227 contiene la dirección privada y el cliente intenta conectarse a un destino que no puede alcanzar.

FileZilla muestra este mensaje exactamente:

Server sent passive reply with unroutable address. Using server address instead.

FileZilla corrige el problema y continúa. Muchos otros clientes no lo hacen. Intentan conectarse a 10.0.0.5 y quedan bloqueados.

curl también oculta el problema, algo importante si curl es su herramienta de prueba. Su manual indica que --ftp-skip-pasv-ip «está habilitado de forma predeterminada (se añadió en 7.74.0)», por lo que curl ignora la dirección de la respuesta 227 y reutiliza la dirección de la conexión de control. Una transferencia que funciona con curl todavía puede fallar en un cliente gráfico por este único motivo.

Establezca la dirección explícitamente. vsftpd acepta pasv_address=203.0.113.10 y también pasv_addr_resolve=YES (valor predeterminado: NO) si prefiere escribir un nombre de host. ProFTPD acepta MasqueradeAddress, que admite una dirección, un nombre DNS o un nombre de interfaz. Pure-FTPd acepta -P, documentado para el caso en que «el servidor está detrás de un dispositivo de enmascaramiento (NAT)». EPSV evita todo el problema porque su respuesta no contiene ningún campo de dirección, pero no puede depender de ello, ya que el cliente decide qué comando enviar.

Qué cambia con TLS

FTPS es FTP sobre TLS (seguridad de la capa de transporte). El cliente se conecta al puerto 21 como de costumbre, envía AUTH TLS para proteger el canal de control y después envía PROT P para cifrar también el canal de datos. FTP sin cifrado transmite la contraseña como texto legible, por lo que, si debe mantener FTP, ejecute FTPS. vsftpd se distribuye con ssl_enable establecido de forma predeterminada en NO.

De aquí se derivan dos consecuencias. Ningún helper de seguimiento de conexiones puede funcionar, que es el mismo punto anterior visto desde el otro lado. Además, sudo tcpdump -nAi any 'tcp port 21' ya no le mostrará la respuesta 227, por lo que, cuando necesite saber qué dirección y puerto anunció el servidor, debe consultar el registro del propio servidor en lugar del tráfico de red.

Prueba del cambio desde el exterior

Ejecute estos comandos desde otra máquina. Probar desde el propio servidor omite el firewall que intenta corregir.

sudo ss -ltnp | grep :21
curl -v --disable-epsv --user ftpuser:secret ftp://example.com/
nc -vz example.com 30000

ss debe mostrar el daemon FTP escuchando en el puerto 21. Cuando el servidor está inactivo, ningún proceso escucha en el rango pasivo, porque esos sockets se crean para una transferencia y se cierran después.

--disable-epsv obliga a curl a usar la ruta PASV, que es la que expone el problema de la dirección. La traza muestra la respuesta del servidor y, después, la dirección y el puerto a los que curl se conecta:

< 227 Entering Passive Mode (203,0,113,10,117,52)

117 * 256 + 52 = 30004, dentro del rango declarado. Una dirección privada en esa línea significa que pasv_address no está definido. Un puerto fuera del rango significa que el servidor nunca leyó el cambio de configuración. Compruebe que editó el archivo que usa el servicio en ejecución.

nc responde por sí solo a la pregunta sobre el firewall. Un Connection refused inmediato significa que el paquete llegó al servidor y no encontró ningún proceso escuchando. Este es el resultado correcto para un puerto pasivo inactivo: la regla funciona. Si la conexión queda bloqueada hasta que nc la abandona, algo descartó el paquete de forma silenciosa. Se trata de un firewall, ya sea el del servidor o el del panel del proveedor. Esta distinción es la misma que se describe en conexión rechazada frente a tiempo de espera agotado para SSH y se aplica a todos los puertos.

¿Debe seguir ejecutando FTP?

Para trabajos nuevos, no. SFTP (protocolo de transferencia de archivos de SSH) funciona dentro de una única conexión SSH en el puerto 22. No hay un segundo canal, un rango pasivo, una configuración de NAT ni un daemon adicional que proteger, porque OpenSSH ya proporciona esta función. sftp user@example.com funciona en un equipo en el que nunca se configuró un servicio de transferencia de archivos. Para entregar archivos sin conceder nada más, sshd_config toma ForceCommand internal-sftp junto con ChrootDirectory. Ese directorio debe pertenecer a root y el usuario no debe poder escribir en él; de lo contrario, sshd rechaza la sesión y registra una línea bad ownership or modes for chroot directory.

FTP sigue siendo útil cuando el otro extremo no se puede cambiar. Los escáneres y las impresoras multifunción se distribuyen con firmware que sólo admite FTP. Los equipos de laboratorio e industriales suelen ejecutar una imagen fija que nadie volverá a certificar. Los socios comerciales publican un destino FTPS y no añadirán otro protocolo para un único proveedor. En cada uno de estos casos, el rango pasivo y la regla de firewall correspondiente son todo el trabajo necesario, y se debe ejecutar FTPS en lugar de FTP sin cifrar. El diseño de dos canales es una decisión de 1985 que ahora funciona en un entorno que nunca se tuvo en cuenta, una historia que se explica en la historia de los protocolos de transferencia de archivos.

FAQ

¿Por qué FTP inicia sesión, pero se bloquea el listado del directorio?

El inicio de sesión usa sólo la conexión de control en el puerto 21, que el firewall permite. El listado del directorio necesita una segunda conexión TCP en otro puerto, y esa conexión está bloqueada. Declare un intervalo de puertos pasivos en el servidor FTP y abra el mismo intervalo en el firewall. Entonces el listado se completará. Un listado bloqueado es un problema del canal de datos, nunca de la contraseña.

¿Qué puertos debo abrir para el modo pasivo de FTP?

El puerto 21 para el canal de control, además del intervalo que haya configurado para las conexiones de datos pasivas. No existe un intervalo estándar, porque usted lo elige. Un intervalo como 30000 a 30099 funciona: ajústelo al número máximo de transferencias simultáneas y manténgalo fuera del intervalo de puertos salientes del kernel, que puede consultar con sysctl net.ipv4.ip_local_port_range. Si su proveedor ejecuta un firewall de red en su panel de control, abra allí también el mismo intervalo.

¿Sigo necesitando nf_conntrack_ftp?

No, y no puede depender de él en un kernel actual. La asignación automática de helpers está deshabilitada de forma predeterminada, y en los kernels recientes se ha eliminado la opción net.netfilter.nf_conntrack_helper, por lo que sysctl informa de que el archivo no existe. El manual de ufw considera obsoleta la carga incondicional de esos módulos, y firewalld ignora AutomaticHelpers por completo. Además, un helper debe leer el canal de control como texto sin cifrar, por lo que deja de funcionar en cuanto habilita FTPS. Declare un intervalo de puertos pasivos en su lugar.

¿Por qué mi cliente FTP indica que la respuesta pasiva contiene una dirección no enrutable?

El servidor respondió PASV con la dirección que ve en su propia interfaz, y esa dirección es privada. Esto ocurre cuando la plataforma asigna una dirección pública a una dirección privada. Establezca explícitamente la dirección pública: pasv_address en vsftpd, MasqueradeAddress en ProFTPD o -P en Pure-FTPd. FileZilla lo corrige reutilizando la dirección a la que ya se había conectado y registra "Using server address instead". Por eso algunos clientes superan la configuración incorrecta y otros se bloquean.

¿Debo usar FTPS o SFTP?

Use SFTP para todo lo que controle en ambos extremos: una conexión mediante SSH en el puerto 22, sin ningún canal de datos que abrir, y ya está en funcionamiento. FTPS es FTP sobre TLS, por lo que mantiene el diseño de dos canales y todos los problemas de firewall asociados. Elíjalo cuando el otro extremo no admita ninguna otra opción. No use FTP sin cifrado a través de Internet, porque la contraseña atraviesa la red como texto legible.