@electerm/ftp-srv

中文文档
1.1.0发布于 2026/10/29MITTypeScriptESM + CJS构建来源已验证近 30 天下载 1.4万

现代可扩展的 FTP 服务器( TypeScript 版本)

中文使用文档
文档目录22 节
  1. 安装
  2. 使用
  3. 基本示例
  4. 按用户设置根目录
  5. 匿名访问
  6. TLS(FTPS)
  7. 安全说明
  8. API
  9. new FtpServer(options)
  10. server.listen() → Promise<string>
  11. server.close() → Promise<void>
  12. 事件
  13. login
  14. connect
  15. disconnect
  16. client-error
  17. server-error
  18. closing / closed
  19. 自定义文件系统
  20. 导出
  21. 命令行
  22. License

@electerm/ftp-srv

English 中文

现代、可扩展的 FTP 服务器(TypeScript 版本)。

本项目是 ftp-srv 的 TypeScript 重构版本,同时发布 ESM 和 CJS 格式——并修复了原版中的安全漏洞。API 与原版 ftp-srv 向后兼容。

原始实现的全部功劳归于原作者 Tyler Stewart。详见 CREDITS 文件。

安装

npm install @electerm/ftp-srv

使用

// ESM
import FtpServer from '@electerm/ftp-srv';

// CJS
const { FtpServer } = require('@electerm/ftp-srv');

// 向后兼容别名(兼容原始 ftp-srv 包)
const { FtpSrv } = require('@electerm/ftp-srv');

基本示例

import FtpServer from '@electerm/ftp-srv';

const server = new FtpServer({
  url: 'ftp://0.0.0.0:21',
  anonymous: false,
});

server.on('login', ({ connection, username, password }, resolve, reject) => {
  if (username === 'admin' && password === 'secret') {
    return resolve({ root: '/srv/ftp' });
  }
  return reject(new Error('用户名或密码无效'));
});

await server.listen();
console.log('FTP 服务器已在 21 端口启动');

// 优雅关闭
await server.close();

按用户设置根目录

const server = new FtpServer({
  url: 'ftp://0.0.0.0:2121',
  pasv_min: 10000,
  pasv_max: 10100,
  anonymous: false,
});

server.on('login', ({ username, password }, resolve, reject) => {
  if (username === 'alice' && password === 'pass') {
    return resolve({
      root: '/home/alice',
      cwd: '/uploads',  // 初始工作目录(相对于 root)
    });
  }
  return reject(new Error('凭据无效'));
});

await server.listen();

匿名访问

const server = new FtpServer({
  url: 'ftp://0.0.0.0:21',
  anonymous: true,   // 接受任意用户名/密码
  root: '/srv/ftp',  // 所有连接的默认根目录
});

server.on('login', (_, resolve) => resolve({}));

await server.listen();

TLS(FTPS)

import fs from 'fs';

const server = new FtpServer({
  url: 'ftps://0.0.0.0:990',
  tls: {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.crt'),
  },
});

配置了 tls 后两种方式都支持:

  • 隐式 FTPS —— url: 'ftps://...',控制连接从第一个字节起就是 TLS。
  • 显式 FTPS(FTPES) —— url: 'ftp://...',客户端发 AUTH TLS 后控制连接就地升级(RFC 4217), 传输前再 PBSZ 0 / PROT P。数据连接同样加密。FEAT 只在配置了 tls 时才通告 AUTH TLS / PBSZ / PROT;没配 tls 时直接回 502,不会假装升级成功。

安全说明

  • FTP bounce 防护 —— 只有当 PORT / EPRT 给出的地址就是客户端自己(控制连接的对端地址)时才接受; 被动数据连接来自其他主机时一律回 550 并断开。两个命令都要求已登录。
  • 被动端口会释放 —— 重复发送 PASV / EPSV 会先关闭上一个监听,空闲 30s 的被动监听也会自动关闭, 客户端连进来却不传输也吃不满端口段。
  • 数据通道加密 —— 配置 tls 后,被动/主动数据连接同样是 TLS,不只是控制连接。

API

new FtpServer(options)

选项类型默认值说明
urlstring'ftp://127.0.0.1:21'监听的协议、主机名和端口。使用 ftp:// 或 ftps://。
rootstring—所有连接的默认根目录(当 login 的 resolve 未指定时使用)。
pasv_urlstring | (clientIp: string) => string自动检测被动连接时向客户端通告的 IP。省略时优先使用控制连接的本机地址(客户端实际连进来的地址),再回落到绑定地址 / 与客户端同网段的网卡地址。
pasv_minnumber1024被动端口范围起始值。
pasv_maxnumber65535被动端口范围结束值。
anonymousbooleanfalse允许匿名登录(接受任意用户名/密码)。
blackliststring[][]全局拒绝的 FTP 命令列表。
whiteliststring[][]全局允许的 FTP 命令列表(其余均拒绝)。
greetingstring | string[]—客户端连接时发送的欢迎消息。
tlsobject—Node.js TLS 选项(key、cert 等),用于 ftps:// 连接。
file_format'ls' | 'ep' | function'ls'LIST 响应格式。'ls' = Unix 风格,'ep' = EPLF,或自定义 (stat) => string 函数。
logLoggerbunyan logger兼容 bunyan 的日志对象(trace、debug、info、warn、error、fatal、child)。
timeoutnumber0空闲 socket 超时时间(毫秒)。0 表示禁用。
endOnProcessSignalbooleantrue收到 SIGTERM/SIGINT/SIGQUIT 时调用 close() 并退出进程。

