# MyFTP Server - 部署与使用手册

> **版本**: v1.0.0 | **日期**: 2026-05-16 | **语言**: Go 1.21+

---

## 九、SFTP 客户端连接

### 9.1 OpenSSH 命令行（推荐）

```bash
# 使用 sftp 命令连接
sftp -P 2222 admin@localhost

# 输入密码后进入交互式会话
sftp> ls              # 列出文件
sftp> cd 目录名        # 切换目录
sftp> get 文件名       # 下载文件
sftp> put 文件名       # 上传文件
sftp> mkdir 目录名     # 创建目录
sftp> rm 文件名        # 删除文件
sftp> exit            # 退出
```

### 9.2 FileZilla 客户端

1. 打开 FileZilla
2. 主机：`sftp://localhost`
3. 端口：`2222`
4. 协议：`SFTP - SSH File Transfer Protocol`
5. 登录类型：`正常`
6. 用户名：`admin`
7. 密码：`admin123`
8. 点击"快速连接"

### 9.3 WinSCP 客户端

1. 打开 WinSCP
2. 文件协议：`SFTP`
3. 主机名：`localhost`
4. 端口号：`2222`
5. 用户名：`admin`
6. 密码：`admin123`
7. 点击"登录"

### 9.4 Linux/Mac 命令行

```bash
# 连接 SFTP 服务器
sftp -P 2222 admin@<服务器IP>

# 批量下载示例
sftp admin@<服务器IP>:2222 << EOF
cd /remote/path
lcd /local/path
mget *
bye
EOF
```

> **注意**：首次连接 SFTP 时，服务器会自动在 `./keys/` 目录下生成 2048 位 RSA SSH 主机密钥。

---

## 十、Web 文件管理

### 10.1 访问 Web 界面

1. 打开浏览器访问 `http://localhost:8080`
2. 使用 config.ini 中配置的用户名和密码登录
3. 登录后进入文件浏览器界面

### 10.2 功能说明

| 功能 | 操作 | 说明 |
|------|------|------|
| 浏览文件 | 点击文件夹 | 进入子目录 |
| 面包屑导航 | 点击路径段 | 快速跳转上级目录 |
| 下载文件 | 点击文件行"下载"按钮 | 浏览器直接下载 |
| 上传文件 | 点击"上传文件"按钮 | 支持点击选择或拖拽上传 |
| 删除文件 | 点击"删除"按钮 | 弹窗确认 |
| 重命名 | 点击"重命名"按钮 | 弹窗输入新名称 |
| 新建目录 | 点击"新建目录"按钮 | 弹窗输入目录名 |

### 10.3 上传限制

- 默认单文件最大 `100 MB`（可在 config.ini `[web]upload_max_size` 修改）
- 支持多文件拖拽上传
- 上传过程中显示进度条

### 10.4 Session 管理

- 登录状态通过 Cookie 维持
- 默认超时时间 `3600 秒`（1 小时，可在 config.ini 修改）
- 超时后需重新登录
- 点击"退出登录"按钮主动注销

---

## 目录

