SFTP搭建-自动检测上传文件修改权限-rsync 自动同步到其他服务器

配置SFTP服务

##sftp10.12.76.20
useradd sftps20
useradd sftpg20

# 设置密码
passwd sftps20 
# xxxxxxxxx

passwd sftpg20
# xxxxxxxx

mkdir -p /data/sftp/sftps20
mkdir -p /data/sftp/sftpg20

chmod 755 /data/sftp

chown sftps20:sftps20 /data/sftp/sftps20
chown sftpg20:sftpg20 /data/sftp/sftpg20

chmod 775 /data/sftp/sftps20 
chmod 775 /data/sftp/sftpg20

 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.250805
 vi /etc/ssh/sshd_config

# 找到并注释掉原SFTP子系统配置
# Subsystem      sftp    /usr/libexec/openssh/sftp-server  # CentOS
# Subsystem      sftp    /usr/lib/openssh/sftp-server      # Ubuntu

# 添加新的SFTP配置(使用内置模块)
Subsystem       sftp    internal-sftp

# 添加用户限制配置(放在文件末尾)
# 限制特定用户(如sftpuser)仅能使用SFTP,不能SSH登录
Match User sftps20,sftpg20
    ChrootDirectory /data/sftp
    ForceCommand internal-sftp   
    AllowTcpForwarding no
    X11Forwarding no
 
sshd -t
systemctl restart sshd

验证 SFTP 服务


sftp sftps20@localhost
put test.txt /upload/
exit

安装inotify-tools


cd /tmp/
mv inotify-tools-3.13.tar.gz /data/
cd /data/
tar -zxvf inotify-tools-3.13.tar.gz 
cd inotify-tools-3.13/
./configure --prefix=/usr/local
cd  /usr/local/
cd /data/inotify-tools-3.13/
make 
make install
inotifywait -h

自动修改权限脚本

cd /data/zz/
vi sftpfilechmod.sh 


#!/bin/bash
#SFTP file chmod 
#MagicConch
#CreateAt:ember.zhang
#CreateTime:2025-08-05
# 配置:SFTP上传目录 
WATCH_DIR="/data/sftp"

# 配置:日志文件路径
LOG_FILE="/var/log/sftp_permissions.log"

# 检查监控目录是否存在
if [ ! -d "$WATCH_DIR" ]; then
    echo "错误:监控目录 $WATCH_DIR 不存在!"
    exit 1
fi

# 创建日志文件(如果不存在)
if [ ! -f "$LOG_FILE" ]; then
    touch "$LOG_FILE"
    chmod 644 "$LOG_FILE"
fi

# 记录启动信息
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 启动SFTP权限监控脚本,监控目录:$WATCH_DIR" >> "$LOG_FILE"

# 监控目录事件:
# - close_write:文件写入完成(确保文件上传完整)
# - create:目录创建事件
# - moved_to:文件/目录被移动到监控目录(处理通过移动方式上传的内容)
inotifywait -m -r -e close_write,create,moved_to --format "%e %w%f" "$WATCH_DIR" | while read EVENT FILE; do
    # 处理文件
    if [ -f "$FILE" ]; then
        # 设置文件权限为755
        chmod 755 "$FILE"
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 处理文件:$FILE,事件:$EVENT,设置权限为775" >> "$LOG_FILE"
    
    # 处理目录
    elif [ -d "$FILE" ]; then
        # 设置目录权限为755
        chmod 755 "$FILE"
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 处理目录:$FILE,事件:$EVENT,设置权限为775" >> "$LOG_FILE"
    fi
done

封装服务/etc/systemd/system/sftp-permissions.service


chmod 775 sftpfilechmod.sh 

# 后台运行脚本
# sudo nohup /data/zz/sftpfilechmod.sh &

# 设置开机自启(适用于systemd系统)
 tee /etc/systemd/system/sftp-permissions.service <<EOF
[Unit]
Description=SFTP Upload Permissions Controller
After=network.target

[Service]
Type=simple
ExecStart=/data/zz/sftpfilechmod.sh
Restart=always
User=root

[Install]
WantedBy=multi-user.target
EOF

# 启用并启动服务
systemctl daemon-reload
systemctl enable sftp-permissions
systemctl start sftp-permissions

自动同步远端服务器脚本

vi /data/zz/zsync.sh
#!/bin/bash
#sync
#MagicConch
#CreateAt:ember.zhang
#CreateTime:2025-09-03 
#########################################################################