server.listen() → Promise<string>

启动服务器并开始接受连接。

server.close() → Promise<void>

优雅关闭所有连接并停止服务器。

事件

login

客户端尝试登录时触发。必须监听此事件并调用 resolve 或 reject。

server.on('login', ({ connection, username, password }, resolve, reject) => {
  // 使用每用户选项 resolve:
  resolve({
    root: '/srv/ftp/alice',  // 本次会话的根目录
    cwd: '/',                // 初始工作目录(相对于 root)
    fs: customFsInstance,    // 自定义 FileSystem 实例(可选)
    blacklist: ['DELE'],     // 每连接命令黑名单
    whitelist: [],           // 每连接命令白名单
  });

  // 或拒绝登录:
  reject(new Error('凭据无效'));
});

connect

新客户端 socket 连接时触发(登录前)。

server.on('connect', ({ connection, id, newConnectionCount }) => {});

disconnect

客户端断开连接时触发。

server.on('disconnect', ({ connection, id, newConnectionCount }) => {});

client-error

客户端连接发生错误时触发。

server.on('client-error', ({ connection, context, error }) => {});

server-error

底层 TCP 服务器发生错误时触发。

server.on('server-error', ({ error }) => {});

closing / closed

调用 close() 时及关闭完成后触发。

server.on('closing', () => {});
server.on('closed', () => {});

自定义文件系统

继承 FileSystem 可覆盖服务器读写文件的方式。

import { FileSystem } from '@electerm/ftp-srv';

class MyFileSystem extends FileSystem {
  async list(dirPath = '.') {
    // 返回带有 name 属性的 fs.Stats 类对象数组
    const entries = await super.list(dirPath);
    return entries.filter(e => !e.name.startsWith('.'));  // 隐藏点文件
  }

  async get(fileName) {
    return super.get(fileName);
  }
}

server.on('login', (_, resolve) => {
  resolve({ fs: new MyFileSystem(connection, { root: '/srv/ftp' }) });
});

可覆盖的方法:

方法说明
currentDirectory()返回当前工作目录路径。
get(fileName)返回带有 name 属性的 fs.Stats 类对象。
list(dirPath)返回带有 name 属性的 fs.Stats 类对象数组。
chdir(dirPath)切换工作目录,返回新路径。
write(fileName, options)返回 { stream, clientPath } 用于写入。
read(fileName, options)返回 { stream, clientPath } 用于读取。
delete(fileName)删除文件。
mkdir(dirPath)创建目录。
rename(from, to)重命名文件或目录。
chmod(fileName, mode)修改文件权限。
getUniqueName(fileName)返回唯一文件名(用于 STOU 命令)。

导出

import FtpServer, {
  FtpServer,       // 具名导出(同一个类)
  FtpSrv,          // 向后兼容别名,兼容原始 ftp-srv 包
  FileSystem,
  FtpConnection,
  errors,
} from '@electerm/ftp-srv';

命令行

npx electermftpsrv ftp://0.0.0.0:9876 --root ~/Documents

License

MIT

版本与发布记录

@electerm/ftp-srv 共发布 11 个版本,首次发布于 2026/04/25;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.1.0latest2026/10/2915 天前
1.0.62026/09/281 个月前
1.0.52026/04/256 个月前
1.0.42026/04/256 个月前
1.0.32026/04/256 个月前
1.0.1-beta.4beta2026/04/256 个月前

关于 @electerm/ftp-srv 的常见问题

@electerm/ftp-srv 是什么?

现代可扩展的 FTP 服务器( TypeScript 版本)

如何安装 @electerm/ftp-srv?

在项目目录运行 npm install @electerm/ftp-srv,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 electermftpsrv,可以用 npx electermftpsrv 直接运行。

@electerm/ftp-srv 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@electerm/ftp-srv 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@electerm/ftp-srv 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=16。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@electerm/ftp-srv 可以商用吗?

@electerm/ftp-srv 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@electerm/ftp-srv 的下载量有多少?

根据 npm 官方下载统计,@electerm/ftp-srv 在 2026/10/14 – 2026/11/12 这 30 天内被下载 14,135 次,日均约 471 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@electerm/ftp-srv 还在维护吗?

最新版本 1.1.0 发布于 2026/10/29(15 天前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/04/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。