Of course! Building an FTP server in Java is a common requirement, and you have several excellent options, ranging from simple libraries to full-featured frameworks.

Here’s a comprehensive guide covering the best approaches, code examples, and key considerations.
The Best Libraries for Java FTP Servers
You don't need to implement the FTP protocol from scratch. Instead, use a robust, well-tested library. Here are the top choices:
- Apache Mina FTP Server: This is the most popular and feature-rich choice. It's a mature, production-ready server that implements the FTP, FTPS, and SFTP protocols. It's highly configurable and extensible.
- Apache Commons Net: While primarily known for its client-side utilities, it also includes a simple
FTPServerclass. It's easier to set up for basic needs but less powerful and configurable than Mina. - Jetty (with FTP Extension): Jetty is a well-known web server and servlet container. It has an optional FTP extension that allows you to serve files from its web context. This is a great choice if you're already using Jetty or need to integrate FTP with a web application.
- NanoFTPd: A very lightweight and simple FTP server. It's good for embedded systems or very basic needs but lacks advanced features.
For most use cases, Apache Mina FTP Server is the recommended path. We'll focus on it in detail.
Option 1: Apache Mina FTP Server (Recommended)
This library uses an event-driven architecture, which is very efficient for handling many concurrent connections.

Step 1: Add the Dependency
First, add the Mina FTP Server library to your project. If you're using Maven, add this to your pom.xml:
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftpserver-core</artifactId>
<version>1.2.0</version> <!-- Check for the latest version -->
</dependency>
Step 2: Create a Basic Server Configuration
The core of Mina FTP Server is the FtpServerFactory. You use it to configure listeners, users, file systems, and more.
Here is a complete, runnable example of a basic FTP server.
SimpleFtpServer.java