# -------------------------- 1. 配置参数(需用户根据实际环境修改!)--------------------------
MONITOR_DIR="/data/sftp/sftpn21"                  # 本地监控根目录 
REMOTE_RSYNC_USER="rsync"            # 远端rsync服务端配置的用户名
REMOTE_IP="10.12.8.37"               # 远端服务器IP 
REMOTE_RSYNC_MODULE="lotus_nexchip"        # 远端rsync服务端配置的模块名 
PASSWORD_FILE="/etc/rsyncd.pass"     # rsync密码文件路径 
LOG_DIR="/var/log/sftp_sync"         # 日志存储目录
SYNC_DELETE="false"                  # 是否同步删除(false时删除操作仅记录日志)
EXCLUDE_TMP_FILES="true"             # 是否过滤临时文件 

# -------------------------- 2. 依赖检查(自动检测,无需修改)--------------------------
check_dependency() {
    local cmd=$1
    if ! command -v $cmd &> /dev/null; then
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:未安装依赖工具 $cmd,请先执行:yum install -y $cmd"
        exit 1
    fi
}
# 检查核心依赖
check_dependency "inotifywait"
check_dependency "rsync"

# -------------------------- 3. 前置检查(避免同步失败,无需修改)--------------------------
# 检查监控目录是否存在
if [ ! -d "$MONITOR_DIR" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:本地监控目录 $MONITOR_DIR 不存在,请先创建!"
    exit 1
fi

# 检查密码文件是否存在且权限正确(rsync要求密码文件权限必须为600,否则报错)
if [ ! -f "$PASSWORD_FILE" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:rsync密码文件 $PASSWORD_FILE 不存在,请先创建!"
    exit 1
fi
if [ "$(stat -c %a "$PASSWORD_FILE")" -ne 600 ]; then
    chmod 600 "$PASSWORD_FILE"
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 提示:已自动将密码文件 $PASSWORD_FILE 权限设置为600(rsync要求)"
fi

# 检查远端rsync服务是否可连接(避免启动后无法同步)
check_remote_rsync() {
    # 通过rsync命令测试远端模块是否可达(--list-only仅列目录,不实际同步)
    rsync -avz --list-only "${REMOTE_RSYNC_USER}@${REMOTE_IP}::${REMOTE_RSYNC_MODULE}/" \
          --password-file="${PASSWORD_FILE}" &> /dev/null
    if [ $? -ne 0 ]; then
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:远端rsync服务不可达!请检查:"
        echo "1. 远端IP(${REMOTE_IP})是否正确;2. 远端rsync模块(${REMOTE_RSYNC_MODULE})是否存在;"
        echo "3. 密码文件(${PASSWORD_FILE})中的密码是否正确;4. 远端rsync服务是否已启动"
        exit 1
    fi
}
check_remote_rsync

# 创建日志目录(不存在则创建)
if [ ! -d "$LOG_DIR" ]; then
    mkdir -p "$LOG_DIR"
    chmod 755 "$LOG_DIR"
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 提示:已自动创建日志目录 $LOG_DIR"
fi

# 日志文件(按日期拆分,避免单文件过大)
LOG_FILE="${LOG_DIR}/sftp_sync_daemon_$(date +%Y%m%d).log"

# -------------------------- 4. 日志函数(无需修改)--------------------------
write_log() {
    local level=$1    # 日志级别(INFO/ERROR/WARN)
    local message=$2  # 日志内容
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] [${level}] ${message}" >> "$LOG_FILE"
    # 终端也打印关键日志(方便调试)
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] [${level}] ${message}"
}

# -------------------------- 5. 同步函数(核心:同步触发的文件+目录)--------------------------
sync_file_or_dir() {
    local event=$1    # 触发事件(如CREATE/MODIFY/MOVED_TO/DELETE)
    local path=$2     # 触发事件的文件/目录路径

    # 逻辑1:删除事件处理(SYNC_DELETE=false时仅记录日志)
    if [ "$SYNC_DELETE" = "false" ] && [[ "$event" =~ DELETE ]]; then
        local target_type=$(if [ -d "$path" ]; then echo "目录"; else echo "文件"; fi)
        write_log "INFO" "检测到${target_type}删除操作(SYNC_DELETE=false),仅记录日志:事件=${event},路径=${path}"
        return 0
    fi

    # 逻辑2:过滤临时文件(仅过滤文件,不影响目录)
    if [ "$EXCLUDE_TMP_FILES" = "true" ] && [ -f "$path" ]; then
        if [[ "$path" =~ \.(swp|tmp|swx|bak|~)$ ]]; then
            write_log "INFO" "跳过临时文件:${path}(事件:${event})"
            return 0
        fi
    fi

    # 核心:区分文件/目录,计算相对路径和远端目标
    local target_type=$(if [ -d "$path" ]; then echo "目录"; else echo "文件"; fi)
    local relative_path="${path#$MONITOR_DIR/}"  # 本地相对路径(保留目录结构)
    local remote_target="${REMOTE_RSYNC_USER}@${REMOTE_IP}::${REMOTE_RSYNC_MODULE}/${relative_path}"

    # 构建rsync参数(目录需保留-r递归,文件无需;统一保留权限/时间配置)
    local rsync_args="-avz --progress --no-group --no-owner --no-times --no-perms"
    # 仅当SYNC_DELETE=true且为删除事件时,添加--delete(删除远端对应文件/目录)
    if [ "$SYNC_DELETE" = "true" ] && [[ "$event" =~ DELETE ]]; then
        rsync_args="${rsync_args} --delete"
        write_log "WARN" "开启同步删除模式,将删除远端${target_type}${remote_target}"
    fi

    # 执行同步(文件/目录通用逻辑,rsync自动适配)
    write_log "INFO" "开始同步${target_type}:事件=${event},本地路径=${path}"
    write_log "INFO" "执行命令:rsync ${rsync_args} '${path}' '${remote_target}' --password-file='${PASSWORD_FILE}'"
    
    # 捕获同步日志(stdout+stderr)
    rsync ${rsync_args} "${path}" "${remote_target}" \
          --password-file="${PASSWORD_FILE}" &>> "$LOG_FILE"

    # 判断同步结果
    if [ $? -eq 0 ]; then
        write_log "INFO" "${target_type}同步成功:远端目标=${remote_target}"
    else
        write_log "ERROR" "${target_type}同步失败:请查看日志文件 ${LOG_FILE} 中的详细错误信息"
    fi
}

