SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-21

Почему зависает список файлов FTP в пассивном режиме

Если авторизация проходит успешно, а команда LIST зависает, проблема в блокировке портов данных. Узнайте, какой диапазон портов PassivePorts нужно открыть в firewall.

Почему FTP авторизуется, но список каталогов зависает

Пассивный режим FTP перестает работать при наличии межсетевого экрана, так как протокол FTP использует два TCP-соединения, а не одно. Соединение с портом 21 передает данные авторизации и команды, поэтому имя пользователя и пароль принимаются, и межсетевой экран кажется настроенным верно. Первое ls затем требует второго соединения на другом порту. Межсетевой экран не разрешает это соединение, поэтому клиент ожидает ответа до истечения времени ожидания.

Решение заключается в фиксации диапазона портов для этих соединений передачи данных и добавлении правила в межсетевой экран, разрешающего этот диапазон. Серверу за NAT (network address translation) требуется дополнительная настройка, чтобы он анонсировал корректный адрес. Раньше эту работу выполняли модули отслеживания соединений (connection tracking helpers). Сейчас они этого не делают, и стоит понять причину, прежде чем копировать старые руководства.

Канал управления и канал передачи данных

Протокол FTP (file transfer protocol) описан в RFC 959 и появился раньше NAT и stateful-файрволов. Сессия открывает одно управляющее соединение на TCP-порт 21 и удерживает его открытым на протяжении всего сеанса. Команды передаются в виде обычного текста. Ответы приходят в виде трёхзначного кода и строки текста. Это соединение никогда не передаёт содержимое файлов.

Для каждой порции данных создаётся отдельное TCP-соединение: одно для листинга директории (LIST), по одному для каждой загрузки (RETR) и выгрузки (STOR). Соединение открывается, используется один раз и закрывается. Аутентификация происходит полностью через канал управления, поэтому неисправный канал данных всегда выглядит одинаково: успешный вход в систему, а затем зависание. Если клиент выводит ответ 230, а затем останавливается на листинге, проблема заключается в канале передачи данных, а не в учётных данных.

Активный режим: сервер подключается к клиенту

В активном режиме клиент выбирает порт, начинает его прослушивать и сообщает серверу, куда нужно подключиться:

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

Первые четыре числа — это IP-адрес клиента. Последние два — порт, закодированный как два байта: 195 * 256 + 80 = 50000. Затем сервер открывает соединение для передачи данных с собственного порта 20 на порт 50000 клиента.

С точки зрения клиента это входящее и не запрашиваемое соединение, поэтому межсетевой экран клиента его блокирует. Если клиент находится за домашним маршрутизатором, адрес в команде PORT является частным, и сервер не может получить к нему доступ. Именно из-за активного режима FTP получил репутацию протокола, который постоянно не работает.

Пассивный режим: клиент открывает оба соединения

Пассивный режим меняет направление соединения для передачи данных. Клиент отправляет PASV, а сервер отвечает своим адресом и портом:

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

Кодировка та же, поэтому клиент подключается к 203.0.113.10 на порт 50000. Теперь клиент открывает оба соединения, поэтому пассивный режим работает при наличии NAT на стороне клиента, и именно поэтому все современные клиенты запрашивают его в первую очередь.

Проблема не исчезла, а переместилась. Теперь нежелательное входящее соединение поступает на ваш сервер, на высокий порт, который меняется при каждой передаче. Этот файрвол — ваш, поэтому теперь это ваша проблема.

EPSV (расширенный пассивный режим, RFC 2428) использует ту же идею, но с более понятным ответом:

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

В нем нет адреса. Клиент повторно использует адрес, который уже применяется для управляющего соединения, что обеспечивает работу через IPv6 и устраняет целый класс ошибок, связанных с NAT. В руководстве curl указано, что curl обычно пытается использовать EPSV перед PASV. Порт по-прежнему выбирается во время выполнения, поэтому EPSV никак не меняет ваши правила файрвола.

Почему обычное правило межсетевого экрана не может разрешить канал передачи данных

Потому что номер порта еще не существует в момент создания правила. Сервер выбирает его для каждой передачи отдельно. При стандартных настройках в документации vsftpd указаны pasv_min_port и pasv_max_port как 0, что означает «использовать любой порт», поэтому соединение для передачи данных может прийти на любой порт выше 1023. sudo ufw allow 21/tcp разрешает только канал управления и ничего более, именно эта конфигурация приводит к успешному входу в систему и зависанию при попытке получения списка файлов. Если концепция сервиса, ожидающего соединение на одном фиксированном порту, все еще неясна, как работают порты и слушающие сокеты в Linux содержит необходимую справочную информацию.