- [一、项目简介](#一项目简介)
- [二、功能实现状态](#二功能实现状态)
- [三、环境要求](#三环境要求)
- [四、目录结构](#四目录结构)
- [五、配置文件详解](#五配置文件详解)
- [六、编译方法](#六编译方法)
- [七、启动方法](#七启动方法)
- [八、FTP 客户端连接](#八ftp-客户端连接)
- [九、SFTP 客户端连接](#九sftp-客户端连接)
- [十、Web 文件管理](#十web-文件管理)
- [十一、支持的 FTP 命令清单](#十一支持的-ftp-命令清单)
- [十二、日志说明](#十二日志说明)
- [十三、安全性说明](#十三安全性说明)
- [十四、常见问题排查](#十四常见问题排查)
- [十五、开发路线图](#十五开发路线图)

---

## 一、项目简介

MyFTP Server 是一个采用 Go 语言编写的多协议文件传输服务器，目标是同时支持 FTP、SFTP 和 Web 文件管理三大协议。项目采用模块化架构，核心模块全部采用接口抽象，支持依赖注入，具备良好的可扩展性。

**核心特性**：

-   **FTP 协议** - 支持主动/被动模式，34 个 FTP 命令，断点续传
-   **SFTP 协议** - 基于 SSH，密码认证，文件读写/列表/重命名/删除
-   **Web 文件管理** - 文件浏览、上传、下载、删除、重命名、新建目录
-   **密码认证** - 基于 config.ini 的明文用户密码管理
-   **模块化设计** - 认证、日志、文件系统、FTP、SFTP、Web 均独立模块
-   **多级日志** - DEBUG / INFO / WARN / ERROR / FATAL 五级日志
-   **线程安全** - 原子操作 + RWMutex 保护所有共享状态
-   **目录穿越防护** - 文件系统层 + 路径解析层双重保护

---

## 二、功能实现状态

| 模块 | 状态 | 完成度 | 说明 |
|------|------|--------|------|
| FTP 服务器 | **已完成** | 100% | 34 个命令，主动/被动模式，断点续传 |
| SFTP 服务器 | **已完成** | 100% | SSH 密码认证，文件读写/列表/重命名/删除 |
| Web 文件管理 | **已完成** | 100% | Cookie Session，文件浏览/上传/下载/删除/重命名 |
| 认证管理 | **已完成** | 100% | config.ini 用户管理，线程安全 |
| 文件系统 | **已完成** | 100% | 本地文件系统，目录穿越保护 |
| 日志系统 | **已完成** | 100% | 五级日志，控制台+文件双输出 |
| 配置管理 | **已完成** | 100% | INI 解析，完整校验 |
| SSL/TLS (FTPS) | **未实现** | 0% | 计划中 |
| Docker 部署 | **未实现** | 0% | 计划中 |

> **当前可用功能**：FTP、SFTP、Web 文件管理三大模块全部完成，可直接部署使用。

---

## 三、环境要求

| 项目 | 要求 |
|------|------|
| 操作系统 | Windows / Linux / macOS |
| Go 版本 | 1.21+ |
| Go 路径 | `c:\go\go\bin\go.exe`（Windows）或系统 PATH 中的 `go` |
| 磁盘空间 | 50 MB 以上 |
| 开放端口 | FTP: 2121（可配）、被动端口: 30000-30010（可配） |
| 防火墙 | 放行 TCP 2121 端口及被动端口范围 |

### Windows 环境变量设置

```powershell
# 临时设置
$env:PATH = "c:\go\go\bin;$env:PATH"

# 永久设置（管理员 PowerShell）
[Environment]::SetEnvironmentVariable("Path", "c:\go\go\bin;" + [Environment]::GetEnvironmentVariable("Path", "User"), "User")
```

---

## 四、目录结构

```
d:\kimi\myftp\
├── cmd/server/main.go          # 主程序入口
├── internal/
│   ├── ftp/                    # FTP 服务器实现
│   │   ├── server.go           # 核心：监听、连接管理、命令路由
│   │   ├── commands.go         # 文件传输命令 (RETR/STOR/APPE/RNFR...)
│   │   └── extra_commands.go   # 辅助命令 (HELP/STAT/MDTM/SITE...)
│   ├── sftp/                   # SFTP 服务器实现
│   │   ├── server.go           # SSH+SFTP 协议栈，密码认证，文件操作
│   │   └── server_test.go      # SFTP 单元测试
│   ├── web/                    # Web 文件管理实现
│   │   ├── server.go           # Gin HTTP 服务器，路由配置
│   │   ├── handlers.go         # HTTP handler（登录/列表/上传/下载等）
│   │   └── templates/          # HTML 前端模板
│   │       ├── login.html      # 登录页面
│   │       └── browser.html    # 文件浏览器页面
│   ├── auth/auth.go            # 用户认证管理
│   ├── config/config.go        # INI 配置加载与校验
│   ├── filesystem/local.go     # 本地文件系统实现
│   └── logger/logger.go        # 五级日志系统
├── config.ini                  # 主配置文件
├── deploy/                     # 部署文档目录（本文件所在）
│   └── 使用手册.md
├── data/                       # 文件存储根目录（服务器工作目录）
├── logs/                       # 日志输出目录
├── keys/                       # SSH 密钥目录（SFTP 自动生成）
├── docs/                       # 开发文档和需求
└── go.mod                      # Go 模块定义
```

---

## 五、配置文件详解

配置文件 `config.ini` 位于项目根目录，使用 INI 格式。

### 完整配置示例

```ini
# ========== 服务器基础配置 ==========
[server]
# FTP 监听端口
ftp_port = 2121

# SFTP 监听端口
sftp_port = 2222

# Web 管理界面监听端口
web_port = 8080

# 文件存储根目录（客户端访问的文件都在此目录下）
root_dir = ./data

# 最大并发连接数（0 表示不限制）
max_connections = 100

# 客户端读超时时间（秒，0 表示使用默认 300 秒）
timeout = 300

# ========== FTP 配置 ==========
[ftp]
# 是否启用 FTP 服务
enable = true

# 被动模式端口范围（格式：起始-结束）
passive_ports = 30000-30010

# 客户端连接后的欢迎信息
welcome_message = Welcome to MyFTP Server

# ========== SFTP 配置 ==========
[sftp]
enable = true
host_key_file = ./keys/host_key

# ========== Web 配置 ==========
[web]
enable = true
session_timeout = 3600
upload_max_size = 104857600

# ========== 用户列表 ==========
[users]
# 格式：用户名 = 密码（明文）
admin = admin123
user1 = password1
# 可添加更多用户：
# 张三 = zhangsan_pwd
# guest = guest_pass

# ========== 日志配置 ==========
[logging]
# 日志级别：debug / info / warn / error / fatal
level = info

# 日志文件路径
file = ./logs/server.log

# 单个日志文件最大大小（MB，预留，暂未实现轮转）
max_size = 10

# 保留的历史日志文件数（预留，暂未实现轮转）
max_backups = 5
```

### 配置项说明

| 段 | 键 | 类型 | 默认值 | 必填 | 说明 |
|----|----|-----|--------|------|------|
| [server] | ftp_port | int | 2121 | 是 | FTP 监听端口 (1-65535) |
| [server] | sftp_port | int | 2222 | 否 | SFTP 端口（预留） |
| [server] | web_port | int | 8080 | 否 | Web 端口（预留） |
| [server] | root_dir | string | ./data | 是 | 文件存储根目录 |
| [server] | max_connections | int | 0 | 否 | 最大连接数（0=不限） |
| [server] | timeout | int | 300 | 否 | 读超时秒数 |
| [ftp] | enable | bool | true | 否 | 是否启用 FTP |
| [ftp] | passive_ports | string | 30000-30010 | 否 | 被动模式端口范围 |
| [ftp] | welcome_message | string | - | 否 | 欢迎信息 |
| [users] | 用户名 | string | - | 至少一个 | 用户名=密码 |
| [logging] | level | string | info | 否 | 日志级别 |
| [logging] | file | string | - | 是 | 日志文件路径 |

### 端口冲突检测

启动时会自动检测以下冲突并报错：

-   FTP 与 SFTP 使用同一端口
-   FTP 与 Web 使用同一端口
-   SFTP 与 Web 使用同一端口

---

## 六、编译方法

### 方式一：编译全部模块

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe build ./internal/... ./cmd/...
```

### 方式二：仅编译主程序

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe build -o myftp-server.exe ./cmd/server/
```

编译成功后在项目根目录生成 `myftp-server.exe`（或 `server.exe`）。

### 方式三：一键编译（Windows）

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe build -o server.exe ./cmd/server/
```

### 交叉编译（Linux）

```powershell
# 从 Windows 编译 Linux 版本
$env:GOOS = "linux"
$env:GOARCH = "amd64"
c:\go\go\bin\go.exe build -o myftp-server-linux ./cmd/server/
```

### 编译后验证

```powershell
# 检查二进制文件
ls server.exe

# 查看版本信息
.\server.exe
# 输出: MyFTP Server v1.0.0
#       Copyright (c) 2024
```

---

## 七、启动方法

### 方法一：直接运行编译好的二进制

```powershell
cd d:\kimi\myftp
.\server.exe
```

### 方法二：用 go run 直接运行（无需预编译）

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe run ./cmd/server/
```

### 方法三：指定配置文件路径

默认读取当前目录下的 `config.ini`，如需指定其他路径：

```powershell
cd d:\kimi\myftp
.\server.exe -config ./config.ini
```

### 启动成功的标志

```
MyFTP Server v1.0.0
Copyright (c) 2024

2026/05/14 12:00:00 [INFO] Configuration loaded successfully
2026/05/14 12:00:00 [INFO] Filesystem initialized: ./data
2026/05/14 12:00:00 [INFO] Loaded 2 users from config
2026/05/14 12:00:00 [INFO] Starting servers...
2026/05/14 12:00:00 [INFO] FTP server started on port 2121 (max connections: 100)
2026/05/14 12:00:00 [INFO] Generating new SSH host key: ./keys/host_key
2026/05/14 12:00:00 [INFO] SFTP server started on port 2222
2026/05/14 12:00:00 [INFO] Web server started on port 8080
2026/05/14 12:00:00 [INFO] 3 server(s) started successfully
```

### 停止服务器

-   **Windows**: 按 `Ctrl+C`
-   **Linux**: 按 `Ctrl+C` 或发送 SIGTERM/SIGINT 信号
-   服务器会优雅关闭，等待当前传输完成后退出

---

## 八、FTP 客户端连接

### 8.1 Windows 命令行

```powershell
# 连接 FTP 服务器
ftp localhost 2121

# 输入用户名和密码
User: admin
Password: admin123

# 常用 FTP 命令
ftp> ls              # 列出文件
ftp> cd 目录名        # 切换目录
ftp> get 文件名       # 下载文件
ftp> put 文件名       # 上传文件
ftp> delete 文件名    # 删除文件
ftp> mkdir 目录名     # 创建目录
ftp> quit            # 退出
```

### 8.2 FileZilla 客户端（推荐）

1. 打开 FileZilla
2. 主机：`localhost` 或服务器 IP
3. 端口：`2121`
4. 协议：`FTP - 文件传输协议`
5. 加密：`仅使用普通 FTP（不安全）`
6. 登录类型：`正常`
7. 用户名：`admin`
8. 密码：`admin123`
9. 点击"快速连接"

> **注意**：当前版本不支持 FTPS（加密 FTP），请选择"仅使用普通 FTP"。

### 8.3 WinSCP 客户端

1. 打开 WinSCP
2. 文件协议：`FTP`
3. 主机名：`localhost`
4. 端口号：`2121`
5. 用户名：`admin`
6. 密码：`admin123`
7. 点击"登录"

### 8.4 Linux 命令行

```bash
# 安装 ftp 客户端（如未安装）
apt install ftp    # Debian/Ubuntu
yum install ftp    # CentOS/RHEL

# 连接
ftp <服务器IP> 2121
```

---

## 九、支持的 FTP 命令清单

### 认证命令

| 命令 | 说明 | 状态 |
|------|------|------|
| USER | 指定用户名 | ✅ |
| PASS | 指定密码 | ✅ |
| ACCT | 账户（返回 230） | ✅ |
| REIN | 重新初始化连接 | ✅ |

### 目录导航

| 命令 | 说明 | 状态 |
|------|------|------|
| PWD | 显示当前工作目录 | ✅ |
| CWD | 切换工作目录 | ✅ |
| CDUP | 返回上级目录 | ✅ |

### 文件传输

| 命令 | 说明 | 状态 |
|------|------|------|
| RETR | 下载文件 | ✅ |
| STOR | 上传文件 | ✅ |
| APPE | 追加文件（O(1)内存） | ✅ |
| REST | 断点续传偏移 | ✅ |

### 文件管理

| 命令 | 说明 | 状态 |
|------|------|------|
| LIST | 列出目录内容 | ✅ |
| DELE | 删除文件 | ✅ |
| MKD  | 创建目录 | ✅ |
| RMD  | 删除目录 | ✅ |
| RNFR | 重命名（源） | ✅ |
| RNTO | 重命名（目标） | ✅ |
| SIZE | 获取文件大小 | ✅ |

### 连接模式

| 命令 | 说明 | 状态 |
|------|------|------|
| PASV | 被动模式 | ✅ |
| PORT | 主动模式 | ✅ |

### 传输设置

| 命令 | 说明 | 状态 |
|------|------|------|
| TYPE | 设置传输类型（A/I） | ✅ |
| STRU | 文件结构（F） | ✅ |
| MODE | 传输模式（S） | ✅ |

### 信息查询

| 命令 | 说明 | 状态 |
|------|------|------|
| SYST | 系统类型 | ✅ |
| FEAT | 功能列表 | ✅ |
| HELP | 帮助信息 | ✅ |
| STAT | 服务器状态 | ✅ |
| MDTM | 文件修改时间 | ✅ |

### 其他命令

| 命令 | 说明 | 状态 |
|------|------|------|
| NOOP | 空操作 | ✅ |
| QUIT | 断开连接 | ✅ |
| OPTS | 选项设置 | ✅ |
| SITE | 站点命令 | ✅ |
| ALLO | 分配空间 | ✅ |
| SMNT | 挂载（不支持）| ✅ |

---

## 十、日志说明

### 日志级别

| 级别 | 说明 | 使用场景 |
|------|------|----------|
| DEBUG | 调试信息 | 命令执行、数据传输细节 |
| INFO | 一般信息 | 服务启动、用户连接、配置加载 |
| WARN | 警告信息 | 认证失败、资源接近上限 |
| ERROR | 错误信息 | 文件操作失败、传输异常 |
| FATAL | 致命错误 | 无法初始化文件系统、端口被占用 |

### 日志位置

-   **控制台输出**：启动时的 stdout
-   **文件输出**：`./logs/server.log`（由 config.ini 配置）

### 日志格式

```
2026/05/14 12:00:00 [INFO] server.go:123 FTP server started on port 2121
```

### 查看实时日志

```powershell
# Windows PowerShell
Get-Content .\logs\server.log -Wait -Tail 50
```

```bash
# Linux
tail -f ./logs/server.log
```

---

## 十一、安全性说明

### 已实现的安全措施

| 措施 | 位置 | 说明 |
|------|------|------|
| 目录穿越防护 | local.go + server.go | 双重防护，防止 `../` 逃逸 |
| 连接数限制 | server.go:acceptLoop | 防止连接耗尽 |
| 读超时 | server.go:handleCommands | 防止僵尸连接 |
| 空密码拒绝 | server.go:handlePASS | 不允许空密码登录 |
| IP 格式校验 | server.go:handlePORT | 拒绝非法 IP 和端口 |
| 负数偏移拒绝 | commands.go:handleREST | REST 偏移≥0 |
| CWD 目录校验 | server.go:handleCWD | 不能 CD 到文件 |
| 被动端口授权锁 | server.go:closeDataListener | mutex 保护并发访问 |

### 已知安全局限

| 局限 | 说明 | 计划 |
|------|------|------|
| 明文密码 | config.ini 中密码明文存储 | 后续支持加密 |
| 无 FTPS/TLS | 网络传输不加密 | 计划中 |
| 无 IP 白名单 | 不限制客户端 IP | 后续版本 |
| 无速率限制 | 不限制上传/下载速度 | 后续版本 |

> **建议**：生产环境请配合 VPN 或内网部署使用，不要直接暴露到公网。

---

## 十二、常见问题排查

### Q1: 提示端口被占用

**现象**：`Failed to start FTP server: listen tcp :2121: bind: ...`

**解决**：

```powershell
# 查找占用 2121 端口的程序
netstat -ano | findstr 2121

# 杀掉占用程序（将 PID 替换为实际值）
taskkill /PID <PID> /F

# 或者修改 config.ini 中的 ftp_port 为其他端口（如 2122）
```

### Q2: 客户端无法连接

**检查清单**：

1.  服务器是否正常启动（看日志输出）
2.  端口是否正确（默认 2121）
3.  防火墙是否放行该端口
    ```powershell
    # Windows 防火墙添加入站规则
    netsh advfirewall firewall add rule name="FTP 2121" dir=in action=allow protocol=TCP localport=2121
    ```
4.  IP 地址是否正确（本地用 localhost，远程用服务器 IP）

### Q3: 被动模式连接失败

**现象**：能登录但 LIST/RETR 超时

**解决**：

1.  确保被动端口范围（30000-30010）在防火墙中已放行
    ```powershell
    netsh advfirewall firewall add rule name="FTP Passive" dir=in action=allow protocol=TCP localport=30000-30010
    ```
2.  如果用 Docker/NAT 网络，请确保端口映射包含了被动端口范围

### Q4: 文件上传/下载失败

**检查清单**：

1.  用户权限是否正确（config.ini 中用户名/密码）
2.  文件存储目录 `data/` 是否有写入权限
3.  磁盘空间是否充足
4.  查看 `logs/server.log` 中的错误信息

### Q5: 编译失败

**现象**：`go: cannot find main module`

**解决**：

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe mod tidy
c:\go\go\bin\go.exe build ./cmd/server/
```

### Q6: 中文文件名乱码

FTP 协议默认不支持 UTF-8。客户端需启用 UTF-8 选项（`OPTS UTF8 ON`），或使用支持 UTF-8 的客户端（如 FileZilla，在站点管理器中设置字符集为"强制 UTF-8"）。

---

## 十五、开发路线图

| 阶段 | 内容 | 状态 |
|------|------|------|
| Phase 1 | 基础架构（配置/日志/认证/文件系统） | ✅ 完成 |
| Phase 2 | FTP 服务器（34 个命令，主动/被动，断点续传） | ✅ 完成 |
| Phase 3 | SFTP 服务器（SSH 密码认证，文件操作） | ✅ 完成 |
| Phase 4 | Web 文件管理界面（Gin + HTML/JS） | ✅ 完成 |
| Phase 5 | 集成测试、性能测试、安全加固 | 🔲 待开发 |
| Phase 6 | FTPS/TLS、Docker、配置热重载 | 🔲 待开发 |

### 运行测试

```powershell
cd d:\kimi\myftp
c:\go\go\bin\go.exe test ./internal/... -v
```

当前测试用例：**40+ 个**，全部通过，包括 FTP、SFTP、认证、配置、文件系统、日志等模块。

### 运行单个模块测试

```powershell
# FTP 模块测试
c:\go\go\bin\go.exe test ./internal/ftp/... -v -count=1

# SFTP 模块测试
c:\go\go\bin\go.exe test ./internal/sftp/... -v -count=1

# 认证模块测试
c:\go\go\bin\go.exe test ./internal/auth/... -v

# 配置模块测试
c:\go\go\bin\go.exe test ./internal/config/... -v
```

---

> **文档维护**：本文档随代码同步更新。如有疑问，请查看 `docs/` 目录下的开发文档或 `config.ini` 中的注释。

---

*© 2024 MyFTP Server - All rights reserved.*