> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-34-zhang-wen-jian-chuan-shu-xie-yi-ftp/di-34.2-jie-pure-ftpd-ji-yu-mysql.md).

# 34.2 Pure-FTPd（基于 MySQL）

## Pure-FTPd 不支持中文环境

Pure-FTPd 已移除 RFC 2640 所定义的 FTP 协议国际化框架支持。在 Windows 系统中使用 FTP 命令行访问非英文字符文件时可能出现乱码。具体变更可参见 Pure-FTPd 1.0.48 版本发布公告。

启用 UTF-8 编码的示例如下：

```powershell
ftp> quote opts utf8 on
504 Unknown command
```

在 FreeBSD 中使用命令行或 WinSCP 等客户端测试 Pure-FTPd 不会出现乱码。

## 安装 Pure-FTPd

通过 pkg 安装的 Pure-FTPd 不包含数据库支持，需通过 Ports 安装以启用 MySQL 集成。

```sh
# cd /usr/ports/ftp/pure-ftpd
# make config
```

在配置过程中勾选 `MYSQL`，其余选项保持默认值并确认。

![配置 Port pure-ftpd](/files/BV03Ixs4kQnF8t5MCcBY)

```sh
# make install clean
```

## 配置文件

配置文件需先复制示例文件，再据实际需要进行编辑。配置文件路径为：**/usr/local/etc/pure-ftpd.conf**。

### 生成配置文件

将示例配置文件复制为实际使用的配置文件：

```sh
# cp /usr/local/etc/pure-ftpd.conf.sample /usr/local/etc/pure-ftpd.conf          # 复制 Pure-FTPd 配置示例文件为默认配置
# cp /usr/local/etc/pureftpd-mysql.conf.sample /usr/local/etc/pureftpd-mysql.conf   # 复制 Pure-FTPd MySQL 配置示例文件为默认配置
```

配置文件结构如下：

```sh
/usr/local/etc/
├── pure-ftpd.conf.sample      # Pure-FTPd 配置示例文件
├── pure-ftpd.conf             # Pure-FTPd 主配置文件
├── pureftpd-mysql.conf.sample # Pure-FTPd MySQL 配置示例文件
└── pureftpd-mysql.conf        # Pure-FTPd MySQL 配置文件
```

### MySQL 集成配置

编辑 **/usr/local/etc/pure-ftpd.conf** 文件，调整相关配置项以启用 MySQL 认证：

```ini
# 兼容 IE 等非标准化的 FTP 客户端

BrokenClientsCompatibility yes

# 被动连接响应的端口范围。

PassivePortRange 30000 50000

# 允许认证用户登录的最小 UID。
# 例如，值为 100 会阻止所有 UID 小于 100 的用户登录。
# 如果希望 root 能够登录，请使用 0。

MinUID 2000

# 仅允许认证用户进行 FXP 传输。

AllowUserFXP yes

# 如果不注释此项，日志中将找不到 ftp 用户的提示信息

# AntiWarez                    yes

# 用户主目录不存在时，自动创建

CreateHomeDir yes

# MySQL 配置文件（参见 README.MySQL）

MySQLConfigFile /usr/local/etc/pureftpd-mysql.conf
```

## 配置 MySQL

本节以 MySQL 8.x 为示例。

请参照其他相关章节完成 MySQL 8.x 的安装配置。

### 创建数据库

创建 Pure-FTPd 使用的数据库和用户表：

```sql
CREATE DATABASE pureftpd;   -- 创建数据库 pureftpd
USE pureftpd;                -- 选择使用 pureftpd 数据库

DROP TABLE IF EXISTS `users`;  -- 如果存在 users 表则删除
CREATE TABLE `users` (
   `User` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,  -- 用户名，主键
   `Password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,  -- 密码
   `Uid` int(11) NOT NULL DEFAULT -1 COMMENT '用户 ID',  -- 用户 ID
   `Gid` int(11) NOT NULL DEFAULT -1 COMMENT '用户组 ID',  -- 用户组 ID
   `Dir` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,  -- 用户目录
   `QuotaFiles` int(11) NULL DEFAULT 500,  -- 文件数量配额
   `QuotaSize` int(11) NULL DEFAULT 30,  -- 存储空间配额
   `ULBandwidth` int(11) NULL DEFAULT 80,  -- 上传带宽限制
   `DLBandwidth` int(11) NULL DEFAULT 80,  -- 下载带宽限制
   `ipaddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '*',  -- 限制 IP 地址
   `comment` varchar(255) NULL DEFAULT NULL,  -- 备注
   `status` tinyint(4) NULL DEFAULT 1,  -- 用户状态
   `ulratio` int(11) NULL DEFAULT 1,  -- 上传比例
   `dlratio` int(11) NULL DEFAULT 1,  -- 下载比例
   PRIMARY KEY (`User`) USING BTREE  -- 设置主键为 User
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=Dynamic;  -- 表引擎和字符集配置
```

### 创建数据库登录用户及设置密码

创建用于连接数据库的 Pure-FTPd 专用用户：

