Skip to content

22.3 ProFTPD(基于 MySQL)

技巧

通过 Windows 自带 FTP 客户端连接 ProFTPD 服务器时不会出现乱码。

22.3.1 安装 ProFTPD

注意

本节基于 MySQL 8.0。有关 MySQL 的安装和基本设置,请参见其他章节。

请自行安装配置 MySQL 8.x,需确保与 proftpd-mod_sql_mysql 安装的 databases/mysql8X-client 版本一致。

安装 ProFTPD 及其 MySQL 模块:

sh
# pkg install proftpd proftpd-mod_sql_mysql

或使用 Ports 安装:

sh
# cd /usr/ports/ftp/proftpd/ && make install clean
# cd /usr/ports/databases/proftpd-mod_sql_mysql/ && make install clean

22.3.2 ProFTPD 配置文件

编辑 ProFTPD 的配置文件 /usr/local/etc/proftpd.conf

技巧

示例文件参见 /usr/local/etc/proftpd.conf.sample

ini
ServerName "Test Ftp Server"                     # FTP 服务器名称
ServerType standalone                             # 独立运行模式
DefaultServer on                                  # 设置为默认服务器
ServerIdent on "FTP Server ready"                # 客户端连接时显示的服务器标识
Port 21                                          # 监听端口
Umask 022                                        # 文件创建掩码

# 超时设置
TimeoutLogin 300                                 # 登录超时时间(秒)
TimeoutIdle 36000                                # 空闲超时时间(秒)
TimeoutNoTransfer 36000                          # 无传输超时时间(秒)

# 资源限制
User proftpd                                     # 运行服务的用户
Group proftpd                                    # 运行服务的用户组
RLimitMemory 256M 256M                           # 内存限制
RLimitOpenFiles 1024 1024                        # 打开文件数量限制
PassivePorts 50000 60000                          # 被动模式端口范围

# 日志配置
LogFormat default "%h %l %u %t \"%r\" %s %b"     # 默认日志格式
LogFormat auth "%v [%P] %h %t \"%r\" %s"         # 认证日志格式
SystemLog /var/log/proftpd/proftpd.log           # 系统日志路径
TransferLog /var/log/proftpd/xfer.log            # 文件传输日志路径
ExtendedLog /var/log/proftpd/auth.log AUTH auth  # 扩展认证日志

# MySQL 模块加载
LoadModule mod_sql.c
LoadModule mod_sql_mysql.c
LoadModule mod_sql_passwd.c

# 只允许访问各自的目录
DefaultRoot ~                                    # 将用户限制于主目录内

# 允许覆盖文件
AllowOverwrite on                                # 允许文件覆盖

<Global>
  # 数据库连接
  SQLConnectInfo proftpd@localhost proftpd 123456   # 数据库连接信息(用户、主机、密码)

  # 密码认证设置
  SQLAuthTypes SHA256                             # 使用 SHA256 加密认证
  SQLPasswordEngine on                            # 启用 SQL 密码引擎

  # 用户表映射
  SQLUserInfo users username password uid gid homedir shell   # 映射 users 表字段
  SQLDefaultGID 2000                              # 默认 GID
  SQLDefaultUID 2000                              # 默认 UID
  RequireValidShell off                            # 不要求有效 Shell

  # 认证顺序
  AuthOrder mod_sql.c
  SQLAuthenticate users                            # 使用 SQL 用户表认证

  # 登录统计
  SQLNamedQuery getcount SELECT "CONCAT('Total logins: ', count) FROM users WHERE username='%u'"   # 查询登录次数
  SQLNamedQuery updatecount UPDATE "count=count+1 WHERE username='%u'" users                       # 更新登录次数
  SQLShowInfo PASS "230" "%{getcount}"              # 显示登录统计信息
  SQLLog PASS updatecount                            # 记录登录统计

  # 文件操作日志
  SQLNamedQuery log_work FREEFORM "INSERT INTO worklog (user_name, file_and_path, bytes, send_time, client_ip, client_name, client_command) VALUES ('%u', '%f', %b, NULLIF('%T', ''), '%a', '%h', '%m')"  # 文件操作日志记录
  SQLLog RETR,STOR,DELE log_work                    # 将 RETR、STOR、DELE 操作记录到 worklog 表
</Global>

创建日志目录:

sh
# mkdir /var/log/proftpd

警告

若未手动创建目录,系统将提示 proftpd[3435]: warning: handling possibly truncated configuration data at line 65 of '/usr/local/etc/proftpd.conf'

技巧

ProFTPD 配置文件 /usr/local/etc/proftpd.conf 有语法检查命令 proftpd -t -d5

本配置中,服务器主动模式使用端口 21,被动模式使用端口 50000-60000,须确保防火墙已放行上述端口。

对于 PF 防火墙,通过以下规则实现:

允许从外部接口 $ext_if(需要改为实际网络接口)到本机端口 21 及 50000-60000 的 TCP 入站流量:

ini
pass in quick on $ext_if proto tcp from any to $ext_if port { 21, 50000:60000 }

22.3.3 相关文件结构

sh
/usr/local/etc/
├── proftpd.conf # ProFTPD 主配置文件
└── proftpd.conf.sample # ProFTPD 配置示例文件

22.3.4 创建用户

出于安全考虑,以非 root 用户身份运行 ProFTPD。添加新用户:

