Protocols
All protocols share users, roots, permissions, quotas, rate limits, bans, and the audit log. Paths are virtual: / is the user's root, and .. past it is refused with invalid_path everywhere.
FTP and FTPS
| Group | Commands |
|---|---|
| Session | USER PASS ACCT QUIT SYST NOOP HELP FEAT OPTS SITE HELP HOST |
| Navigation | PWD CWD CDUP (and X variants) |
| Transfer setup | TYPE A/I MODE S STRU F PASV EPSV EPSV ALL PORT EPRT REST ABOR |
| Transfers | RETR STOR STOU APPE LIST NLST MLSD |
| Files | DELE MKD RMD RNFR RNTO SIZE MDTM MFMT MLST |
| TLS | AUTH TLS PBSZ 0 PROT P/C (CCC refused) |
- Replies carry the error code first:
550 permission_denied: .... MLSD/MLSTfacts:type,size,modify,perm,unique;OPTS MLST type;size;selects a subset.permreflects each entry's own directory rules.HOST name(RFC 7151) must come beforeUSER. With[ftp].virtual_hostsset, other names get504; a user withhostslogs in only under those names.MFMT YYYYMMDDHHMMSS pathsets the modification time (UTC, needsw).RNTOreplaces an existing target.TYPE Atranslates line endings;TYPE Iis byte-exact.- Passive data connections must come from the client's address (
passive_promiscuous = trueturns this off for exotic NATs). Active mode connects only to the client's own address, port 1024 or higher. - Behind NAT, set
[ftp].passive_external_ipand openpassive_port_range. - FTPS data connections resume the control connection's TLS session;
[ftps].require_session_reuse = truerefuses those that do not. The data channel never issues TLS tickets (upload-only clients would leave them unread and reset the connection).
SFTP
SFTP version 3 over SSH-2, OpenSSH wire numbering.
| Item | Value |
|---|---|
| Requests | OPEN CLOSE READ WRITE STAT LSTAT FSTAT SETSTAT FSETSTAT OPENDIR READDIR REMOVE MKDIR RMDIR RENAME READLINK SYMLINK REALPATH |
| Extensions | posix-rename statvfs fstatvfs expand-path limits fsync (all @openssh.com) |
| Key exchange | mlkem768x25519-sha256 (post-quantum hybrid), curve25519-sha256, ecdh-sha2-nistp256; strict KEX |
| Ciphers | aes256-gcm@openssh.com, aes128-gcm@openssh.com; chacha20-poly1305@openssh.com first only on CPUs without AES instructions. [sftp].ciphers sets the list |
| Host keys | Ed25519 (generated) or ECDSA; RSA host keys are refused |
| Client auth | Password, or public key: Ed25519, ECDSA, RSA (SHA-2) |
| Limits | 256 KiB packets, 255 KiB reads/writes, 256 open handles |
- Plain
RENAMEwill not overwrite (draft v3);posix-renamedoes. OpenSSH'ssftpusesposix-renamewhen offered. dfinsftpshows the quota as the disk size when one is set.SETSTATapplies size, time, and permission bits; setuid, setgid, and sticky bits are stripped.scpworks in its default SFTP mode. Shell, exec, and forwarding are refused.
WebDAV/HTTP (read-only)
Set [webdav].bind (and tls = true for HTTPS with the FTPS certificate). Clients: Finder, Windows Explorer, rclone, cadaver, browsers, curl.
| Method | Behaviour |
|---|---|
OPTIONS | DAV: 1, allowed methods |
PROPFIND | Depth 0 or 1 (infinity is treated as 1); needs l |
GET, HEAD | Files with single Range (needs r); directories as HTML, or JSON with Accept: application/json (needs l) |
| Anything else | 403 permission_denied |
curl -u alice:password http://127.0.0.1:8081/docs/report.pdf -o report.pdf
curl -u alice:password -X PROPFIND -H 'Depth: 1' http://127.0.0.1:8081/docs/
Authentication is HTTP Basic against the same users (bans and LDAP apply); verified credentials are cached for 60 seconds.