# FTP и SFTP - передача файлов _Протоколы · LinuxLab Knowledge Base_ **TL;DR:** FTP, старый протокол с control + data соединениями (active/passive modes), без шифрования. SFTP, подсистема SSH, ничего общего с FTP кроме имени. Сегодня, SFTP или [[cmd-rsync|rsync]]. ## Зачем понимать оба **FTP** (RFC 959, 1985), древний протокол. На современных серверах его место занял **SFTP** (часть SSH). Но FTP ещё встречается: - Старые ISP и hosting-панели (cPanel, Plesk) - Embedded-устройства (роутеры, прошивки firmware-апдейтов) - Anonymous FTP-зеркала Linux-distro (`ftp.debian.org` → теперь HTTPS) - Legacy CI/CD pipelines SFTP, стандарт для нового кода. Один порт, шифрование, аутентификация по ключу, работает через NAT, не требует отдельного сервиса (если есть SSH). ## FTP, два соединения Принципиальная странность FTP: **два TCP-соединения** на сессию: ``` Client Server │ │ │ TCP-соединение к порту 21 (control) ├───────────────────────────────────►│ │ USER alice │ │ PASS secret │ │ (команды и ответы текстом) │ │ │ │ STOR file.bin │ │ ←─── server ОТКРЫВАЕТ data-соединение к клиенту (active) │ ИЛИ: server говорит "слушаю на N", клиент подключается (passive) │ │ ``` - **Control connection** (порт 21), команды текстом: `USER`, `PASS`, `LIST`, `RETR`, `STOR`, `QUIT`. Ответы, три цифры + текст (`220 Welcome`, `530 Login incorrect`, `226 Transfer complete`). - **Data connection**, отдельное TCP. Может открываться двумя способами. ### Active mode Клиент шлёт `PORT a,b,c,d,p1,p2`, "я слушаю на IP `a.b.c.d` порту `p1*256+p2`". Сервер **подключается к клиенту**. Проблема: клиент за NAT не имеет публичного IP, не может принять входящий коннект. Active mode на современных клиентах редко работает. ### Passive mode (PASV) Клиент шлёт `PASV`. Сервер отвечает `227 Entering Passive Mode (a,b,c,d,p1,p2)`, "подключайся ко мне на этом IP/порту". Клиент подключается. **Клиент-инициированы оба соединения.** Современный default. Но проблема перемещается на сервер: его NAT/firewall должен пробрасывать **диапазон портов** для PASV-data-каналов. В `vsftpd.conf`: ``` pasv_enable=YES pasv_min_port=40000 pasv_max_port=40100 pasv_address=203.0.113.10 # для NAT'а перед сервером ``` Затем открыть в фаерволе диапазон 40000-40100 + 21. ## FTPS, FTP + TLS Не путать с SFTP! **FTPS**, это FTP с TLS-обёрткой: - **Implicit FTPS**: TLS-handshake сразу при подключении на 990 - **Explicit FTPS**: подключение на 21 → команда `AUTH TLS` → TLS-handshake Решает шифрование, но **не решает** двухсоединительную архитектуру. Data-канал тоже надо шифровать (`PROT P`), и фаервол всё равно должен знать про PASV-диапазон. В 2026 FTPS, нишевый легаси. Используется в финсекторе для compliance, если "стандарт говорит FTP с шифрованием". ## SFTP, это SSH SFTP (SSH File Transfer Protocol, не путать с simple FTP), **подсистема SSH** (RFC 4254). Внутри SSH-соединения запускается `sftp-server`, который отвечает на бинарный protocol для файловых операций. Никакого TCP-21, никакого PASV/active. Один TCP-22 порт, шифрование и аутентификация, те же, что у `ssh`. Включено в openssh-server по дефолту, в `/etc/ssh/sshd_config`: ``` Subsystem sftp /usr/lib/openssh/sftp-server ``` Использование: ```bash sftp user@server # интерактивный shell sftp> ls sftp> put localfile remotefile sftp> get remotefile localfile sftp> bye sftp -P 2222 user@server # нестандартный SSH-порт # batch-режим echo "put file.bin /upload/" | sftp user@server ``` ## SCP vs SFTP ```bash scp file.bin user@server:/upload/ ``` - **scp** (Secure Copy), простой "rcp поверх SSH"; один файл/директория, без интерактивности. - **sftp**, полный shell с `cd`, `ls`, `mkdir`, glob. С OpenSSH 9.0 (2022) дефолтный `scp` использует **SFTP** под капотом (legacy-режим через `-O`). Это закрыло несколько CVE и привело поведение в порядок (например glob-expansion). Для простых случаев, `scp` или `rsync -e ssh`. Для интерактивной работы, `sftp`. Между серверами больших объёмов, [[cmd-rsync|rsync]]. ## SFTP-only-юзеры (chroot) Часто хочется дать доступ к загрузке файлов **без shell**. В sshd_config: ``` Match Group sftponly ChrootDirectory /var/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no ``` Требования к chroot-директории: - Owner = root, mode 755 (sshd проверяет, иначе отвалится с `bad ownership or modes`) - Внутри неё уже владельцем юзера могут быть поддиректории для записи ```bash groupadd sftponly useradd -G sftponly -s /usr/sbin/nologin alice mkdir -p /var/sftp/alice/upload chown root:root /var/sftp/alice chmod 755 /var/sftp/alice chown alice:alice /var/sftp/alice/upload ``` Юзер видит `/upload` как корень, никакого shell'а, только sftp. ## FTP vs SFTP vs FTPS | Признак | FTP | SFTP | FTPS | |---------|-----|------|------| | Транспорт | 2 TCP (21 + data) | 1 TCP (22) | 2 TCP + TLS | | Шифрование | нет | да (SSH) | да (TLS) | | Аутентификация | password в открытую | ключ или пароль | TLS-cert + password | | NAT-friendly | нет (PASV-диапазон) | да | нет | | Часть стандартного дистро | vsftpd, proftpd | openssh-server | vsftpd-with-tls | | Сертификаты PKI | - | можно SSH-CA | да | | Production-выбор | избегать | стандарт | только legacy | ## Anonymous FTP Историческая фича: подключение под `ftp` или `anonymous` без пароля (либо email-as-password). Использовалось для public-mirror'ов. Сегодня - мёртвая практика. Linux-mirror'ы перешли на HTTP/HTTPS (rsync под капотом), Anonymous FTP отключают на новых vsftpd: ``` anonymous_enable=NO ``` ## Когда что-то пошло не так - **`Connection refused` после login на FTP**, PASV не настроен или диапазон портов не открыт в фаерволе. - **FTP "висит" после `LIST`**, active mode пытается, клиент за NAT. `quote PASV` (или клиент в passive-only). - **FTPS падает на data-канале**, `PROT P` не задан, либо TLS-session не переиспользуется. На vsftpd: `require_ssl_reuse=NO` (или нет). - **`Subsystem request failed`** на SFTP, `Subsystem sftp` закомментирован в sshd_config, либо путь к sftp-server неправильный. - **`bad ownership or modes for chroot directory`**, chroot должен принадлежать root и иметь mode ≤755. Никаких group-write. - **`scp` стал странно работать после OpenSSH 9.0**, теперь использует SFTP под капотом. `scp -O` для legacy-протокола. ## Альтернативы - **[[cmd-rsync|rsync]]** через SSH, для синхронизации (инкрементальная) - **HTTPS** + [[cmd-curl|curl]] / wget для public download - **Object storage** (S3/MinIO) для приложений - **WebDAV**, HTTP-based, иногда удобнее ## Команды ```bash sftp user@server ``` Интерактивный SFTP - типичная замена FTP ```bash sftp -P 2222 user@server ``` Нестандартный SSH-порт - заглавная P (lowercase p в scp/ssh) ```bash scp -O file.bin user@server:/upload/ ``` Legacy SCP-протокол через -O (с OpenSSH 9.0 default = SFTP) ```bash lftp -u user,pass ftps://server.example.com ``` Современный CLI FTP-клиент с поддержкой FTPS - удобнее ftp(1) ```bash openssl s_client -starttls ftp -connect server:21 ``` Дебажить explicit FTPS - выполнит AUTH TLS и покажет сертификат ```bash ss -tlnp | grep -E ':21|:22|:990' ``` Какие порты file-transfer демоны слушают локально ```bash echo 'put file.bin' | sftp -b /dev/stdin user@server ``` Скрипт-friendly SFTP с batch из stdin ## См. также - [SSH - secure shell](/kb/ssh.md) - [SSH hardening - закрытие сервера](/kb/ssh-hardening.md) - [rsync - инкрементальная синхронизация файлов](/kb/cmd-rsync.md) - [TCP three-way handshake](/kb/tcp-handshake.md) - [TLS handshake](/kb/tls-handshake.md)