Часто системные администраторы сталкиваются с ситуацией, когда FTP-сервер доступен через браузер или графический клиент (например, FileZilla), но попытка подключения через стандартную командную строку (cmd) заканчивается ошибкой «Время подключения истекло». Особенно это критично при настройке автоматической передачи резервных копий между серверами. Разберем подробно, почему так происходит и какие способы решения существуют в современных операционных системах, таких как Windows 10 и Windows Server 2019.
Для начала проанализируем ситуацию. Основная проблема кроется в архитектуре самого протокола FTP и реализации стандартной утилиты ftp.exe в Windows. Рассмотрим два главных фактора:
ftp.exe поддерживает только активный режим. Если клиент находится за брандмауэром или NAT (что обычно и бывает), сервер не может «простучаться» обратно к клиенту, и соединение обрывается. Браузеры же по умолчанию используют пассивный режим, поэтому в них все работает.open ip_address в консоли не сработает, так как она по умолчанию ищет 21 порт.Поскольку на Windows Server 2019 и Windows 10 утилита curl уже встроена в систему, это самый простой и надежный способ передачи файлов через консоль. Она поддерживает пассивный режим «из коробки» и отлично справляется с нестандартными портами. Рассмотрим пример команды для загрузки файла на сервер:
curl.exe --upload-file C:\Backups\backup8.rar ftp://username:password@192.168.0.111:2121/
Разберем параметры этой команды подробнее. Флаг --upload-file указывает путь к локальному файлу, который мы хотим передать. Далее следует строка подключения, где мы указываем логин, пароль, IP-адрес и порт 2121. Этот метод лишен проблем с портами данных и брандмауэром, которые возникают у ftp.exe.
Если нам нужно реализовать более сложную логику (например, проверку существования файла или ведение логов), проанализируем возможности PowerShell. Это мощный инструмент, который позволяет использовать классы .NET для работы с FTP в пассивном режиме. Рассмотрим пример скрипта для отправки файла:
$sourceFile = "C:\Backups\data.zip"
$ftpUrl = "ftp://192.168.0.111:2121/data.zip"
$user = "ftp_user"
$pass = "ftp_password"
$webClient = New-Object System.Net.WebClient
$webClient.Credentials = New-Object System.Net.NetworkCredential($user, $pass)
$webClient.UploadFile($ftpUrl, $sourceFile)
В данном примере мы создаем объект WebClient, который по умолчанию умеет корректно обходить сетевые ограничения. Это гораздо стабильнее, чем использование устаревшей команды ftp.
Если по каким-то причинам нам необходимо использовать именно ftp.exe, выясним, как правильно настроить окружение. Нам потребуется открыть не только управляющий порт, но и порты передачи данных.
Чтобы подключиться к нестандартному порту в консоли, используем следующий синтаксис:
C:\>ftp
ftp> open 192.168.0.111 2121
Обратите внимание, что порт указывается через пробел после IP-адреса, а не через двоеточие. Однако помните: даже при правильном указании порта, передача данных (команда ls или put) может зависнуть из-за блокировки активного режима вашим роутером или провайдером.
Проанализируем вопрос безопасности. Передача данных по обычному протоколу FTP в открытом интернете крайне небезопасна, так как пароли передаются в незашифрованном виде. Посмотрим на альтернативы:
FileZilla Server. Он предоставляет более наглядные логи, где сразу видно, на каком этапе (авторизация или открытие порта данных) происходит сбой.Таким образом, для решения проблемы в cmd мы рекомендуем отказаться от использования ftp.exe в пользу curl или PowerShell. Это сэкономит время на настройке маршрутизации и обеспечит стабильную работу ваших автоматических процессов.