FTP en modo pasivo: puertos y regla del firewall
Si FTP acepta el inicio de sesión pero el listado queda bloqueado, declara un rango fijo para el canal de datos y permite esos puertos en el firewall.
Por qué FTP permite iniciar sesión, pero el listado de directorios se bloquea
El modo pasivo de FTP falla con un firewall porque FTP utiliza 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. La primera ls necesita después una segunda conexión en otro puerto. El firewall no permite esa conexión, por lo que el cliente permanece bloqueado hasta que se agota el tiempo de espera.
La solución consiste en definir un rango fijo de puertos para esas conexiones de datos y añadir una regla del firewall que permita el mismo rango. Un servidor detrás de NAT (traducción de direcciones de red) necesita un ajuste adicional para anunciar la dirección correcta. Antes, los asistentes de seguimiento de conexiones se encargaban de esta tarea. Ya no lo hacen, y conviene conocer 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 constan de un código de tres dígitos y una línea de texto. Esa conexión nunca transporta contenido de archivos.
Cada bloque de datos usa su propia conexión TCP: una para un 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 un canal de datos interrumpido siempre produce el mismo síntoma: el inicio de sesión se completa y después la conexión se 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, empieza a escucharlo e indica al servidor dónde conectarse:
PORT 192,168,1,50,195,80Los cuatro primeros números son la dirección IP del cliente. Los dos últimos representan el puerto, codificado en 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 acceder a ella. El modo activo es la causa de la conocida 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. Ahora el cliente abre ambas conexiones. Por eso el modo pasivo funciona detrás de 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 con cada transferencia. Ese firewall es suyo, por lo que ahora el problema también es suyo.
EPSV (modo pasivo extendido, RFC 2428) aplica la misma idea con una respuesta más sencilla:
229 Entering Extended Passive Mode (|||50000|)No contiene ninguna dirección. El cliente reutiliza la dirección que ya tiene para la conexión de control. Esto permite que funcione sobre IPv6 y elimina toda una categoría 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 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 todavía no está claro qué significa que un servicio escuche en un puerto fijo, cómo funcionan los puertos y los sockets de escucha en Linux proporciona el contexto necesario.
Un firewall con seguimiento de estado sí registra las conexiones, y el kernel puede admitir una conexión nueva como RELATED de una conexión existente. En FTP, para ello se necesita algo que 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 indique su puerto. Desde que se escribieron esas guías, han cambiado cuatro aspectos.
La asignación automática de helpers está desactivada y, en los kernels actuales, ya no se puede volver a activar. El kernel la desactivó de forma predeterminada en 2016. Después, el commit de Pablo Neira Ayuso "netfilter: remove nf_conntrack_helper sysctl and modparam toggles" (agosto de 2022) eliminó por completo el interruptor y estableció que "users now have to rely on explicit conntrack helper configuration via ruleset." El sysctl nf_conntrack_helper está presente en Linux 5.19 y desaparece a partir de Linux 6.0; la documentación de sysctl de seguimiento de conexiones del kernel ya no lo incluye. Cargar el módulo por sí solo no consigue nada.
Puede comprobar qué tipo de kernel tiene. 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 obtiene un número, está usando un kernel anterior a 6.0, el interruptor todavía está presente y su valor predeterminado es 0.
Las interfaces de configuración del 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: "La carga incondicional de módulos de seguimiento de conexiones (nf_conntrack_*) de esta forma está obsoleta", y añade que las reglas de helpers "deben gestionarse mediante los ARCHIVOS DE REGLAS". firewalld documenta AutomaticHelpers en firewalld.conf como "Obsoleto. Esta opción se ignora y ya no se utiliza". Asociar ahora un helper implica 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 hay solución para esto, y tampoco debería haberla: un dispositivo intermedio capaz de leer su canal de control es un dispositivo intermedio que ha leído su contraseña.
Declare un rango de puertos pasivos en el servidor
Todos los servidores FTP pueden configurarse para elegir sus puertos pasivos dentro 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=30099pasv_enable ya tiene el valor predeterminado YES. Las dos opciones de puertos tienen 0 de forma predeterminada: el comportamiento de «usar cualquier puerto» descrito antes. Aplique el cambio con sudo systemctl restart vsftpd y confirme después que el servicio haya vuelto a iniciarse con systemctl status vsftpd. vsftpd se niega a iniciar cuando no puede analizar una línea de configuración, en lugar de ignorarla. 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 30099ProFTPD no documenta ningún valor predeterminado en este caso: sin la directiva, el kernel elige el puerto. La documentación de ProFTPD también indica que, cuando ningún puerto del rango está libre, el servidor recurre a 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 resulta mucho más difícil de diagnosticar. Use puertos no privilegiados, 1024 o superiores.
Pure-FTPd usa un indicador, -p first:last, documentado en man pure-ftpd como «usar primero sólo los puertos del rango entre el primero y el último, ambos inclusive, para las descargas en modo pasivo». Esto «hace que pure-ftpd sea más compatible con los filtros de paquetes». Las compilaciones empaquetadas suelen incluir ese indicador 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 correspondiente al pico previsto. Cien puertos son suficientes para unos pocos usuarios, pero un servidor público con mucha actividad necesita muchos más. vsftpd es menos tolerante que ProFTPD en este aspecto: su código fuente intenta usar varios puertos aleatorios dentro del rango y, si todos están ocupados, termina la sesión con 500 OOPS: vsf_sysutil_bind en lugar de tomar un puerto fuera del rango. En cualquiera de los dos servidores, un rango demasiado pequeño interrumpe las transferencias en el momento de mayor actividad.
¿Dónde debe ubicarse 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 esté usando el puerto, 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.
Abrir 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 ese caso, el protocolo es obligatorio»:
sudo ufw allow 21/tcp
sudo ufw allow 30000:30099/tcp
sudo ufw status verboseufw status verbose debería mostrar ahora las dos entradas. El mismo comando sin /tcp se rechaza con un error que indica que debe especificar tcp o udp, porque ufw no hace suposiciones. sintaxis de reglas de ufw en un VPS explica 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 figura en la definición de servicio incluida. 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 ofrece una visión más amplia.
nftables directamente, dentro de la cadena input:
tcp dport { 21, 30000-30099 } acceptHay otro firewall que debe tener en cuenta: 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 también allí el mismo rango.
Indicar la dirección pública al servidor cuando está detrás de NAT
Ejecute ip -4 addr show en el servidor. Si la dirección de la interfaz es la que usan los clientes para conectarse, 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 recibe una dirección a la que no puede acceder.
FileZilla muestra este mensaje exactamente:
Server sent passive reply with unroutable address. Using server address instead.FileZilla lo corrige 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, lo cual es importante si usa curl para realizar la prueba. Su manual indica que --ftp-skip-pasv-ip «está habilitado de forma predeterminada (añadido 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 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, además de 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 por la red como texto legible. Si debe mantener FTP, use FTPS. vsftpd se distribuye con ssl_enable configurado de forma predeterminada en NO.
De aquí se derivan dos consecuencias. Ningún helper de seguimiento de conexiones puede funcionar. 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 de inspeccionar el tráfico de red.
Pruebas del cambio desde el exterior
Ejecute estos comandos desde otra máquina. Si prueba desde el propio servidor, omitirá el firewall que intenta corregir.
sudo ss -ltnp | grep :21
curl -v --disable-epsv --user ftpuser:secret ftp://example.com/
nc -vz example.com 30000ss debería mostrar el daemon FTP escuchando en el puerto 21. Mientras 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 dirección. El trazado 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 de su rango significa que el servidor nunca leyó el cambio de configuración. Compruebe que editó el archivo que utiliza 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 abandona, significa que 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 en 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 otro daemon que proteger, porque OpenSSH ya proporciona todo ello. sftp user@example.com funciona en un sistema en el que nunca haya configurado un servicio de transferencia de archivos. Para proporcionar a alguien archivos y nada más, sshd_config acepta 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 necesario 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 todos esos casos, el rango pasivo y la regla de firewall correspondiente son todo el trabajo necesario, y debe usarse FTPS en lugar de FTP sin cifrar. El diseño de dos canales es una decisión de 1980, ya presente en RFC 765 cinco años antes de que RFC 959 lo mantuviera, y ahora funciona en un entorno que nunca anticipó, una historia que se explica en la historia de los protocolos de transferencia de archivos.
FAQ
¿Por qué FTP inicia sesión, pero el listado del directorio se bloquea?
El inicio de sesión usa sólo la conexión de control del 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 rango de puertos pasivos en el servidor FTP, abra el mismo rango en el firewall y el listado se completará. Un listado bloqueado indica un problema del canal de datos, nunca un problema de contraseña.
¿Qué puertos debo abrir para el modo pasivo de FTP?
El puerto 21 para el canal de control, además del rango que haya configurado para las conexiones de datos pasivas. No existe un rango estándar, porque usted lo elige. Un rango como 30000 a 30099 funciona: ajústelo al número máximo de transferencias simultáneas y manténgalo fuera del rango 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 también allí el mismo rango.
¿Sigo necesitando nf_conntrack_ftp?
No, y en un kernel actual no puede depender de él. La asignación automática de helpers está deshabilitada de forma predeterminada y, desde Linux 6.0, se eliminó el conmutador 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 rango 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ó a 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 conectó y registra "Using server address instead". Por eso algunos clientes funcionan pese a la configuración incorrecta y otros se bloquean.
¿Debo usar FTPS o SFTP?
Use SFTP para cualquier conexión que controle en ambos extremos: utiliza una única conexión SSH en el puerto 22, no requiere abrir un canal de datos y normalmente ya está disponible. FTPS es FTP sobre TLS, por lo que mantiene el diseño de dos canales y todos los problemas de firewall asociados. Elija FTPS 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.