Межсетевой экран с поддержкой отслеживания состояний (stateful firewall) действительно отслеживает соединения, и ядро может разрешить новое соединение как RELATED для уже существующего. Для FTP требуется, чтобы некий механизм считывал поток управления и извлекал номер порта из строки 227 или PORT. По умолчанию это не делает никто.

Почему вспомогательный модуль отслеживания соединений FTP больше не является решением

Модуль ядра nf_conntrack_ftp — это то, на что ссылаются устаревшие руководства. Он считывает управляющий канал в открытом виде, находит объявленный порт и регистрирует ожидание, благодаря чему соединение для передачи данных разрешается без создания правила, явно указывающего этот порт. С момента написания этих руководств изменились четыре вещи.

Автоматическое назначение вспомогательных модулей отключено. В документации ядра параметр sysctl nf_conntrack_helper описан как «0 — отключено (по умолчанию)» с примечанием: «Если отключено, необходимо настроить правила iptables для назначения вспомогательных модулей соединениям». Загрузка модуля сама по себе ничего не дает.

В современных ядрах этот переключатель отсутствует. Выполните sysctl net.netfilter.nf_conntrack_helper. Ответ sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_helper: No such file or directory означает, что в ядре больше нет функции автоматического назначения вспомогательных модулей, которую можно было бы включить. Если в ответ приходит число, значит, переключатель все еще присутствует, а его значение по умолчанию — 0.

Интерфейсы управления межсетевым экраном также отказались от этого метода. man ufw-framework в Ubuntu 24.04 сообщает о строке IPT_MODULES в файле /etc/default/ufw: «Безусловная загрузка модулей отслеживания соединений (nf_conntrack_*) таким способом является устаревшей», и добавляет, что правила для вспомогательных модулей «должны управляться через ФАЙЛЫ ПРАВИЛ». В документации firewalld параметр AutomaticHelpers в firewalld.conf помечен как «Устаревший. Эта опция игнорируется и больше не используется». Подключение вспомогательного модуля теперь требует ручного создания явного правила с целью CT, что сложнее, чем предлагаемое ниже решение, и перестает работать в момент включения TLS. В iptables и nftables в Ubuntu описано, где именно располагаются эти правила.

TLS окончательно закрывает этот вопрос. Вспомогательный модуль работает, считывая управляющий канал как текст. Зашифруйте этот канал, и модуль увидит только зашифрованные данные, поэтому он не сможет найти порт. Исправить это невозможно, да и не нужно: промежуточное устройство, способное прочитать ваш управляющий канал, — это устройство, которое может прочитать ваш пароль.

Declare a passive port range on the server

Every FTP server can be told to choose its passive ports from a range you pick. The option names differ, so check the documentation for the server you actually run.

vsftpd, in /etc/vsftpd.conf:

pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30099

pasv_enable already defaults to YES. The two port options default to 0, the "use any port" behaviour described above. Apply with sudo systemctl restart vsftpd, then confirm the service came back with systemctl status vsftpd. vsftpd refuses to start on a configuration line it cannot parse rather than ignoring it, so if the restart fails, read journalctl -u vsftpd -n 20 for the 500 OOPS: line naming the option you just typed.

ProFTPD, in proftpd.conf:

PassivePorts 30000 30099

ProFTPD documents no default here: without the directive the kernel picks the port. Its documentation also states that when no port in your range is free, the server falls back to a kernel assigned port and logs a message. A range that is too small therefore fails now and then instead of failing cleanly, which is far harder to diagnose. Use non privileged ports, 1024 and above.

Pure-FTPd takes a flag, -p first:last, documented in man pure-ftpd as "Use only ports in the range first to last inclusive for passive-mode downloads", which "makes pure-ftpd more compatible with packet filters". Packaged builds usually wrap that flag in a config file, so check your distribution's own docs for the file name rather than guessing.

How many ports do you need? One per data connection in flight. A closed TCP port stays in TIME_WAIT for a couple of minutes before it can be reused, so allow several times your expected peak. A hundred ports is comfortable for a few users, and a busy public server needs far more.

Where should the range sit? Run sysctl net.ipv4.ip_local_port_range first. On a stock Ubuntu box it reads 32768 60999, the ports the kernel hands out for outgoing connections. A passive range inside that window can collide with an outbound connection that already holds the port, so keep the range below it. 30000 to 30099 is clear on a default box. Check your own box rather than trusting that number.

Откройте тот же диапазон в межсетевом экране

ufw записывает диапазон через двоеточие, и в руководстве указано, что диапазон или список «также могут использоваться для указания нескольких портов, в этом случае требуется указать протокол»:

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