```sql
-- 请将 'your_secure_password' 替换为强密码
CREATE USER 'pftp'@'localhost' IDENTIFIED BY 'your_secure_password';   -- 创建 MySQL 用户 pftp，允许从本地主机连接
GRANT SELECT, INSERT, UPDATE, DELETE ON pureftpd.* TO 'pftp'@'localhost';   -- 授予 pftp 用户对 pureftpd 数据库的增删改查权限
FLUSH PRIVILEGES;   -- 刷新权限，使配置立即生效
```

测试数据库连接：

```sh
# mysql -u pftp -p -h localhost pureftpd
```

### 配置文件

**/usr/local/etc/pureftpd-mysql.conf** 文件完整示例：

```ini
##############################################
#                                            #
# 示例 Pure-FTPd 的 MySQL 配置文件。         #
# 详细说明请参阅 README.MySQL。              #
#                                            #
##############################################

# MYSQLServer 数据库服务器地址
MYSQLServer     127.0.0.1

# MYSQLServer 数据库服务器端口
MYSQLPort       3306

# 可选：如果数据库服务器运行在本机，指定 mysql.sock 的路径。
MYSQLSocket     /tmp/mysql.sock

# 数据库用户名
MYSQLUser       pftp

# 数据库密码
MYSQLPassword   <你的数据库密码>

# 数据库名
MYSQLDatabase   pureftpd

# 密码加密方式（此处为明文）
# 有效值包括：“cleartext”（明文）、“argon2”、“scrypt”、“crypt”和“any”
MYSQLCrypt      cleartext

# 以下设置中的字符串部分在运行时会被替换：
#
# \L 会被替换为尝试认证的用户名。
# \I 会被替换为用户连接到的 IP 地址。
# \P 会被替换为用户连接到的端口号。
# \R 会被替换为用户来源的 IP 地址。
# \D 会被替换为远程 IP 地址的长整数形式。
#
# 使用这些替换字符串可以执行非常复杂的查询，特别适用于虚拟主机设置。

# 用于获取密码的 SQL 查询语句
MYSQLGetPW      SELECT Password FROM users WHERE User='\L'

# 用于获取系统用户名或 UID 的 SQL 查询语句
MYSQLGetUID     SELECT Uid FROM users WHERE User='\L'

# 默认 UID - 设置后将覆盖 MYSQLGetUID 的查询结果
MYSQLDefaultUID 2000

# 用于获取系统用户组名或 GID 的 SQL 查询语句
MYSQLGetGID     SELECT Gid FROM users WHERE User='\L'

# 默认 GID - 设置后将覆盖 MYSQLGetGID 的查询结果
MYSQLDefaultGID 2000

# 用于获取用户主目录的 SQL 查询语句
MYSQLGetDir     SELECT Dir FROM users WHERE User='\L'

# 可选：用于获取最大文件数的查询（虚拟配额支持需开启）
MySQLGetQTAFS  SELECT QuotaFiles FROM users WHERE User='\L'

# 可选：用于获取最大磁盘使用量（单位为 MB，需要虚拟配额支持）
MySQLGetQTASZ  SELECT QuotaSize FROM users WHERE User='\L'

# 可选：上传/下载比率，服务器需支持比率功能
MySQLGetRatioUL SELECT ULRatio FROM users WHERE User='\L'
MySQLGetRatioDL SELECT DLRatio FROM users WHERE User='\L'

# 可选：带宽限制，单位为 KB/s，服务器需支持带宽限制功能
MySQLGetBandwidthUL SELECT ULBandwidth FROM users WHERE User='\L'
MySQLGetBandwidthDL SELECT DLBandwidth FROM users WHERE User='\L'

# 启用 ~ 路径扩展。切勿盲目启用，除非满足以下条件：
# 1) 明确了解其作用。
# 2) 实际用户与虚拟用户一致。
# MySQLForceTildeExpansion 1

# 如果使用事务型存储引擎，可以启用 SQL 事务以避免竞态条件。
# 如果使用传统的 MyISAM 引擎，请保持此项注释。
# MySQLTransactions On
```

### 添加 FTP 组和用户

> **警告**
>
> 使用数据库后，`pure-pw` 命令将不再生效。

创建系统用户和组，供虚拟 FTP 用户继承权限：

```sh
# pw groupadd ftpgroup -g 2000   # 创建用户组 ftpgroup，GID 为 2000
# pw useradd ftpuser -u 2001 -g 2000 -s /sbin/nologin -w no -d /home/pureftp -c "VirtualUser Pure-FTPd" -m   # 创建虚拟 FTP 用户 ftpuser，UID 2001，主目录 /home/pureftp，不允许登录系统，自动创建主目录
```

添加 FTP 登录用户时，需手动将其信息写入 MySQL 数据库。以下示例创建用户 `test`，密码为 `test2`：

```sql
USE pureftpd;   -- 选择 pureftpd 数据库
INSERT INTO `users` (`User`, `Password`, `Uid`, `Gid`, `Dir`, `quotafiles`, `quotasize`, `ulbandwidth`, `dlbandwidth`, `ipaddress`, `comment`, `status`, `ulratio`, `dlratio`)
VALUES ('test', 'test2', 2001, 2000, '/home/pureftp/www', 500, 30, 80, 80, '*', NULL, 1, 1, 1);   -- 向 users 表中插入一个测试用户记录
```