# -------------------------- 6. 监控主逻辑(保留目录事件,监控文件+目录)--------------------------
write_log "INFO" "==================== SFTP同步服务启动 ===================="
write_log "INFO" "本地监控目录:${MONITOR_DIR}"
write_log "INFO" "远端rsync模块:${REMOTE_RSYNC_USER}@${REMOTE_IP}::${REMOTE_RSYNC_MODULE}/"
write_log "INFO" "密码文件路径:${PASSWORD_FILE}"
write_log "INFO" "日志文件路径:${LOG_FILE}"
write_log "INFO" "同步模式:同步监控到的文件(创建/修改)和目录(创建/修改)"
write_log "INFO" "同步删除模式:$(if [ "$SYNC_DELETE" = "true" ]; then echo "开启"; else echo "关闭(删除操作仅记录日志)"; fi)"
write_log "INFO" "---------------------------------------------------------"

# 启动inotifywait监控(保留目录事件,不排除任何文件/目录)
inotifywait -mrq \
    --format '%e %w%f' \
    -e create,modify,moved_to,delete \
    "$MONITOR_DIR" | while read -r event path; do

    # 调用同步函数(处理文件+目录事件)
    sync_file_or_dir "$event" "$path"
done
 

封装服务/usr/lib/systemd/system/sftprsync.service

vi /usr/lib/systemd/system/sftprsync.service
[Unit]
# 服务描述(自定义,便于识别)
Description=SFTP Directory Sync Service  
# 服务依赖:网络启动后、fs 服务启动后再启动本服务(确保网络和依赖可用)
After=network.target local-fs.target
# 服务文档(可选,指向命令手册)
#Documentation=man:inotifywait(1) man:rsync(1)

[Service]
# 服务类型:simple(前台运行,适合持续监控的脚本)
Type=simple
# 执行服务的用户/组(建议用 root,避免目录、密码文件权限不足)
User=root
Group=root
# 工作目录(脚本所在目录,避免相对路径问题)
WorkingDirectory=/data/zz
# 核心:服务启动命令(脚本绝对路径,必须正确)
ExecStart=/data/zz/zsync.sh
# 服务意外退出时自动重启(确保稳定性,如脚本崩溃后恢复)
Restart=always
# 重启间隔(意外退出后,5秒再重启,避免频繁重启)
RestartSec=5
# 停止服务时,杀死所有子进程(避免 inotifywait 残留)
KillMode=control-group
# 输出重定向到 journalctl(可通过 journalctl 查看服务运行日志)
StandardOutput=journal
StandardError=journal