ufw status verbose теперь должен отобразить обе записи. Та же команда без /tcp будет отклонена с ошибкой, требующей указать tcp или udp, так как ufw не будет пытаться угадать настройки. Синтаксис правил ufw на VPS описывает остальные детали.

firewalld записывает диапазон через дефис и требует перезагрузки:

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 открывает 21/tcp и запрашивает вспомогательный модуль ftp, который указан в поставляемом определении службы. Это не открывает ваш пассивный диапазон, поэтому само по себе это действие не меняет ситуацию. Зоны и службы firewalld на VPS дает более полное представление.

Прямая настройка nftables внутри вашей цепочки input:

tcp dport { 21, 30000-30099 } accept

Еще один межсетевой экран, о котором стоит помнить: большинство провайдеров используют сетевой экран в панели управления, за пределами операционной системы. Если правила на сервере выглядят корректно, но пакеты всё равно не доходят, откройте тот же диапазон и там.

Укажите серверу его публичный адрес при работе за NAT

Запустите ip -4 addr show на сервере. Если адрес на сетевом интерфейсе совпадает с тем, к которому подключаются клиенты, пропустите этот раздел. Если на интерфейсе указан частный адрес (10.x, 172.16–172.31.x, 192.168.x), а платформа транслирует его в публичный, сервер не знает свой внешний адрес. В документации vsftpd для pasv_address указано, что по умолчанию «адрес берется из входящего сокета подключения», поэтому в ответе 227 передается частный адрес, и клиент пытается подключиться туда, куда нет доступа.

FileZilla называет эту проблему прямо:

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

FileZilla исправляет её и продолжает работу. Многие другие клиенты этого не делают. Они пытаются подключиться к 10.0.0.5 и зависают.

curl также скрывает эту проблему, что важно, если вы используете curl для тестирования. В руководстве сказано, что --ftp-skip-pasv-ip «включен по умолчанию (добавлено в 7.74.0)», поэтому curl игнорирует адрес в ответе 227 и повторно использует адрес управляющего соединения. Передача данных, которая работает через curl, может не работать в графическом клиенте именно по этой причине.

Укажите адрес явно. vsftpd использует параметр pasv_address=203.0.113.10, а также pasv_addr_resolve=YES (по умолчанию NO), если вы предпочитаете использовать имя хоста. ProFTPD использует MasqueradeAddress, который принимает адрес, DNS-имя или имя интерфейса. Pure-FTPd использует -P, предназначенный для случаев, когда «сервер находится за NAT (masquerading)». EPSV позволяет избежать этой проблемы, так как в ответе нет поля с адресом, но полагаться на это нельзя, поскольку клиент сам решает, какую команду отправить.

Изменения в TLS

FTPS — это FTP поверх TLS (transport layer security). Клиент подключается к порту 21 как обычно, отправляет AUTH TLS для защиты канала управления, а затем отправляет PROT P для шифрования канала передачи данных. Обычный FTP передает пароль в открытом виде, поэтому, если использование FTP необходимо, используйте FTPS. В состав vsftpd входит ssl_enable, где по умолчанию установлено NO.

Из этого следуют два вывода. Во-первых, вспомогательные модули отслеживания соединений (connection tracking helpers) не будут работать, что является следствием описанного выше пункта. Во-вторых, sudo tcpdump -nAi any 'tcp port 21' больше не покажет вам ответ 227. Поэтому, если вам нужно узнать, какой адрес и порт анонсировал сервер, читайте собственный лог сервера, а не сетевой трафик.

Тестирование изменений извне

Запускайте эти команды с другого компьютера. Тестирование с самого сервера пропускает межсетевой экран, который вы пытаетесь настроить.

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

ss должен показать, что FTP-демон ожидает соединений на 21 порту. В режиме ожидания в пассивном диапазоне портов ничего не должно быть открыто, так как эти сокеты создаются только на время передачи данных и закрываются сразу после её завершения.

--disable-epsv принудительно направляет curl по пути PASV, который и выявляет проблему с адресом. Трассировка выводит ответ сервера, а затем адрес и порт, к которым пытается подключиться curl:

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

117 * 256 + 52 = 30004, что находится внутри заданного диапазона. Если в этой строке указан частный IP-адрес, значит, параметр pasv_address не задан. Если порт выходит за пределы вашего диапазона, значит, сервер не применил изменения конфигурации; проверьте, что вы редактировали именно тот файл, который использует запущенный сервис.

