ftpd — UCSPI-TCP FTP server for static content


ftpd {root}


ftpd prints requested public files from the root directory hierarchy. The Bernstein convention is for root to be /public/file, but it can use other conventional locations such as /home/publicfile/public or /var/www.

ftpd accepts FEAT, OPTS, HOST, PWD, CWD, CDUP, TYPE, PORT, EPSV, PASV, SPSV, REST, RETR, LIST, NLST, and QUIT requests on standard input in FTP format. It prints responses on standard output, and local log information on standard error.

ftpd recognizes USER, PASS, and ACCT, but it does not check usernames or passwords. To work around a problem with various badly written FTP application-level gateways, it always asks for a password after a USER command if the username is "anonymous".

It has minimal support for STRU, MODE, SIZE, SYST, HELP, and NOOP.

ftpd exits silently if it runs out of memory, encounters an I/O error, or does not receive an input packet within 60 seconds.

Normally ftpd is run under a UCSPI-TCP server program (tcp-socket-accept, s6-tcpserver, or tcpserver spawning a server program per connection) to handle FTP connections from hosts around the Internet. Note that ftpd does not print the FTP greeting message; sending the greeting message is handled by the server (line-banner or the -B option to tcpserver).

File handling

Initially, ftpd attempts to take the virtual host name v from UCSPI-TCP or UCSPI-SSL environment variables, in particular the PROTO and SSLLOCALHOST/TCPLOCALHOST environment variables. If those variables are not set, ftpd uses the host name 0 as an initial default. FTP clients may subsequently specify a host name with the HOST command. ftpd always converts the host name to lowercase.

A request for a file or directory named f refers to ./v/f inside the root directory hierarchy. ftpd thus advertises that it supports the TVFS feature.

ftpd has built-in support for NLST and LIST; it does not run an external root /bin/ls. It provides EPLF LIST responses, including EPLF options "i", "s", and "m".

Unsupported features

ftpd does not support file/directory modification requests such as STOR, STOU, APPE, DELE, RNFR, and RNTO.

ftpd does not support REIN.


ftpd chroots to root when it starts. It then sets its group id and user id to the numbers given in environment variables GID and UID, as set by envuidgid (or equivalent). ftpd does not allow dots immediately after slashes in file names. It converts any such dots to colons before attempting to open the file.

ftpd will refuse to read a file if the file

  • is unreadable to user;

  • is unreadable to group;

  • is unreadable to world;

  • is world-executable without being user-executable; or

  • is anything but a regular file or directory: a socket, device, etc.

In directory listings, ftpd will skip a file if the name begins with a dot. It will also skip names that contain tildes, spaces, or control characters; note, however, that these files can still be accessed by someone who knows or guesses the name.

ftpd uses local ports above 1024 for PORT connections, rather than the standard port 20. It rejects remote ports below 1024, and it rejects third-party PORT. It also rejects third-party PASV.


ftpd was originally part of Daniel J. Bernstein's publicfile toolset in 1999.


Original code and documentation by Daniel J. Bernstein. Documentation modernizations by Jonathan de Boyne Pollard.