ftp_server 2.3.1 copy "ftp_server: ^2.3.1" to clipboard
ftp_server: ^2.3.1 copied to clipboard

Standards-compliant FTP/FTPS server in Dart. Supports plain FTP and encrypted FTPS (explicit/implicit TLS), read-only and read-write modes, with pluggable file system backends.

Dart FTP Server #

A standards-compliant FTP/FTPS server in Dart. Supports plain FTP and encrypted FTPS (explicit and implicit TLS), read-only and read-write modes, with pluggable file system backends.


Table of Contents #

  1. Quick Start
  2. Features
  3. Compatibility
  4. Usage
  5. File Sharing Backends
  6. Contributing
  7. License

1. Quick Start #

import 'package:ftp_server/ftp_server.dart';
import 'package:ftp_server/server_type.dart';
import 'package:ftp_server/file_operations/virtual_file_operations.dart';

void main() async {
  final server = FtpServer(
    21,
    fileOperations: VirtualFileOperations(['/home/user/shared']),
    serverType: ServerType.readAndWrite,
  );

  await server.start();
}

That's it — an anonymous FTP server sharing a directory. Add username/password for authentication, or securityMode/tlsConfig for FTPS. See below for details.


2. Features #

  • FTP and FTPS: Plain FTP, explicit FTPS (AUTH TLS), and implicit FTPS
  • Passive and Active Modes: Both passive (PASV/EPSV) and active (PORT) data connections
  • File Operations: Retrieve, store, delete, rename, and list files
  • Directory Operations: Change, make, remove, and list directories
  • Read-Only Mode: Disable all write operations for security
  • Authentication: Optional username/password with flexible credential configs
  • Pluggable Backends: Virtual (multiple directories) or Physical (single root)
  • Standards Compliant:
    • RFC 959 — File Transfer Protocol (core)
    • RFC 2228 — FTP Security Extensions
    • RFC 2389 — Feature negotiation (FEAT/OPTS)
    • RFC 2428 — Extended passive mode (EPSV)
    • RFC 3659 — Extensions (MLST, MDTM, SIZE)
    • RFC 4217 — Securing FTP with TLS (FTPS)

3. Compatibility #

Tested on macOS, Linux, and Windows. CI/CD runs 231 tests on all three platforms on every commit.


4. Usage #

4.1 Starting the Server #

Basic (anonymous, no auth)

import 'package:ftp_server/ftp_server.dart';
import 'package:ftp_server/server_type.dart';
import 'package:ftp_server/file_operations/virtual_file_operations.dart';

void main() async {
  final server = FtpServer(
    21,
    fileOperations: VirtualFileOperations(['/home/user/shared']),
    serverType: ServerType.readAndWrite,
  );
  await server.start();
}

With authentication

final server = FtpServer(
  21,
  username: 'admin',
  password: 'secret',
  fileOperations: VirtualFileOperations(['/home/user/shared']),
  serverType: ServerType.readAndWrite,
);

Using PhysicalFileOperations (single directory)

import 'package:ftp_server/file_operations/physical_file_operations.dart';

final server = FtpServer(
  21,
  fileOperations: PhysicalFileOperations('/home/user/ftp_root'),
  serverType: ServerType.readAndWrite,
);

4.2 Running in the Background #

await server.startInBackground();
// Your app continues running while the FTP server handles connections

To stop:

await server.stop();

4.3 Supported FTP Commands #

Command Description
Authentication
USER <username> Set username. Returns 230 directly if no auth configured.
PASS <password> Set password. Supports username-only or password-only configs.
ACCT <info> Account info (accepted, not required).
REIN Reset session — logout without disconnecting.
QUIT Close the connection.
Directory Navigation
PWD Print current directory (absolute FTP path).
CWD <directory> Change directory.
CDUP Change to parent directory.
MKD <directory> Create directory. Response includes absolute path.
RMD <directory> Remove directory.
File Operations
LIST [<path>] List files with details (permissions, size, date).
NLST [<path>] List filenames only.
MLSD [<path>] Machine-readable directory listing (RFC 3659).
STAT [<path>] File/directory status over control connection.
RETR <filename> Download a file.
STOR <filename> Upload a file.
DELE <filename> Delete a file.
RNFR <filename> Rename from (start rename sequence).
RNTO <filename> Rename to (complete rename sequence).
SIZE <filename> Get file size in bytes.
MDTM <filename> Get last modification time (UTC).
Data Connection
PASV Enter passive mode.
EPSV [<protocol>] Enter extended passive mode (RFC 2428).
PORT <h1,h2,h3,h4,p1,p2> Enter active mode.
ABOR Abort current transfer.
TYPE <type> Set transfer type (A=ASCII, I=binary).
STRU <code> Set file structure (F=file only).
MODE <code> Set transfer mode (S=stream only).
ALLO <bytes> [R <size>] Allocate storage (accepted, not required).
Security (FTPS)
AUTH TLS Upgrade control connection to TLS (explicit FTPS).
PBSZ 0 Set protection buffer size (required before PROT).
PROT P|C Set data protection: P=private (encrypted), C=clear.
CCC Clear command channel (not supported — returns 534).
Server Info
SYST Return system type (UNIX Type: L8).
FEAT List supported features and extensions.
OPTS <option> Set options (e.g., OPTS UTF8 ON).
HELP List all supported commands.
NOOP No operation (keep-alive).
SITE <cmd> Site-specific commands (not implemented — returns 502).

