--- How to install cuftpd ---

- unpack to a suitable location
- install the Java JDK (if you haven't already)
- create your certificates (how varies depending on if you are going to use a local or remote synchronous userbase)
- configure ("Configure cuftpd")
- OPTIONAL: Set up a remote userbase.
- run ("Running cuftpd (with a remote userbase)")

--- Installing Java ---
 - REQUIRES java 7 (1.7)!
    - the JDK is preferred to the JRE, as the "-server" flag can increase performance, but technically only the JRE is necessary
    - the JDK can be downloaded from or
 cuftpd only officially supports Sun's java (but it might work with other JDKs as well, such as the OpenJDK). 
 Sun has simple java installation files for Windows, Linux and Solaris.
 Both 32 and 64 bit versions in most cases.
 Sun doesn't have a simple solution for java on FreeBSD (or any other BSD), but you can still install java on *BSD.
 One resource for this, and google has more, is:

--- Getting help ---

 Try the "site help" or "site help $command" commands when logged on to the ftpd.

--- Configure cuftpd ---

- edit 'data/cuftpd.xml' to reflect the settings you want
- edit 'data/permissions.acl' to reflect the permissions you want (information provided in the file)
- after this, all the configuration is done online via "site"-commands.
NOTE: While the configuration files regarding users and such CAN be edited by hand, it should not be done while the server
is online. This is because the server keeps copies of its data in memory, and will therefore overwrite any changes to
the userfiles upon each save.

--- Running cuftpd ---

#java [-server] -jar cuftpd-$VERSION.jar
The "-server" is optional. It can improve performance in some cases. It affects the policies regarding memory, mostly.
The "-server" switch is only available if you have the full JDK, not when you run just the JRE.

When you see "cuftpd $VERSION online", where $VERSION is the version you are currently running, cuftpd is online.
cuftpd will NOT fork into the background, so you need to do that yourself in an appropriate manner.

--- NEW - Running cuftpd with an ASYNCHRONOUS remove userbase ---
This is a new cuftpd feature in 1.5. The asynchronous userbase lets your cuftpd instance operate as if it were local,
and simply update its peers asynchronously in the background. This works even if one of the peers goes offline for
a time, provided if was configured as a peer. Simply choose authentication type 4, and configure your peers (other cuftpd
instances) in cuftpd.xml and you are good to go.
IMPORTANT: You must ensure that no loops are set up in the peer structure. Having a tree-like structure is fine. Circles are not.

If you are just starting out with empty userbases for all peers, simply connecting them via peer configuration as specified above.
If, however, you already have a userbase one a peer, or perhaps you want to add a new peer to an existing network of peers, then
you must do the following: Shut down one of the running peers that you intend to connect the new peer to. Make a copy of the stopped
peer's userbase, and copy it to the new peer. Then start them back up. This should provide them both with a common sync point.
It is important that you copy the userbase BEFORE you start them up as peers for the first time, because otherwise any pending
changes will be in the queue, and will cause inconsistencies.
"But what if I don't want to shut down my running hosts?", you ask. Well, you have to, to add a peer, because every peer-relationship
is two-sided, so you have to restart one of the peers anyway, after having changed its configuration, so there is little you can do.
In the future, it will perhaps be possible to forgo this manual step, but for now, it is necessary.

--- Running cuftpd with a remote synchronous userbase ---

- create certificates for the userbase and the clients. See the "Setting up your certificates"-section

- on the machine running the userbase: (this is ONLY done on ONE machine)
    - copy the server.keystore file to an appropriate location
    - edit 'data/userbase.conf' to indicate data directory and ssl-values (and some of the other stuff, if you feel like it)
    - NOTE: this machine does NOT use cuftpd.xml, ONLY userbase.conf
    - start by executing 'java -cp cuftpd-$version.jar cu.ftpd.user.userbases.remote.server.RmiDelegateUserbaseServer"

- on the machine(s) running the ftpd: (this is done on all the other machines)
    - change the values in 'data/cuftpd.xml' for /ftpd/user/authentication/type and /ftpd/user/statistics/type to 2.
        - Note: you can run statistics locally or remotely, but only remotely if the userbase is also run remotely.
    - set the values for certificates and certificate password in the /ftpd/ssl section of 'data/cuftpd.xml'
    - NOTE: this machine does NOT use userbase.conf, ONLY cuftpd.xml
    - run (See "How to run cuftpd")

NOTE: You will need to have cuftpd.jar in the same directory as userbase.jar
If you're having trouble connecting to the remote userbase, try adding -Djava.rmi.server.hostname=IP to the command line
of the host running the userbase, i.e. "java -Djava.rmi.server.hostname=IP -jar userbase.jar", where IP is the IP of
the host running the userbase

--- A note on certificates ---

The certificates created by the methods below will have a default expiration time of 90 days. This can be altered by
using different command line switches. I would suggest using more or less "real" values for the dname, such as
maybe a hostname for the CN, or a correct IP. This will help you identify and keep track of the certificates
when you start juggling more than one set.
Using correct information might also prevent dialog boxes from popping up for ftp client users if the CN matches
the hostname in question.

--- Setting up your certificates for a local userbase installation ---

This is quite simple. It uses only one step from the section below, namely:
#keytool -genkey -v -keyalg RSA -keystore client.keystore -dname "CN=Client, OU=Bar, O=Foo, L=Some, ST=Where, C=UN"

Executing this will create a keystore that can be used by cuftpd.

--- Setting up your certificates for a remote synchronous (rmi) userbase and the servers connecting to it ---

Most of this information is taken from the "Key Management" section of
It does a good job of detailing what needs to be done.
The "server" parts refer to the remote userbase, and the "client" parts refer to computer running the ftpd.
The command can all be executed on the same machine, and then the "server.keystore" file can be moved
to the computer running the remote userbase.
When executing these commands, you will be asked to supply a password. Both when creating the keystores and when adding
the public keys to them.

1.  Create a self-signed server and a self-signed client key each in its own keystore
    keytool -genkey -v -keyalg RSA -keystore server.keystore -dname "CN=Server, OU=Bar, O=Foo, L=Some, ST=Where, C=UN"
    keytool -genkey -v -keyalg RSA -keystore client.keystore -dname "CN=Client, OU=Bar, O=Foo, L=Some, ST=Where, C=UN"

2. Export the server's and the client's public keys from their respective keystores
    keytool -export -rfc -keystore server.keystore -alias mykey -file server.public-key
    keytool -export -rfc -keystore client.keystore -alias mykey -file client.public-key

3. Import the client's public key to the server's keystore, and vice-versa:
    keytool -import -alias client -keystore server.keystore -file client.public-key
    keytool -import -alias server -keystore client.keystore -file server.public-key
(Answer "yes" when asked if you want to import)

When adding more servers to the set of hosts connecting to the remote userbase, you will repeat all but the first command.
This ensures that all your clients will trust the remote userbase, and that the remote userbase knows which clients to trust.
Clients without this dual trust will not be allowed to connect to the remote userbase.

When adding more servers, create the client keystore, extract the client public key (all as above), then copy the public
key to the computer running the remote userbase, and use the method above to import it to the server.keystore.

Normally the remote userbase will use "server.keystore" as both keystore and truststore, however it is possible to use
a different file as a truststore, thus the different settings in userbase.conf.
A similar situation exists for the clients (cuftpd server instances).

NOTE: The server.keystore file is ONLY CREATED ONCE and then you ADD public keys from cuftpd servers to it.
The client.keystore file is created FOR EACH SERVER, and then you ADD the REMOTE USERBASE PUBLIC KEY to client.keystore

--- Using sitebots with cuftpd ---

This really depends on your sitebot, but if you choose to use the internal zipscript in cuftpd, the race log can be found in data/logs/cuftpd.log
It is also possible to use external zipscripts with cuftpd. Currently only pzs-ng is supported. To use pzs-ng, edit the /ftpd/site/zipscript section
in cuftpd.xml appropriately.

--- Configuring external zipscripts (pzs-ng only, currently) ---

Read the information in:

If any problems arise, talk to the nice people in #pzs-ng on EFNet

--- Getting transfer statistics in cuftpd ---

This is done by a set of site-commands. Each section configured in cuftpd.xml tracks a separate set of statistics.
The statistics for all sections combined (and directories that are "sectionless", such as "/" by default) are collected
in the "default" section.
These transfer statistics can be viewed via the following site commands: allup, alldn, mnup, mndn, wkup, wkdn, dayup, daydn
They represent all, month, week and day uploads and downloads, respectively.
To get statistics based groups, just prefix each command with "gp", as in gpallup or gpwkdn.
To get more information about these commands, view the site help for each command.

--- How does the userbase work? ---

As was made clear earlier in this document, cuftpd supports two types of userbases (three if you count the anonymous one).
One is remote, and the other one is local. They both work in the same manner though, transparently to the user.
The user information is kept on files on disk. The information in these files is mirrored in memory in cuftpd, so making
changes to the userfiles while cuftpd is running will NOT change the user information (which is true for most files
internal to cuftpd).
In the case of a local userbase, these files are kept on the computer running the ftpd. In the case of the remote userbase,
these files are kept on the computer running the remote userbase, and served up to the computers running the ftpd via
RMI secured by SSL and implementing certificate validation for both server and client. This certificate validation prevents
rogue implementations from connecting to your userbase.

cuftpd comes with a default user, aptly named "cuftpd", with the password "cuftpd". This user can, by default, only log
in from localhost. Users are added, deleted and modified online via site-commands.
To find more information about these commands, request site help for: adduser, gadduser, deluser.
Users can be suspended and unsuspended. A suspended user still retains his/her account, but is unable to log in.
Users can be suspended via the site-command "change". This command can also set other properties for a user.
This command is reserved for administrators only. If a user wants to change his/her details, there are some convenience
functions to do this, such as "site passwd" and "site tagline".

Users can be allowed to download without using up any credits. This is called "leech".
Users can be allotted a certain amount of credits on a weekly basis. This is called "allotment".
Both "leech" and "allotment" settings are accessible via the "site change" command.

User with "leech" and "allotment" can be viewed via the "site leechers" and "site allotments" commands.
I recommend viewing the help for these commands, as well as the "change" command.

--- Configuring permissions in cuftpd ---

Some commands in cuftpd requires that the user have certain permissions. These are different from the permissions
in data/permissions.acl, in that they are not path bound, and are connected to the userfile itself.
When requesting help for a certain command, it will say if any permission is required, and if so, which.
These permissions will be described with names. These names can be resolved to numbers by executing "site permissions".
When granting or removing a permission from a user, use the commands "site addpermissions" and "site delpermissions".
These commands take as parameters the user in question, and the permissions to be added or removed.
Permissions can either be a sole number, or a comma-separated list of numbers, such as: 1,2,3,4,5,6,7
To see a user's permission, execute "site user username".

Note: the permissions contained in the 'data/permissions.acl' file are reloaded each time someone logs in, so there is
no need to restart the server just because the permissions changed.

--- Note on IPv6 ---

Because java supports IPv6 out-of-the-box, cuftpd supports IPv6 if the underlying operating system supports IPv6.
Currently most major operating systems have default or enableable support for IPv6.
cuftpd also supports the EPSV and EPRT commands.

--- Custom site commands ---

If you want to add custom site commands, then see the /ftpd/commands section in data/cuftpd.xml.
You can add custom site commands there that will invoke external scripts for you.
NOTE: Choose the names of the commands with care, as they will overwrite any original site commands with the same name.

The processes are sent the following parameters in the following order:

  $1 = username
  $2 = primary group
  $3 = tagline
  $4 = current section name
  $5 = current path (absolute in the file system)
  $6 = command parameters
where 'command parameters' indicate any parameters that were sent to the command itself via the ftp.
Note that these will parameters will show up as one variable. 'command parameters' will also include the name of the site command.

Thus, if you are invoking some external script called "/cuftpd/bin/", then the command line will look as follows:

# /cuftpd/bin/ captain some_group "I have no tagline" mp3 "/cuftpd/site/mp3/some/dir" "site pre blah kek lol"

To deliver help for these commands to your users, put a file named "command.txt" in data/help/, where 'command' is the
name of the command.

UPDATE: You can also use java classes as custom site commands with cuftpd.
Just create a class that extends In this class you can override the execute(..)
method. To use java classes as custom site commands, you have to set the <type> tag to "java".
For more information, just look at any of the classes in*, and it should become clear what to do.
NOTE: when using type=java, the add_response_code parameter will do nothing. Your classes have to provide a response
code by themselves

--- 7bit templates for site output ---

If your output looks weird, look in the FAQ for information on how to change your display templates.

--- CRITICAL errors ---

When you get errors tagged with CRITICAL in your error log, it's a sure sign that something is VERY wrong. Therefore,
I suggest checking it every now and then, or doing a selective 'tail' of it, so you can see when errors happen.
Some critical errors are recoverable, and some are not. If they are recoverable, that means that the system will keep
running, but the problem needs to be looked at right away.

--- Compiling cuftpd ---

The normal distribution comes with jar-files that you can use. If you want to recompile the source code, the easiest
way is to download maven from and use that in conjunction with the 'pom.xml' file included
in the cuftpd distribution, and do "mvn clean install".

--- Handling events ---

cuftpd comes with an event handling system. For some selected events (listed below), it will trigger event handlers
both "before" and "after" the event in question. These event handlers can be either java classes or shell scripts.
Handlers for "before" events have the ability to write to the control connection. If you want to send a message to
the user, this is the only way.
NOTE: IF you want to write to the control connection you MUST include ftp response codes. It is crucial that these codes
correspond to the respond code of the original command, if the command is to continue. I.e. if you want to echo something
before an MKD, then you HAVE to respond with 257 if it is good.
Also note that all lines in a multiple line respond have a "-" just after the 3-digit number. The last line does not have
this, indicating the end of the message. This information is available in RFC 959 (google it).
If you want to halt execution of the command, you do this by returning false in the case of the java handlers, and
anything other than 0 for the shell handlers.
Halting execution means that any other event handlers will also not be run. You can have multiple event handlers for
each event. Some events have a set of pre-defined event handlers that are initialized in the code. These are automatically
run before any user-defined event handlers. These pre-defined handlers include things like dupecheck and dirlog.

Java classes:
All java class event handlers must implement the AfterEventHandler and/or BeforeEventHandler as appropriate.
These interfaces reside in src/cu/ftpd/events/. These interface have javadoc comments about what implementing
them means, and how they work. Each class will only be instantiated once, so if you have multiple event handlers
that use the same class, they will all be invoked on the same object.
Upon triggering an event, these event handlers will receive the event in question. Different events contain different
types of data. What this data is can be seen where the events are issued, for instance in the Connection, CommadnSTOR
and CommandRETR classes. The events currently in use are:

    Event name                  Event id
    CREATE_DIRECTORY            0
    REMOVE_DIRECTORY            1
    DELETE_FILE                 2
    RENAME_FROM                 3
    RENAME_TO                   4
    SITE_COMMAND                100
    UPLOAD                      1000
    DOWNLOAD                    1001

Shell scripts/applications:
These can be any shell scripts or applications that are executable on the host system.
These scripts receive a different set of parameters depending on what event is triggered.
They also receive a string indicating "before" or "after" ("time" below), as well as an interger event type id.
This event type id is the one described in the table above.

    All events share these parameters:
    $1 = time
    $2 = event type
    $3 = username
    $4 = group
    $5 = tagline
    $6 = pwd (absolute path)
    $7 = pwd (path relative to the ftp root)

    After that the events send these commands, respectively

    $8 = source (absolute path)
    $9 = source (path relative to the ftp root)
    $10 = target (absolute path)
    $11 = target (path relative to the ftp root)
    $12 = directory (boolean)
    $13 = file size (long)

    $8 = state (0 = PENDING, 1 = COMPLETE)
    $9 = bytes transferred
    $10 = transfer time
    $11 = transfer type
    $12 = remote hostname

    $8 = file (absolute path)
    $9 = file (path relative to the ftp root)
    $10 = file size

    $8 = site command parameters (e.g. "WIPE /some/dir/")

    All others contain:
    $8 = file (absolute path)
    $9 = file (path relative to the ftp root)