#!/bin/bash

###############################################################################
# FTP 服务器安装和配置脚本
# 功能:在 Ubuntu 22 下安装 vsftpd,配置 FTP 服务器
###############################################################################

set -e  # 遇到错误立即退出

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 打印带颜色的消息
print_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

print_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

print_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

print_error() {
    echo -e "${RED}❌ $1${NC}"
}

# 检查是否为 root 用户
check_root() {
    if [ "$EUID" -ne 0 ]; then
        print_error "请使用 root 权限运行此脚本"
        echo "使用方法: sudo $0"
        exit 1
    fi
}

# 检查系统类型
check_system() {
    if [ ! -f /etc/os-release ]; then
        print_error "无法检测系统类型"
        exit 1
    fi
    
    . /etc/os-release
    
    if [ "$ID" != "ubuntu" ]; then
        print_warning "此脚本专为 Ubuntu 设计,当前系统: $ID"
        read -p "是否继续?(y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            exit 0
        fi
    fi
    
    print_info "检测到系统: $PRETTY_NAME"
}

# 安装 vsftpd
install_vsftpd() {
    print_info "更新软件包列表..."
    apt-get update -qq
    
    print_info "安装 vsftpd..."
    if dpkg -l | grep -q "^ii.*vsftpd "; then
        print_warning "vsftpd 已安装,跳过安装步骤"
    else
        apt-get install -y vsftpd
        print_success "vsftpd 安装完成"
    fi
}

# 备份现有配置
backup_config() {
    VSFTPD_CONFIG="/etc/vsftpd.conf"
    if [ -f "$VSFTPD_CONFIG" ]; then
        BACKUP_FILE="${VSFTPD_CONFIG}.backup.$(date +%Y%m%d_%H%M%S)"
        print_info "备份现有配置到: $BACKUP_FILE"
        cp "$VSFTPD_CONFIG" "$BACKUP_FILE"
    fi
}

# 配置 vsftpd
configure_vsftpd() {
    print_info "配置 vsftpd..."
    
    VSFTPD_CONFIG="/etc/vsftpd.conf"
    
    # 备份配置
    backup_config
    
    # 读取配置选项
    read -p "是否允许匿名访问?(y/N): " -n 1 -r
    echo
    ALLOW_ANONYMOUS=$([[ $REPLY =~ ^[Yy]$ ]] && echo "YES" || echo "NO")
    
    read -p "是否允许本地用户登录?(Y/n): " -n 1 -r
    echo
    ALLOW_LOCAL=$([[ $REPLY =~ ^[Nn]$ ]] && echo "NO" || echo "YES")
    
    read -p "是否允许用户写入?(Y/n): " -n 1 -r
    echo
    ALLOW_WRITE=$([[ $REPLY =~ ^[Nn]$ ]] && echo "NO" || echo "YES")
    
    read -p "是否启用被动模式(PASV)?(Y/n): " -n 1 -r
    echo
    ENABLE_PASV=$([[ $REPLY =~ ^[Nn]$ ]] && echo "NO" || echo "YES")
    
    if [ "$ENABLE_PASV" = "YES" ]; then
        read -p "请输入 PASV 端口范围(默认: 40000-50000): " PASV_RANGE
        PASV_RANGE=${PASV_RANGE:-40000-50000}
        
        read -p "请输入服务器公网 IP(用于被动模式,留空则自动检测): " PASV_ADDRESS
    fi
    
    # 读取是否启用 SSL/TLS
    read -p "是否启用 SSL/TLS 加密?(y/N): " -n 1 -r
    echo
    ENABLE_SSL=$([[ $REPLY =~ ^[Yy]$ ]] && echo "YES" || echo "NO")
    
    # 创建新的配置文件
    print_info "生成配置文件..."
    cat > "$VSFTPD_CONFIG" << EOF
# vsftpd 配置文件
# 生成时间: $(date)

# 基本设置
listen=NO
listen_ipv6=YES
anonymous_enable=$ALLOW_ANONYMOUS
local_enable=$ALLOW_LOCAL
write_enable=$ALLOW_WRITE
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES

# 日志设置
xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES

# 安全设置
chroot_local_user=YES
allow_writeable_chroot=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=$ENABLE_SSL

# 用户设置
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

# 被动模式设置
EOF

    if [ "$ENABLE_PASV" = "YES" ]; then
        cat >> "$VSFTPD_CONFIG" << EOF
pasv_enable=YES
pasv_min_port=$(echo $PASV_RANGE | cut -d'-' -f1)
pasv_max_port=$(echo $PASV_RANGE | cut -d'-' -f2)
EOF
        if [ -n "$PASV_ADDRESS" ]; then
            echo "pasv_address=$PASV_ADDRESS" >> "$VSFTPD_CONFIG"
        else
            # 自动检测 IP
            LOCAL_IP=$(hostname -I | awk '{print $1}')
            if [ -n "$LOCAL_IP" ]; then
                echo "pasv_address=$LOCAL_IP" >> "$VSFTPD_CONFIG"
            fi
        fi
    else
        echo "pasv_enable=NO" >> "$VSFTPD_CONFIG"
    fi
    
    # 如果启用匿名访问,配置匿名目录
    if [ "$ALLOW_ANONYMOUS" = "YES" ]; then
        ANON_DIR="/srv/ftp"
        if [ ! -d "$ANON_DIR" ]; then
            mkdir -p "$ANON_DIR"
            chown ftp:ftp "$ANON_DIR"
            chmod 755 "$ANON_DIR"
        fi
        cat >> "$VSFTPD_CONFIG" << EOF

# 匿名访问设置
anon_root=$ANON_DIR
anon_upload_enable=$ALLOW_WRITE
anon_mkdir_write_enable=$ALLOW_WRITE
anon_other_write_enable=$ALLOW_WRITE
EOF
    fi
    
    # 创建用户列表文件
    touch /etc/vsftpd.userlist
    chmod 644 /etc/vsftpd.userlist
    
    print_success "vsftpd 配置完成"
}

