Ubuntu 22.04 安装 Apache FtpServer 1.2.1 指南
从零在 Ubuntu 22.04 安装 Apache FtpServer 1.2.1:下载校验、SHA-512 口令坑、FTPS 密钥库重建、systemd 托管与客户端连通全流程实测
Ubuntu 22.04 安装 Apache FtpServer 1.2.1 指南
一、环境信息
本文所有命令与回显均在以下环境实测采集,读者在其他环境操作时输出可能略有差异。
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(GNU/Linux x86_64) |
| 内核 | 5.15.0 |
| 主机名 | node1.ftp.example |
| IP | 172.17.0.4 |
| 登录账号 | root / q1w2e3r4 |
| Java | OpenJDK 11.0.32.1(openjdk-11-jre-headless) |
| 目标版本 | Apache FtpServer 1.2.1(2025-01-29 构建) |
| 安装目录 | /opt/apache-ftpserver-1.2.1(软链 /opt/ftpserver) |
| 监听端口 | 2121(控制连接,默认端口) |
Apache FtpServer 是 Apache MINA 旗下的纯 Java FTP 服务器,发行包仅约 4.3 MB,解压即可运行,无需数据库与编译步骤。
二、前置条件
2.1 更新软件源并安装基础工具
apt-get update
实测输出(节选):
Get:1 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
...
Reading package lists... Done
Building dependency tree... Done
DEBIAN_FRONTEND=noninteractive apt-get install -y curl wget openjdk-11-jre-headless
实测输出(节选):
Setting up openjdk-11-jre-headless:amd64 (11.0.32.1+1-0ubuntu1~22.04) ...
Setting up curl (7.81.0-1ubuntu1.21) ...
Setting up wget (1.21.2-2ubuntu1.1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.14) ...
2.2 验证 Java
java -version
实测输出:
openjdk version "11.0.32.1" 2026-08-18
OpenJDK Runtime Environment (build 11.0.32.1+1-post-1ubuntu1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 11.0.32.1+1-post-1ubuntu1-22.04-Ubuntu, mixed mode, sharing)
FtpServer 1.2.1 官方要求 Java 8 及以上,实测 OpenJDK 11 运行正常。若使用 OpenJDK 17 亦兼容。
2.3 规划磁盘目录
| 目录 | 用途 |
|---|---|
| /opt/downloads | 发行包存放 |
| /opt/apache-ftpserver-1.2.1 | 程序目录 |
| /opt/ftpserver | 软链接(便于升级与脚本引用) |
| /data/ftp/demo | FTP 用户主目录示例 |
| /opt/ftpserver/res/log | 运行日志(发行包自带) |
三、版本选型与下载
3.1 版本说明
FtpServer 的发行包挂在 Apache MINA 的下载目录下(/mina/ftpserver/),当前发行版为 1.1.4 与 1.2.1,本文选 1.2.1。历史版本(1.0.x、1.1.0~1.1.1)可在 archive.apache.org 查询。
各版本现状:
| 版本线 | 最新版本 | 说明 |
|---|---|---|
| 1.2.x | 1.2.1 | 当前推荐版本,口令默认 SHA-512 散列 |
| 1.1.x | 1.1.4 | 维护线 |
| 1.0.x | 1.0.6 | 仅存档,不建议新部署 |
3.2 下载发行包
mkdir -p /opt/downloads && cd /opt/downloads
curl -sS -O https://dlcdn.apache.org/mina/ftpserver/1.2.1/apache-ftpserver-1.2.1-bin.tar.gz \
-O https://dlcdn.apache.org/mina/ftpserver/1.2.1/apache-ftpserver-1.2.1-bin.tar.gz.sha512
ls -lh
实测输出:
total 4.3M
-rw-r--r-- 1 root root 4.3M Oct 14 13:18 apache-ftpserver-1.2.1-bin.tar.gz
-rw-r--r-- 1 root root 292 Oct 14 13:18 apache-ftpserver-1.2.1-bin.tar.gz.sha512
3.3 校验 SHA-512
官方 .sha512 文件内容为按 8 位分组的十六进制串:
cat apache-ftpserver-1.2.1-bin.tar.gz.sha512
实测输出:
./apache-ftpserver-1.2.1-bin.tar.gz: 133D0537 220F7408 EEBB6945 70DE6FC1
48DCB397 0BE6A7D6 FA5D305D 3A833161
C68BD889 46E126CC 31A17604 1B7CEF8D
040309CD 6AEE0710 8BFC26CC 663DF73C
本地计算并比对(去掉分组空格、统一小写):
sha512sum apache-ftpserver-1.2.1-bin.tar.gz | awk '{print $1}' > calc.sha
grep -oE '[0-9A-F]{8}( [0-9A-F]{8}){3}' apache-ftpserver-1.2.1-bin.tar.gz.sha512 | tr -d ' \n' | tr 'A-Z' 'a-z' > expected.sha
cat calc.sha && cat expected.sha
[ "$(cat calc.sha)" = "$(cat expected.sha)" ] && echo CHECKSUM-OK || echo CHECKSUM-FAIL
实测输出:
133d0537220f7408eebb694570de6fc148dcb3970be6a7d6fa5d305d3a833161c68bd88946e126cc31a176041b7cef8d040309cd6aee07108bfc26cc663df73c
133d0537220f7408eebb694570de6fc148dcb3970be6a7d6fa5d305d3a833161c68bd88946e126cc31a176041b7cef8d040309cd6aee07108bfc26cc663df73cCHECKSUM-OK
四、安装步骤
4.1 解压并建立软链接
cd /opt
tar xzf downloads/apache-ftpserver-1.2.1-bin.tar.gz
ln -s /opt/apache-ftpserver-1.2.1 /opt/ftpserver
ls -l /opt/ftpserver
实测输出:
lrwxrwxrwx 1 root root 27 Oct 14 13:19 /opt/ftpserver -> /opt/apache-ftpserver-1.2.1
4.2 发行包目录结构
ls /opt/ftpserver
实测输出:
DEPENDENCIES LICENSE LICENSE.slf4j.txt LICENSE.springframework.txt NOTICE README.txt
bin common res
| 目录/文件 | 说明 |
|---|---|
| bin/ | 启动脚本:ftpd.sh(Linux)、ftpd.bat、ftpd.exe、ftpdw.exe(Windows 服务)、service.bat |
| common/classes/ | 扩展类与 log4j.properties |
| common/lib/ | 全部依赖 jar(共 13 个) |
| res/conf/ | 服务端配置:ftpd-typical.xml、ftpd-full.xml、users.properties |
| res/home/ | 默认用户主目录 |
| res/log/ | 运行日志 ftpd.log 输出目录 |
| res/ftpserver.jks | 自带示例 TLS 密钥库(见第八章,已过期不可直接用) |
| res/ftp-db.sql | 数据库用户管理器的建表参考 SQL |
查看依赖清单:
ls /opt/ftpserver/common/lib
实测输出:
aopalliance-1.0.jar
ftplet-api-1.2.1.jar
ftpserver-core-1.2.1.jar
jcl-over-slf4j-1.7.36.jar
log4j-api-2.24.3.jar
log4j-core-2.24.3.jar
mina-core-2.2.4.jar
reload4j-1.2.19.jar
slf4j-api-1.7.36.jar
slf4j-reload4j-1.7.36.jar
spring-beans-2.5.5.jar
spring-context-2.5.5.jar
spring-core-2.5.5.jar
核心依赖:mina-core 2.2.4(网络框架)、Spring 2.5.5(XML 配置解析)、log4j2/reload4j(日志)。
五、首次启动验证
5.1 前台启动
cd /opt/ftpserver
bin/ftpd.sh res/conf/ftpd-typical.xml
实测输出:
Using XML configuration file res/conf/ftpd-typical.xml...
FtpServer started
启动后进程保持前台运行。ftpd.sh 不支持后台参数,生产部署须配合 systemd(第八章)或 nohup。
另开终端确认监听端口(2121 为 ftpd-typical.xml 中 nio-listener 默认配置):
ss -tlnp | grep java
实测输出:
LISTEN 0 50 *:2121 *:* users:(("java",pid=3606,fd=62))
5.2 匿名账号连通测试
发行包默认 users.properties 中 anonymous 账号口令为空、只读:
curl --user anonymous: ftp://127.0.0.1:2121/
实测输出:
-r-------- 1 user group 28 Jan 29 2025 README.txt
返回 230 与目录列表说明服务器已正常工作。此时 admin 账号尚不能登录,原因见第六章。
六、用户配置(重要:默认文件必须修改)
6.1 发行包默认口令的问题
发行包 res/conf/users.properties 自带的 admin 账号口令为 admin,存储值是大写 MD5:
ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3
FtpServer 1.2.x 的 PropertiesUserManagerFactory 默认使用 Sha512PasswordEncryptor(而非老版本的 MD5),登录校验时会把客户端提交的明文口令做小写 SHA-512 后与存储值做大小写敏感比较。因此默认文件里的 MD5 值无论大小写都无法通过校验,直接登录必然失败。
实测失败过程(口令为 admin/admin 时):
curl --user admin:admin ftp://127.0.0.1:2121/
实测输出:
curl: (67) Access denied: 530
服务端日志(res/log/ftpd.log)同步记录:
[ INFO] 2026-10-14 13:20:01,631 [admin] [127.0.0.1] SENT: 331 User name okay, need password for admin.
[ INFO] 2026-10-14 13:20:01,632 [admin] [127.0.0.1] RECEIVED: PASS *****
[ WARN] 2026-10-14 13:20:01,632 [admin] [127.0.0.1] User failed to log in
[ WARN] 2026-10-14 13:20:02,132 [admin] [127.0.0.1] Login failure - admin
[ INFO] 2026-10-14 13:20:02,133 [admin] [127.0.0.1] SENT: 530 Authentication failed.
6.2 生成正确的 SHA-512 口令值
printf %s admin | sha512sum | awk '{print $1}'
实测输出:
c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec
将 users.properties 中 admin 的 userpassword 替换为上述小写 SHA-512 值:
sed -i 's/^ftpserver.user.admin.userpassword=.*/ftpserver.user.admin.userpassword=c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec/' /opt/ftpserver/res/conf/users.properties
6.3 重启服务并验证 admin 登录
重启后再次测试:
curl --user admin:admin ftp://127.0.0.1:2121/
实测输出:
-rw------- 1 user group 28 Jan 29 2025 README.txt
-rw------- 1 user group 26 Oct 14 13:20 upload-test.txt
登录成功(230),且 admin 具备写权限(列表字段为 rw-)。
6.4 新增业务用户
在 users.properties 末尾追加用户段落。以下创建 demo 用户(口令 demo123,主目录 /data/ftp/demo,限速 10 KB/s,并发 1):
mkdir -p /data/ftp/demo
printf %s demo123 | sha512sum | awk '{print $1}'
实测输出:
45153ecd716a4b5bb7779d43fb38b3b115e384425ce7d4a75fc410199b19558055dd6d09b8b96847ad658f1c474ed081c252e40a0078dd8b0a41bebefa857721
ftpserver.user.demo.userpassword=45153ecd716a4b5bb7779d43fb38b3b115e384425ce7d4a75fc410199b19558055dd6d09b8b96847ad658f1c474ed081c252e40a0078dd8b0a41bebefa857721
ftpserver.user.demo.homedirectory=/data/ftp/demo
ftpserver.user.demo.enableflag=true
ftpserver.user.demo.writepermission=true
ftpserver.user.demo.maxloginnumber=1
ftpserver.user.demo.maxloginperip=0
ftpserver.user.demo.idletime=0
ftpserver.user.demo.uploadrate=10240
ftpserver.user.demo.downloadrate=10240
注意事项:
- users.properties 在 1.2.1 中启动时一次性加载,新增或修改用户后必须重启进程才生效(实测结论,见第十二章 FAQ)
- 主目录不存在时登录后首次列目录会报错,建议提前创建
七、方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 发行包独立部署(本文) | 独立 FTP 服务器 | 零编译、4.3 MB 即装即用、自带 systemd 可托管能力 | 无内置高级虚拟化存储 |
| 嵌入式 Java API | 应用内嵌文件服务 | 与业务进程同生命周期、可编程 Ftplet 扩展 | 需要开发与依赖管理 |
| vsftpd | 系统级静态文件服务 | C 实现、性能高 | 用户与业务系统集成弱,非 Java 生态 |
| 数据库用户管理器(db-user-manager) | 用户量大、集中管理 | 用户存 DB、SQL 认证 | 需额外建表与数据源配置 |
八、FTPS 加密配置
8.1 自带密钥库不能直接用
ftpd-typical.xml 默认引用 ./res/ftpserver.jks(口令 password)。该密钥库是 2011 年生成的示例证书:
keytool -list -v -keystore /opt/ftpserver/res/ftpserver.jks -storepass password | head -12
实测输出(节选):
Alias name: apache ftpserver example
Creation date: Jun 19, 2011
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Apache FtpServer Example, OU=MINA, O=Apache Software Foundation, C=US
Valid from: Sun Jun 19 10:01:23 GMT 2011 until: Wed Jun 18 10:01:23 GMT 2014
Signature algorithm name: SHA1withDSA (weak)
Subject Public Key Algorithm: 1024-bit DSA key (weak)
证书已于 2014 年过期,且 SHA1withDSA + 1024 位 DSA 在 OpenJDK 11 的默认 jdk.tls.disabledAlgorithms 中被禁用。客户端显式开启 TLS 时握手直接失败:
> AUTH SSL
< 234 Command AUTH okay; starting SSL connection.
* TLSv1.3 (IN), TLS alert, handshake failure (552):
curl: (35) error:0A000410:SSL routines::sslv3 alert handshake failure
8.2 重新生成 RSA 密钥库
keytool -genkeypair -alias ftpserver -keyalg RSA -keysize 2048 -validity 3650 \
-keystore /opt/ftpserver/res/ftpserver-rsa.jks -storepass password -keypass password \
-dname "CN=node1.ftp.example, O=Demo, C=CN"
实测输出(节选):
ftpserver, Oct 14, 2026, PrivateKeyEntry,
Certificate fingerprint (SHA-256): 03:AF:60:F9:48:02:EA:D7:A6:83:F4:5C:3E:99:0F:D9:2A:27:52:C5:E4:FF:31:95:82:8D:59:57:0A:A4:DA:C2
8.3 修改配置启用 FTPS
将 ftpd-typical.xml 中 keystore 指向新密钥库:
<ssl>
<keystore file="./res/ftpserver-rsa.jks" password="password" />
</ssl>
重启后用 curl 显式 TLS 验证:
curl -k --ssl-reqd --user admin:admin ftp://127.0.0.1:2121/
实测输出:
-rw------- 1 user group 28 Jan 29 2025 README.txt
-rw------- 1 user group 26 Oct 14 13:20 upload-test.txt
AUTH SSL → 234 → TLS 握手 → 登录 230 → 列表成功,FTPS 可用。内网亦可用 --ssl 放宽要求;对公网服务建议强制 TLS 并尽快用受信任 CA 证书替换自签名证书。
九、systemd 托管
9.1 编写服务单元
ftpd.sh 本身不支持 JVM 参数透传,systemd 直接调用 java 最干净(classpath 通配符由 JVM 自己展开)。创建 /etc/systemd/system/ftpserver.service:
[Unit]
Description=Apache FtpServer 1.2.1
Documentation=https://mina.apache.org/ftpserver-project/
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/ftpserver
ExecStart=/usr/bin/java -Xms256m -Xmx256m -classpath common/classes:common/lib/* org.apache.ftpserver.main.CommandLine res/conf/ftpd-typical.xml
Restart=on-failure
RestartSec=5
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
要点:
- WorkingDirectory 必须是 /opt/ftpserver,配置里的相对路径(./res/conf/...)全部基于它解析
- 堆内存 256MB 起步,按并发量在 256~512MB 区间调整
- SuccessExitStatus=143 避免 systemd 把 stop 信号误判为失败
9.2 启用并启动
systemctl daemon-reload
systemctl enable --now ftpserver
实测输出(节选):
Created symlink /etc/systemd/system/multi-user.target.wants/ftpserver.service → /etc/systemd/system/ftpserver.service.
9.3 状态确认
systemctl status ftpserver --no-pager -n 3
实测输出:
● ftpserver.service - Apache FtpServer 1.2.1
Loaded: loaded (/etc/systemd/system/ftpserver.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-10-14 13:27:33 UTC; 5s ago
Docs: https://mina.apache.org/ftpserver-project/
Main PID: 4760 (java)
Tasks: 26 (limit: 5753)
Memory: 78.5M
CPU: 2.398s
CGroup: /system.slice/.../system.slice/ftpserver.service
└─4760 /usr/bin/java -Xms256m -Xmx256m -classpath "common/classes:common/lib/*" org.apache.ftpserver.main.CommandLine res/conf/ftpd-typical.xml
Oct 14 13:27:33 node1.ftp.example systemd[1]: Started Apache FtpServer 1.2.1.
journalctl 中可看到启动横幅:
journalctl -u ftpserver -n 5 --no-pager
实测输出:
Oct 14 13:27:33 node1.ftp.example systemd[1]: Started Apache FtpServer 1.2.1.
Oct 14 13:27:33 node1.ftp.example java[4760]: Using XML configuration file res/conf/ftpd-typical.xml...
Oct 14 13:27:34 node1.ftp.example java[4760]: FtpServer started
十、客户端连通验证
10.1 curl 上传下载全流程
echo 'hello from ftpserver demo' > /tmp/upload-test.txt
curl -T /tmp/upload-test.txt --user admin:admin ftp://127.0.0.1:2121/
curl -s --user admin:admin ftp://127.0.0.1:2121/upload-test.txt
实测输出:
hello from ftpserver demo
10.2 lftp 完整会话
lftp -u admin,admin 127.0.0.1 -p 2121 -e 'set ftp:ssl-allow no; ls; put /tmp/upload-test.txt; ls -l; bye'
实测输出:
-rw------- 1 user group 28 Jan 29 2025 README.txt
-rw------- 1 user group 26 Oct 14 13:20 upload-test.txt
258 bytes transferred
-rw------- 1 user group 28 Jan 29 2025 README.txt
-rw------- 1 user group 258 Oct 14 13:32 upload-test.txt
若客户端与服务器都启用了 TLS 但证书是自签名,curl 需要加 -k,lftp 需要 set ssl:verify-certificate no。
10.3 限速与并发限制实测
demo 用户配置了 downloadrate=10240(字节/秒)与 maxloginnumber=1,行为与配置精确一致:
- 下载 512 KB 文件耗时 51.2 秒(10240 B/s 精确生效)
- 已有连接未断开时第二个登录被拒绝:
< 421 Maximum login limit has been reached.
只读用户(writepermission=false)上传与删除分别被拒绝:
< 550 /hostname.txt: Permission denied.
< 450 No permission to delete /put-target.txt.
十一、配置汇总
| 配置项 | 路径/值 | 说明 |
|---|---|---|
| 服务配置 | /opt/ftpserver/res/conf/ftpd-typical.xml | 监听 2121、TLS、用户文件 |
| 用户文件 | /opt/ftpserver/res/conf/users.properties | SHA-512 散列口令 |
| 日志配置 | /opt/ftpserver/common/classes/log4j.properties | INFO、滚动 10MB×10 |
| 运行日志 | /opt/ftpserver/res/log/ftpd.log | 含用户名与远端 IP |
| systemd 单元 | /etc/systemd/system/ftpserver.service | 开机自启、异常自动拉起 |
| TLS 密钥库 | /opt/ftpserver/res/ftpserver-rsa.jks | RSA 2048,口令 password |
firewalld/ufw 环境需放行 2121 及被动端口段(本文未启用防火墙;如启用请参考 FAQ 12.6)。
十二、常见问题 FAQ
12.1 admin/admin 登录报 530 Authentication failed
原因:1.2.x 默认口令加密器是 SHA-512,发行包 users.properties 中的大写 MD5 不被接受。按第六章把 userpassword 换成小写 SHA-512 值后重启即可。判断口令属于哪种格式:小写 128 位十六进制 = SHA-512,32 位十六进制 = MD5(需配合 encrypt-passwords="md5"),$1$... 开头 = salted。
12.2 修改 users.properties 后不生效
users.properties 由 PropertiesUserManager 在启动时一次性加载,1.2.1 无热加载与轮询机制,改完必须 systemctl restart ftpserver。修改前已连接的会话不受影响。
12.3 客户端 TLS 握手失败(alert handshake failure)
自带 ftpserver.jks 是 2011 年 SHA1withDSA/1024 位证书,已过期且被现代 JDK 禁用。按第八章重新生成 RSA 2048 密钥库并更新 keystore 路径。
12.4 启动报 JAVA_HOME is not defined correctly
ftpd.sh 找不到可执行的 java。安装 openjdk-11-jre-headless 后重试,或显式 export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64。systemd 方式直接写 /usr/bin/java 全路径可完全规避。
12.5 启动报 Address already in use
2121 端口被占用:ss -tlnp | grep 2121 找到占用进程,或修改 ftpd-typical.xml 中 nio-listener 的 port。
12.6 防火墙环境被动模式连不上
控制连接 2121 通但数据连接超时。在 nio-listener 内配置固定被动端口段并放行:
<data-connection>
<passive ports="50000-50100" />
</data-connection>
实测配置后 EPSV 返回端口落在区间内:229 Entering Passive Mode (|||50039|)。防火墙同步放行 50000-50100。NAT 环境还需 <passive external-address="公网IP" />。
12.7 上传文件报 550 Permission denied
writepermission=false 的用户不可写。检查该用户段落是否配置 ftpserver.user.<name>.writepermission=true,同时确认服务器进程对主目录有 OS 层写权限。
12.8 匿名登录看到的是 /opt/ftpserver/res/home
anonymous 的 homedirectory 默认指向 ./res/home。改 homedirectory 并重启即可;口令留空(userpassword=)即代表匿名可登录。
12.9 日志里大量 WARN User failed to log in
口令错误或账号未启用(enableflag=false)。结合 WARN 行上下的 USER/PASS 记录确认账号名;口令格式错配(12.1)是最常见原因。
12.10 如何迁移到数据库用户管理
把 ftpd-typical.xml 的 file-user-manager 换成 db-user-manager(含 data-source 与 6 条 SQL),参考发行包 res/ftp-db.sql 建表,表结构含 userid/userpassword/homedirectory 等列。
十三、卸载
systemctl disable --now ftpserver
rm -f /etc/systemd/system/ftpserver.service
systemctl daemon-reload
rm -f /opt/ftpserver
rm -rf /opt/apache-ftpserver-1.2.1 /opt/downloads/apache-ftpserver-1.2.1-bin.tar.gz*
rm -rf /data/ftp
如需彻底清理 Java 环境:apt-get purge -y openjdk-11-jre-headless。