局域网两台VPS 使用同步文件

局域网两台VPS 使用同步文件

VPS间自动同步SSL证书配置指南

场景说明

两台VPS(vpsA和vpsB)在同一局域网内,需要实现vpsB每6天自动从vpsA同步x-ui的SSL证书文件。

环境信息:

  • vpsA IP: 192.168.1.250(证书源服务器)
  • vpsB IP: 192.168.1.251(证书目标服务器)
  • 证书路径: /etc/x-ui/server.crt/etc/x-ui/server.key

一、在vpsA上的配置

1.1 创建同步专用用户


sudo useradd -m -s /bin/bash syncuser
sudo mkdir -p /home/syncuser/.ssh
sudo chmod 700 /home/syncuser/.ssh
sudo chown syncuser:syncuser /home/syncuser/.ssh

1.2 安装rsync工具


sudo apt update
sudo apt install rsync -y
which rsync

1.3 创建证书文件副本目录


sudo mkdir -p /home/syncuser/certs
sudo cp -L /etc/x-ui/server.crt /home/syncuser/certs/
sudo cp -L /etc/x-ui/server.key /home/syncuser/certs/
sudo chown syncuser:syncuser /home/syncuser/certs/*
sudo chmod 644 /home/syncuser/certs/server.crt
sudo chmod 644 /home/syncuser/certs/server.key
ls -la /home/syncuser/certs/

1.4 创建自动更新副本的脚本


sudo bash -c 'cat > /usr/local/bin/update-cert-copies.sh << "EOF"
#!/bin/bash
cp -L /etc/x-ui/server.crt /home/syncuser/certs/
cp -L /etc/x-ui/server.key /home/syncuser/certs/
chown syncuser:syncuser /home/syncuser/certs/server.*
chmod 644 /home/syncuser/certs/server.*
EOF'
sudo chmod +x /usr/local/bin/update-cert-copies.sh
sudo /usr/local/bin/update-cert-copies.sh

1.5 设置定时任务自动更新副本


(sudo crontab -l 2>/dev/null; echo "*/10 * * * * /usr/local/bin/update-cert-copies.sh") | sudo crontab -
sudo crontab -l

二、在vpsB上的配置

2.1 生成SSH密钥对


ssh-keygen -t ed25519 -f ~/.ssh/cert_sync_key -C "cert-sync-from-vpsB" -N ""
cat ~/.ssh/cert_sync_key.pub

2.2 配置SSH密钥认证

方法一(推荐)


sudo passwd syncuser
ssh-copy-id -i ~/.ssh/cert_sync_key.pub syncuser@192.168.1.250

方法二(手动配置)


cat ~/.ssh/cert_sync_key.pub
sudo bash -c 'cat > /home/syncuser/.ssh/authorized_keys << EOF
《密钥内容》
EOF'
sudo chown syncuser:syncuser /home/syncuser/.ssh/authorized_keys
sudo chmod 600 /home/syncuser/.ssh/authorized_keys

2.3 测试SSH连接


ssh -i ~/.ssh/cert_sync_key syncuser@192.168.1.250 "whoami"
ssh -i ~/.ssh/cert_sync_key syncuser@192.168.1.250 "ls -la /home/syncuser/certs/"

2.4 创建同步脚本


cat > ~/sync_certs.sh << 'EOF'
#!/bin/bash

# 配置变量
VPS_A_IP="192.168.1.250"
SSH_KEY="~/.ssh/cert_sync_key"
SYNC_USER="syncuser"
LOCAL_CERT_DIR="/etc/x-ui"
BACKUP_DIR="/backup/x-ui-certs"
LOG_FILE="/var/log/cert-sync.log"

# 展开波浪号
SSH_KEY="${SSH_KEY/#\\~/$HOME}"

echo "$(date '+%Y-%m-%d %H:%M:%S'): 开始同步证书文件" | sudo tee -a "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S'): 使用SSH密钥: $SSH_KEY" | sudo tee -a "$LOG_FILE"