sh
# adduser
Username: proftpd # 用户名
Full name: FTP User # 用户全名
Uid (Leave empty for default):
Login group [proftpd]:
Login group is proftpd. Invite proftpd into other groups? []:
Login class [default]:
Shell (sh csh tcsh bash nologin) [sh]: nologin # 不允许登录系统
Home directory [/home/proftpd]:
Home directory permissions (Leave empty for default):
Enable ZFS encryption? (yes/no) [no]:
Use password-based authentication? [yes]: no
Lock out the account after creation? [no]:
Username    : proftpd
Password    : <disabled>
Full Name   : FTP User
Uid         : 1002
ZFS dataset : zroot/home/proftpd
Class       :
Groups      : proftpd
Home        : /home/proftpd
Home Mode   :
Shell       : /usr/sbin/nologin
Locked      : no
adduser: INFO: Successfully created ZFS dataset (zroot/home/proftpd).
adduser: INFO: Successfully added (proftpd) to the user database.
Add another user? (yes/no) [no]:
Goodbye!

22.3.5 MySQL 数据库相关

创建 MySQL 数据库和用户:

sql
CREATE DATABASE `proftpd` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;	 -- 创建 proftpd 数据库,使用 utf8mb4 字符集和通用校对规则

创建数据库用户和密码:

sql
CREATE USER 'proftpd'@'localhost' IDENTIFIED BY '123456';   -- 创建 MySQL 用户 proftpd,仅允许从本地主机连接
GRANT SELECT, INSERT, UPDATE, DELETE ON proftpd.* TO 'proftpd'@'localhost';   -- 授予 proftpd 用户对 proftpd 数据库的增删改查权限
FLUSH PRIVILEGES;   -- 刷新权限,使配置立即生效

创建数据表:

sql
USE proftpd;   -- 选择 proftpd 数据库

-- 创建 users 表
DROP TABLE IF EXISTS users;
CREATE TABLE `users` (
   `username` VARCHAR(30) NOT NULL,   -- 用户名
   `descr` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,   -- 用户描述
   `password` VARCHAR(64) NOT NULL,   -- 用户密码(SHA-256 加密)
   `uid` INT(11) DEFAULT NULL,        -- 用户 UID
   `gid` INT(11) DEFAULT NULL,        -- 用户 GID
   `homedir` VARCHAR(255) DEFAULT NULL,   -- 用户主目录
   `shell` VARCHAR(255) DEFAULT NULL,     -- 用户 Shell
   `count` INT(11) NOT NULL DEFAULT 0,    -- 登录次数统计
   PRIMARY KEY (`username`)                 -- 主键为 username
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 创建 worklog 表
DROP TABLE IF EXISTS worklog;
CREATE TABLE worklog (
   id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,   -- 日志 ID,自增主键
   date TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP(0),   -- 操作时间
   user_name VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,  -- 用户名
   file_and_path VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,  -- 文件及路径
   bytes BIGINT UNSIGNED DEFAULT NULL,   -- 文件大小
   send_time VARCHAR(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,  -- 文件传输时间
   client_ip VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,  -- 客户端 IP
   client_name TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,        -- 客户端名称
   client_command VARCHAR(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,  -- 客户端命令
   PRIMARY KEY (id),
   UNIQUE INDEX id (id)
) ENGINE=InnoDB CHARACTER SET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;

-- 插入测试用户
INSERT INTO `proftpd`.`users` (`username`, `descr`, `password`, `uid`, `gid`, `homedir`, `shell`, `count`)
VALUES ('test', 'Test user', SHA2('FTPpassword_here', 256), '1002', '1002', '/home/www/ftp', NULL, '0');   -- 添加测试用户记录

已创建以下内容:

  • FTP 用户名 test
  • FTP 登录密码 FTPpassword_here
  • UID 1002
  • GID 1002

警告

上面的 UID 和 GID 必须与 proftpd 用户相同,否则仅有读取权限而无写入权限。

可以通过以下方式获取用户 proftpd 的 UID、GID 及所属组信息:

sh
# id proftpd
uid=1002(proftpd) gid=1002(proftpd) groups=1002(proftpd)

测试数据库连接:

sh
# mysql -u proftpd -p -h localhost proftpd	# 使用 proftpd 用户连接本地主机上的 proftpd 数据库,系统提示输入密码

proftpd@localhost [proftpd]> show databases;   -- 显示 MySQL 服务器上的所有数据库列表
+--------------------+
| Database           |
+--------------------+
| information_schema |
| performance_schema |
| proftpd            |
+--------------------+
3 rows in set (0.00 sec)

proftpd@localhost [proftpd]> use proftpd;   -- 选择 proftpd 数据库作为当前操作的数据库
Database changed
proftpd@localhost [proftpd]> select * from users;   -- 查询 users 表中的所有记录
+----------+-----------+------------------------------------------------------------------+------+------+---------------+-------+-------+
| username | descr     | password                                                         | uid  | gid  | homedir       | shell | count |
+----------+-----------+------------------------------------------------------------------+------+------+---------------+-------+-------+
| test     | Test user | d1d6930fda5f964acba51ec4c35d0ddb3b36d25bfef59f1120abd2e4f9f140d9 | 1002 | 1002 | /home/www/ftp | NULL  |     0 |
+----------+-----------+------------------------------------------------------------------+------+------+---------------+-------+-------+
1 row in set (0.00 sec)

创建目录和测试 FTP 用户:

sh
# mkdir -p /home/www/ftp                  # 创建 FTP 用户的主目录及子目录
# chown -R proftpd:proftpd /home/www/ftp # 设置目录所有者和所属组为 proftpd
# chmod -R 775 /home/www/ftp             # 设置目录权限为 775,允许同组用户读写

22.3.6 服务操作

配置完成后,启动并管理 ProFTPD 服务:

sh
# service proftpd enable    # 设置 ProFTPD 服务开机启动
# service proftpd start     # 启动 ProFTPD 服务
# service proftpd stop      # 停止 ProFTPD 服务
# service proftpd restart   # 重启 ProFTPD 服务

以用户名 test、密码 FTPpassword_here 登录 FTP。