nc самостоятельно отвечает на вопрос о работе межсетевого экрана. Мгновенный ответ Connection refused означает, что пакет достиг сервера и не обнаружил слушающего процесса, что является корректным результатом для пассивного порта в режиме ожидания: ваше правило работает. Если соединение зависает до тех пор, пока nc не прервет операцию, значит, пакеты были молча отброшены межсетевым экраном — либо на самом сервере, либо на стороне вашего провайдера. Это различие аналогично описанному в отказе в соединении против таймаута для SSH, и оно применимо к любому порту.

Стоит ли до сих пор использовать FTP?

Для новых задач — нет. SFTP (SSH file transfer protocol) работает внутри одного SSH-соединения через порт 22. Здесь нет второго канала, нет диапазона пассивных портов, нет настроек NAT и нет дополнительного демона, требующего защиты, так как всё это уже обеспечивает OpenSSH. sftp user@example.com работает на сервере, где вы вообще не настраивали службу передачи файлов. Чтобы предоставить кому-либо доступ только к файлам, sshd_config использует ForceCommand internal-sftp вместе с ChrootDirectory. Этот каталог должен принадлежать пользователю root и не должен быть доступен для записи пользователю, иначе sshd отклонит сессию и запишет в лог строку bad ownership or modes for chroot directory.

FTP сохраняет актуальность в тех случаях, когда на другой стороне ничего нельзя изменить. Сканеры и многофункциональные устройства поставляются с прошивками, которые поддерживают только FTP. Лабораторное и промышленное оборудование часто работает на фиксированном образе, который никто не будет пересертифицировать. Бизнес-партнеры предоставляют FTP-ресурс и не будут добавлять новый протокол ради одного поставщика. В каждом из этих случаев настройка диапазона пассивных портов и соответствующего правила межсетевого экрана — это вся работа, при этом следует использовать FTPS, а не обычный FTP. Двухканальная архитектура — это решение 1985 года, которое сейчас работает в мире, к которому оно не было готово; эта история описана в истории протоколов передачи файлов.

FAQ

Почему FTP авторизуется, но список файлов не загружается?

Авторизация использует только управляющее соединение на порту 21, которое разрешено вашим межсетевым экраном. Список файлов требует второго TCP-соединения на другом порту, и это соединение блокируется. Укажите диапазон пассивных портов в настройках FTP-сервера и откройте этот же диапазон в межсетевом экране — тогда список будет загружаться. Зависание при получении списка файлов — это проблема канала передачи данных, а не пароля.

Какие порты нужно открыть для пассивного режима FTP?

Порт 21 для канала управления, плюс диапазон, который вы настроили для пассивных соединений передачи данных. Стандартного диапазона не существует, так как вы выбираете его сами. Подойдет, например, диапазон от 30000 до 30099: подберите его размер в соответствии с пиковым количеством одновременных передач и убедитесь, что он не пересекается с диапазоном исходящих портов ядра, который можно узнать через sysctl net.ipv4.ip_local_port_range. Если ваш провайдер предоставляет межсетевой экран в панели управления, откройте этот же диапазон и там.

Нужен ли мне еще nf_conntrack_ftp?

Нет, и в актуальных версиях ядра полагаться на него нельзя. Автоматическое назначение помощников (helpers) отключено по умолчанию, а в последних версиях ядра переключатель net.netfilter.nf_conntrack_helper был удален, поэтому sysctl сообщает об отсутствии файла. В документации ufw ручная загрузка этих модулей помечена как устаревшая, а firewalld полностью игнорирует AutomaticHelpers. Кроме того, помощник должен читать канал управления в открытом виде, поэтому он перестает работать, как только вы включаете FTPS. Вместо этого используйте явно заданный диапазон пассивных портов.

Почему FTP-клиент сообщает, что пассивный ответ содержит немаршрутизируемый адрес?

Сервер ответил PASV адресом, который он видит на своем собственном интерфейсе, и этот адрес является частным. Это происходит, когда платформа транслирует публичный адрес в частный. Укажите публичный адрес явно: pasv_address в vsftpd, MasqueradeAddress в ProFTPD или -P в Pure-FTPd. FileZilla обходит эту проблему, повторно используя адрес, к которому уже подключилась, и записывает в лог "Using server address instead" — именно поэтому некоторые клиенты работают при такой неверной конфигурации, а другие зависают.

Что использовать: FTPS или SFTP?

SFTP подходит для случаев, когда вы контролируете обе стороны: одно соединение по SSH на порту 22, не нужно открывать дополнительные каналы данных, и всё уже работает. FTPS — это FTP поверх TLS, поэтому он сохраняет архитектуру из двух каналов и все сопутствующие проблемы с межсетевыми экранами. Выбирайте его, если другая сторона не поддерживает ничего другого. Не используйте обычный FTP через Интернет, так как пароль передается по сети в открытом виде.