# 创建 FTP 用户
create_ftp_user() {
    if [ "$ALLOW_LOCAL" != "YES" ]; then
        print_info "本地用户登录已禁用,跳过用户创建"
        return 0
    fi
    
    print_info "创建 FTP 用户..."
    
    read -p "请输入 FTP 用户名(默认: ftpuser): " FTP_USER
    FTP_USER=${FTP_USER:-ftpuser}
    
    # 检查用户是否已存在
    if id "$FTP_USER" &>/dev/null; then
        print_warning "用户 $FTP_USER 已存在"
        read -p "是否更新密码?(Y/n): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Nn]$ ]]; then
            read -p "请输入新密码: " -s USER_PASSWORD
            echo
            echo "$FTP_USER:$USER_PASSWORD" | chpasswd
            print_success "密码已更新"
        fi
    else
        print_info "创建系统用户: $FTP_USER"
        read -p "请输入用户密码: " -s USER_PASSWORD
        echo
        
        # 创建用户,设置主目录
        read -p "请输入用户主目录(默认: /home/$FTP_USER): " FTP_HOME
        FTP_HOME=${FTP_HOME:-/home/$FTP_USER}
        
        useradd -m -d "$FTP_HOME" -s /bin/bash "$FTP_USER"
        echo "$FTP_USER:$USER_PASSWORD" | chpasswd
        
        # 设置目录权限
        chmod 755 "$FTP_HOME"
        chown "$FTP_USER:$FTP_USER" "$FTP_HOME"
        
        print_success "FTP 用户创建完成"
    fi
    
    # 将用户添加到允许列表
    if ! grep -q "^$FTP_USER$" /etc/vsftpd.userlist 2>/dev/null; then
        echo "$FTP_USER" >> /etc/vsftpd.userlist
        print_success "用户已添加到允许列表"
    fi
    
    print_info "FTP 用户名: $FTP_USER"
    print_info "FTP 主目录: $(getent passwd "$FTP_USER" | cut -d: -f6)"
}