> **注意**
>
> 写入表中的 `Uid` 和 `Gid` 必须与此前通过 `pw useradd` 创建的用户保持一致。

> **技巧**
>
> 其设计思路是：数据库中的虚拟用户继承 `pw useradd` 所创建用户的权限及 UID/GID，并通过数据库中的用户信息进行 FTP 文件操作。

```sh
系统用户 ftpuser（UID 2001 / GID 2000）
   │
   │ 提供权限与 UID/GID
   ▼
MySQL users 表（虚拟用户）
   ├── User     → test
   ├── Password → test2
   ├── Uid      → 2001（继承自 ftpuser）
   ├── Gid      → 2000（继承自 ftpgroup）
   └── Dir      → /home/pureftp/www
   │
   │ FTP 登录认证
   ▼
Pure-FTPd 守护进程
   │
   │ 以 ftpuser 权限操作文件
   ▼
/home/pureftp/www（FTP 目录）
```

实际操作示例：

```sql
root@localhost [(none)]> show databases;	-- 显示当前 MySQL 服务器上的所有数据库列表
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| pureftpd           |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
root@localhost [pureftpd]> USE pureftpd;   -- 选择 pureftpd 数据库作为当前操作的数据库
Database changed
root@localhost [pureftpd]> INSERT INTO `users` (`User`, `Password`, `Uid`, `Gid`, `Dir`, `quotafiles`, `quotasize`, `ulbandwidth`, `dlbandwidth`, `ipaddress`, `comment`, `status`, `ulratio`, `dlratio`)
    -> VALUES ('test', 'test2', 2001, 2000, '/home/pureftp/www', 500, 30, 80, 80, '*', NULL, 1,1, 1);
Query OK, 1 row affected (0.01 sec)
root@localhost [pureftpd]> select * from users;   -- 查询 users 表中的所有记录
+------+----------+------+------+-------------------+------------+-----------+-------------+-------------+-----------+---------+--------+---------+---------+
| User | Password | Uid  | Gid  | Dir               | quotafiles | quotasize | ulbandwidth | dlbandwidth | ipaddress | comment | status | ulratio | dlratio |
+------+----------+------+------+-------------------+------------+-----------+-------------+-------------+-----------+---------+--------+---------+---------+
| test | test2    | 2001 | 2000 | /home/pureftp/www |        500 |        30 |          80 |    80 | *         |    NULL |      1 |       1 |       1 |
+------+----------+------+------+-------------------+------------+-----------+-------------+-------------+-----------+---------+--------+---------+---------+
1 row in set (0.01 sec)
```

配置 FTP 目录：

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

结构概览：

```sh
/home/
└── pureftp/
    └── www/ # FTP 用户的主目录
```

### 参考文献

* osc\_e0e3b1a8. Linux 环境下 FTP 权限设置详解与操作步骤全攻略\[EB/OL]. \[2026-03-25]. <https://my.oschina.net/emacs_8748786/blog/17171107>. 详解 FTP 服务的用户权限配置与目录访问控制方法。

## 服务操作

配置完成后，启动并管理 Pure-FTPd 服务：

```sh
# service pure-ftpd enable    # 设置 Pure-FTPd 服务开机启动
# service pure-ftpd start     # 启动 Pure-FTPd 服务
# service pure-ftpd stop      # 停止 Pure-FTPd 服务
# service pure-ftpd restart   # 重启 Pure-FTPd 服务
```

## 参考文献

* Curtin B. RFC 2640: Internationalization of the File Transfer Protocol\[EB/OL]. (1999-07)\[2026-03-26]. <https://www.rfc-editor.org/rfc/rfc2640>. 该 RFC 定义了 FTP 协议的国际化框架。
* Pure-FTPd. Version 1.0.48 released\[EB/OL]. \[2026-03-26]. <https://www.pureftpd.org/project/pure-ftpd/news>. Pure-FTPd 1.0.48 发行公告。
* Denis F. COPYING for Pure-FTPd\[EB/OL]. (2001–2026)\[2026-04-18]. <https://github.com/jedisct1/pure-ftpd/blob/master/COPYING>. Pure-FTPd 许可证为 ISC 许可证，与 2 条款 BSD 许可证功能等价。
* falko. Virtual Hosting With PureFTPd And MySQL (Incl. Quota And Bandwidth Management)\[EB/OL]. (2007-11-07)\[2026-03-25]. <https://archive.org/download/pdfbackup_18_aout-2014/Virtual_Hosting_With_PureFTPd_And_MySQL__Incl._Quota_And_Ban.pdf>. PureFTPd 配置教程。

## 故障排除

* Pure-FTPd 日志文件位于 **/var/log/messages**。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-34-zhang-wen-jian-chuan-shu-xie-yi-ftp/di-34.2-jie-pure-ftpd-ji-yu-mysql.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