# 检查SSH密钥文件是否存在
if [ ! -f "$SSH_KEY" ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S'): 错误:SSH密钥文件不存在: $SSH_KEY" | sudo tee -a "$LOG_FILE"
    exit 1
fi

# 创建必要目录
sudo mkdir -p "$BACKUP_DIR"
sudo mkdir -p "$(dirname $LOG_FILE)"

# 测试SSH连接
echo "$(date '+%Y-%m-%d %H:%M:%S'): 测试SSH连接..." | sudo tee -a "$LOG_FILE"
if ! ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$SYNC_USER@$VPS_A_IP" "echo 'SSH连接成功'" 2>&1 | sudo tee -a "$LOG_FILE"; then
    echo "$(date '+%Y-%m-%d %H:%M:%S'): 错误:SSH连接失败" | sudo tee -a "$LOG_FILE"
    exit 1
fi

# 备份当前证书(如果存在)
if [ -f "$LOCAL_CERT_DIR/server.crt" ] || [ -f "$LOCAL_CERT_DIR/server.key" ]; then
    BACKUP_SUFFIX=$(date +%Y%m%d_%H%M%S)

    if [ -f "$LOCAL_CERT_DIR/server.crt" ]; then
        sudo cp "$LOCAL_CERT_DIR/server.crt" "$BACKUP_DIR/server.crt.$BACKUP_SUFFIX"
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 已备份现有 server.crt" | sudo tee -a "$LOG_FILE"
    fi

    if [ -f "$LOCAL_CERT_DIR/server.key" ]; then
        sudo cp "$LOCAL_CERT_DIR/server.key" "$BACKUP_DIR/server.key.$BACKUP_SUFFIX"
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 已备份现有 server.key" | sudo tee -a "$LOG_FILE"
    fi

    # 删除旧的证书文件
    echo "$(date '+%Y-%m-%d %H:%M:%S'): 删除旧的证书文件..." | sudo tee -a "$LOG_FILE"
    sudo rm -f "$LOCAL_CERT_DIR/server.crt" "$LOCAL_CERT_DIR/server.key"

    if [ $? -eq 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 旧证书文件已删除" | sudo tee -a "$LOG_FILE"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 警告:删除旧证书文件失败" | sudo tee -a "$LOG_FILE"
    fi
fi

# 创建临时目录
TEMP_DIR="/tmp/cert_sync_$$"
mkdir -p "$TEMP_DIR"

# 同步证书文件到临时目录(使用 -L 参数跟随符号链接)
echo "$(date '+%Y-%m-%d %H:%M:%S'): 开始从 $VPS_A_IP 同步证书" | sudo tee -a "$LOG_FILE"

rsync -avzL --chmod=644 -e "ssh -i '$SSH_KEY' -o StrictHostKeyChecking=no" \\
    "${SYNC_USER}@${VPS_A_IP}:/home/syncuser/certs/server.crt" \\
    "${SYNC_USER}@${VPS_A_IP}:/home/syncuser/certs/server.key" \\
    "$TEMP_DIR/" 2>&1 | sudo tee -a "$LOG_FILE"

# 检查同步结果
if [ ${PIPESTATUS[0]} -eq 0 ]; then
    # 验证文件完整性(检查文件大小是否合理)
    if [ -f "$TEMP_DIR/server.crt" ] && [ -f "$TEMP_DIR/server.key" ]; then
        CRT_SIZE=$(stat -f%z "$TEMP_DIR/server.crt" 2>/dev/null || stat -c%s "$TEMP_DIR/server.crt")
        KEY_SIZE=$(stat -f%z "$TEMP_DIR/server.key" 2>/dev/null || stat -c%s "$TEMP_DIR/server.key")

        echo "$(date '+%Y-%m-%d %H:%M:%S'): 证书文件大小 - CRT: ${CRT_SIZE} bytes, KEY: ${KEY_SIZE} bytes" | sudo tee -a "$LOG_FILE"

        # 检查文件大小是否合理(证书文件通常大于100字节)
        if [ "$CRT_SIZE" -gt 100 ] && [ "$KEY_SIZE" -gt 100 ]; then
            # 移动文件到目标位置
            sudo cp "$TEMP_DIR/server.crt" "$LOCAL_CERT_DIR/"
            sudo cp "$TEMP_DIR/server.key" "$LOCAL_CERT_DIR/"
            sudo chmod 644 "$LOCAL_CERT_DIR/server.crt"
            sudo chmod 600 "$LOCAL_CERT_DIR/server.key"
            sudo chown root:root "$LOCAL_CERT_DIR/server.crt" "$LOCAL_CERT_DIR/server.key"

            echo "$(date '+%Y-%m-%d %H:%M:%S'): 证书同步成功" | sudo tee -a "$LOG_FILE"
            echo "$(date '+%Y-%m-%d %H:%M:%S'): 新证书文件已部署到 $LOCAL_CERT_DIR" | sudo tee -a "$LOG_FILE"

            # 验证新文件
            sudo ls -la "$LOCAL_CERT_DIR/server."* 2>&1 | sudo tee -a "$LOG_FILE"

            # 重启x-ui服务
            if systemctl is-active --quiet x-ui; then
                echo "$(date '+%Y-%m-%d %H:%M:%S'): 正在重启 x-ui 服务..." | sudo tee -a "$LOG_FILE"
                sudo systemctl restart x-ui

                if [ $? -eq 0 ]; then
                    echo "$(date '+%Y-%m-%d %H:%M:%S'): x-ui服务已成功重启" | sudo tee -a "$LOG_FILE"
                else
                    echo "$(date '+%Y-%m-%d %H:%M:%S'): 警告:x-ui服务重启失败" | sudo tee -a "$LOG_FILE"
                fi
            else
                echo "$(date '+%Y-%m-%d %H:%M:%S'): x-ui服务未运行,跳过重启" | sudo tee -a "$LOG_FILE"
            fi

            # 清理旧备份(保留最近10个)
            sudo find "$BACKUP_DIR" -name "server.crt.*" | sort -r | tail -n +11 | sudo xargs -r rm
            sudo find "$BACKUP_DIR" -name "server.key.*" | sort -r | tail -n +11 | sudo xargs -r rm
        else
            echo "$(date '+%Y-%m-%d %H:%M:%S'): 错误:同步的文件大小异常" | sudo tee -a "$LOG_FILE"

            # 恢复备份
            LATEST_BACKUP=$(ls -t "$BACKUP_DIR/server.crt."* 2>/dev/null | head -1)
            if [ -n "$LATEST_BACKUP" ]; then
                BACKUP_SUFFIX="${LATEST_BACKUP##*.crt.}"
                echo "$(date '+%Y-%m-%d %H:%M:%S'): 尝试恢复最近的备份: $BACKUP_SUFFIX" | sudo tee -a "$LOG_FILE"
                sudo cp "$BACKUP_DIR/server.crt.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.crt"
                sudo cp "$BACKUP_DIR/server.key.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.key"
                sudo chmod 644 "$LOCAL_CERT_DIR/server.crt"
                sudo chmod 600 "$LOCAL_CERT_DIR/server.key"
                echo "$(date '+%Y-%m-%d %H:%M:%S'): 已恢复备份" | sudo tee -a "$LOG_FILE"
            fi

            rm -rf "$TEMP_DIR"
            exit 1
        fi
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 错误:同步的文件不完整" | sudo tee -a "$LOG_FILE"

        # 恢复备份
        LATEST_BACKUP=$(ls -t "$BACKUP_DIR/server.crt."* 2>/dev/null | head -1)
        if [ -n "$LATEST_BACKUP" ]; then
            BACKUP_SUFFIX="${LATEST_BACKUP##*.crt.}"
            echo "$(date '+%Y-%m-%d %H:%M:%S'): 尝试恢复最近的备份: $BACKUP_SUFFIX" | sudo tee -a "$LOG_FILE"
            sudo cp "$BACKUP_DIR/server.crt.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.crt"
            sudo cp "$BACKUP_DIR/server.key.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.key"
            sudo chmod 644 "$LOCAL_CERT_DIR/server.crt"
            sudo chmod 600 "$LOCAL_CERT_DIR/server.key"
            echo "$(date '+%Y-%m-%d %H:%M:%S'): 已恢复备份" | sudo tee -a "$LOG_FILE"
        fi

        rm -rf "$TEMP_DIR"
        exit 1
    fi
else
    echo "$(date '+%Y-%m-%d %H:%M:%S'): 证书同步失败,rsync返回错误" | sudo tee -a "$LOG_FILE"

    # 恢复备份
    LATEST_BACKUP=$(ls -t "$BACKUP_DIR/server.crt."* 2>/dev/null | head -1)
    if [ -n "$LATEST_BACKUP" ]; then
        BACKUP_SUFFIX="${LATEST_BACKUP##*.crt.}"
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 尝试恢复最近的备份: $BACKUP_SUFFIX" | sudo tee -a "$LOG_FILE"
        sudo cp "$BACKUP_DIR/server.crt.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.crt"
        sudo cp "$BACKUP_DIR/server.key.$BACKUP_SUFFIX" "$LOCAL_CERT_DIR/server.key"
        sudo chmod 644 "$LOCAL_CERT_DIR/server.crt"
        sudo chmod 600 "$LOCAL_CERT_DIR/server.key"
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 已恢复备份" | sudo tee -a "$LOG_FILE"
    fi

    rm -rf "$TEMP_DIR"
    exit 1
fi

# 清理临时目录
rm -rf "$TEMP_DIR"
echo "$(date '+%Y-%m-%d %H:%M:%S'): 证书同步完成" | sudo tee -a "$LOG_FILE"
echo "================================================" | sudo tee -a "$LOG_FILE"
EOF
EOF chmod +x ~/sync_certs.sh 

2.5 测试同步脚本


~/sync_certs.sh
sudo tail -50 /var/log/cert-sync.log
sudo ls -lh /etc/x-ui/server.*
sudo systemctl status x-ui

2.6 设置定时任务


(sudo crontab -l 2>/dev/null; echo "0 2 */6 * * /root/sync_certs.sh") | sudo crontab -
sudo crontab -l

三、验证和维护

3.1 验证证书内容一致性


diff <(ssh -i ~/.ssh/cert_sync_key syncuser@192.168.1.250 'cat /home/syncuser/certs/server.crt') <(sudo cat /etc/x-ui/server.crt)

3.2 查看备份文件


ls -lh /backup/x-ui-certs/
sudo systemctl restart x-ui

3.3 查看同步日志


sudo tail -100 /var/log/cert-sync.log
sudo grep "2025-10-21" /var/log/cert-sync.log

3.4 手动触发同步


~/sync_certs.sh

四、安全建议

  • SSH密钥安全:定期轮换,权限600
  • 限制局域网内访问
  • syncuser 权限最小化
  • 监控日志与告警
  • 定期备份与恢复测试

五、故障排查

5.1 SSH连接失败


ssh -i ~/.ssh/cert_sync_key -v syncuser@192.168.1.250

5.2 权限问题


sudo ls -la /home/syncuser/certs/
sudo chmod 644 /home/syncuser/certs/*

5.3 rsync失败


ssh -i ~/.ssh/cert_sync_key syncuser@192.168.1.250 "which rsync"
sudo apt install rsync -y

5.4 服务重启失败


sudo systemctl status x-ui
sudo journalctl -u x-ui -n 50

六、工作流程总结

自动化流程:

  1. vpsA 每10分钟更新证书副本
  2. vpsB 每6天同步新证书并重启服务

文件路径说明:

  • vpsA: /etc/x-ui/server.crt /home/syncuser/certs/
  • vpsB: /etc/x-ui/server.crt /root/sync_certs.sh /backup/x-ui-certs/

七、常见问题

  • 同步周期: vpsA每10分钟更新,vpsB每6天同步
  • 同步失败: 自动恢复备份
  • 修改频率: 调整crontab的*/6
  • 空间占用: 保留10份备份仅几十KB
  • 扩展用途: 可同步其他配置文件

结语

本方案通过SSH密钥认证 + rsync实现自动化证书同步,具备以下优点:

  • ✅ 安全可靠(SSH密钥 + 权限隔离)
  • ✅ 自动运行(cron计划任务)
  • ✅ 出错可恢复(备份机制)
  • ✅ 可扩展性强(适配其他文件)
 
© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享