4.4 Authentication #

Authentication is optional. The server supports several configurations:

Configuration Behavior
No credentials Anonymous access. USER returns 230 immediately.
Username + password Both must match. USER returns 331, then PASS required.
Username only Any password accepted if username matches.
Password only Any username accepted if password matches.
// Anonymous (no auth)
FtpServer(21, fileOperations: fileOps, serverType: serverType);

// Full credentials
FtpServer(21, username: 'admin', password: 'secret', ...);

// Username only (password ignored)
FtpServer(21, username: 'admin', ...);

When credentials are configured, commands like LIST, RETR, STOR, etc. require authentication. Pre-auth commands (USER, PASS, QUIT, FEAT, SYST, NOOP, OPTS, AUTH, PBSZ, PROT) always work.

4.5 Read-Only Mode #

final server = FtpServer(
  21,
  fileOperations: fileOps,
  serverType: ServerType.readOnly, // STOR, DELE, MKD, RMD disabled
);

Write commands return 550 Command not allowed in read-only mode.

4.6 FTPS (TLS/SSL) #

The server supports FTPS per RFC 4217. Three security modes:

Mode Description Typical Port
FtpSecurityMode.none Plain FTP (default) 21
FtpSecurityMode.explicit Plain connection, client upgrades via AUTH TLS 21
FtpSecurityMode.implicit TLS from connection start 990

Explicit FTPS

Client connects on a plain port and upgrades to TLS:

final server = FtpServer(
  21,
  fileOperations: fileOps,
  serverType: ServerType.readAndWrite,
  securityMode: FtpSecurityMode.explicit,
  tlsConfig: TlsConfig(
    certFilePath: '/path/to/cert.pem',
    keyFilePath: '/path/to/key.pem',
  ),
);

Implicit FTPS

All connections are TLS-encrypted from the start:

final server = FtpServer(
  990,
  fileOperations: fileOps,
  serverType: ServerType.readAndWrite,
  securityMode: FtpSecurityMode.implicit,
  tlsConfig: TlsConfig(
    certFilePath: '/path/to/cert.pem',
    keyFilePath: '/path/to/key.pem',
  ),
);

TLS Configuration Options

// Simple: PEM files
TlsConfig(
  certFilePath: 'cert.pem',
  keyFilePath: 'key.pem',
)

// Advanced: pre-built SecurityContext
TlsConfig(
  securityContext: myCustomContext,
)

// Mutual TLS (client certificates)
TlsConfig(
  certFilePath: 'cert.pem',
  keyFilePath: 'key.pem',
  requireClientCert: true,
  trustedCertificatesPath: 'ca.pem',
)

Enforcing Encrypted Data Channels

By default, clients choose whether to encrypt data channels (PROT P or PROT C). To require encryption:

FtpServer(
  21,
  fileOperations: fileOps,
  serverType: ServerType.readAndWrite,
  securityMode: FtpSecurityMode.explicit,
  tlsConfig: tlsConfig,
  requireEncryptedData: true, // Refuse PROT C, require PROT P
);

For implicit mode, requireEncryptedData is automatically set to true.

Known Limitations

  • CCC (Clear Command Channel): Returns 534. Dart's SecureSocket cannot be downgraded to plain TCP.
  • REIN under TLS: Returns 502. Same Dart limitation — TLS cannot be unwrapped.
  • FileZilla/GnuTLS: May warn "TLS connection was non-properly terminated" on data channels. This is a client-side GnuTLS issue; data transfers complete successfully.

5. File Sharing Backends #

5.1 Quick Comparison #

Feature Virtual Physical
Shared folders Multiple One
Write at root? No Yes
Root meaning Virtual (not a real folder) The actual folder
Best for Sharing several separate folders Sharing one folder tree

5.2 Virtual (Multiple Directories) #

Shares multiple folders as top-level directories. Users cannot modify the root / directly.

final fileOps = VirtualFileOperations([
  '/home/user/photos',
  '/home/user/documents',
]);
// Users see: /photos/ and /documents/

5.3 Physical (Single Directory) #

Shares one folder as the FTP root. Users can create/delete files directly at root level.

final fileOps = PhysicalFileOperations('/home/user/ftp_root');
// Users see the contents of ftp_root directly

5.4 Choosing a Backend #

  • VirtualFileOperations: Multiple directories, restricted root, better isolation
  • PhysicalFileOperations: Single directory, full root access, simpler

5.5 Key Points #

  • Both enforce boundaries — no access outside allowed root(s)
  • Neither allows deleting the root directory
  • VirtualFileOperations prevents writes at the virtual root /
  • PhysicalFileOperations allows writes at root, but not deleting root itself

6. Contributing #

Contributions are welcome! Please fork the repository and submit a pull request. Follow the existing code style and include tests for new features.


7. License #

MIT License. See LICENSE for details.

8
likes
160
points
295
downloads

Documentation

API reference

Publisher

verified publisherzcreations.info

Weekly Downloads

Standards-compliant FTP/FTPS server in Dart. Supports plain FTP and encrypted FTPS (explicit/implicit TLS), read-only and read-write modes, with pluggable file system backends.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

intl, path

More

Packages that depend on ftp_server