import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import java.io.File;
public class SimpleFtpServer {
public static void main(String[] args) throws Exception {
// 1. Create a user manager
PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
// The file will be created if it doesn't exist
userManagerFactory.setFile(new File("myusers.properties"));
userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor()); // For simplicity. Use a real one in production!
// 2. Create the server factory
FtpServerFactory serverFactory = new FtpServerFactory();
serverFactory.setUserManager(userManagerFactory.createUserManager());
// 3. Configure and add a listener (the port the server listens on)
ListenerFactory listenerFactory = new ListenerFactory();
// Set the port
listenerFactory.setPort(2221);
// Replace the default listener
serverFactory.addListener("default", listenerFactory.createListener());
// 4. (Optional) Configure an anonymous user
// BaseUser anonymousUser = new BaseUser();
// anonymousUser.setName("anonymous");
// anonymousUser.setPassword("");
// anonymousUser.setHomeDirectory("./ftp_files/anonymous");
// serverFactory.getUserManager().save(anonymousUser);
// 5. Start the server
FtpServer server = serverFactory.createServer();
server.start();
System.out.println("FTP Server started on port 2221. Press any key to stop.");
System.in.read(); // Wait for a key press to stop the server
server.stop();
}
}
Step 3: Create a Password Encryptor (Important for Production)
The example above uses ClearTextPasswordEncryptor for simplicity, which is not secure. For a real application, you should use a proper encryptor. Mina provides one, or you can use Spring Security's.
Here's how to use Mina's default SaltedPasswordEncryptor:
import org.apache.ftpserver.usermanager.impl.SaltedPasswordEncryptor; // In your main method, replace the setPasswordEncryptor line: userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor()); // When you save a user, you provide the plain password. // The encryptor will handle the salting and hashing automatically. // userManagerFactory.createUserManager().save(aUser);
Step 4: Define Users and File System
You can define users programmatically or via a properties file (as shown above). Let's see how to do it programmatically for more control.
// ... inside your main method, after creating the serverFactory ...
// Create a user
BaseUser user = new BaseUser();
user.setName("testuser");
user.setPassword("testpass"); // Remember to use a real encryptor in production!
user.setHomeDirectory(System.getProperty("user.dir") + "/ftp_files"); // Use the current directory's 'ftp_files' folder
// Grant permissions
user.setAuthorities( Arrays.asList(new WritePermission()) ); // Allow writing
// Add the user to the server's user manager
serverFactory.getUserManager().save(user);
// ... then create and start the server as before
This example creates a user testuser with password testpass who can log in and has write permissions to a directory named ftp_files in your project's root.
Option 2: Apache Commons Net (Simpler Alternative)
This is much simpler for a "quick and dirty" server but lacks the advanced features of Mina.
Step 1: Add the Dependency
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version> <!-- Check for the latest version -->
</dependency>
Step 2: Create the Server
The Commons Net server runs in its own thread.
SimpleCommonsNetFtpServer.java
import org.apache.commons.net.ftp.FtpServer;
import org.apache.commons.net.ftp.FtpServerFactory;
import org.apache.commons.net.ftp.ftplet.FtpException;
import org.apache.commons.net.ftp.ftplet.UserManager;
import org.apache.commons.net.ftp.impl.DefaultFtpServerFactory;
import org.apache.commons.net.ftp.usermanager.PropertiesUserManager;
import org.apache.commons.net.ftp.usermanager.PropertiesUserManagerFactory;
import org.apache.commons.net.ftp.usermanager.impl.BaseUser;
import org.apache.commons.net.ftp.usermanager.impl.WritePermission;
import java.io.File;
import java.util.Properties;
public class SimpleCommonsNetFtpServer {
public static void main(String[] args) throws FtpException {
// Use the factory to create the server
FtpServerFactory serverFactory = new DefaultFtpServerFactory();
// Configure the listener
ListenerFactory listenerFactory = new ListenerFactory();
listenerFactory.setPort(2222);
serverFactory.addListener("default", listenerFactory.createListener());
// Configure the user manager
PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
userManagerFactory.setFile(new File("commons_net_users.properties"));
// For production, use a proper password encoder
// userManagerFactory.setPasswordEncryptor(new org.apache.commons.net.ftp.usermanager.Md5PasswordEncryptor());
UserManager um = userManagerFactory.createUserManager();
serverFactory.setUserManager(um);
// Or, add a user programmatically:
BaseUser user = new BaseUser();
user.setName("commonsuser");
user.setPassword("commonspass");
user.setHomeDirectory(System.getProperty("user.dir") + "/ftp_files_commons");
user.setAuthorities(Arrays.asList(new WritePermission()));
um.save(user);
// Start the server
FtpServer server = serverFactory.createServer();
server.start();
System.out.println("Apache Commons Net FTP Server started on port 2222. Press any key to stop.");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
server.stop();
}
}
Key Considerations When Building an FTP Server
-
Security is Paramount
- Use FTPS (FTP over SSL/TLS): Never use plain FTP, as all data (including passwords) is sent in clear text. Both Mina and Commons Net support FTPS. You'll need to configure an SSLContext and enable it on your listener.
- Strong Passwords: Enforce strong password policies.
- Password Encryption: Always use a proper password hashing mechanism (like bcrypt or PBKDF2) instead of storing plain text passwords.
-
File System Management
- Chroot (Jail): For security, you should restrict users to their home directory. This prevents them from navigating outside their allowed folder. Mina supports this well.
- Permissions: Carefully manage read, write, and delete permissions for different users.
-
Concurrency and Performance
The event-driven model of libraries like Mina is highly efficient for handling many simultaneous connections. Avoid using simple blocking I/O for your server implementation if you expect high traffic.
-
Logging
Configure logging (e.g., with SLF4J and Logback) to monitor server activity, log successful and failed logins, and troubleshoot errors. Both Mina and Commons Net are well-integrated with standard logging frameworks.
-
FTP vs. SFTP
- FTP/FTPS: Runs over TCP port 21 (control) and various dynamic ports (data). It's a simple, widely supported protocol.
- SFTP (SSH File Transfer Protocol): Do not confuse this with FTPS! SFTP runs over SSH (port 22) and is a completely different protocol. It's generally considered more secure and modern. If you need SFTP, you would use an SSH library like Apache Mina SSHD or JSch.
Summary: Which One to Choose?
| Scenario | Recommended Library | Why? |
|---|---|---|
| Production-grade, feature-rich server | Apache Mina FTP Server | Best performance, most features (FTPS, SFTP if using SSHD), highly configurable, and actively maintained. |
| Quick prototype or simple internal tool | Apache Commons Net | Easier to set up for basic needs, but less powerful and flexible. |
| Integration with an existing web app | Jetty with FTP Extension | Seamless integration if you're already using Jetty. |
| Embedded system or micro-service | NanoFTPd | Extremely lightweight and simple, but minimal features. |
For any serious application, start with Apache Mina FTP Server. It provides the right balance of power, flexibility, and reliability.