# 配置防火墙
configure_firewall() {
    print_info "配置防火墙..."
    
    if command -v ufw &> /dev/null; then
        if ufw status | grep -q "Status: active"; then
            print_info "UFW 防火墙已启用,添加 FTP 规则..."
            ufw allow 21/tcp
            ufw allow 20/tcp
            
            if [ "$ENABLE_PASV" = "YES" ]; then
                PASV_MIN=$(echo $PASV_RANGE | cut -d'-' -f1)
                PASV_MAX=$(echo $PASV_RANGE | cut -d'-' -f2)
                ufw allow ${PASV_MIN}:${PASV_MAX}/tcp
                print_info "已开放 PASV 端口范围: $PASV_RANGE"
            fi
            
            print_success "防火墙规则已添加"
        else
            print_info "UFW 防火墙未启用,跳过配置"
        fi
    elif command -v firewall-cmd &> /dev/null; then
        print_info "配置 firewalld..."
        firewall-cmd --permanent --add-service=ftp
        if [ "$ENABLE_PASV" = "YES" ]; then
            PASV_MIN=$(echo $PASV_RANGE | cut -d'-' -f1)
            PASV_MAX=$(echo $PASV_RANGE | cut -d'-' -f2)
            firewall-cmd --permanent --add-port=${PASV_MIN}-${PASV_MAX}/tcp
        fi
        firewall-cmd --reload
        print_success "防火墙规则已添加"
    else
        print_warning "未检测到防火墙管理工具,请手动配置防火墙"
        echo "需要开放的端口:"
        echo "  - 21 (FTP 控制端口)"
        echo "  - 20 (FTP 数据端口)"
        if [ "$ENABLE_PASV" = "YES" ]; then
            echo "  - $PASV_RANGE (PASV 端口范围)"
        fi
    fi
}

# 启动和启用服务
start_service() {
    print_info "启动 vsftpd 服务..."
    
    systemctl enable vsftpd
    
    systemctl restart vsftpd
    
    # 检查服务状态
    sleep 2
    if systemctl is-active --quiet vsftpd; then
        print_success "vsftpd 服务已启动"
    else
        print_error "vsftpd 服务启动失败"
        systemctl status vsftpd
        return 1
    fi
}

# 显示连接信息
show_connection_info() {
    echo ""
    echo "============================================================"
    print_success "FTP 服务器配置完成!"
    echo "============================================================"
    echo ""
    
    # 获取本机 IP 地址
    LOCAL_IP=$(hostname -I | awk '{print $1}')
    
    print_info "连接信息:"
    echo "  服务器 IP: $LOCAL_IP"
    echo "  服务器名称: $(hostname)"
    echo "  FTP 端口: 21"
    if [ "$ENABLE_PASV" = "YES" ]; then
        echo "  PASV 端口范围: $PASV_RANGE"
    fi
    echo ""
    
    if [ "$ALLOW_ANONYMOUS" = "YES" ]; then
        echo "  匿名访问:"
        echo "    用户名: anonymous 或 ftp"
        echo "    密码: (留空或任意)"
        echo ""
    fi
    
    if [ "$ALLOW_LOCAL" = "YES" ] && [ -n "$FTP_USER" ]; then
        echo "  本地用户访问:"
        echo "    用户名: $FTP_USER"
        echo "    密码: (您设置的密码)"
        echo "    主目录: $(getent passwd "$FTP_USER" | cut -d: -f6)"
        echo ""
    fi
    
    echo "  访问方式:"
    echo "    FTP 客户端: ftp://$LOCAL_IP"
    echo "    命令行: ftp $LOCAL_IP"
    echo ""
    
    if [ "$ENABLE_SSL" = "YES" ]; then
        echo "  SSL/TLS 已启用,使用 FTPS 连接"
        echo "    FTPS: ftps://$LOCAL_IP"
        echo ""
    fi
    
    print_info "常用命令:"
    echo "  查看服务状态: systemctl status vsftpd"
    echo "  重启服务: systemctl restart vsftpd"
    echo "  查看日志: tail -f /var/log/vsftpd.log"
    echo "  测试连接: ftp localhost"
    echo ""
    
    print_info "配置文件位置:"
    echo "  /etc/vsftpd.conf"
    echo "  用户列表: /etc/vsftpd.userlist"
    echo ""
    
    print_info "添加新用户:"
    echo "  1. 创建系统用户: useradd -m -d /home/username username"
    echo "  2. 设置密码: passwd username"
    echo "  3. 添加到允许列表: echo username >> /etc/vsftpd.userlist"
    echo "  4. 重启服务: systemctl restart vsftpd"
    echo ""
}

# 主函数
main() {
    echo "============================================================"
    echo "FTP 服务器安装和配置脚本"
    echo "============================================================"
    echo ""
    
    # 检查 root 权限
    check_root
    
    # 检查系统
    check_system
    
    # 安装 vsftpd
    install_vsftpd
    
    # 配置 vsftpd
    configure_vsftpd
    
    # 创建用户
    create_ftp_user
    
    # 配置防火墙
    configure_firewall
    
    # 启动服务
    start_service
    
    # 显示连接信息
    show_connection_info
}

# 运行主函数
main "$@"

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