[Install]
# 服务安装目标:多用户模式下开机自启(适配服务器环境)
WantedBy=multi-user.target
<think>嗯,用户想查找自动上传本地文件到FTP指定目录的方法或工具。从用户的提问中可以看出,用户已经做过一些调研,引用了多个与FTP自动上传相关的参考内容。这说明用户不是初次接触这个概念,而是需要更具体、更实用的解决方案。用户提到的引用涵盖了多种技术实现方式,包括Shell脚本、批处理、CDM工具等。这些引用虽然零散,但共同指向了一个核心需求:如何高效、自动地将本地文件同步到FTP服务器。用户的关注点可能不仅限于“如何实现”,还包括实现过程的稳定性、安全性以及维护成本。用户可能是系统管理员或开发人员,需要为团队或项目搭建自动化的文件传输流程。用户对技术细节有一定了解(能引用Shell脚本和FTP类代码),但可能希望获得更系统化的方案对比或工具推荐。用户的深层需求可能包括:避免手动操作、保证传输可靠性、处理子目录结构、设置定时任务等。从专业角度看,这个问题需要分层解答:第一层是基础工具选择(脚本方案vs图形工具),第二层是具体实现细节(如认证安全、错误处理),第三层是进阶优化(如增量同步、日志监控)。用户引用的资料集中在脚本层面,但实际应用中可能需要考虑更多生产环境因素。值得注意的是用户特别提到“自动上传到指定目录”,这说明FTP目录结构可能是固定的业务需求,因此方案必须支持路径定制。另外用户没有提及操作系统环境,不过引用中既有Linux也有Windows案例,回答时需要覆盖跨平台方案。在整理方案时,应该优先推荐用户成本低、易验证的方法(如cron+脚本),再补充企业级工具作为备选。需要特别强调安全风险(如脚本中明文密码问题),因为引用[2]展示的PHP类代码存在硬编码凭证的反模式。</think> 以下是自动上传本地文件到FTP指定目录的完整方案,结合Shell脚本、任务调度工具和企业级方案,按操作环境分类说明: ### 一、基础脚本方案(Linux/Unix) ```bash #!/bin/bash # 脚本名:auto_upload_ftp.sh HOST="ftp.yourserver.com" USER="your_username" PASS="your_password" REMOTE_DIR="/target_directory" # FTP服务器目标目录 LOCAL_DIR="/local/path/to/files" # 本地待上传目录 ftp -n $HOST <<END_SCRIPT quote USER $USER quote PASS $PASS binary cd $REMOTE_DIR mput $LOCAL_DIR/* # 上传整个目录文件 lcd $LOCAL_DIR mput * # 兼容部分FTP版本 quit END_SCRIPT exit 0 ``` **关键改进:** 1. **凭证加密**:使用`.netrc`文件存储密码(权限设为600): ```bash machine ftp.yourserver.com login your_username password your_password ``` 脚本改为: ```bash ftp -n $HOST <<END_SCRIPT quote USER $(awk '/machine '$HOST'/{print $2}' ~/.netrc) quote PASS $(awk '/machine '$HOST'/{print $4}' ~/.netrc) ... ``` 2. **子目录递归上传**:使用`lftp`工具(需安装): ```bash lftp -e "mirror -R $LOCAL_DIR $REMOTE_DIR; quit" $HOST -u $USER,$PASS ``` ### 二、Windows系统方案 **1. 批处理脚本(保存为`.bat`文件)** ```batch @echo off set HOST=ftp.yourserver.com set USER=your_username set PASS=your_password set REMOTE_DIR=/target_directory set LOCAL_DIR=C:\local\path ( echo open %HOST% echo %USER% echo %PASS% echo cd %REMOTE_DIR% echo binary echo prompt echo mput "%LOCAL_DIR%\*" echo quit ) > ftpcmd.dat ftp -s:ftpcmd.dat del ftpcmd.dat ``` **2. 图形化工具推荐** - **WinSCP**:支持脚本化操作 ```powershell # WinSCP脚本示例 option batch abort option confirm off open ftp://user:pass@ftp.yourserver.com/ cd /target_directory put C:\local\path\* exit ``` 通过任务计划程序定时执行 ### 三、自动化调度实现 | 操作系统 | 工具 | 配置命令示例 | 功能说明 | |----------|------------|----------------------------------|----------------------------| | Linux | crontab | `crontab -e` 添加:<br>`*/30 * * * * /path/to/auto_upload_ftp.sh` | 每30分钟执行 | | Windows | 任务计划程序 | 创建基本任务→触发器→启动程序 | 图形界面配置定时任务 | ### 四、企业级解决方案 1. **云数据迁移工具**(如华为云CDM[^4]): - 可视化配置FTP到OBS的自动同步 - 支持增量文件识别和断点续传 - 提供传输加密和完整性校验 2. **专业FTP客户端扩展**: - FileZilla Pro:商业版支持自动化脚本 - Cyberduck:支持CLI和AppleScript自动化 ### 五、安全增强措施 1. **使用SFTP替代FTP**(修改协议头): ```bash sftp -b batch_file.txt user@host ``` 2. **SSH密钥认证**:消除密码泄露风险 3. **传输加密**:强制启用FTPS(FTP over SSL) ### 典型错误处理方案 ```bash # Shell脚本增加错误重试 MAX_RETRY=3 for i in $(seq 1 $MAX_RETRY); do if lftp -e "..."; then echo "Upload success!" break else echo "Retrying in 60s... ($i/$MAX_RETRY)" sleep 60 fi done ``` > **重要提示**:生产环境务必避免脚本中明文存储密码,建议使用SSH密钥或API令牌认证[^1][^3]。对于高频传输场景,建议使用`rsync over SSH`替代基础FTP协议提升可靠性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为什么不问问神奇的海螺呢丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值