Compare commits
3 Commits
b5e802ebc3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
837bdb4a91 | ||
|
|
dcc8afffba | ||
|
|
9d93a1ee6e |
2
.idea/dataSources.local.xml
generated
2
.idea/dataSources.local.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="dataSourceStorageLocal" created-in="IU-252.25557.131">
|
<component name="dataSourceStorageLocal" created-in="IU-252.28238.7">
|
||||||
<data-source name="腾讯云-成都" uuid="79c9466f-d8a3-418a-b54a-f6e314306a0c">
|
<data-source name="腾讯云-成都" uuid="79c9466f-d8a3-418a-b54a-f6e314306a0c">
|
||||||
<database-info product="MySQL" version="8.0.27" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-java-8.0.25 (Revision: 08be9e9b4cba6aa115f9b27b215887af40b159e0)" dbms="MYSQL" exact-version="8.0.27" exact-driver-version="8.0">
|
<database-info product="MySQL" version="8.0.27" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-java-8.0.25 (Revision: 08be9e9b4cba6aa115f9b27b215887af40b159e0)" dbms="MYSQL" exact-version="8.0.27" exact-driver-version="8.0">
|
||||||
<extra-name-characters>#@</extra-name-characters>
|
<extra-name-characters>#@</extra-name-characters>
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 定时任务 每天凌晨2点执行
|
|
||||||
# 环境变量
|
|
||||||
vault_warden_host_ip=s5
|
|
||||||
|
|
||||||
|
|
||||||
remote_fetch_vault_warden_backup_data() {
|
|
||||||
|
|
||||||
ssh -p 22333 root@s5 "docker exec -it vault-warden /vaultwarden backup"
|
|
||||||
|
|
||||||
ssh -p 22333 root@s5 "rm -rf /data/vault-warden/persist-data/db_*.sqlite3"
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdir -p /tmp/vault_warden_backup_stage/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rsync -a /data/vault-warden/persist-data/config.json /data/vault-warden/persist-data/rsa_key* /data/vault-warden/persist-data/attachments /data/vault-warden/persist-data/sends /data/vault-warden/persist-data/db_*.sqlite3 /tmp/vault_warden_backup_stage/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
将暂存目录的全部内容打包成最终的归档文件。
|
|
||||||
cd /tmp/vault_warden_backup_stage/
|
|
||||||
tar -czf vaultwarden-backup-$(date +%Y%m%d-%H%M%S).tar.gz /tmp/vault_warden_backup_stage/*
|
|
||||||
|
|
||||||
|
|
||||||
rm -rf /tmp/vault_warden_backup_stage/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
271
0-部署应用/CloudCone-备份中心/common.sh
Normal file
271
0-部署应用/CloudCone-备份中心/common.sh
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# Meta : 公共函数与变量库
|
||||||
|
# Version : 1.0.0
|
||||||
|
# Author : Bash Shell Senior Development Engineer
|
||||||
|
# License : MIT
|
||||||
|
# Description : 为备份脚本体系提供标准化的日志、远程执行、加解密及云存储管理功能。
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 脚本严格模式
|
||||||
|
# -e: 命令失败时立即退出
|
||||||
|
# -u: 变量未定义时报错
|
||||||
|
# -o pipefail: 管道中任一命令失败则整个管道失败
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 全局常量定义区
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# > 基础路径配置
|
||||||
|
readonly SCRIPT_RUN_DIR="/root/wdd/backup"
|
||||||
|
readonly LOG_DIR="/root/wdd/backup/logs"
|
||||||
|
|
||||||
|
# > 通用配置
|
||||||
|
readonly REMOTE_SSH_PORT="22333"
|
||||||
|
readonly ENCRYPTION_PASSWORD_7ZIP="SuperWdd.CCC.123" # !!!请务必修改为强密码!!!
|
||||||
|
readonly RCLONE_REMOTE_REPO="gd-zeaslity:CloneCone-BackUp" # rclone配置的远程仓库名及路径
|
||||||
|
|
||||||
|
# > 日志级别常量
|
||||||
|
readonly LOG_LEVEL_DEBUG=0
|
||||||
|
readonly LOG_LEVEL_INFO=1
|
||||||
|
readonly LOG_LEVEL_WARN=2
|
||||||
|
readonly LOG_LEVEL_ERROR=3
|
||||||
|
|
||||||
|
# > 默认日志级别 (可被调用脚本覆盖)
|
||||||
|
CURRENT_LOG_LEVEL=${LOG_LEVEL_INFO}
|
||||||
|
|
||||||
|
# > 颜色输出定义
|
||||||
|
readonly C_RED='\033[0;31m'
|
||||||
|
readonly C_GREEN='\033[0;32m'
|
||||||
|
readonly C_YELLOW='\033[1;33m'
|
||||||
|
readonly C_BLUE='\033[0;34m'
|
||||||
|
readonly C_NC='\033[0m'
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 模块依赖检查
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
if ! command -v 7z &> /dev/null || ! command -v rclone &> /dev/null || ! command -v ssh &> /dev/null; then
|
||||||
|
echo -e "${C_RED}[ERROR] Essential commands (7z, rclone, ssh) are not installed. Aborting.${C_NC}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 函数定义区
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 记录标准化的分级日志
|
||||||
|
# @param level <string> 日志级别 (DEBUG/INFO/WARN/ERROR)
|
||||||
|
# @param message <string> 要记录的日志消息
|
||||||
|
# @return <0> 成功
|
||||||
|
# @require LOG_DIR, CURRENT_LOG_LEVEL
|
||||||
|
###
|
||||||
|
log_message() {
|
||||||
|
local level="$1"
|
||||||
|
local message="$2"
|
||||||
|
local log_level_value
|
||||||
|
local log_file
|
||||||
|
|
||||||
|
log_file="${LOG_DIR}/backup_$(date +%Y%m%d).log"
|
||||||
|
mkdir -p "${LOG_DIR}"
|
||||||
|
|
||||||
|
case "${level}" in
|
||||||
|
"DEBUG") log_level_value=${LOG_LEVEL_DEBUG} ;;
|
||||||
|
"INFO") log_level_value=${LOG_LEVEL_INFO} ;;
|
||||||
|
"WARN") log_level_value=${LOG_LEVEL_WARN} ;;
|
||||||
|
"ERROR") log_level_value=${LOG_LEVEL_ERROR} ;;
|
||||||
|
*) log_level_value=${LOG_LEVEL_INFO} ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ ${CURRENT_LOG_LEVEL} -le ${log_level_value} ]]; then
|
||||||
|
local timestamp
|
||||||
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
local color_prefix="${C_GREEN}"
|
||||||
|
|
||||||
|
case "${level}" in
|
||||||
|
"DEBUG") color_prefix="${C_BLUE}" ;;
|
||||||
|
"INFO") color_prefix="${C_GREEN}" ;;
|
||||||
|
"WARN") color_prefix="${C_YELLOW}" ;;
|
||||||
|
"ERROR") color_prefix="${C_RED}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# > 格式化日志条目
|
||||||
|
local log_entry
|
||||||
|
log_entry=$(printf "[%-5s] %s: %s" "${level}" "${timestamp}" "${message}")
|
||||||
|
|
||||||
|
# > 输出到标准输出/错误
|
||||||
|
echo -e "${color_prefix}${log_entry}${C_NC}"
|
||||||
|
|
||||||
|
# > INFO及以上级别写入日志文件
|
||||||
|
if [[ ${log_level_value} -ge ${LOG_LEVEL_INFO} ]]; then
|
||||||
|
echo "${log_entry}" >> "${log_file}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 通过SSH在远程主机上安全地执行命令
|
||||||
|
# @param remote_user <string> 远程主机用户名
|
||||||
|
# @param remote_host <string> 远程主机名或IP地址
|
||||||
|
# @param remote_command <string> 待执行的命令
|
||||||
|
# @param ssh_port <string> SSH端口 (可选, 默认22333)
|
||||||
|
# @return <exit_code> 远程命令的退出码
|
||||||
|
# @require REMOTE_SSH_PORT, ssh client
|
||||||
|
###
|
||||||
|
execute_remote_command() {
|
||||||
|
local remote_user="$1"
|
||||||
|
local remote_host="$2"
|
||||||
|
local remote_command="$3"
|
||||||
|
local ssh_port=${4:-${REMOTE_SSH_PORT}}
|
||||||
|
|
||||||
|
log_message "DEBUG" "Executing on [${remote_user}@${remote_host}:${ssh_port}]: ${remote_command}"
|
||||||
|
|
||||||
|
ssh -p "${ssh_port}" "${remote_user}@${remote_host}" "${remote_command}"
|
||||||
|
local exit_code=$?
|
||||||
|
|
||||||
|
if [[ ${exit_code} -ne 0 ]]; then
|
||||||
|
log_message "ERROR" "Remote command failed with exit code ${exit_code}."
|
||||||
|
return ${exit_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "DEBUG" "Remote command executed successfully."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 使用7zip加密并压缩指定目录
|
||||||
|
# @param source_directory <string> 需要压缩的源目录路径
|
||||||
|
# @param archive_path <string> 生成的加密压缩包完整路径
|
||||||
|
# @return <0> 成功 | >0 失败
|
||||||
|
# @require ENCRYPTION_PASSWORD_7ZIP, 7z command
|
||||||
|
###
|
||||||
|
encrypt_with_7zip() {
|
||||||
|
local source_directory="$1"
|
||||||
|
local archive_path="$2"
|
||||||
|
|
||||||
|
if [[ ! -d "${source_directory}" ]]; then
|
||||||
|
log_message "ERROR" "Source directory for encryption does not exist: ${source_directory}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "Encrypting '${source_directory}' to '${archive_path}'..."
|
||||||
|
|
||||||
|
# > -mhe=on: 加密文件头, 防止泄露文件列表
|
||||||
|
# > -p: 指定密码
|
||||||
|
7z a -mhe=on -p"${ENCRYPTION_PASSWORD_7ZIP}" "${archive_path}" "${source_directory}"/*
|
||||||
|
local exit_code=$?
|
||||||
|
|
||||||
|
if [[ ${exit_code} -ne 0 ]]; then
|
||||||
|
log_message "ERROR" "7zip encryption failed with exit code ${exit_code}."
|
||||||
|
return ${exit_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "Encryption completed successfully."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 使用rclone将本地文件复制到远程仓库
|
||||||
|
# @param source_file <string> 本地源文件路径
|
||||||
|
# @param remote_destination <string> rclone远程目标路径 (e.g., "google-drive:backup/app1/")
|
||||||
|
# @return <0> 成功 | >0 失败
|
||||||
|
# @require rclone command
|
||||||
|
###
|
||||||
|
rclone_copy() {
|
||||||
|
local source_file="$1"
|
||||||
|
local remote_destination="$2"
|
||||||
|
|
||||||
|
if [[ ! -f "${source_file}" ]]; then
|
||||||
|
log_message "ERROR" "Source file for rclone copy does not exist: ${source_file}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "Copying '${source_file}' to remote '${remote_destination}'..."
|
||||||
|
|
||||||
|
rclone copy -P "${source_file}" "${remote_destination}"
|
||||||
|
local exit_code=$?
|
||||||
|
|
||||||
|
if [[ ${exit_code} -ne 0 ]]; then
|
||||||
|
log_message "ERROR" "rclone copy failed with exit code ${exit_code}."
|
||||||
|
return ${exit_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "rclone copy completed successfully."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 控制rclone远程仓库中的副本数量,删除最旧的副本
|
||||||
|
# @param remote_path <string> 远程仓库中的目录路径
|
||||||
|
# @param file_prefix <string> 需要管理副本数量的文件名前缀
|
||||||
|
# @param max_replicas <integer> 允许保留的最大副本数量
|
||||||
|
# @return <0> 成功 | >0 失败
|
||||||
|
# @require rclone command
|
||||||
|
###
|
||||||
|
rclone_control_replicas() {
|
||||||
|
local remote_path="$1"
|
||||||
|
local file_prefix="$2"
|
||||||
|
local max_replicas="$3"
|
||||||
|
|
||||||
|
log_message "INFO" "Checking replicas for '${file_prefix}*' in '${remote_path}'. Max allowed: ${max_replicas}."
|
||||||
|
|
||||||
|
# > 获取远程文件列表及其修改时间
|
||||||
|
local remote_files
|
||||||
|
remote_files=$(rclone lsf --format "tp" "${remote_path}" | grep "${file_prefix}" || true)
|
||||||
|
|
||||||
|
if [[ -z "${remote_files}" ]]; then
|
||||||
|
log_message "INFO" "No remote files found with prefix '${file_prefix}'. Nothing to do."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local file_count
|
||||||
|
file_count=$(echo "${remote_files}" | wc -l)
|
||||||
|
|
||||||
|
if [[ ${file_count} -le ${max_replicas} ]]; then
|
||||||
|
log_message "INFO" "Current replica count (${file_count}) is within the limit (${max_replicas})."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local files_to_delete_count
|
||||||
|
files_to_delete_count=$((file_count - max_replicas))
|
||||||
|
log_message "WARN" "Exceeding replica limit. Need to delete ${files_to_delete_count} oldest file(s)."
|
||||||
|
|
||||||
|
# > 按时间排序并提取需要删除的文件名
|
||||||
|
local files_to_delete
|
||||||
|
files_to_delete=$(echo "${remote_files}" | sort -k2 | head -n "${files_to_delete_count}" | awk -F';' '{print $1}')
|
||||||
|
|
||||||
|
for file in ${files_to_delete}; do
|
||||||
|
log_message "INFO" "Deleting oldest replica: ${file}"
|
||||||
|
rclone deletefile "${remote_path}/${file}"
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
log_message "ERROR" "Failed to delete remote file: ${file}"
|
||||||
|
# > 继续尝试删除其他文件,不立即失败
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_message "INFO" "Replica control process finished."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 功能描述段: 清理指定目录下的所有.7z加密压缩包
|
||||||
|
# @param target_directory <string> 需要清理的目录路径
|
||||||
|
# @return <0> 成功
|
||||||
|
# @require find command
|
||||||
|
###
|
||||||
|
cleanup_local_encrypted_files() {
|
||||||
|
local target_directory="$1"
|
||||||
|
|
||||||
|
log_message "INFO" "Cleaning up local encrypted files (*.7z) in '${target_directory}'..."
|
||||||
|
|
||||||
|
find "${target_directory}" -maxdepth 1 -type f -name "*.7z" -delete
|
||||||
|
|
||||||
|
log_message "INFO" "Local cleanup finished."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
264
0-部署应用/CloudCone-备份中心/deepseek-v3.1/b-gitea-dsv3.1.sh
Normal file
264
0-部署应用/CloudCone-备份中心/deepseek-v3.1/b-gitea-dsv3.1.sh
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Gitea 远程备份脚本
|
||||||
|
# Author: System Administrator
|
||||||
|
# Version: 1.0.0
|
||||||
|
# License: MIT
|
||||||
|
#
|
||||||
|
# 功能描述:通过SSH远程执行Gitea备份操作,并将备份文件同步到本地
|
||||||
|
# 依赖要求:ssh, rsync, docker, date, grep, awk 等基础工具
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 全局常量定义区
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
readonly REMOTE_PORT="22333"
|
||||||
|
readonly REMOTE_HOST="t0"
|
||||||
|
readonly SCRIPT_DIR="/root/wdd/backup"
|
||||||
|
readonly REMOTE_GITEA_CONTAINER="gitea-gitea-1"
|
||||||
|
readonly REMOTE_GITEA_CONFIG="/bitnami/gitea/custom/conf/app.ini"
|
||||||
|
readonly REMOTE_BACKUP_SOURCE="/data/gitea/gitea_data/data/tmp/gitea-dump-*.zip"
|
||||||
|
readonly LOCAL_BACKUP_TARGET="/data/t0_150_230_198_103/gitea/"
|
||||||
|
|
||||||
|
# > 日志配置
|
||||||
|
readonly LOG_DIR="${SCRIPT_DIR}/logs"
|
||||||
|
readonly LOG_FILE="${LOG_DIR}/gitea_backup_$(date +%Y%m%d).log"
|
||||||
|
|
||||||
|
# 日志级别常量
|
||||||
|
readonly LOG_LEVEL_DEBUG=0
|
||||||
|
readonly LOG_LEVEL_INFO=1
|
||||||
|
readonly LOG_LEVEL_WARN=2
|
||||||
|
readonly LOG_LEVEL_ERROR=3
|
||||||
|
|
||||||
|
# 当前日志级别(默认INFO)
|
||||||
|
CURRENT_LOG_LEVEL=${LOG_LEVEL_INFO}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 函数声明区
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# 输出格式化日志信息(同时输出到控制台和日志文件)
|
||||||
|
# @param level string 日志级别(DEBUG/INFO/WARN/ERROR)
|
||||||
|
# @param message string 日志消息内容
|
||||||
|
# @return void
|
||||||
|
# @require CURRENT_LOG_LEVEL, LOG_FILE
|
||||||
|
log_message() {
|
||||||
|
local level="$1"
|
||||||
|
local message="$2"
|
||||||
|
local timestamp
|
||||||
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
local log_entry=""
|
||||||
|
case "$level" in
|
||||||
|
"DEBUG")
|
||||||
|
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_DEBUG} ]; then
|
||||||
|
log_entry="[DEBUG][${timestamp}] ${message}"
|
||||||
|
echo "${log_entry}"
|
||||||
|
echo "${log_entry}" >> "${LOG_FILE}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"INFO")
|
||||||
|
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_INFO} ]; then
|
||||||
|
log_entry="[INFO][${timestamp}] ${message}"
|
||||||
|
echo "${log_entry}"
|
||||||
|
echo "${log_entry}" >> "${LOG_FILE}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"WARN")
|
||||||
|
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_WARN} ]; then
|
||||||
|
log_entry="[WARN][${timestamp}] ${message}"
|
||||||
|
echo "${log_entry}" >&2
|
||||||
|
echo "${log_entry}" >> "${LOG_FILE}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"ERROR")
|
||||||
|
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_ERROR} ]; then
|
||||||
|
log_entry="[ERROR][${timestamp}] ${message}"
|
||||||
|
echo "${log_entry}" >&2
|
||||||
|
echo "${log_entry}" >> "${LOG_FILE}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_entry="[UNKNOWN][${timestamp}] ${message}"
|
||||||
|
echo "${log_entry}" >&2
|
||||||
|
echo "${log_entry}" >> "${LOG_FILE}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 执行远程SSH命令
|
||||||
|
# @param command string 需要执行的远程命令
|
||||||
|
# @return int 命令执行退出码
|
||||||
|
# @require REMOTE_HOST, REMOTE_PORT
|
||||||
|
execute_remote_command() {
|
||||||
|
local command="$1"
|
||||||
|
local exit_code
|
||||||
|
|
||||||
|
log_message "DEBUG" "执行远程命令: ${command}"
|
||||||
|
|
||||||
|
# > 通过SSH连接到远程主机执行命令
|
||||||
|
ssh -p "${REMOTE_PORT}" "${REMOTE_HOST}" "${command}"
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
if [ ${exit_code} -ne 0 ]; then
|
||||||
|
log_message "ERROR" "远程命令执行失败,退出码: ${exit_code}"
|
||||||
|
return ${exit_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 执行Gitea备份操作
|
||||||
|
# @return int 操作执行状态码
|
||||||
|
# @require REMOTE_GITEA_CONTAINER, REMOTE_GITEA_CONFIG
|
||||||
|
perform_gitea_backup() {
|
||||||
|
local backup_command="docker exec -i ${REMOTE_GITEA_CONTAINER} /opt/bitnami/gitea/bin/gitea dump -c ${REMOTE_GITEA_CONFIG}"
|
||||||
|
|
||||||
|
log_message "INFO" "开始执行Gitea备份..."
|
||||||
|
|
||||||
|
# > 执行Gitea dump命令生成备份文件
|
||||||
|
if ! execute_remote_command "${backup_command}"; then
|
||||||
|
log_message "ERROR" "Gitea备份命令执行失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "Gitea备份命令执行成功"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 重命名备份文件(添加时间戳)
|
||||||
|
# @return int 操作执行状态码
|
||||||
|
# @require REMOTE_GITEA_CONTAINER
|
||||||
|
rename_backup_file() {
|
||||||
|
local rename_command="docker exec -i ${REMOTE_GITEA_CONTAINER} /bin/sh -c \"mv /opt/bitnami/gitea/gitea-dump-*.zip /opt/bitnami/gitea/data/tmp/gitea-dump-\$(date +%Y%m%d-%H%M%S).zip\""
|
||||||
|
|
||||||
|
log_message "INFO" "开始重命名备份文件..."
|
||||||
|
|
||||||
|
# > 在容器内重命名备份文件,添加时间戳
|
||||||
|
if ! execute_remote_command "${rename_command}"; then
|
||||||
|
log_message "ERROR" "备份文件重命名失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "备份文件重命名成功"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 同步备份文件到本地
|
||||||
|
# @return int 操作执行状态码
|
||||||
|
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_BACKUP_SOURCE, LOCAL_BACKUP_TARGET
|
||||||
|
sync_backup_to_local() {
|
||||||
|
log_message "INFO" "开始同步备份文件到本地..."
|
||||||
|
|
||||||
|
# > 创建本地目标目录(如果不存在)
|
||||||
|
if [ ! -d "${LOCAL_BACKUP_TARGET}" ]; then
|
||||||
|
mkdir -p "${LOCAL_BACKUP_TARGET}"
|
||||||
|
log_message "DEBUG" "创建本地目录: ${LOCAL_BACKUP_TARGET}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# > 使用rsync同步文件,保留关键属性
|
||||||
|
rsync -avz -e "ssh -p ${REMOTE_PORT}" \
|
||||||
|
"${REMOTE_HOST}:${REMOTE_BACKUP_SOURCE}" \
|
||||||
|
"${LOCAL_BACKUP_TARGET}"
|
||||||
|
|
||||||
|
local exit_code=$?
|
||||||
|
if [ ${exit_code} -ne 0 ]; then
|
||||||
|
log_message "ERROR" "rsync同步失败,退出码: ${exit_code}"
|
||||||
|
return ${exit_code}
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "备份文件同步成功"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 清理远程备份文件
|
||||||
|
# @return int 操作执行状态码
|
||||||
|
# @require REMOTE_BACKUP_SOURCE
|
||||||
|
cleanup_remote_backup() {
|
||||||
|
local cleanup_command="rm -f ${REMOTE_BACKUP_SOURCE}"
|
||||||
|
|
||||||
|
log_message "INFO" "开始清理远程备份文件..."
|
||||||
|
|
||||||
|
# > 删除远程主机上的临时备份文件
|
||||||
|
if ! execute_remote_command "${cleanup_command}"; then
|
||||||
|
log_message "ERROR" "远程备份文件清理失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "远程备份文件清理成功"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 主执行函数 - 协调整个备份流程
|
||||||
|
# @return int 脚本执行最终状态码
|
||||||
|
main() {
|
||||||
|
local overall_success=true
|
||||||
|
|
||||||
|
log_message "INFO" "=== Gitea备份流程开始 ==="
|
||||||
|
|
||||||
|
# 切换到工作目录
|
||||||
|
cd "${SCRIPT_DIR}" || {
|
||||||
|
log_message "ERROR" "无法切换到工作目录: ${SCRIPT_DIR}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 执行备份流程
|
||||||
|
if ! perform_gitea_backup; then
|
||||||
|
overall_success=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! rename_backup_file; then
|
||||||
|
overall_success=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! sync_backup_to_local; then
|
||||||
|
overall_success=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cleanup_remote_backup; then
|
||||||
|
overall_success=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 汇总执行结果
|
||||||
|
if [ "${overall_success}" = true ]; then
|
||||||
|
log_message "INFO" "=== Gitea备份流程完成 ==="
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_message "ERROR" "=== Gitea备份流程部分失败 ==="
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 异常处理设置
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# 设置trap捕获信号
|
||||||
|
trap 'log_message "ERROR" "脚本被中断"; exit 1' INT TERM
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 主执行流程
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# 函数调用关系:
|
||||||
|
# main -> perform_gitea_backup -> execute_remote_command
|
||||||
|
# -> rename_backup_file -> execute_remote_command
|
||||||
|
# -> sync_backup_to_local
|
||||||
|
# -> cleanup_remote_backup -> execute_remote_command
|
||||||
|
|
||||||
|
# 执行主函数
|
||||||
|
if main; then
|
||||||
|
log_message "INFO" "脚本执行成功"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
log_message "ERROR" "脚本执行失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
361
0-部署应用/CloudCone-备份中心/deepseek-v3.1/b-nextcloud-dsv3.1.sh
Normal file
361
0-部署应用/CloudCone-备份中心/deepseek-v3.1/b-nextcloud-dsv3.1.sh
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# =============================================================================
|
||||||
|
# nextcloud备份脚本
|
||||||
|
# 功能:远程Nextcloud维护模式切换、数据库备份、文件同步及清理
|
||||||
|
# 版本:1.0.0
|
||||||
|
# 作者:Shell脚本工程师
|
||||||
|
# 许可证:MIT License
|
||||||
|
# 依赖:ssh, rsync, docker (远程主机), mariadb-client (远程主机)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
# > 全局常量定义
|
||||||
|
readonly SCRIPT_NAME="$(basename "$0")"
|
||||||
|
readonly SCRIPT_DIR="/root/wdd/backup"
|
||||||
|
readonly LOCK_FILE="/root/wdd/backup/${SCRIPT_NAME}.lock"
|
||||||
|
|
||||||
|
# > 远程主机配置
|
||||||
|
readonly REMOTE_HOST="s5"
|
||||||
|
readonly REMOTE_PORT="22333"
|
||||||
|
readonly REMOTE_USER="root"
|
||||||
|
readonly REMOTE_NEXTCLOUD_DIR="/data/nextcloud"
|
||||||
|
readonly REMOTE_DB_CONTAINER="nextcloud-db"
|
||||||
|
readonly REMOTE_WEB_CONTAINER="nextcloud_web"
|
||||||
|
|
||||||
|
# > 数据库配置
|
||||||
|
readonly DB_NAME="nextcloud"
|
||||||
|
readonly DB_USER="nextcloud"
|
||||||
|
readonly DB_PASSWORD="boge14@Level5"
|
||||||
|
|
||||||
|
# > 本地配置
|
||||||
|
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/nextcloud"
|
||||||
|
|
||||||
|
# > 日志配置
|
||||||
|
readonly LOG_DIR="${SCRIPT_DIR}/logs"
|
||||||
|
readonly LOG_FILE="${LOG_DIR}/nextcloud_backup_$(date +%Y%m%d).log"
|
||||||
|
|
||||||
|
# > 颜色输出定义
|
||||||
|
readonly RED='\033[0;31m'
|
||||||
|
readonly GREEN='\033[0;32m'
|
||||||
|
readonly YELLOW='\033[1;33m'
|
||||||
|
readonly BLUE='\033[0;34m'
|
||||||
|
readonly NC='\033[0m'
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 日志函数集
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
###
|
||||||
|
# 初始化日志系统
|
||||||
|
# @require 无
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
init_log_system() {
|
||||||
|
mkdir -p "${LOG_DIR}" || return 1
|
||||||
|
touch "${LOG_FILE}" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 记录日志消息
|
||||||
|
# @param level string 日志级别(DEBUG/INFO/WARN/ERROR)
|
||||||
|
# @param message string 日志消息
|
||||||
|
# @require LOG_FILE
|
||||||
|
# @return 0 成功
|
||||||
|
###
|
||||||
|
log_message() {
|
||||||
|
local level="$1"
|
||||||
|
local message="$2"
|
||||||
|
local timestamp
|
||||||
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
case "${level}" in
|
||||||
|
"DEBUG") echo -e "${BLUE}[DEBUG]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
|
||||||
|
"INFO") echo -e "${GREEN}[INFO]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
|
||||||
|
"WARN") echo -e "${YELLOW}[WARN]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
|
||||||
|
"ERROR") echo -e "${RED}[ERROR]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
|
||||||
|
*) echo "${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 工具函数集
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
###
|
||||||
|
# 检查命令是否存在
|
||||||
|
# @param command_name string 命令名称
|
||||||
|
# @require 无
|
||||||
|
# @return 0 存在 | 1 不存在
|
||||||
|
###
|
||||||
|
check_command() {
|
||||||
|
local command_name="$1"
|
||||||
|
if ! command -v "${command_name}" >/dev/null 2>&1; then
|
||||||
|
log_message "ERROR" "命令不存在: ${command_name}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 执行远程SSH命令
|
||||||
|
# @param command string 要执行的命令
|
||||||
|
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER
|
||||||
|
# @return 远程命令的退出码
|
||||||
|
###
|
||||||
|
execute_remote_command() {
|
||||||
|
local command="$1"
|
||||||
|
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "${command}"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 创建锁文件防止并发执行
|
||||||
|
# @require LOCK_FILE
|
||||||
|
# @return 0 成功获取锁 | 1 锁已存在
|
||||||
|
###
|
||||||
|
acquire_lock() {
|
||||||
|
if [ -e "${LOCK_FILE}" ]; then
|
||||||
|
log_message "ERROR" "备份任务正在运行或异常退出,请检查锁文件: ${LOCK_FILE}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "$$" > "${LOCK_FILE}"
|
||||||
|
trap 'release_lock' EXIT
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 释放锁文件
|
||||||
|
# @require LOCK_FILE
|
||||||
|
# @return 0 成功
|
||||||
|
###
|
||||||
|
release_lock() {
|
||||||
|
[ -e "${LOCK_FILE}" ] && rm -f "${LOCK_FILE}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Nextcloud核心备份函数
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
###
|
||||||
|
# 启用Nextcloud维护模式
|
||||||
|
# @require execute_remote_command, REMOTE_WEB_CONTAINER
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
enable_maintenance_mode() {
|
||||||
|
log_message "INFO" "启用Nextcloud维护模式..."
|
||||||
|
|
||||||
|
local maintenance_cmd="docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --on"
|
||||||
|
|
||||||
|
if ! execute_remote_command "${maintenance_cmd}"; then
|
||||||
|
log_message "ERROR" "启用维护模式失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "维护模式已启用"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 禁用Nextcloud维护模式
|
||||||
|
# @require execute_remote_command, REMOTE_WEB_CONTAINER
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
disable_maintenance_mode() {
|
||||||
|
log_message "INFO" "禁用Nextcloud维护模式..."
|
||||||
|
|
||||||
|
local maintenance_cmd="docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --off"
|
||||||
|
|
||||||
|
if ! execute_remote_command "${maintenance_cmd}"; then
|
||||||
|
log_message "ERROR" "禁用维护模式失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "维护模式已禁用"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 远程执行MariaDB数据库备份
|
||||||
|
# @require execute_remote_command, REMOTE_DB_CONTAINER, DB_NAME, DB_USER, DB_PASSWORD, REMOTE_NEXTCLOUD_DIR
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
backup_database() {
|
||||||
|
log_message "INFO" "开始数据库备份..."
|
||||||
|
|
||||||
|
local backup_file="${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql"
|
||||||
|
local backup_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${backup_file}"
|
||||||
|
|
||||||
|
if ! execute_remote_command "${backup_cmd}"; then
|
||||||
|
log_message "ERROR" "数据库备份失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# > 验证备份文件是否创建成功
|
||||||
|
local verify_cmd="[ -f \"${backup_file}\" ] && echo \"exists\" || echo \"missing\""
|
||||||
|
if [ "$(execute_remote_command "${verify_cmd}")" != "exists" ]; then
|
||||||
|
log_message "ERROR" "数据库备份文件创建失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "数据库备份完成: ${backup_file}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 使用rsync同步Nextcloud文件到本地
|
||||||
|
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_NEXTCLOUD_DIR, LOCAL_BACKUP_DIR
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
sync_nextcloud_files() {
|
||||||
|
log_message "INFO" "开始同步Nextcloud文件到本地..."
|
||||||
|
|
||||||
|
# > 创建本地暂存目录
|
||||||
|
mkdir -p "${LOCAL_BACKUP_DIR}" || {
|
||||||
|
log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_BACKUP_DIR}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# > 构建rsync命令
|
||||||
|
local rsync_cmd="rsync -avz --progress -e 'ssh -p ${REMOTE_PORT}'"
|
||||||
|
rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_NEXTCLOUD_DIR}/"
|
||||||
|
rsync_cmd+=" ${LOCAL_BACKUP_DIR}/"
|
||||||
|
|
||||||
|
# > 执行rsync同步
|
||||||
|
if ! eval "${rsync_cmd}"; then
|
||||||
|
log_message "ERROR" "Nextcloud文件同步失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "Nextcloud文件同步完成"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# 远程删除数据库备份文件
|
||||||
|
# @require execute_remote_command, REMOTE_NEXTCLOUD_DIR
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
remote_cleanup_backup() {
|
||||||
|
log_message "INFO" "清理远程数据库备份文件..."
|
||||||
|
|
||||||
|
local cleanup_cmd="rm -f ${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_*.sql"
|
||||||
|
|
||||||
|
if ! execute_remote_command "${cleanup_cmd}"; then
|
||||||
|
log_message "ERROR" "远程清理失败"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_message "INFO" "远程清理完成"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# 清理本地暂存目录
|
||||||
|
# @require LOCAL_BACKUP_DIR
|
||||||
|
# @return 0 成功
|
||||||
|
###
|
||||||
|
local_cleanup() {
|
||||||
|
log_message "INFO" "清理本地暂存目录..."
|
||||||
|
[ -d "${LOCAL_BACKUP_DIR}" ] && rm -rf "${LOCAL_BACKUP_DIR}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 主执行流程
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
###
|
||||||
|
# 主备份流程
|
||||||
|
# @require 所有上述函数
|
||||||
|
# @return 0 成功 | >0 失败
|
||||||
|
###
|
||||||
|
main_backup_process() {
|
||||||
|
log_message "INFO" "=== 开始Nextcloud备份任务 ==="
|
||||||
|
|
||||||
|
# > 检查依赖命令
|
||||||
|
local required_commands=("ssh" "rsync")
|
||||||
|
for cmd in "${required_commands[@]}"; do
|
||||||
|
if ! check_command "${cmd}"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# > 执行备份流程
|
||||||
|
local steps=(
|
||||||
|
enable_maintenance_mode
|
||||||
|
backup_database
|
||||||
|
sync_nextcloud_files
|
||||||
|
remote_cleanup_backup
|
||||||
|
disable_maintenance_mode
|
||||||
|
# local_cleanup
|
||||||
|
)
|
||||||
|
|
||||||
|
for step in "${steps[@]}"; do
|
||||||
|
if ! "${step}"; then
|
||||||
|
log_message "ERROR" "备份任务失败,正在尝试恢复..."
|
||||||
|
# > 尝试禁用维护模式
|
||||||
|
disable_maintenance_mode || true
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_message "INFO" "=== Nextcloud备份任务完成 ==="
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 脚本入口点
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# > 设置错误处理
|
||||||
|
trap 'log_message "ERROR" "脚本异常退出"; disable_maintenance_mode || true; release_lock; exit 1' ERR
|
||||||
|
|
||||||
|
# > 主执行块
|
||||||
|
main() {
|
||||||
|
if ! acquire_lock; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! init_log_system; then
|
||||||
|
log_message "ERROR" "日志系统初始化失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! main_backup_process; then
|
||||||
|
log_message "ERROR" "备份任务执行失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_lock
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# > 脚本执行入口
|
||||||
|
main "$@"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 函数调用关系图
|
||||||
|
# =============================================================================
|
||||||
|
# main
|
||||||
|
# ├── acquire_lock
|
||||||
|
# ├── init_log_system
|
||||||
|
# └── main_backup_process
|
||||||
|
# ├── check_command (多次调用)
|
||||||
|
# ├── enable_maintenance_mode
|
||||||
|
# │ └── execute_remote_command
|
||||||
|
# ├── backup_database
|
||||||
|
# │ └── execute_remote_command
|
||||||
|
# ├── sync_nextcloud_files
|
||||||
|
# ├── move_to_backup_dir
|
||||||
|
# ├── remote_cleanup_backup
|
||||||
|
# │ └── execute_remote_command
|
||||||
|
# ├── disable_maintenance_mode
|
||||||
|
# │ └── execute_remote_command
|
||||||
|
# └── local_cleanup
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ IFS=$'\n\t'
|
|||||||
|
|
||||||
# > 全局常量定义
|
# > 全局常量定义
|
||||||
readonly SCRIPT_NAME="$(basename "$0")"
|
readonly SCRIPT_NAME="$(basename "$0")"
|
||||||
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
readonly SCRIPT_DIR="/root/wdd/backup"
|
||||||
readonly LOCK_FILE="/tmp/${SCRIPT_NAME}.lock"
|
readonly LOCK_FILE="/root/wdd/backup/${SCRIPT_NAME}.lock"
|
||||||
|
|
||||||
# > 配置参数(可根据需要调整为环境变量)
|
# > 配置参数(可根据需要调整为环境变量)
|
||||||
readonly REMOTE_HOST="s5"
|
readonly REMOTE_HOST="s5"
|
||||||
@@ -22,20 +22,20 @@ readonly REMOTE_PORT="22333"
|
|||||||
readonly REMOTE_USER="root"
|
readonly REMOTE_USER="root"
|
||||||
readonly REMOTE_BACKUP_CMD="docker exec vault-warden /vaultwarden backup"
|
readonly REMOTE_BACKUP_CMD="docker exec vault-warden /vaultwarden backup"
|
||||||
readonly REMOTE_DATA_DIR="/data/vault-warden/persist-data"
|
readonly REMOTE_DATA_DIR="/data/vault-warden/persist-data"
|
||||||
readonly LOCAL_STAGE_DIR="/tmp/vault_warden_backup_stage"
|
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/vault_warden"
|
||||||
readonly LOCAL_BACKUP_DIR="${SCRIPT_DIR}/backups"
|
|
||||||
readonly BACKUP_PATTERNS=(
|
readonly BACKUP_PATTERNS=(
|
||||||
"config.json"
|
"config.json"
|
||||||
"rsa_key*"
|
"rsa_key*"
|
||||||
"attachments"
|
"attachments"
|
||||||
|
"icon_cache"
|
||||||
"sends"
|
"sends"
|
||||||
"db_*.sqlite3"
|
"db_*.sqlite3"
|
||||||
)
|
)
|
||||||
readonly ENCRYPTION_PASSWORD="your_encryption_password_here" # > 请在实际使用时修改
|
readonly ENCRYPTION_PASSWORD="SuperWdd.123" # > 请在实际使用时修改
|
||||||
|
|
||||||
# > 日志配置
|
# > 日志配置
|
||||||
readonly LOG_DIR="${SCRIPT_DIR}/logs"
|
readonly LOG_DIR="${SCRIPT_DIR}/logs"
|
||||||
readonly LOG_FILE="${LOG_DIR}/backup_$(date +%Y%m%d).log"
|
readonly LOG_FILE="${LOG_DIR}/vault_warden_backup_$(date +%Y%m%d).log"
|
||||||
|
|
||||||
# > 颜色输出定义
|
# > 颜色输出定义
|
||||||
readonly RED='\033[0;31m'
|
readonly RED='\033[0;31m'
|
||||||
@@ -161,15 +161,15 @@ remote_execute_backup() {
|
|||||||
|
|
||||||
###
|
###
|
||||||
# 使用rsync同步备份文件到本地
|
# 使用rsync同步备份文件到本地
|
||||||
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_DATA_DIR, LOCAL_STAGE_DIR, BACKUP_PATTERNS
|
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_DATA_DIR, LOCAL_BACKUP_DIR, BACKUP_PATTERNS
|
||||||
# @return 0 成功 | >0 失败
|
# @return 0 成功 | >0 失败
|
||||||
###
|
###
|
||||||
sync_backup_files() {
|
sync_backup_files() {
|
||||||
log_message "INFO" "开始同步备份文件到本地..."
|
log_message "INFO" "开始同步备份文件到本地..."
|
||||||
|
|
||||||
# > 创建本地暂存目录
|
# > 创建本地暂存目录
|
||||||
mkdir -p "${LOCAL_STAGE_DIR}" || {
|
mkdir -p "${LOCAL_BACKUP_DIR}" || {
|
||||||
log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_STAGE_DIR}"
|
log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_BACKUP_DIR}"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ sync_backup_files() {
|
|||||||
rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DATA_DIR}/${pattern}"
|
rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DATA_DIR}/${pattern}"
|
||||||
done
|
done
|
||||||
|
|
||||||
rsync_cmd+=" ${LOCAL_STAGE_DIR}/"
|
rsync_cmd+=" ${LOCAL_BACKUP_DIR}/"
|
||||||
|
|
||||||
# > 执行rsync同步
|
# > 执行rsync同步
|
||||||
if ! eval "${rsync_cmd}"; then
|
if ! eval "${rsync_cmd}"; then
|
||||||
@@ -194,7 +194,7 @@ sync_backup_files() {
|
|||||||
|
|
||||||
###
|
###
|
||||||
# 使用7zip加密压缩备份文件
|
# 使用7zip加密压缩备份文件
|
||||||
# @require LOCAL_STAGE_DIR, LOCAL_BACKUP_DIR, ENCRYPTION_PASSWORD
|
# @require LOCAL_BACKUP_DIR, LOCAL_BACKUP_DIR, ENCRYPTION_PASSWORD
|
||||||
# @return 0 成功 | >0 失败
|
# @return 0 成功 | >0 失败
|
||||||
###
|
###
|
||||||
encrypt_and_compress() {
|
encrypt_and_compress() {
|
||||||
@@ -215,7 +215,7 @@ encrypt_and_compress() {
|
|||||||
local backup_file="${LOCAL_BACKUP_DIR}/vaultwarden-backup-$(date +%Y%m%d-%H%M%S).7z"
|
local backup_file="${LOCAL_BACKUP_DIR}/vaultwarden-backup-$(date +%Y%m%d-%H%M%S).7z"
|
||||||
|
|
||||||
# > 执行加密压缩
|
# > 执行加密压缩
|
||||||
if ! (cd "${LOCAL_STAGE_DIR}" && 7z a -p"${ENCRYPTION_PASSWORD}" -mhe=on "${backup_file}" . >/dev/null); then
|
if ! (cd "${LOCAL_BACKUP_DIR}" && 7z a -p"${ENCRYPTION_PASSWORD}" -mhe=on "${backup_file}" . >/dev/null); then
|
||||||
log_message "ERROR" "加密压缩失败"
|
log_message "ERROR" "加密压缩失败"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -245,12 +245,12 @@ remote_cleanup_backup() {
|
|||||||
|
|
||||||
###
|
###
|
||||||
# 清理本地暂存目录
|
# 清理本地暂存目录
|
||||||
# @require LOCAL_STAGE_DIR
|
# @require LOCAL_BACKUP_DIR
|
||||||
# @return 0 成功
|
# @return 0 成功
|
||||||
###
|
###
|
||||||
local_cleanup() {
|
local_cleanup() {
|
||||||
log_message "INFO" "清理本地暂存目录..."
|
log_message "INFO" "清理本地暂存目录..."
|
||||||
[ -d "${LOCAL_STAGE_DIR}" ] && rm -rf "${LOCAL_STAGE_DIR}"
|
[ -d "${LOCAL_BACKUP_DIR}" ] && rm -rf "${LOCAL_BACKUP_DIR}"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ main_backup_process() {
|
|||||||
sync_backup_files
|
sync_backup_files
|
||||||
encrypt_and_compress
|
encrypt_and_compress
|
||||||
remote_cleanup_backup
|
remote_cleanup_backup
|
||||||
local_cleanup
|
# local_cleanup
|
||||||
)
|
)
|
||||||
|
|
||||||
for step in "${steps[@]}"; do
|
for step in "${steps[@]}"; do
|
||||||
90
0-部署应用/CloudCone-备份中心/gitea-backup.sh
Normal file
90
0-部署应用/CloudCone-备份中心/gitea-backup.sh
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# Meta : Gitea 备份执行脚本
|
||||||
|
# Version : 2.0.0
|
||||||
|
# Author : Bash Shell Senior Development Engineer
|
||||||
|
# License : MIT
|
||||||
|
# Description : 自动化执行Gitea远程备份、同步、加密、上传及清理任务。
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
source "$(dirname "$0")/common.sh" || { echo "FATAL: common.sh not found." >&2; exit 1; }
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 脚本配置区
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
readonly APP_NAME="Gitea"
|
||||||
|
readonly REMOTE_USER="root"
|
||||||
|
readonly REMOTE_HOST="t0"
|
||||||
|
readonly MAX_ENCRYPTED_REPLICAS=4
|
||||||
|
|
||||||
|
# > 远程配置
|
||||||
|
readonly REMOTE_CONTAINER="gitea-gitea-1"
|
||||||
|
readonly REMOTE_GITEA_CONF="/bitnami/gitea/custom/conf/app.ini"
|
||||||
|
readonly REMOTE_TMP_DIR="/opt/bitnami/gitea/data/tmp"
|
||||||
|
readonly REMOTE_RSYNC_SOURCE_DIR="/data/gitea/gitea_data/data/tmp/" # 注意末尾的斜杠
|
||||||
|
|
||||||
|
# > 本地路径
|
||||||
|
readonly LOCAL_BACKUP_DIR="/data/t0_150_230_198_103/gitea"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 主执行流程
|
||||||
|
# =============================================================================
|
||||||
|
main() {
|
||||||
|
trap 'log_message "ERROR" "${APP_NAME}的备份任务出现错误! 终止"' ERR
|
||||||
|
log_message "INFO" "====== 开始 ${APP_NAME} 备份任务 ======"
|
||||||
|
|
||||||
|
# > 步骤 1: 执行Gitea备份命令
|
||||||
|
log_message "INFO" "[Step 1/8] 远程执行${APP_NAME} 备份 DUMP..."
|
||||||
|
local dump_cmd="docker exec ${REMOTE_CONTAINER} /opt/bitnami/gitea/bin/gitea dump -c ${REMOTE_GITEA_CONF}"
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${dump_cmd}"
|
||||||
|
|
||||||
|
# > 步骤 2: 移动并重命名备份文件
|
||||||
|
log_message "INFO" "[Step 2/8] 移动并重命名备份文件..."
|
||||||
|
local new_filename="gitea-dump-$(date +%Y%m%d-%H%M%S).zip"
|
||||||
|
local move_cmd="docker exec ${REMOTE_CONTAINER} /bin/sh -c 'mv /opt/bitnami/gitea/gitea-dump-*.zip ${REMOTE_TMP_DIR}/${new_filename}'"
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${move_cmd}"
|
||||||
|
|
||||||
|
# > 步骤 3: rsync复制备份文件到本地
|
||||||
|
log_message "INFO" "[Step 3/8] rsync复制备份文件到本地..."
|
||||||
|
mkdir -p "${LOCAL_BACKUP_DIR}"
|
||||||
|
rsync -avz --progress -e "ssh -p ${REMOTE_SSH_PORT}" \
|
||||||
|
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_RSYNC_SOURCE_DIR}${new_filename}" \
|
||||||
|
"${LOCAL_BACKUP_DIR}/"
|
||||||
|
|
||||||
|
# > 步骤 4: 远程清理备份文件
|
||||||
|
log_message "INFO" "[Step 4/8] Cleaning up remote dump file..."
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "rm -f ${REMOTE_RSYNC_SOURCE_DIR}gitea-dump-*.zip"
|
||||||
|
|
||||||
|
# > 步骤 5: 7zip加密
|
||||||
|
local archive_file="${SCRIPT_RUN_DIR}/${APP_NAME}-backup-$(date +%Y%m%d-%H%M%S).7z"
|
||||||
|
log_message "INFO" "[Step 5/8] 开始加密本地备份目录..."
|
||||||
|
encrypt_with_7zip "${LOCAL_BACKUP_DIR}" "${archive_file}"
|
||||||
|
|
||||||
|
# > 步骤 6: rclone上传
|
||||||
|
log_message "INFO" "[Step 6/8] 上传加密压缩包至冷存储 => ${RCLONE_REMOTE_REPO}..."
|
||||||
|
rclone_copy "${archive_file}" "${RCLONE_REMOTE_REPO}"
|
||||||
|
|
||||||
|
# > 步骤 7: 控制远程副本数
|
||||||
|
log_message "INFO" "[Step 7/8] 控制冷备份的副本数量 => ${MAX_ENCRYPTED_REPLICAS}..."
|
||||||
|
rclone_control_replicas "${RCLONE_REMOTE_REPO}" "${APP_NAME}-backup-" "${MAX_ENCRYPTED_REPLICAS}"
|
||||||
|
|
||||||
|
# > 步骤 8: 清理本地
|
||||||
|
log_message "INFO" "[Step 8/8] 清理本地压缩包..."
|
||||||
|
cleanup_local_encrypted_files "${SCRIPT_RUN_DIR}"
|
||||||
|
# rm -rf "${LOCAL_BACKUP_DIR}"
|
||||||
|
|
||||||
|
log_message "INFO" "====== ${APP_NAME} 备份任务已全部完成! ======"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 脚本入口点
|
||||||
|
# =============================================================================
|
||||||
|
# 函数调用关系图
|
||||||
|
# main
|
||||||
|
# ├─ execute_remote_command (4)
|
||||||
|
# ├─ encrypt_with_7zip
|
||||||
|
# ├─ rclone_copy
|
||||||
|
# ├─ rclone_control_replicas
|
||||||
|
# └─ cleanup_local_encrypted_files
|
||||||
|
# =============================================================================
|
||||||
|
main "$@"
|
||||||
111
0-部署应用/CloudCone-备份中心/next-cloud-backup.sh
Normal file
111
0-部署应用/CloudCone-备份中心/next-cloud-backup.sh
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# Meta : NextCloud 备份执行脚本
|
||||||
|
# Version : 2.0.0
|
||||||
|
# Author : Bash Shell Senior Development Engineer
|
||||||
|
# License : MIT
|
||||||
|
# Description : 自动化执行NextCloud维护模式切换、数据库和文件备份、加密、上传及清理。
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
source "$(dirname "$0")/common.sh" || { echo "FATAL: common.sh not found." >&2; exit 1; }
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 脚本配置区
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
readonly APP_NAME="NextCloud"
|
||||||
|
readonly REMOTE_USER="root"
|
||||||
|
readonly REMOTE_HOST="s5"
|
||||||
|
readonly MAX_ENCRYPTED_REPLICAS=3
|
||||||
|
|
||||||
|
# > 远程配置
|
||||||
|
readonly REMOTE_WEB_CONTAINER="nextcloud_web"
|
||||||
|
readonly REMOTE_DB_CONTAINER="nextcloud-db"
|
||||||
|
readonly REMOTE_DATA_DIR="/data/nextcloud"
|
||||||
|
readonly DB_USER="nextcloud"
|
||||||
|
readonly DB_PASSWORD="boge14@Level5" # 建议使用更安全的方式管理密码
|
||||||
|
readonly DB_NAME="nextcloud"
|
||||||
|
|
||||||
|
# > 本地路径
|
||||||
|
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/nextcloud"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 核心函数
|
||||||
|
# =============================================================================
|
||||||
|
###
|
||||||
|
# 功能描述段: 切换Nextcloud维护模式 (on/off)
|
||||||
|
# @param mode <string> 模式, 'on' 或 'off'
|
||||||
|
# @return <0> 成功 | >0 失败
|
||||||
|
###
|
||||||
|
toggle_maintenance_mode() {
|
||||||
|
local mode="$1"
|
||||||
|
log_message "INFO" "Setting maintenance mode to '${mode}'..."
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" \
|
||||||
|
"docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --${mode}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 主执行流程
|
||||||
|
# =============================================================================
|
||||||
|
main() {
|
||||||
|
# > 设置陷阱,确保任何情况下都能尝试关闭维护模式
|
||||||
|
trap 'log_message "ERROR" "${APP_NAME}中止的备份任务。试图禁用维护模式..."; toggle_maintenance_mode "off" || true; exit 1' ERR
|
||||||
|
|
||||||
|
log_message "INFO" "${APP_NAME}的备份任务出现错误! 终止! "
|
||||||
|
|
||||||
|
# > 步骤 1: 启用维护模式
|
||||||
|
log_message "INFO" "[Step 1/8] 启用维护模式..."
|
||||||
|
toggle_maintenance_mode "on"
|
||||||
|
|
||||||
|
# > 步骤 2: 数据库备份
|
||||||
|
log_message "INFO" "[Step 2/8] 执行远程数据库备份..."
|
||||||
|
local db_backup_file="${REMOTE_DATA_DIR}/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql"
|
||||||
|
local db_backup_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${db_backup_file}"
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${db_backup_cmd}"
|
||||||
|
|
||||||
|
# > 步骤 3: rsync复制备份文件
|
||||||
|
log_message "INFO" "[Step 3/8] Srsync复制远程备份文件..."
|
||||||
|
mkdir -p "${LOCAL_BACKUP_DIR}"
|
||||||
|
rsync -avz --progress -e "ssh -p ${REMOTE_SSH_PORT}" \
|
||||||
|
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DATA_DIR}/" \
|
||||||
|
"${LOCAL_BACKUP_DIR}/"
|
||||||
|
|
||||||
|
# > 步骤 4: 远程清理数据库备份
|
||||||
|
log_message "INFO" "[Step 4/8] 远程清理数据库备份..."
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "rm -f ${REMOTE_DATA_DIR}/nextcloud-db_backup_*.sql"
|
||||||
|
|
||||||
|
# > 步骤 5: 禁用维护模式
|
||||||
|
log_message "INFO" "[Step 5/8] 禁用维护模式..."
|
||||||
|
toggle_maintenance_mode "off"
|
||||||
|
|
||||||
|
# > 步骤 6: 7zip加密
|
||||||
|
local archive_file="${SCRIPT_RUN_DIR}/${APP_NAME}-backup-$(date +%Y%m%d-%H%M%S).7z"
|
||||||
|
log_message "INFO" "[Step 6/8] 7zip加密本地目录..."
|
||||||
|
encrypt_with_7zip "${LOCAL_BACKUP_DIR}" "${archive_file}"
|
||||||
|
|
||||||
|
# > 步骤 7: rclone上传
|
||||||
|
log_message "INFO" "[Step 7/8] 上传加密压缩包至冷存储 => ${RCLONE_REMOTE_REPO}..."
|
||||||
|
rclone_copy "${archive_file}" "${RCLONE_REMOTE_REPO}"
|
||||||
|
|
||||||
|
# > 步骤 8: 控制副本数并清理本地
|
||||||
|
log_message "INFO" "[Step 8/8] 控制冷备份的副本数量 => ${MAX_ENCRYPTED_REPLICAS}..."
|
||||||
|
rclone_control_replicas "${RCLONE_REMOTE_REPO}" "${APP_NAME}-backup-" "${MAX_ENCRYPTED_REPLICAS}"
|
||||||
|
cleanup_local_encrypted_files "${SCRIPT_RUN_DIR}"
|
||||||
|
# rm -rf "${LOCAL_BACKUP_DIR}"
|
||||||
|
|
||||||
|
log_message "INFO" "====== ${APP_NAME} 备份任务已全部完成! ======"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 脚本入口点
|
||||||
|
# =============================================================================
|
||||||
|
# 函数调用关系图
|
||||||
|
# main
|
||||||
|
# ├─ toggle_maintenance_mode (2)
|
||||||
|
# │ └─ execute_remote_command
|
||||||
|
# ├─ execute_remote_command (2)
|
||||||
|
# ├─ encrypt_with_7zip
|
||||||
|
# ├─ rclone_copy
|
||||||
|
# ├─ rclone_control_replicas
|
||||||
|
# └─ cleanup_local_encrypted_files
|
||||||
|
# =============================================================================
|
||||||
|
main "$@"
|
||||||
85
0-部署应用/CloudCone-备份中心/vault-warden-backup.sh
Normal file
85
0-部署应用/CloudCone-备份中心/vault-warden-backup.sh
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# Meta : Vault-Warden 备份执行脚本
|
||||||
|
# Version : 2.0.0
|
||||||
|
# Author : Bash Shell Senior Development Engineer
|
||||||
|
# License : MIT
|
||||||
|
# Description : 自动化执行Vaultwarden远程备份、同步、加密、上传及清理任务。
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# > 导入公共库
|
||||||
|
source "$(dirname "$0")/common.sh" || { echo "FATAL: common.sh not found." >&2; exit 1; }
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# 脚本配置区
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
readonly APP_NAME="VaultWarden"
|
||||||
|
readonly REMOTE_USER="root"
|
||||||
|
readonly REMOTE_HOST="s5"
|
||||||
|
readonly MAX_ENCRYPTED_REPLICAS=5 # 远程保留的最大加密副本数
|
||||||
|
|
||||||
|
# > 远程路径
|
||||||
|
readonly REMOTE_BACKUP_CMD="docker exec vault-warden /vaultwarden backup"
|
||||||
|
readonly REMOTE_DATA_DIR="/data/vault-warden/persist-data"
|
||||||
|
readonly REMOTE_DB_BACKUP_GLOB="${REMOTE_DATA_DIR}/db_*.sqlite3"
|
||||||
|
|
||||||
|
# > 本地路径
|
||||||
|
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/vault-warden"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 主执行流程
|
||||||
|
# =============================================================================
|
||||||
|
main() {
|
||||||
|
trap 'log_message "ERROR" "${APP_NAME}的备份任务出现错误! 终止"' ERR
|
||||||
|
log_message "INFO" "====== 开始 ${APP_NAME} 备份任务 ======"
|
||||||
|
|
||||||
|
# > 步骤 1: 远程执行官方备份命令
|
||||||
|
log_message "INFO" "[Step 1/7] 远程执行官方备份命令..."
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${REMOTE_BACKUP_CMD}"
|
||||||
|
|
||||||
|
# > 步骤 2: rsync复制备份文件到本地
|
||||||
|
log_message "INFO" "[Step 2/7] rsync复制备份文件到本地..."
|
||||||
|
mkdir -p "${LOCAL_BACKUP_DIR}"
|
||||||
|
rsync -avz --progress -e "ssh -p ${REMOTE_SSH_PORT}" \
|
||||||
|
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DATA_DIR}/" \
|
||||||
|
"${LOCAL_BACKUP_DIR}/" --include='db_*.sqlite3' --include='config.json' --include='rsa_key*' --include='attachments/***' --include='icon_cache/***' --include='sends/***' --exclude='*'
|
||||||
|
|
||||||
|
# > 步骤 3: 远程清理备份的数据库文件
|
||||||
|
log_message "INFO" "[Step 3/7] 远程清理备份的数据库文件..."
|
||||||
|
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "rm -f ${REMOTE_DB_BACKUP_GLOB}"
|
||||||
|
|
||||||
|
# > 步骤 4: 7zip加密本地目录
|
||||||
|
local archive_file="${SCRIPT_RUN_DIR}/${APP_NAME}-backup-$(date +%Y%m%d-%H%M%S).7z"
|
||||||
|
log_message "INFO" "[Step 4/7] 7zip加密本地目录..."
|
||||||
|
encrypt_with_7zip "${LOCAL_BACKUP_DIR}" "${archive_file}"
|
||||||
|
|
||||||
|
# > 步骤 5: rclone上传压缩包
|
||||||
|
log_message "INFO" "[Step 5/7] 上传加密压缩包至冷存储 => ${RCLONE_REMOTE_REPO}..."
|
||||||
|
rclone_copy "${archive_file}" "${RCLONE_REMOTE_REPO}"
|
||||||
|
|
||||||
|
# > 步骤 6: 控制远程仓库副本数
|
||||||
|
log_message "INFO" "[Step 6/7] 控制冷备份的副本数量 => ${MAX_ENCRYPTED_REPLICAS}..."
|
||||||
|
rclone_control_replicas "${RCLONE_REMOTE_REPO}" "${APP_NAME}-backup-" "${MAX_ENCRYPTED_REPLICAS}"
|
||||||
|
|
||||||
|
# > 步骤 7: 清理本地加密压缩包
|
||||||
|
log_message "INFO" "[Step 7/7] 清理本地压缩包..."
|
||||||
|
cleanup_local_encrypted_files "${SCRIPT_RUN_DIR}"
|
||||||
|
# > 清理本地临时数据
|
||||||
|
rm -rf "${LOCAL_BACKUP_DIR}/db_*.sqlite3"
|
||||||
|
|
||||||
|
|
||||||
|
log_message "INFO" "====== ${APP_NAME} 备份任务已全部完成! ======"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 脚本入口点
|
||||||
|
# =============================================================================
|
||||||
|
# 函数调用关系图
|
||||||
|
# main
|
||||||
|
# ├─ execute_remote_command (2)
|
||||||
|
# ├─ encrypt_with_7zip
|
||||||
|
# ├─ rclone_copy
|
||||||
|
# ├─ rclone_control_replicas
|
||||||
|
# └─ cleanup_local_encrypted_files
|
||||||
|
# =============================================================================
|
||||||
|
main "$@"
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# Vault-Warden备份
|
|
||||||
|
|
||||||
## 备份说明
|
|
||||||
备份频率 每天一次 通过crontab执行 每天凌晨2点执行
|
|
||||||
备份副本数 最近3份
|
|
||||||
官方备份说明 https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault
|
|
||||||
|
|
||||||
## 备份过程
|
|
||||||
1. 远程执行s5:执行vault-warden官方备份命令
|
|
||||||
2. rsync复制s5主机上,特定的备份文件到本地主机备份目录/data/s5_146-56-159-175/vault-warden/
|
|
||||||
3. 远程执行s5:删除掉备份的数据库文件
|
|
||||||
|
|
||||||
|
|
||||||
# NextCloud备份
|
|
||||||
## 备份说明
|
|
||||||
备份频率 每周一次 通过crontab执行 每周日凌晨2点执行
|
|
||||||
备份副本数 最近1份
|
|
||||||
官方备份说明 https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html
|
|
||||||
|
|
||||||
## 备份过程
|
|
||||||
1. 远程执行s5:启用维护模式 docker exec nextcloud_web php occ maintenance:mode --on
|
|
||||||
2. 远程执行s5:数据库备份 (MariaDB) docker exec nextcloud-db mariadb-dump --single-transaction -h localhost -u nextcloud -p'boge14@Level5' nextcloud > /data/nextcloud/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql
|
|
||||||
3. rsync复制s5主机上下面的备份文件,到本地主机目录/data/s5_146-56-159-175/nextcloud/
|
|
||||||
1. /data/nextcloud/*
|
|
||||||
4. 远程执行s5: 删除掉下面的文件
|
|
||||||
1. /data/nextcloud/nextcloud-db_backup_*.sql
|
|
||||||
5. 远程执行s5: 禁用维护模式 docker exec nextcloud_web php occ maintenance:mode --off
|
|
||||||
|
|
||||||
|
|
||||||
# Gitea备份
|
|
||||||
## 备份说明
|
|
||||||
备份频率 每周三 周六凌晨2点执行
|
|
||||||
备份副本数 最近3份
|
|
||||||
官方备份说明 https://docs.gitea.com/zh-tw/administration/backup-and-restore
|
|
||||||
|
|
||||||
## 备份过程
|
|
||||||
1. 远程执行t0: 执行gitea备份命令 docker exec -it --tempdir=/bitnami/gitea/tmp gitea-gitea-1 /opt/bitnami/gitea/bin/gitea dump -c /bitnami/gitea/custom/conf/app.ini
|
|
||||||
108
0-部署应用/CloudCone-备份中心/设计稿/备份说明.md
Normal file
108
0-部署应用/CloudCone-备份中心/设计稿/备份说明.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
|
||||||
|
# 异地冷备份
|
||||||
|
## Rclone的方式
|
||||||
|
- 备份到GoogleDrive里面
|
||||||
|
|
||||||
|
|
||||||
|
抽取三个脚本中复用的函数及变量到公共的sh文件中
|
||||||
|
- 已知公共变量
|
||||||
|
1. 脚本运行目录为 /root/wdd/backup
|
||||||
|
2. 脚本运行日志目录为 /root/wdd/backup/logs
|
||||||
|
3. 远程主机的ssh端口均为22333
|
||||||
|
4. 默认日志级别
|
||||||
|
5. 7zip加密密码
|
||||||
|
6. rclone远程仓库地址
|
||||||
|
- 已知公共函数
|
||||||
|
1. 日志函数
|
||||||
|
1. 不同日志级别
|
||||||
|
2. INFO以上级别日志需要打印至文件中
|
||||||
|
2. 远程执行函数
|
||||||
|
1. 在远程主机执行命令
|
||||||
|
2. ssh端口缺省值为22
|
||||||
|
3. 7zip加密函数-将特定的备份目录,全部加密压缩为压缩包
|
||||||
|
4. rclone复制函数
|
||||||
|
1. 将本地的加密压缩包,上传到远端 rclone copy xxx.7z gd-zeaslity:CloneCone-BackUp
|
||||||
|
5. rclone远程仓库副本数控制函数
|
||||||
|
1. rclone检测google drive种压缩包的数量,根据xxx_max_encrpted_replicas进行限制,控制最大压缩包数量,按照时间排序删除最早的压缩包
|
||||||
|
6. 本地加密压缩包清理函数
|
||||||
|
1. 删除特定目录下的 ***.7z压缩包
|
||||||
|
|
||||||
|
# Vault-Warden备份
|
||||||
|
|
||||||
|
## 备份说明
|
||||||
|
备份频率 每天一次 通过crontab执行 每天凌晨2点执行
|
||||||
|
备份副本数 最近3份
|
||||||
|
官方备份说明 https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault
|
||||||
|
|
||||||
|
## 备份过程
|
||||||
|
1. 远程执行s5:执行vault-warden官方备份命令
|
||||||
|
2. rsync复制s5主机上,特定的备份文件到本地主机备份目录/data/s5_146-56-159-175/vault-warden/
|
||||||
|
3. 远程执行s5:删除掉备份的数据库文件
|
||||||
|
4. 7zip加密函数 压缩本地目录
|
||||||
|
5. rclone复制函数 上传压缩包
|
||||||
|
6. rclone远程仓库副本数控制函数 根据vault-warden_max_encrpted_replicas控制远程的副本数量
|
||||||
|
7. 本地加密压缩包清理函数
|
||||||
|
|
||||||
|
# NextCloud备份
|
||||||
|
## 备份说明
|
||||||
|
备份频率 每周一次 通过crontab执行 每周日凌晨2点执行
|
||||||
|
备份副本数 最近1份
|
||||||
|
官方备份说明 https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html
|
||||||
|
|
||||||
|
## 备份过程
|
||||||
|
1. 远程执行s5:启用维护模式 docker exec nextcloud_web php occ maintenance:mode --on
|
||||||
|
2. 远程执行s5:数据库备份 (MariaDB) docker exec nextcloud-db mariadb-dump --single-transaction -h localhost -u nextcloud -p'boge14@Level5' nextcloud > /data/nextcloud/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql
|
||||||
|
3. rsync复制s5主机上下面的备份文件,到本地主机目录/data/s5_146-56-159-175/nextcloud/
|
||||||
|
1. /data/nextcloud/*
|
||||||
|
4. 远程执行s5: 删除掉下面的文件
|
||||||
|
1. /data/nextcloud/nextcloud-db_backup_*.sql
|
||||||
|
5. 远程执行s5: 禁用维护模式 docker exec nextcloud_web php occ maintenance:mode --off
|
||||||
|
6. 7zip加密函数 压缩本地目录
|
||||||
|
7. rclone复制函数 上传压缩包
|
||||||
|
8. rclone远程仓库副本数控制函数 根据nextcloud_max_encrpted_replicas控制远程的副本数量
|
||||||
|
9. 本地加密压缩包清理函数
|
||||||
|
|
||||||
|
|
||||||
|
# Gitea备份
|
||||||
|
## 备份说明
|
||||||
|
备份频率 每周三 周六凌晨2点执行 /root/wdd/backup/gitea-backup.sh
|
||||||
|
备份副本数 最近3份
|
||||||
|
官方备份说明 https://docs.gitea.com/zh-tw/administration/backup-and-restore
|
||||||
|
|
||||||
|
## 备份过程
|
||||||
|
1. 远程执行t0: 执行gitea备份命令 docker exec -it gitea-gitea-1 /opt/bitnami/gitea/bin/gitea dump -c /bitnami/gitea/custom/conf/app.ini
|
||||||
|
2. 远程执行t0: 执行 docker exec -it gitea-gitea-1 /bin/sh -c "mv /opt/bitnami/gitea/gitea-dump-*.zip /opt/bitnami/gitea/data/tmp/gitea-dump-$(date +%Y%m%d-%H%M%S).zip"
|
||||||
|
3. rsync复制t0主机上的 /data/gitea/gitea_data/data/tmp/gitea-dump-*.zip ,到本地主机目录/data/t0_150_230_198_103/gitea/
|
||||||
|
4. 远程执行t0: 清除本地备份 rm /data/gitea/gitea_data/data/tmp/gitea-dump-*.zip
|
||||||
|
5. 7zip加密函数 压缩本地目录
|
||||||
|
6. rclone复制函数 上传压缩包
|
||||||
|
7. rclone远程仓库副本数控制函数 根据gitea_max_encrpted_replicas控制远程的副本数量
|
||||||
|
8. 本地加密压缩包清理函数
|
||||||
|
|
||||||
|
请在ubnutu环境下使用定时任务,按照定时频率执行如下的任务
|
||||||
|
每周三 周六凌晨2点执行 /root/wdd/backup/gitea-backup.sh
|
||||||
|
每周日凌晨2点执行 /root/wdd/backup/nextcloud-backup.sh
|
||||||
|
每天凌晨2点执行 /root/wdd/backup/vault-warden-backup.sh
|
||||||
|
要求脚本的执行目录为 /root/wdd/backup
|
||||||
|
请给出crontab的命令 请给出查看定时任务执行日志的命令
|
||||||
|
|
||||||
|
|
||||||
|
# 添加以下内容:
|
||||||
|
# Gitea备份 - 每周三、周六凌晨2点
|
||||||
|
0 2 * * 3,6 cd /root/wdd/backup && /root/wdd/backup/gitea-backup.sh
|
||||||
|
# Nextcloud备份 - 每周日凌晨2点
|
||||||
|
0 2 * * 0 cd /root/wdd/backup && /root/wdd/backup/nextcloud-backup.sh
|
||||||
|
# Vaultwarden备份 - 每天凌晨2点
|
||||||
|
0 2 * * * cd /root/wdd/backup && /root/wdd/backup/vault-warden-backup.sh
|
||||||
|
|
||||||
|
|
||||||
|
查看cron服务的系统日志(推荐方式)
|
||||||
|
sudo grep CRON /var/log/syslog
|
||||||
|
# 或者使用journalctl查看系统日志
|
||||||
|
sudo journalctl -u cron.service --since today
|
||||||
|
# 查看特定备份脚本的执行日志(需要脚本内有日志输出)
|
||||||
|
sudo tail -f /var/log/syslog | grep -E "(gitea-backup|nextcloud-backup|vault-warden-backup)"
|
||||||
|
# 查看最近24小时的cron执行记录
|
||||||
|
sudo grep CRON /var/log/syslog | grep "$(date +'%b %e')"
|
||||||
|
# 查看特定日期的执行记录(例如查看10月15日的记录)
|
||||||
|
sudo grep CRON /var/log/syslog | grep "Oct 15"
|
||||||
@@ -19,11 +19,11 @@ services:
|
|||||||
- GITEA_DATABASE_USERNAME=bn_gitea
|
- GITEA_DATABASE_USERNAME=bn_gitea
|
||||||
- GITEA_DATABASE_PASSWORD=Superwdd.12
|
- GITEA_DATABASE_PASSWORD=Superwdd.12
|
||||||
- GITEA_ADMIN_USER=zeaslity
|
- GITEA_ADMIN_USER=zeaslity
|
||||||
- GITEA_ADMIN_PASSWORD=lovemm.23
|
- GITEA_ADMIN_PASSWORD=loveff.cxc.23
|
||||||
- GITEA_ADMIN_EMAIL=wdd@107421.xyz
|
- GITEA_ADMIN_EMAIL=wdd@107421.xyz
|
||||||
- GITEA_HTTP_PORT=3000
|
- GITEA_HTTP_PORT=3000
|
||||||
# - GITEA_DOMAIN=gitea.107421.xyz
|
# - GITEA_DOMAIN=gitea.107421.xyz
|
||||||
# - GITEA_ROOT_URL=gitea.107421.xyz
|
- GITEA_ROOT_URL=https://gitea.107421.xyz
|
||||||
- GITEA_SSH_LISTEN_PORT=22222
|
- GITEA_SSH_LISTEN_PORT=22222
|
||||||
- ARCHIVE_CLEANUP_ENABLED = true
|
- ARCHIVE_CLEANUP_ENABLED = true
|
||||||
- ARCHIVE_CLEANUP_TIMEOUT = 168h #设置归档文件过期时间(默认7天)
|
- ARCHIVE_CLEANUP_TIMEOUT = 168h #设置归档文件过期时间(默认7天)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ sudo sysctl -p /etc/sysctl.d/proxy-wdd.conf
|
|||||||
|
|
||||||
sysctl net.ipv4.tcp_congestion_control
|
sysctl net.ipv4.tcp_congestion_control
|
||||||
|
|
||||||
sudo ethtool -K enp3s0 gro on
|
sudo ethtool -K ens3 gro on
|
||||||
sudo ethtool -K enp3s0 gso on
|
sudo ethtool -K ens3 gso on
|
||||||
sudo ethtool -K enp3s0 tso on
|
sudo ethtool -K ens3 tso on
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ dns: # 启用 DNS 服务器
|
|||||||
# Fake-IP 例外名单,对于这些域名,Clash 将返回其真实的 IP 地址
|
# Fake-IP 例外名单,对于这些域名,Clash 将返回其真实的 IP 地址
|
||||||
# 这对于一些无法处理 Fake-IP 的内网服务或特定应用至关重要
|
# 这对于一些无法处理 Fake-IP 的内网服务或特定应用至关重要
|
||||||
fake-ip-filter:
|
fake-ip-filter:
|
||||||
|
- localhost
|
||||||
- '*.lan'
|
- '*.lan'
|
||||||
- '*.local'
|
- '*.local'
|
||||||
- '*.arpa'
|
- '*.arpa'
|
||||||
@@ -69,7 +70,6 @@ dns: # 启用 DNS 服务器
|
|||||||
- 119.29.29.29
|
- 119.29.29.29
|
||||||
# [优化] 主 DNS 服务器列表 (国内,加密 DoH)
|
# [优化] 主 DNS 服务器列表 (国内,加密 DoH)
|
||||||
# 会与 Fallback DNS 并发请求,如果返回的 IP 是国内 IP,则立即采用,速度快
|
# 会与 Fallback DNS 并发请求,如果返回的 IP 是国内 IP,则立即采用,速度快
|
||||||
# 使用加密 DNS 替代传统 UDP DNS,增强解析的稳定性和抗干扰性。
|
|
||||||
nameserver:
|
nameserver:
|
||||||
- 223.5.5.5 # 阿里云
|
- 223.5.5.5 # 阿里云
|
||||||
- 180.76.76.76 # 百度DNS
|
- 180.76.76.76 # 百度DNS
|
||||||
@@ -85,6 +85,8 @@ dns: # 启用 DNS 服务器
|
|||||||
- https://dns.quad9.net/dns-query # IBM quad9
|
- https://dns.quad9.net/dns-query # IBM quad9
|
||||||
- https://dns.opendns.com/dns-query # CISCO OpenDNS
|
- https://dns.opendns.com/dns-query # CISCO OpenDNS
|
||||||
- https://dns.adguard-dns.com/dns-query # AdGuard DNS
|
- https://dns.adguard-dns.com/dns-query # AdGuard DNS
|
||||||
|
- tls://8.8.8.8:853 # Google DoT (纯IP)
|
||||||
|
- tls://1.1.1.1:853 # Cloudflare DoT (纯IP)
|
||||||
- tls://8.8.4.4:853 # Google DNS (DoT)
|
- tls://8.8.4.4:853 # Google DNS (DoT)
|
||||||
# Fallback DNS 例外名单,匹配此列表的域名将只使用主 DNS 解析
|
# Fallback DNS 例外名单,匹配此列表的域名将只使用主 DNS 解析
|
||||||
fallback-filter:
|
fallback-filter:
|
||||||
@@ -120,12 +122,13 @@ dns: # 启用 DNS 服务器
|
|||||||
prefer-h3: false
|
prefer-h3: false
|
||||||
# DNS也遵循规则进行解析
|
# DNS也遵循规则进行解析
|
||||||
respect-rules: false
|
respect-rules: false
|
||||||
# 代理的DNS解析地址
|
# [关键] 代理节点域名解析,必须用纯IP的国内DNS
|
||||||
proxy-server-nameserver:
|
proxy-server-nameserver:
|
||||||
- 'https://dns.google/dns-query'
|
- 223.5.5.5
|
||||||
- 'https://1.1.1.1/dns-query'
|
- 119.29.29.29
|
||||||
# 直连模式下的DNS服务器
|
# 直连模式下的DNS服务器
|
||||||
direct-nameserver:
|
direct-nameserver:
|
||||||
|
- 192.168.78.39
|
||||||
- 119.29.29.29 # 腾讯 DNSPod
|
- 119.29.29.29 # 腾讯 DNSPod
|
||||||
- 114.114.114.114 # 114 DNS
|
- 114.114.114.114 # 114 DNS
|
||||||
- 223.5.5.5 # 阿里 DNS
|
- 223.5.5.5 # 阿里 DNS
|
||||||
@@ -167,274 +170,6 @@ external-controller-cors: { }
|
|||||||
|
|
||||||
proxies:
|
proxies:
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: TC-HongKong
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24443
|
|
||||||
uuid: f8702759-f402-4e85-92a6-8540d577de22
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: BFC-LosAngles
|
|
||||||
server: 154.40.34.106
|
|
||||||
port: 443
|
|
||||||
uuid: 302fbcb8-e096-46a1-906f-e879ec5ab0c5
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: xx.l4.ca.bg.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: CF-HongKong-R-TCHK
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24453
|
|
||||||
uuid: 93be1d17-8e02-449d-bb99-683ed46fbe50
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-HongKong
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24452
|
|
||||||
uuid: cdf0b19a-9524-48d5-b697-5f10bb567734
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Care-DEU-Dusseldorf-R-TCHK
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24451
|
|
||||||
uuid: 9fa9b4e7-d76d-4890-92cf-ce9251a76f59
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Care-DEU-Dusseldorf
|
|
||||||
server: 45.134.50.233
|
|
||||||
port: 443
|
|
||||||
uuid: b1417d92-998d-410b-a5f3-cf144b6f043e
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: bingo.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-KOR-Seoul
|
|
||||||
server: 140.238.14.103
|
|
||||||
port: 443
|
|
||||||
uuid: 1089cc14-557e-47ac-ac85-c07957b3cce3
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: xx.s4.cc.hh.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-DEU-Frankfurt
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24444
|
|
||||||
uuid: 6055eac4-dee7-463b-b575-d30ea94bb768
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-KOR-Seoul
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24445
|
|
||||||
uuid: 1cd284b2-d3d8-4165-b773-893f836c2b51
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-JPN-Tokyo
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24446
|
|
||||||
uuid: bf0e9c35-84a9-460e-b5bf-2fa9f2fb3bca
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-GBR-London
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24447
|
|
||||||
uuid: adc19390-373d-4dfc-b0f6-19fab1b6fbf6
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-SGP
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24448
|
|
||||||
uuid: e31bc28e-8ebd-4d72-a98e-9227f26dfac3
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-KOR-Seoul-R-TCHK
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24449
|
|
||||||
uuid: 7e27da0c-3013-4ed4-817b-50cc76a0bf81
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-JPN-Tokyo-R-TCHK
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 25000
|
|
||||||
uuid: c751811a-404f-4a05-bc41-5d572e741398
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-USA-Phoenix-R-TCHK
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 25001
|
|
||||||
uuid: fce2a9c6-1380-4ffa-ba84-6b9ec9ee2eea
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: FV-USA-LosAngles
|
|
||||||
server: 43.154.83.213
|
|
||||||
port: 24450
|
|
||||||
uuid: 56fb312c-bdb0-48ca-bf66-4a2dd34040c6
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: book.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
|
|
||||||
- name: CF_VIDEO_1
|
|
||||||
type: vless
|
|
||||||
server: bingo.pp.icederce.ip-ddns.com
|
|
||||||
port: 8443
|
|
||||||
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
|
|
||||||
udp: false
|
|
||||||
tls: true
|
|
||||||
network: ws
|
|
||||||
servername: pp.icederce.ip-ddns.com
|
|
||||||
ws-opts:
|
|
||||||
path: "/?ed=2560"
|
|
||||||
headers:
|
|
||||||
Host: pp.icederce.ip-ddns.com
|
|
||||||
|
|
||||||
- name: CF_VIDEO_2
|
|
||||||
type: vless
|
|
||||||
server: bingo.icederce.ip-ddns.com
|
|
||||||
port: 8443
|
|
||||||
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
|
|
||||||
udp: false
|
|
||||||
tls: true
|
|
||||||
network: ws
|
|
||||||
servername: pp.icederce.ip-ddns.com
|
|
||||||
ws-opts:
|
|
||||||
path: "/?ed=2560"
|
|
||||||
headers:
|
|
||||||
Host: pp.icederce.ip-ddns.com
|
|
||||||
|
|
||||||
- type: socks5
|
|
||||||
name: TC-CHN-Shanghai
|
|
||||||
server: 42.192.52.227
|
|
||||||
port: 22887
|
|
||||||
username: zeaslity
|
|
||||||
password: a1f090ea-e39c-49e7-a3be-9af26b6ce563
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-JPN-Tokyo-R-OSel
|
|
||||||
server: 140.238.14.103
|
|
||||||
port: 20443
|
|
||||||
uuid: 21dab95b-088e-47bd-8351-609fd23cb33c
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: xx.t2.ll.c0.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-JPN-Osaka-R-OSel
|
|
||||||
server: 140.238.14.103
|
|
||||||
port: 21443
|
|
||||||
uuid: 4c2dd763-56e5-408f-bc8f-dbf4c1fe41f9
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: xx.o1.vl.s4.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- type: vless
|
|
||||||
name: Oracle-USA-Phoneix-R-OSel
|
|
||||||
server: 140.238.14.103
|
|
||||||
port: 22443
|
|
||||||
uuid: de576486-e254-4d9d-949a-37088358ec23
|
|
||||||
skip-cert-verify: false
|
|
||||||
network: tcp
|
|
||||||
flow: xtls-rprx-vision
|
|
||||||
servername: xx.p2.vl.s4.107421.xyz
|
|
||||||
tls: true
|
|
||||||
udp: true
|
|
||||||
|
|
||||||
- { "type": "socks5","name": "onetools-35-71","server": "192.168.35.71","port": 22888,"username": "zeaslity","password": "password","udp": true }
|
|
||||||
|
|
||||||
proxy-groups:
|
proxy-groups:
|
||||||
- name: 🚀 节点选择
|
- name: 🚀 节点选择
|
||||||
type: select
|
type: select
|
||||||
@@ -627,14 +362,18 @@ rules: # 1. 广告、追踪器拦截规则 (最高优先级)
|
|||||||
# 直接拒绝连接,提升网页加载速度和隐私保护
|
# 直接拒绝连接,提升网页加载速度和隐私保护
|
||||||
- RULE-SET,reject,REJECT
|
- RULE-SET,reject,REJECT
|
||||||
|
|
||||||
|
# [新增] DNS服务器IP直连,防止DNS请求走代理
|
||||||
|
- IP-CIDR,8.8.8.8/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,8.8.4.4/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,1.1.1.1/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,1.0.0.1/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,223.5.5.5/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,119.29.29.29/32,DIRECT,no-resolve
|
||||||
|
|
||||||
# [优化] 核心国内流量直连规则 (IP 维度)
|
# [优化] 核心国内流量直连规则 (IP 维度)
|
||||||
# 将中国大陆的 IP 地址段置于高优先级。这是解决国内网站访问缓慢和超时的关键。
|
# 将中国大陆的 IP 地址段置于高优先级。这是解决国内网站访问缓慢和超时的关键。
|
||||||
# 任何目标地址在此列表内的连接都会被立即直连,无需进行 DNS 查询和 GEOIP 判断。
|
# 任何目标地址在此列表内的连接都会被立即直连,无需进行 DNS 查询和 GEOIP 判断。
|
||||||
- RULE-SET,cncidr,DIRECT
|
- RULE-SET,cncidr,DIRECT
|
||||||
- # 5. 基于地理位置的补充规则
|
|
||||||
- # 所有目标 IP 位于中国大陆的流量都直连
|
|
||||||
- # 这条规则作为对域名规则的补充,确保国内 IP 流量的直连
|
|
||||||
- GEOIP,CN,DIRECT
|
|
||||||
|
|
||||||
# 工作代理模式
|
# 工作代理模式
|
||||||
- DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连
|
- DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连
|
||||||
@@ -661,6 +400,11 @@ rules: # 1. 广告、追踪器拦截规则 (最高优先级)
|
|||||||
- RULE-SET,telegramcidr,📲 电报信息
|
- RULE-SET,telegramcidr,📲 电报信息
|
||||||
- RULE-SET,proxy,🌍 国外媒体
|
- RULE-SET,proxy,🌍 国外媒体
|
||||||
|
|
||||||
|
- # 5. 基于地理位置的补充规则
|
||||||
|
- # 所有目标 IP 位于中国大陆的流量都直连
|
||||||
|
- # 这条规则作为对域名规则的补充,确保国内 IP 流量的直连
|
||||||
|
- GEOIP,CN,DIREC
|
||||||
|
|
||||||
# 6. 最终的兜底规则 (最低优先级)
|
# 6. 最终的兜底规则 (最低优先级)
|
||||||
# 所有未匹配到以上任何规则的流量,都走代理
|
# 所有未匹配到以上任何规则的流量,都走代理
|
||||||
# 这是确保未知的新网站或国外服务能正常访问的关键
|
# 这是确保未知的新网站或国外服务能正常访问的关键
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
[TCP] dial 🎯 全球直连 (match RuleSet/direct) 127.0.0.1:56064 --> static.zhihu.com:443 error: dns resolve failed: context deadline exceeded
|
[TCP] dial 🎯 全球直连 (match RuleSet/direct) 127.0.0.1:56064 --> static.zhihu.com:443 error: dns resolve failed: context deadline exceeded
|
||||||
访问网址非常卡顿,请给出解决方案.考虑自建DNS服务器是否能够解决问题
|
访问网址非常卡顿,请给出解决方案.考虑自建DNS服务器是否能够解决问题
|
||||||
|
|
||||||
|
请查阅clash的配置规格,修改上述的配置文件,要求对配置进行详细的中文注释说明。
|
||||||
|
|
||||||
|
请帮我分析上述的配置文件,开启TUN模式,开启DNS之后
|
||||||
|
日志出现大量的[UDP] dial 🐟 漏网之鱼 (match Match/) mihomo --> 1.1.1.1:53 error: new vless client error: context canceled错误
|
||||||
|
请分析出现的原因,给出解决办法
|
||||||
|
|
||||||
|
|||||||
31
1-代理Xray/10-clash规则/代理优化prompt.md
Normal file
31
1-代理Xray/10-clash规则/代理优化prompt.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
你是一名精通LINUX服务器内核及网络参数调优的顶级专家,熟练掌握Xray,V2ray,Trojan等各种前沿的代理软件,代理协议
|
||||||
|
|
||||||
|
我现在中国境内,需要避开GFW阻拦访问全球互联网,现在有两台主机
|
||||||
|
1. 主机A位于香港
|
||||||
|
1. 可能存在审查等
|
||||||
|
2. 带宽为30Mbps
|
||||||
|
3. 直接访问其的网络质量良好
|
||||||
|
2. 主机B位于日本
|
||||||
|
1. 不存在审查等风险
|
||||||
|
2. 带宽为50Mbps
|
||||||
|
3. 直接访问网络限度堪忧,丢包率很严重
|
||||||
|
4. 从主机A访问主机B的网络质量目测还行
|
||||||
|
|
||||||
|
请实现如下的内容
|
||||||
|
1. 我直接访问主机A采用vless协议,请分析vless协议是否实现速度和安全性的平衡。国内-主机A-主机B如何实现安全且高效的链式代理,请寻找合适的代理协议
|
||||||
|
|
||||||
|
2.请实现脚本,判定主机A到主机B之间往返之间的网络质量,连接速度,丢包率等,需要在每天的不同时段执行,然后输出一份综合性的报告。使用go或者shell实现,自行寻找最合适的语言
|
||||||
|
|
||||||
|
3.请给出内核及网络优化参数,使得主机A和主机B能够满足极致的转发性能,减少代理的性能及时延损耗
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
你是一名优秀的go编程大师,使用go语言实现一个主机A到主机B之间网络质量检测程序
|
||||||
|
1 真实代理延迟,模拟真实TCP请求,从主机A到主机B,然后数据从主机B返回主机A的真实时延或者丢包情况
|
||||||
|
2 测试主机A到主机B的延迟,测试主机B到主机A的延迟
|
||||||
|
3 测试主机A到主机B的丢包情况,测试主机B到主机A的丢包情况,需要测试TCP及UDP丢包
|
||||||
|
4 [不强制]-针对上述延迟测试, 实现形式为类似tracerooute样式的路由追踪
|
||||||
|
5 需要定时执行,测试不同时间周期的网络质量,需要形成一份测试报告
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
42
1-代理Xray/3-BitsFLowCloud-洛杉矶/防火墙-清除.sh
Normal file
42
1-代理Xray/3-BitsFLowCloud-洛杉矶/防火墙-清除.sh
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# UFW 防火墙规则清除脚本
|
||||||
|
# 适用于 Ubuntu 22.04
|
||||||
|
|
||||||
|
# 检查是否以root权限运行
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "请使用 sudo 运行此脚本"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "开始清除 UFW 防火墙规则"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
# 1. 禁用UFW
|
||||||
|
echo ">>> 禁用 UFW 防火墙"
|
||||||
|
ufw disable
|
||||||
|
echo "执行: ufw disable"
|
||||||
|
|
||||||
|
# 2. 重置UFW到出厂默认状态(删除所有规则)
|
||||||
|
echo ">>> 重置 UFW 到出厂默认状态"
|
||||||
|
echo "y" | ufw reset
|
||||||
|
echo "执行: ufw reset"
|
||||||
|
|
||||||
|
# 3. 恢复默认策略
|
||||||
|
echo ">>> 恢复默认策略"
|
||||||
|
ufw default deny incoming
|
||||||
|
echo "执行: ufw default deny incoming"
|
||||||
|
|
||||||
|
ufw default allow outgoing
|
||||||
|
echo "执行: ufw default allow outgoing"
|
||||||
|
|
||||||
|
# 4. 显示当前状态
|
||||||
|
echo "========================================="
|
||||||
|
echo "UFW 防火墙规则已全部清除"
|
||||||
|
echo "当前状态:"
|
||||||
|
echo "========================================="
|
||||||
|
ufw status verbose
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "清除完成!UFW 已禁用,所有自定义规则已删除"
|
||||||
|
echo "如需重新启用,请运行: sudo ufw enable"
|
||||||
@@ -1,105 +1,90 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
|
||||||
# UFW 防火墙配置脚本
|
# UFW 防火墙配置脚本
|
||||||
# 适用于 Ubuntu 22.04 LTS
|
# 适用于 Ubuntu 22.04
|
||||||
#
|
|
||||||
|
|
||||||
# --- 脚本开始 ---
|
# 检查是否以root权限运行
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "请使用 sudo 运行此脚本"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo "开始配置 UFW 防火墙规则"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
# 1. 禁用UFW(确保配置过程中不会被锁定)
|
||||||
|
echo ">>> 临时禁用 UFW"
|
||||||
|
ufw disable
|
||||||
|
|
||||||
|
# 2. 重置UFW到默认状态(清除所有现有规则)
|
||||||
|
echo ">>> 重置 UFW 到默认状态"
|
||||||
|
echo "y" | ufw reset
|
||||||
|
|
||||||
|
# 3. 设置默认策略:允许所有出站流量,拒绝所有入站流量
|
||||||
|
echo ">>> 设置默认策略:允许出站,拒绝入站"
|
||||||
|
ufw default allow outgoing
|
||||||
|
echo "执行: ufw default allow outgoing"
|
||||||
|
|
||||||
|
ufw default deny incoming
|
||||||
|
echo "执行: ufw default deny incoming"
|
||||||
|
|
||||||
|
# 4. 允许白名单IP的所有流量(入站方向)
|
||||||
|
echo ">>> 添加白名单 IP 规则(允许所有端口和协议)"
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 42.192.52.227/32"
|
||||||
|
ufw allow from 42.192.52.227/32
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 43.154.83.213/32"
|
||||||
|
ufw allow from 43.154.83.213/32
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 144.24.164.121/32"
|
||||||
|
ufw allow from 144.24.164.121/32
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 132.145.87.10/32"
|
||||||
|
ufw allow from 132.145.87.10/32
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 140.238.0.0/16"
|
||||||
|
ufw allow from 140.238.0.0/16
|
||||||
|
|
||||||
|
# 5. 允许公网访问指定端口(TCP 和 UDP)
|
||||||
|
echo ">>> 开放公网端口(0.0.0.0/0)"
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 443 proto tcp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 443 proto tcp
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 443 proto udp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 443 proto udp
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 22333 proto tcp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 22333 proto tcp
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 22333 proto udp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 22333 proto udp
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 25000:26000 proto tcp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 25000:26000 proto tcp
|
||||||
|
|
||||||
|
echo "执行: ufw allow from 0.0.0.0/0 to any port 25000:26000 proto udp"
|
||||||
|
ufw allow from 0.0.0.0/0 to any port 25000:26000 proto udp
|
||||||
|
|
||||||
|
# 6. 禁止非白名单IP的ICMP请求(ping)
|
||||||
|
echo ">>> 配置 ICMP 规则(仅允许白名单IP)"
|
||||||
|
echo "注意:默认拒绝策略已经阻止非白名单的ICMP,白名单IP可以ping"
|
||||||
|
|
||||||
|
# 7. 启用UFW
|
||||||
|
echo ">>> 启用 UFW 防火墙"
|
||||||
|
echo "y" | ufw enable
|
||||||
|
|
||||||
|
# 8. 显示当前规则
|
||||||
|
echo "========================================="
|
||||||
|
echo "UFW 防火墙配置完成!当前规则如下:"
|
||||||
|
echo "========================================="
|
||||||
|
ufw status verbose
|
||||||
|
|
||||||
# 输出提示信息,告知用户脚本即将开始
|
|
||||||
echo "================================================="
|
|
||||||
echo " UFW 防火墙自动配置脚本即将开始... "
|
|
||||||
echo "================================================="
|
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "配置总结:"
|
||||||
# --- 1. 重置 UFW ---
|
echo "- 出站流量:全部允许"
|
||||||
# 为了避免与旧规则冲突,首先重置UFW到初始状态。
|
echo "- 入站流量:默认拒绝"
|
||||||
# --force 选项可以在没有交互提示的情况下完成重置。
|
echo "- 开放端口:443, 22333, 25000-26000 (TCP/UDP)"
|
||||||
echo "--- 步骤 1: 重置UFW防火墙,清除所有现有规则 ---"
|
echo "- 白名单IP:42.192.52.227, 43.154.83.213, 144.24.164.121, 132.145.87.10, 140.238.0.0/16"
|
||||||
echo "执行命令: sudo ufw --force reset"
|
echo "- ICMP:仅白名单IP可访问"
|
||||||
sudo ufw --force reset
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 3. 开放特定端口 (对所有IP) ---
|
|
||||||
# 为公共服务开放指定的端口。
|
|
||||||
echo "--- 步骤 3: 向所有IP开放指定的TCP/UDP端口 ---"
|
|
||||||
# 开放 HTTPS (443) 端口
|
|
||||||
echo "开放端口: 443/tcp 和 443/udp"
|
|
||||||
echo "执行命令: sudo ufw allow 443"
|
|
||||||
sudo ufw allow 443
|
|
||||||
# 开放自定义 (22333) 端口
|
|
||||||
echo "开放端口: 22333/tcp 和 22333/udp"
|
|
||||||
echo "执行命令: sudo ufw allow 22333"
|
|
||||||
sudo ufw allow 22333
|
|
||||||
# 开放自定义 (25000-26000) 端口范围
|
|
||||||
echo "开放端口范围: 25000:26000/tcp"
|
|
||||||
echo "执行命令: sudo ufw allow 25000:26000/tcp"
|
|
||||||
sudo ufw allow 25000:26000/tcp
|
|
||||||
echo "开放端口范围: 25000:26000/udp"
|
|
||||||
echo "执行命令: sudo ufw allow 25000:26000/udp"
|
|
||||||
sudo ufw allow 25000:26000/udp
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 4. 添加IP白名单 ---
|
|
||||||
# 为受信任的IP地址开放所有权限,方便管理和访问。
|
|
||||||
echo "--- 步骤 4: 为白名单IP开放所有协议和端口 ---"
|
|
||||||
WHITELIST_IPS=(
|
|
||||||
"42.192.52.227/32"
|
|
||||||
"43.154.83.213/32"
|
|
||||||
"144.24.164.121/32"
|
|
||||||
"132.145.87.10/32"
|
|
||||||
"140.238.0.0/16"
|
|
||||||
)
|
|
||||||
# 遍历IP列表并添加规则
|
|
||||||
for ip in "${WHITELIST_IPS[@]}"; do
|
|
||||||
echo "添加白名单IP: ${ip}"
|
|
||||||
echo "执行命令: sudo ufw allow from ${ip} to any"
|
|
||||||
sudo ufw allow from ${ip} to any
|
|
||||||
done
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 2. 设置默认策略 ---
|
|
||||||
# 这是防火墙的基础安全策略。
|
|
||||||
# deny incoming: 拒绝所有未经明确允许的进入流量。
|
|
||||||
# allow outgoing: 允许服务器主动发起的任何出站流量。
|
|
||||||
echo "--- 步骤 2: 设置默认防火墙策略 ---"
|
|
||||||
echo "设置默认拒绝所有进入流量..."
|
|
||||||
echo "执行命令: sudo ufw default deny incoming"
|
|
||||||
sudo ufw default deny incoming
|
|
||||||
echo "设置默认允许所有出口流量..."
|
|
||||||
echo "执行命令: sudo ufw default allow outgoing"
|
|
||||||
sudo ufw default allow outgoing
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 5. ICMP (Ping) 请求处理 ---
|
|
||||||
# UFW的默认拒绝策略(deny incoming)已经包含了对ICMP的阻止。
|
|
||||||
# 而上一步的IP白名单规则(ufw allow from <IP>)允许了这些IP的所有协议,因此它们可以ping通。
|
|
||||||
# 这精确地实现了“禁止非白名单IP的ICMP请求”的目标。
|
|
||||||
echo "--- 步骤 5: ICMP (Ping) 请求说明 ---"
|
|
||||||
echo "无需额外规则。默认的'deny incoming'策略已阻止非白名单IP的ping请求。"
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 6. 启用 UFW ---
|
|
||||||
# 应用以上所有规则,正式启动防火墙。
|
|
||||||
echo "--- 步骤 6: 启用UFW防火墙 ---"
|
|
||||||
echo "执行命令: sudo ufw enable"
|
|
||||||
sudo ufw enable
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# --- 7. 显示最终状态 ---
|
|
||||||
# 显示详细的防火墙状态,以便用户检查配置是否正确。
|
|
||||||
echo "--- 步骤 7: 显示当前防火墙状态 ---"
|
|
||||||
echo "执行命令: sudo ufw status verbose"
|
|
||||||
sudo ufw status verbose
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "================================================="
|
|
||||||
echo " 防火墙配置完成!请检查上面的状态。 "
|
|
||||||
echo "================================================="
|
|
||||||
|
|||||||
@@ -2,13 +2,15 @@
|
|||||||
你是一个精通ubuntu22.04系统下ufw使用的计算机高手,请实现一个shell脚本,实现如下的功能
|
你是一个精通ubuntu22.04系统下ufw使用的计算机高手,请实现一个shell脚本,实现如下的功能
|
||||||
- 所有的命令均有清晰的中文注释
|
- 所有的命令均有清晰的中文注释
|
||||||
- 所有执行的命令均使用echo进行打印输出
|
- 所有执行的命令均使用echo进行打印输出
|
||||||
- 开放访问目的地端口为443 22333 25000-26000的tcp udp到0.0.0.0/0
|
- 允许全部的流出方向流量
|
||||||
- 对以下IP开放全部协议及端口
|
- 开放来源为0.0.0.0/0, 流入本机的端口为443 22333 25000-26000的tcp udp流量
|
||||||
|
- 对以下IP的流入本机方向,流量的全部协议及端口
|
||||||
- 42.192.52.227/32
|
- 42.192.52.227/32
|
||||||
- 43.154.83.213/32
|
- 43.154.83.213/32
|
||||||
- 144.24.164.121/32
|
- 144.24.164.121/32
|
||||||
- 132.145.87.10/32
|
- 132.145.87.10/32
|
||||||
- 140.238.0.0/16
|
- 140.238.0.0/16
|
||||||
- 禁止其他端口的访问流量
|
- 禁止其他端口的流入流量
|
||||||
- 禁止非白名单IP的ICMP请求
|
- 禁止非白名单IP的ICMP请求
|
||||||
- 允许全部的出口流量
|
|
||||||
|
请同步写出清除上述所有规则的脚本
|
||||||
47
1-代理Xray/7-日本-tokyo-amd02-节点/1-oracle-tokyo-amd54-02.json
Normal file
47
1-代理Xray/7-日本-tokyo-amd02-节点/1-oracle-tokyo-amd54-02.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "warning"
|
||||||
|
},
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "socks",
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"port": 1234,
|
||||||
|
"settings": {
|
||||||
|
"auth": "noauth",
|
||||||
|
"udp": true,
|
||||||
|
"ip": "127.0.0.1",
|
||||||
|
"userLevel": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"port": 1235,
|
||||||
|
"protocol": "http",
|
||||||
|
"tag": "http-no-auth",
|
||||||
|
"settings": {
|
||||||
|
"timeout": 300
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"port": 1236,
|
||||||
|
"protocol": "http",
|
||||||
|
"tag": "http-with-auth",
|
||||||
|
"settings": {
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"user": "zeaslity",
|
||||||
|
"pass": "loveff.22"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeout": 300
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "freedom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ server {
|
|||||||
server {
|
server {
|
||||||
listen unix:/dev/shm/h1.sock proxy_protocol;
|
listen unix:/dev/shm/h1.sock proxy_protocol;
|
||||||
# listen 5001;
|
# listen 5001;
|
||||||
server_name bingo.107421.xyz;
|
server_name xx.l4.ca.bg.107421.xyz;
|
||||||
|
|
||||||
set_real_ip_from unix:;
|
set_real_ip_from unix:;
|
||||||
real_ip_header proxy_protocol;
|
real_ip_header proxy_protocol;
|
||||||
@@ -42,7 +42,7 @@ server {
|
|||||||
set_real_ip_from unix:;
|
set_real_ip_from unix:;
|
||||||
real_ip_header proxy_protocol;
|
real_ip_header proxy_protocol;
|
||||||
|
|
||||||
server_name bingo.107421.xyz;
|
server_name xx.l4.ca.bg.107421.xyz;
|
||||||
|
|
||||||
# grpc settings
|
# grpc settings
|
||||||
# grpc_read_timeout 1h;
|
# grpc_read_timeout 1h;
|
||||||
|
|||||||
@@ -50,13 +50,13 @@ dns: # 启用 DNS 服务器
|
|||||||
# Fake-IP 例外名单,对于这些域名,Clash 将返回其真实的 IP 地址
|
# Fake-IP 例外名单,对于这些域名,Clash 将返回其真实的 IP 地址
|
||||||
# 这对于一些无法处理 Fake-IP 的内网服务或特定应用至关重要
|
# 这对于一些无法处理 Fake-IP 的内网服务或特定应用至关重要
|
||||||
fake-ip-filter:
|
fake-ip-filter:
|
||||||
|
- localhost
|
||||||
- '*.lan'
|
- '*.lan'
|
||||||
- '*.local'
|
- '*.local'
|
||||||
- '*.arpa'
|
- '*.arpa'
|
||||||
- time.*.com
|
- time.*.com
|
||||||
- ntp.*.com
|
- ntp.*.com
|
||||||
- time.*.com
|
- time.*.com
|
||||||
- +.market.xiaomi.com
|
|
||||||
- localhost.ptlogin2.qq.com
|
- localhost.ptlogin2.qq.com
|
||||||
- '*.msftncsi.com'
|
- '*.msftncsi.com'
|
||||||
- www.msftconnecttest.com
|
- www.msftconnecttest.com
|
||||||
@@ -69,7 +69,6 @@ dns: # 启用 DNS 服务器
|
|||||||
- 119.29.29.29
|
- 119.29.29.29
|
||||||
# [优化] 主 DNS 服务器列表 (国内,加密 DoH)
|
# [优化] 主 DNS 服务器列表 (国内,加密 DoH)
|
||||||
# 会与 Fallback DNS 并发请求,如果返回的 IP 是国内 IP,则立即采用,速度快
|
# 会与 Fallback DNS 并发请求,如果返回的 IP 是国内 IP,则立即采用,速度快
|
||||||
# 使用加密 DNS 替代传统 UDP DNS,增强解析的稳定性和抗干扰性。
|
|
||||||
nameserver:
|
nameserver:
|
||||||
- 223.5.5.5 # 阿里云
|
- 223.5.5.5 # 阿里云
|
||||||
- 180.76.76.76 # 百度DNS
|
- 180.76.76.76 # 百度DNS
|
||||||
@@ -80,11 +79,13 @@ dns: # 启用 DNS 服务器
|
|||||||
# 用于解析国外域名。当主 DNS 返回国外 IP 时,Clash 会认为可能被污染,
|
# 用于解析国外域名。当主 DNS 返回国外 IP 时,Clash 会认为可能被污染,
|
||||||
# 并采用 Fallback DNS 的解析结果,以确保准确性
|
# 并采用 Fallback DNS 的解析结果,以确保准确性
|
||||||
fallback:
|
fallback:
|
||||||
- https://dns.google/dns-query # Google DNS (DoH)
|
|
||||||
- https://dns.cloudflare.com/dns-query # Cloudflare DNS (DoH)
|
- https://dns.cloudflare.com/dns-query # Cloudflare DNS (DoH)
|
||||||
- https://dns.quad9.net/dns-query # IBM quad9
|
- https://dns.quad9.net/dns-query # IBM quad9
|
||||||
|
- https://dns.google.com/dns-query # Google DNS (DoH)
|
||||||
- https://dns.opendns.com/dns-query # CISCO OpenDNS
|
- https://dns.opendns.com/dns-query # CISCO OpenDNS
|
||||||
- https://dns.adguard-dns.com/dns-query # AdGuard DNS
|
- https://dns.adguard-dns.com/dns-query # AdGuard DNS
|
||||||
|
- tls://8.8.8.8:853 # Google DoT (纯IP)
|
||||||
|
- tls://1.1.1.1:853 # Cloudflare DoT (纯IP)
|
||||||
- tls://8.8.4.4:853 # Google DNS (DoT)
|
- tls://8.8.4.4:853 # Google DNS (DoT)
|
||||||
# Fallback DNS 例外名单,匹配此列表的域名将只使用主 DNS 解析
|
# Fallback DNS 例外名单,匹配此列表的域名将只使用主 DNS 解析
|
||||||
fallback-filter:
|
fallback-filter:
|
||||||
@@ -120,15 +121,16 @@ dns: # 启用 DNS 服务器
|
|||||||
prefer-h3: false
|
prefer-h3: false
|
||||||
# DNS也遵循规则进行解析
|
# DNS也遵循规则进行解析
|
||||||
respect-rules: false
|
respect-rules: false
|
||||||
# 代理的DNS解析地址
|
# [关键] 代理节点域名解析,必须用纯IP的国内DNS
|
||||||
proxy-server-nameserver:
|
proxy-server-nameserver:
|
||||||
- 'https://dns.google/dns-query'
|
- 223.5.5.5
|
||||||
- 'https://1.1.1.1/dns-query'
|
- 119.29.29.29
|
||||||
# 直连模式下的DNS服务器
|
# 直连模式下的DNS服务器
|
||||||
direct-nameserver:
|
direct-nameserver:
|
||||||
|
- 223.5.5.5 # 阿里 DNS
|
||||||
|
- 192.168.78.39
|
||||||
- 119.29.29.29 # 腾讯 DNSPod
|
- 119.29.29.29 # 腾讯 DNSPod
|
||||||
- 114.114.114.114 # 114 DNS
|
- 114.114.114.114 # 114 DNS
|
||||||
- 223.5.5.5 # 阿里 DNS
|
|
||||||
|
|
||||||
|
|
||||||
# 禁止远程调试
|
# 禁止远程调试
|
||||||
@@ -181,7 +183,7 @@ proxies:
|
|||||||
|
|
||||||
- type: vless
|
- type: vless
|
||||||
name: BFC-LosAngles
|
name: BFC-LosAngles
|
||||||
server: 154.40.34.106
|
server: 45.143.128.143
|
||||||
port: 443
|
port: 443
|
||||||
uuid: 302fbcb8-e096-46a1-906f-e879ec5ab0c5
|
uuid: 302fbcb8-e096-46a1-906f-e879ec5ab0c5
|
||||||
skip-cert-verify: false
|
skip-cert-verify: false
|
||||||
@@ -478,6 +480,10 @@ proxy-groups:
|
|||||||
- Oracle-JPN-Tokyo-R-OSel
|
- Oracle-JPN-Tokyo-R-OSel
|
||||||
- Oracle-JPN-Osaka-R-OSel
|
- Oracle-JPN-Osaka-R-OSel
|
||||||
- Oracle-USA-Phoneix-R-OSel
|
- Oracle-USA-Phoneix-R-OSel
|
||||||
|
- name: 🛜 DNS
|
||||||
|
type: select
|
||||||
|
proxies:
|
||||||
|
- TC-HongKong
|
||||||
- name: 🌍 国外媒体
|
- name: 🌍 国外媒体
|
||||||
type: select
|
type: select
|
||||||
proxies:
|
proxies:
|
||||||
@@ -627,14 +633,18 @@ rules: # 1. 广告、追踪器拦截规则 (最高优先级)
|
|||||||
# 直接拒绝连接,提升网页加载速度和隐私保护
|
# 直接拒绝连接,提升网页加载速度和隐私保护
|
||||||
- RULE-SET,reject,REJECT
|
- RULE-SET,reject,REJECT
|
||||||
|
|
||||||
|
# [新增] DNS服务器IP直连,防止DNS请求走代理
|
||||||
|
- IP-CIDR,8.8.8.8/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,8.8.4.4/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,1.1.1.1/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,1.0.0.1/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,223.5.5.5/32,DIRECT,no-resolve
|
||||||
|
- IP-CIDR,119.29.29.29/32,DIRECT,no-resolve
|
||||||
|
|
||||||
# [优化] 核心国内流量直连规则 (IP 维度)
|
# [优化] 核心国内流量直连规则 (IP 维度)
|
||||||
# 将中国大陆的 IP 地址段置于高优先级。这是解决国内网站访问缓慢和超时的关键。
|
# 将中国大陆的 IP 地址段置于高优先级。这是解决国内网站访问缓慢和超时的关键。
|
||||||
# 任何目标地址在此列表内的连接都会被立即直连,无需进行 DNS 查询和 GEOIP 判断。
|
# 任何目标地址在此列表内的连接都会被立即直连,无需进行 DNS 查询和 GEOIP 判断。
|
||||||
- RULE-SET,cncidr,DIRECT
|
- RULE-SET,cncidr,DIRECT
|
||||||
- # 5. 基于地理位置的补充规则
|
|
||||||
- # 所有目标 IP 位于中国大陆的流量都直连
|
|
||||||
- # 这条规则作为对域名规则的补充,确保国内 IP 流量的直连
|
|
||||||
- GEOIP,CN,DIRECT
|
|
||||||
|
|
||||||
# 工作代理模式
|
# 工作代理模式
|
||||||
- DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连
|
- DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连
|
||||||
@@ -653,7 +663,6 @@ rules: # 1. 广告、追踪器拦截规则 (最高优先级)
|
|||||||
# 优先匹配已知需要直连的域名和服务 (Apple, iCloud 等)
|
# 优先匹配已知需要直连的域名和服务 (Apple, iCloud 等)
|
||||||
- RULE-SET,icloud,🍎 苹果服务
|
- RULE-SET,icloud,🍎 苹果服务
|
||||||
- RULE-SET,apple,🍎 苹果服务
|
- RULE-SET,apple,🍎 苹果服务
|
||||||
- RULE-SET,direct,🎯 全球直连
|
|
||||||
|
|
||||||
# 4. 明确的代理规则
|
# 4. 明确的代理规则
|
||||||
# 匹配已知需要代理的服务 (Google, Telegram, 以及其他国际服务)
|
# 匹配已知需要代理的服务 (Google, Telegram, 以及其他国际服务)
|
||||||
@@ -661,6 +670,13 @@ rules: # 1. 广告、追踪器拦截规则 (最高优先级)
|
|||||||
- RULE-SET,telegramcidr,📲 电报信息
|
- RULE-SET,telegramcidr,📲 电报信息
|
||||||
- RULE-SET,proxy,🌍 国外媒体
|
- RULE-SET,proxy,🌍 国外媒体
|
||||||
|
|
||||||
|
- # 5. 基于地理位置的补充规则
|
||||||
|
- # 所有目标 IP 位于中国大陆的流量都直连
|
||||||
|
- # 这条规则作为对域名规则的补充,确保国内 IP 流量的直连
|
||||||
|
- GEOIP,CN,DIRECT
|
||||||
|
|
||||||
|
- RULE-SET,direct,🎯 全球直连
|
||||||
|
|
||||||
# 6. 最终的兜底规则 (最低优先级)
|
# 6. 最终的兜底规则 (最低优先级)
|
||||||
# 所有未匹配到以上任何规则的流量,都走代理
|
# 所有未匹配到以上任何规则的流量,都走代理
|
||||||
# 这是确保未知的新网站或国外服务能正常访问的关键
|
# 这是确保未知的新网站或国外服务能正常访问的关键
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
vless://f8702759-f402-4e85-92a6-8540d577de22@43.154.83.213:24443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#TC-HongKong
|
vless://f8702759-f402-4e85-92a6-8540d577de22@43.154.83.213:24443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#TC-HongKong
|
||||||
vless://302fbcb8-e096-46a1-906f-e879ec5ab0c5@154.40.34.106:443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.l4.ca.bg.107421.xyz#BFC-LosAngles
|
vless://302fbcb8-e096-46a1-906f-e879ec5ab0c5@45.143.128.143:443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.l4.ca.bg.107421.xyz#BFC-LosAngles
|
||||||
vless://9fa9b4e7-d76d-4890-92cf-ce9251a76f59@43.154.83.213:24451?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Care-DEU-Dusseldorf-R-TCHK
|
vless://9fa9b4e7-d76d-4890-92cf-ce9251a76f59@43.154.83.213:24451?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Care-DEU-Dusseldorf-R-TCHK
|
||||||
|
|
||||||
vless://7e27da0c-3013-4ed4-817b-50cc76a0bf81@43.154.83.213:24449?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Oracle-KOR-Seoul-R-TCHK
|
vless://7e27da0c-3013-4ed4-817b-50cc76a0bf81@43.154.83.213:24449?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Oracle-KOR-Seoul-R-TCHK
|
||||||
|
|||||||
55
1-代理Xray/99-网络质量分析/30M带宽服务器-网络内核优化.conf
Normal file
55
1-代理Xray/99-网络质量分析/30M带宽服务器-网络内核优化.conf
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# ==========================================================
|
||||||
|
# 核心拥塞控制与队列管理 (解决丢包与延迟)
|
||||||
|
# ==========================================================
|
||||||
|
# 使用 FQ (Fair Queueing) 队列调度算法,这是BBR的必要配合
|
||||||
|
net.core.default_qdisc = fq
|
||||||
|
# 开启 BBR 拥塞控制算法
|
||||||
|
net.ipv4.tcp_congestion_control = bbr
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# TCP 缓冲区调优 (针对 30-50Mbps 带宽优化)
|
||||||
|
# ==========================================================
|
||||||
|
# 格式: min default max
|
||||||
|
# 核心策略:限制 max 值,防止 Bufferbloat。
|
||||||
|
# 2MB (2097152) 的缓冲区足以应对 50Mbps 下 300ms 的抖动,再大就会导致高延迟。
|
||||||
|
|
||||||
|
# 接收缓冲区
|
||||||
|
net.ipv4.tcp_rmem = 4096 87380 2097152
|
||||||
|
# 发送缓冲区
|
||||||
|
net.ipv4.tcp_wmem = 4096 65536 2097152
|
||||||
|
|
||||||
|
# 开启窗口缩放,允许窗口超过 64KB
|
||||||
|
net.ipv4.tcp_window_scaling = 1
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 连接追踪与并发优化 (Xray 高并发转发需求)
|
||||||
|
# ==========================================================
|
||||||
|
# 增加系统级文件描述符限制
|
||||||
|
fs.file-max = 1048576
|
||||||
|
|
||||||
|
# 增加入站连接队列长度,防止突发流量导致握手失败
|
||||||
|
net.core.somaxconn = 4096
|
||||||
|
net.core.netdev_max_backlog = 4096
|
||||||
|
|
||||||
|
# TCP Fast Open (TFO):减少握手延迟
|
||||||
|
# 值 3 表示同时开启客户端和服务端的 TFO 支持
|
||||||
|
# Xray 需要在配置中显式开启 "tcpFastOpen": true 才能生效
|
||||||
|
net.ipv4.tcp_fastopen = 3
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 抗丢包与快速恢复
|
||||||
|
# ==========================================================
|
||||||
|
# 开启 SACK (选择性确认),对丢包环境极其重要
|
||||||
|
net.ipv4.tcp_sack = 1
|
||||||
|
net.ipv4.tcp_dsack = 1
|
||||||
|
net.ipv4.tcp_fack = 1
|
||||||
|
|
||||||
|
# 缩短保活探测时间,快速剔除死连接(GFW常导致连接“假死”)
|
||||||
|
net.ipv4.tcp_keepalive_time = 300
|
||||||
|
net.ipv4.tcp_keepalive_probes = 5
|
||||||
|
net.ipv4.tcp_keepalive_intvl = 15
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 转发功能开启 (主机A必须)
|
||||||
|
# ==========================================================
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
7
1-代理Xray/99-网络质量分析/go.mod
Normal file
7
1-代理Xray/99-网络质量分析/go.mod
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module wdd.io/net-monitor
|
||||||
|
|
||||||
|
go 1.25.3
|
||||||
|
|
||||||
|
require golang.org/x/net v0.47.0
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.38.0 // indirect
|
||||||
4
1-代理Xray/99-网络质量分析/go.sum
Normal file
4
1-代理Xray/99-网络质量分析/go.sum
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
730
1-代理Xray/99-网络质量分析/ne_quality_monitor_claude.go
Normal file
730
1-代理Xray/99-网络质量分析/ne_quality_monitor_claude.go
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ============ 通用数据结构 ============
|
||||||
|
type TestPacket struct {
|
||||||
|
SeqNum uint64
|
||||||
|
Timestamp int64
|
||||||
|
Type string // "tcp", "udp", "ping"
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
PacketsReceived uint64
|
||||||
|
PacketsLost uint64
|
||||||
|
LastSeqNum uint64
|
||||||
|
RTTSamples []time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metrics struct {
|
||||||
|
PacketsSent uint64
|
||||||
|
PacketsReceived uint64
|
||||||
|
PacketsLost uint64
|
||||||
|
RTTSamples []time.Duration
|
||||||
|
MinRTT time.Duration
|
||||||
|
MaxRTT time.Duration
|
||||||
|
AvgRTT time.Duration
|
||||||
|
Jitter time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestReport struct {
|
||||||
|
Timestamp time.Time
|
||||||
|
TestDuration time.Duration
|
||||||
|
TargetHost string
|
||||||
|
TCPMetrics *Metrics
|
||||||
|
UDPMetrics *Metrics
|
||||||
|
TracerouteHops []HopInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type HopInfo struct {
|
||||||
|
TTL int
|
||||||
|
Address string
|
||||||
|
RTT time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 服务端实现 ============
|
||||||
|
type NetworkServer struct {
|
||||||
|
tcpAddr string
|
||||||
|
udpAddr string
|
||||||
|
tcpStats *Stats
|
||||||
|
udpStats *Stats
|
||||||
|
statsLock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkServer(tcpPort, udpPort int) *NetworkServer {
|
||||||
|
return &NetworkServer{
|
||||||
|
tcpAddr: fmt.Sprintf(":%d", tcpPort),
|
||||||
|
udpAddr: fmt.Sprintf(":%d", udpPort),
|
||||||
|
tcpStats: &Stats{},
|
||||||
|
udpStats: &Stats{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NetworkServer) Start() {
|
||||||
|
log.Printf("========== 网络质量检测服务端 ==========")
|
||||||
|
log.Printf("TCP监听端口: %s", ns.tcpAddr)
|
||||||
|
log.Printf("UDP监听端口: %s", ns.udpAddr)
|
||||||
|
log.Printf("服务器已启动,等待客户端连接...")
|
||||||
|
log.Printf("========================================\n")
|
||||||
|
|
||||||
|
// 启动TCP服务器
|
||||||
|
go ns.serveTCP()
|
||||||
|
// 启动UDP服务器
|
||||||
|
go ns.serveUDP()
|
||||||
|
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NetworkServer) serveTCP() {
|
||||||
|
listener, err := net.Listen("tcp", ns.tcpAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("TCP监听失败: %v", err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("TCP连接接受错误: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go ns.handleTCPConnection(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NetworkServer) handleTCPConnection(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
log.Printf("[TCP] 新连接来自 %s", conn.RemoteAddr())
|
||||||
|
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
for {
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[TCP] 连接 %s 断开", conn.RemoteAddr())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var packet TestPacket
|
||||||
|
if err := json.Unmarshal(buf[:n], &packet); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveTime := time.Now().UnixNano()
|
||||||
|
ns.updateStats(ns.tcpStats, packet.SeqNum)
|
||||||
|
|
||||||
|
// 立即回显数据包
|
||||||
|
response := TestPacket{
|
||||||
|
SeqNum: packet.SeqNum,
|
||||||
|
Timestamp: receiveTime,
|
||||||
|
Type: "tcp_response",
|
||||||
|
Data: packet.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, _ := json.Marshal(response)
|
||||||
|
conn.Write(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NetworkServer) serveUDP() {
|
||||||
|
addr, err := net.ResolveUDPAddr("udp", ns.udpAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("UDP地址解析失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.ListenUDP("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("UDP监听失败: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
log.Printf("[UDP] 监听在 %s", ns.udpAddr)
|
||||||
|
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
for {
|
||||||
|
n, remoteAddr, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("UDP读取错误: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var packet TestPacket
|
||||||
|
if err := json.Unmarshal(buf[:n], &packet); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveTime := time.Now().UnixNano()
|
||||||
|
ns.updateStats(ns.udpStats, packet.SeqNum)
|
||||||
|
|
||||||
|
// 回显UDP数据包
|
||||||
|
response := TestPacket{
|
||||||
|
SeqNum: packet.SeqNum,
|
||||||
|
Timestamp: receiveTime,
|
||||||
|
Type: "udp_response",
|
||||||
|
Data: packet.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, _ := json.Marshal(response)
|
||||||
|
conn.WriteToUDP(data, remoteAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NetworkServer) updateStats(stats *Stats, seqNum uint64) {
|
||||||
|
ns.statsLock.Lock()
|
||||||
|
defer ns.statsLock.Unlock()
|
||||||
|
|
||||||
|
stats.PacketsReceived++
|
||||||
|
|
||||||
|
if seqNum > stats.LastSeqNum+1 {
|
||||||
|
stats.PacketsLost += seqNum - stats.LastSeqNum - 1
|
||||||
|
}
|
||||||
|
stats.LastSeqNum = seqNum
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 客户端实现 ============
|
||||||
|
type NetworkClient struct {
|
||||||
|
targetHost string
|
||||||
|
tcpPort int
|
||||||
|
udpPort int
|
||||||
|
testDuration time.Duration
|
||||||
|
packetSize int
|
||||||
|
reportFile string
|
||||||
|
|
||||||
|
tcpMetrics *Metrics
|
||||||
|
udpMetrics *Metrics
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkClient(host string, tcpPort, udpPort int, duration time.Duration) *NetworkClient {
|
||||||
|
return &NetworkClient{
|
||||||
|
targetHost: host,
|
||||||
|
tcpPort: tcpPort,
|
||||||
|
udpPort: udpPort,
|
||||||
|
testDuration: duration,
|
||||||
|
packetSize: 1024,
|
||||||
|
reportFile: "network_quality_report.json",
|
||||||
|
tcpMetrics: &Metrics{MinRTT: time.Hour},
|
||||||
|
udpMetrics: &Metrics{MinRTT: time.Hour},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) testTCPLatency() error {
|
||||||
|
addr := fmt.Sprintf("%s:%d", nc.targetHost, nc.tcpPort)
|
||||||
|
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("TCP连接失败: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
log.Printf("[TCP] 开始延迟测试 -> %s", addr)
|
||||||
|
|
||||||
|
var seqNum uint64
|
||||||
|
deadline := time.Now().Add(nc.testDuration)
|
||||||
|
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
seqNum++
|
||||||
|
|
||||||
|
packet := TestPacket{
|
||||||
|
SeqNum: seqNum,
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
Type: "tcp_probe",
|
||||||
|
Data: make([]byte, nc.packetSize),
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTime := time.Now()
|
||||||
|
|
||||||
|
data, _ := json.Marshal(packet)
|
||||||
|
if _, err := conn.Write(data); err != nil {
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.tcpMetrics.PacketsLost++
|
||||||
|
nc.mu.Unlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.tcpMetrics.PacketsSent++
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||||
|
_, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.tcpMetrics.PacketsLost++
|
||||||
|
nc.mu.Unlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rtt := time.Since(sendTime)
|
||||||
|
nc.updateTCPMetrics(rtt)
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[TCP] 测试完成")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) testUDPLatency() error {
|
||||||
|
addr := fmt.Sprintf("%s:%d", nc.targetHost, nc.udpPort)
|
||||||
|
raddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("UDP地址解析失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialUDP("udp", nil, raddr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("UDP连接失败: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
log.Printf("[UDP] 开始延迟测试 -> %s", addr)
|
||||||
|
|
||||||
|
var seqNum uint64
|
||||||
|
deadline := time.Now().Add(nc.testDuration)
|
||||||
|
sentPackets := make(map[uint64]time.Time)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// 发送协程
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
seqNum++
|
||||||
|
|
||||||
|
packet := TestPacket{
|
||||||
|
SeqNum: seqNum,
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
Type: "udp_probe",
|
||||||
|
Data: make([]byte, nc.packetSize),
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTime := time.Now()
|
||||||
|
nc.mu.Lock()
|
||||||
|
sentPackets[seqNum] = sendTime
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
data, _ := json.Marshal(packet)
|
||||||
|
conn.Write(data)
|
||||||
|
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.udpMetrics.PacketsSent++
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 接收协程
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
for time.Now().Before(deadline.Add(3 * time.Second)) {
|
||||||
|
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var response TestPacket
|
||||||
|
if err := json.Unmarshal(buf[:n], &response); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nc.mu.Lock()
|
||||||
|
if sendTime, ok := sentPackets[response.SeqNum]; ok {
|
||||||
|
rtt := time.Since(sendTime)
|
||||||
|
nc.updateUDPMetrics(rtt)
|
||||||
|
delete(sentPackets, response.SeqNum)
|
||||||
|
}
|
||||||
|
nc.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.udpMetrics.PacketsLost = uint64(len(sentPackets))
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
log.Printf("[UDP] 测试完成")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) performTraceroute() ([]HopInfo, error) {
|
||||||
|
log.Printf("[Traceroute] 路由追踪到 %s", nc.targetHost)
|
||||||
|
|
||||||
|
hops := make([]HopInfo, 0, 30)
|
||||||
|
maxTTL := 30
|
||||||
|
timeout := 2 * time.Second
|
||||||
|
|
||||||
|
for ttl := 1; ttl <= maxTTL; ttl++ {
|
||||||
|
hopInfo, reached, err := nc.probeHop(ttl, timeout)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hops = append(hops, hopInfo)
|
||||||
|
if hopInfo.Address != "*" {
|
||||||
|
log.Printf(" %2d %-15s %.2fms", ttl, hopInfo.Address,
|
||||||
|
float64(hopInfo.RTT.Microseconds())/1000.0)
|
||||||
|
} else {
|
||||||
|
log.Printf(" %2d *", ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reached {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hops, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) probeHop(ttl int, timeout time.Duration) (HopInfo, bool, error) {
|
||||||
|
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||||
|
if err != nil {
|
||||||
|
return HopInfo{}, false, err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if err := conn.IPv4PacketConn().SetTTL(ttl); err != nil {
|
||||||
|
return HopInfo{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := icmp.Message{
|
||||||
|
Type: ipv4.ICMPTypeEcho,
|
||||||
|
Code: 0,
|
||||||
|
Body: &icmp.Echo{
|
||||||
|
ID: os.Getpid() & 0xffff,
|
||||||
|
Seq: ttl,
|
||||||
|
Data: []byte("TRACEROUTE"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
msgBytes, err := msg.Marshal(nil)
|
||||||
|
if err != nil {
|
||||||
|
return HopInfo{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dst, err := net.ResolveIPAddr("ip4", nc.targetHost)
|
||||||
|
if err != nil {
|
||||||
|
return HopInfo{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if _, err := conn.WriteTo(msgBytes, dst); err != nil {
|
||||||
|
return HopInfo{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reply := make([]byte, 1500)
|
||||||
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
_, peer, err := conn.ReadFrom(reply)
|
||||||
|
rtt := time.Since(start)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return HopInfo{TTL: ttl, Address: "*", RTT: 0}, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hopAddr := peer.String()
|
||||||
|
reachedTarget := (hopAddr == dst.String())
|
||||||
|
|
||||||
|
return HopInfo{
|
||||||
|
TTL: ttl,
|
||||||
|
Address: hopAddr,
|
||||||
|
RTT: rtt,
|
||||||
|
}, reachedTarget, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) updateTCPMetrics(rtt time.Duration) {
|
||||||
|
nc.mu.Lock()
|
||||||
|
defer nc.mu.Unlock()
|
||||||
|
|
||||||
|
nc.tcpMetrics.PacketsReceived++
|
||||||
|
nc.tcpMetrics.RTTSamples = append(nc.tcpMetrics.RTTSamples, rtt)
|
||||||
|
|
||||||
|
if rtt < nc.tcpMetrics.MinRTT {
|
||||||
|
nc.tcpMetrics.MinRTT = rtt
|
||||||
|
}
|
||||||
|
if rtt > nc.tcpMetrics.MaxRTT {
|
||||||
|
nc.tcpMetrics.MaxRTT = rtt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) updateUDPMetrics(rtt time.Duration) {
|
||||||
|
nc.udpMetrics.PacketsReceived++
|
||||||
|
nc.udpMetrics.RTTSamples = append(nc.udpMetrics.RTTSamples, rtt)
|
||||||
|
|
||||||
|
if rtt < nc.udpMetrics.MinRTT {
|
||||||
|
nc.udpMetrics.MinRTT = rtt
|
||||||
|
}
|
||||||
|
if rtt > nc.udpMetrics.MaxRTT {
|
||||||
|
nc.udpMetrics.MaxRTT = rtt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) calculateMetrics() {
|
||||||
|
// 计算TCP平均RTT和抖动
|
||||||
|
if len(nc.tcpMetrics.RTTSamples) > 0 {
|
||||||
|
var sum time.Duration
|
||||||
|
for _, rtt := range nc.tcpMetrics.RTTSamples {
|
||||||
|
sum += rtt
|
||||||
|
}
|
||||||
|
nc.tcpMetrics.AvgRTT = sum / time.Duration(len(nc.tcpMetrics.RTTSamples))
|
||||||
|
|
||||||
|
var jitterSum time.Duration
|
||||||
|
for i := 1; i < len(nc.tcpMetrics.RTTSamples); i++ {
|
||||||
|
diff := nc.tcpMetrics.RTTSamples[i] - nc.tcpMetrics.RTTSamples[i-1]
|
||||||
|
if diff < 0 {
|
||||||
|
diff = -diff
|
||||||
|
}
|
||||||
|
jitterSum += diff
|
||||||
|
}
|
||||||
|
if len(nc.tcpMetrics.RTTSamples) > 1 {
|
||||||
|
nc.tcpMetrics.Jitter = jitterSum / time.Duration(len(nc.tcpMetrics.RTTSamples)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算UDP平均RTT和抖动
|
||||||
|
if len(nc.udpMetrics.RTTSamples) > 0 {
|
||||||
|
var sum time.Duration
|
||||||
|
for _, rtt := range nc.udpMetrics.RTTSamples {
|
||||||
|
sum += rtt
|
||||||
|
}
|
||||||
|
nc.udpMetrics.AvgRTT = sum / time.Duration(len(nc.udpMetrics.RTTSamples))
|
||||||
|
|
||||||
|
var jitterSum time.Duration
|
||||||
|
for i := 1; i < len(nc.udpMetrics.RTTSamples); i++ {
|
||||||
|
diff := nc.udpMetrics.RTTSamples[i] - nc.udpMetrics.RTTSamples[i-1]
|
||||||
|
if diff < 0 {
|
||||||
|
diff = -diff
|
||||||
|
}
|
||||||
|
jitterSum += diff
|
||||||
|
}
|
||||||
|
if len(nc.udpMetrics.RTTSamples) > 1 {
|
||||||
|
nc.udpMetrics.Jitter = jitterSum / time.Duration(len(nc.udpMetrics.RTTSamples)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) generateReport(hops []HopInfo) error {
|
||||||
|
nc.calculateMetrics()
|
||||||
|
|
||||||
|
report := TestReport{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
TestDuration: nc.testDuration,
|
||||||
|
TargetHost: nc.targetHost,
|
||||||
|
TCPMetrics: nc.tcpMetrics,
|
||||||
|
UDPMetrics: nc.udpMetrics,
|
||||||
|
TracerouteHops: hops,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将报告序列化为JSON(单行,不格式化)
|
||||||
|
data, err := json.Marshal(report)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以追加模式打开文件,如果不存在则创建
|
||||||
|
file, err := os.OpenFile(nc.reportFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("打开报告文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 写入JSON数据并添加换行符(JSON Lines格式)
|
||||||
|
if _, err := file.Write(data); err != nil {
|
||||||
|
return fmt.Errorf("写入报告数据失败: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := file.WriteString("\n"); err != nil {
|
||||||
|
return fmt.Errorf("写入换行符失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("测试报告已追加至: %s", nc.reportFile)
|
||||||
|
|
||||||
|
nc.printReport(&report)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) printReport(report *TestReport) {
|
||||||
|
fmt.Println("\n" + strings.Repeat("=", 50))
|
||||||
|
fmt.Println(" 网络质量检测报告")
|
||||||
|
fmt.Println(strings.Repeat("=", 50))
|
||||||
|
fmt.Printf("测试时间: %s\n", report.Timestamp.Format("2006-01-02 15:04:05"))
|
||||||
|
fmt.Printf("目标主机: %s\n", report.TargetHost)
|
||||||
|
fmt.Printf("测试时长: %v\n", report.TestDuration)
|
||||||
|
fmt.Println(strings.Repeat("-", 50))
|
||||||
|
|
||||||
|
fmt.Println("\n【TCP 测试结果】")
|
||||||
|
fmt.Printf(" 发送包数: %d\n", report.TCPMetrics.PacketsSent)
|
||||||
|
fmt.Printf(" 接收包数: %d\n", report.TCPMetrics.PacketsReceived)
|
||||||
|
if report.TCPMetrics.PacketsSent > 0 {
|
||||||
|
lossRate := float64(report.TCPMetrics.PacketsLost) / float64(report.TCPMetrics.PacketsSent) * 100
|
||||||
|
fmt.Printf(" 丢包数量: %d (丢包率: %.2f%%)\n", report.TCPMetrics.PacketsLost, lossRate)
|
||||||
|
}
|
||||||
|
if report.TCPMetrics.MinRTT < time.Hour {
|
||||||
|
fmt.Printf(" 最小RTT: %v\n", report.TCPMetrics.MinRTT)
|
||||||
|
fmt.Printf(" 平均RTT: %v\n", report.TCPMetrics.AvgRTT)
|
||||||
|
fmt.Printf(" 最大RTT: %v\n", report.TCPMetrics.MaxRTT)
|
||||||
|
fmt.Printf(" 抖动: %v\n", report.TCPMetrics.Jitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n【UDP 测试结果】")
|
||||||
|
fmt.Printf(" 发送包数: %d\n", report.UDPMetrics.PacketsSent)
|
||||||
|
fmt.Printf(" 接收包数: %d\n", report.UDPMetrics.PacketsReceived)
|
||||||
|
if report.UDPMetrics.PacketsSent > 0 {
|
||||||
|
lossRate := float64(report.UDPMetrics.PacketsLost) / float64(report.UDPMetrics.PacketsSent) * 100
|
||||||
|
fmt.Printf(" 丢包数量: %d (丢包率: %.2f%%)\n", report.UDPMetrics.PacketsLost, lossRate)
|
||||||
|
}
|
||||||
|
if report.UDPMetrics.MinRTT < time.Hour {
|
||||||
|
fmt.Printf(" 最小RTT: %v\n", report.UDPMetrics.MinRTT)
|
||||||
|
fmt.Printf(" 平均RTT: %v\n", report.UDPMetrics.AvgRTT)
|
||||||
|
fmt.Printf(" 最大RTT: %v\n", report.UDPMetrics.MaxRTT)
|
||||||
|
fmt.Printf(" 抖动: %v\n", report.UDPMetrics.Jitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(strings.Repeat("=", 50))
|
||||||
|
fmt.Printf("报告已保存至: %s\n\n", nc.reportFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nc *NetworkClient) RunScheduledTests(interval time.Duration) {
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
log.Printf("\n========== 开始定时测试 [%s] ==========",
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
|
// 执行TCP测试
|
||||||
|
if err := nc.testTCPLatency(); err != nil {
|
||||||
|
log.Printf("TCP测试错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置UDP指标
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.udpMetrics = &Metrics{MinRTT: time.Hour}
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
// 执行UDP测试
|
||||||
|
if err := nc.testUDPLatency(); err != nil {
|
||||||
|
log.Printf("UDP测试错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行Traceroute
|
||||||
|
hops, err := nc.performTraceroute()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Traceroute错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成报告
|
||||||
|
if err := nc.generateReport(hops); err != nil {
|
||||||
|
log.Printf("报告生成错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置TCP指标准备下一轮
|
||||||
|
nc.mu.Lock()
|
||||||
|
nc.tcpMetrics = &Metrics{MinRTT: time.Hour}
|
||||||
|
nc.mu.Unlock()
|
||||||
|
|
||||||
|
log.Printf("========== 测试完成,等待下一轮 ==========\n")
|
||||||
|
|
||||||
|
<-ticker.C
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 主程序 ============
|
||||||
|
func main() {
|
||||||
|
// 定义命令行参数
|
||||||
|
var (
|
||||||
|
mode = flag.String("mode", "", "运行模式: server(服务端) 或 client(客户端)")
|
||||||
|
tcpPort = flag.Int("tcp", 9001, "TCP测试端口")
|
||||||
|
udpPort = flag.Int("udp", 9002, "UDP测试端口")
|
||||||
|
targetHost = flag.String("target", "", "目标主机地址(客户端模式必需)")
|
||||||
|
testDuration = flag.Int("duration", 60, "单次测试时长(秒)")
|
||||||
|
interval = flag.Int("interval", 3600, "定时测试间隔(秒), 0表示只执行一次")
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, "\n网络质量检测工具\n\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "用法:\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " 服务端模式: %s -mode server [-tcp 端口] [-udp 端口]\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " 客户端模式: %s -mode client -target 目标IP [-tcp 端口] [-udp 端口] [-duration 秒] [-interval 秒]\n\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, "参数说明:\n")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
fmt.Fprintf(os.Stderr, "\n示例:\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " # 启动服务端,使用默认端口\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " %s -mode server\n\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " # 启动服务端,自定义端口\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " %s -mode server -tcp 8001 -udp 8002\n\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " # 启动客户端,单次测试60秒\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " %s -mode client -target 192.168.1.100 -duration 60 -interval 0\n\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " # 启动客户端,每小时测试一次\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " %s -mode client -target 192.168.1.100 -interval 3600\n\n", os.Args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// 验证参数
|
||||||
|
if *mode == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "错误: 必须指定运行模式 -mode server 或 -mode client\n\n")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *mode {
|
||||||
|
case "server":
|
||||||
|
// 服务端模式
|
||||||
|
server := NewNetworkServer(*tcpPort, *udpPort)
|
||||||
|
server.Start()
|
||||||
|
|
||||||
|
case "client":
|
||||||
|
// 客户端模式
|
||||||
|
if *targetHost == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "错误: 客户端模式必须指定 -target 参数\n\n")
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := NewNetworkClient(*targetHost, *tcpPort, *udpPort, time.Duration(*testDuration)*time.Second)
|
||||||
|
|
||||||
|
if *interval == 0 {
|
||||||
|
// 单次执行
|
||||||
|
log.Printf("开始单次网络质量测试...")
|
||||||
|
|
||||||
|
if err := client.testTCPLatency(); err != nil {
|
||||||
|
log.Printf("TCP测试错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.testUDPLatency(); err != nil {
|
||||||
|
log.Printf("UDP测试错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hops, err := client.performTraceroute()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Traceroute错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.generateReport(hops); err != nil {
|
||||||
|
log.Printf("报告生成错误: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 定时执行
|
||||||
|
log.Printf("开始定时网络质量监控,间隔: %d秒", *interval)
|
||||||
|
client.RunScheduledTests(time.Duration(*interval) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "错误: 无效的运行模式 '%s',必须是 'server' 或 'client'\n\n", *mode)
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
407
1-代理Xray/99-网络质量分析/net_quality_monitor.go
Normal file
407
1-代理Xray/99-网络质量分析/net_quality_monitor.go
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
//
|
||||||
|
//import (
|
||||||
|
// "encoding/binary"
|
||||||
|
// "encoding/json"
|
||||||
|
// "flag"
|
||||||
|
// "fmt"
|
||||||
|
// "io"
|
||||||
|
// "log"
|
||||||
|
// "net"
|
||||||
|
// "os"
|
||||||
|
// "sync"
|
||||||
|
// "time"
|
||||||
|
//)
|
||||||
|
//
|
||||||
|
//// 配置常量
|
||||||
|
//const (
|
||||||
|
// ProtocolTCP = "tcp"
|
||||||
|
// ProtocolUDP = "udp"
|
||||||
|
// PacketSize = 64 // 探测包大小
|
||||||
|
// LossTestCount = 20 // 每次丢包测试发送的数据包数量
|
||||||
|
// TraceMaxTTL = 30 // 路由追踪最大跳数
|
||||||
|
// ReportFileName = "network_quality_report.log"
|
||||||
|
//)
|
||||||
|
//
|
||||||
|
//// 命令行参数
|
||||||
|
//var (
|
||||||
|
// mode = flag.String("mode", "client", "运行模式: server 或 client")
|
||||||
|
// targetIP = flag.String("target", "127.0.0.1", "目标IP地址 (客户端模式填写服务端的IP)")
|
||||||
|
// tcpPort = flag.String("tcp-port", "8080", "TCP监听/连接端口")
|
||||||
|
// udpPort = flag.String("udp-port", "8081", "UDP监听/连接端口")
|
||||||
|
// interval = flag.Int("interval", 10, "测试间隔时间(秒)")
|
||||||
|
// doTrace = flag.Bool("trace", false, "是否执行路由追踪 (可能较慢)")
|
||||||
|
//)
|
||||||
|
//
|
||||||
|
//// TestResult 单次测试结果报告
|
||||||
|
//type TestResult struct {
|
||||||
|
// Timestamp string `json:"timestamp"`
|
||||||
|
// Target string `json:"target"`
|
||||||
|
// TCPLatencyMs float64 `json:"tcp_latency_ms"` // TCP 往返时延
|
||||||
|
// TCPJitterMs float64 `json:"tcp_jitter_ms"` // 抖动
|
||||||
|
// LossRateAtoB float64 `json:"loss_rate_a_to_b"` // A到B丢包率 0.0 - 1.0
|
||||||
|
// LossRateBtoA float64 `json:"loss_rate_b_to_a"` // B到A丢包率 0.0 - 1.0 (模拟)
|
||||||
|
// TraceRoute []string `json:"traceroute,omitempty"` // 路由路径
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Global logger
|
||||||
|
//var logger *log.Logger
|
||||||
|
//
|
||||||
|
//// C:\Users\wddsh\go\bin\gox.exe -osarch="linux/amd64" -output "build/agent-wdd_{{.OS}}_{{.Arch}}"
|
||||||
|
//// rm -rf netmonitor_linux_amd64
|
||||||
|
//// chmod +x netmonitor_linux_amd64 && ./netmonitor_linux_amd64 version
|
||||||
|
//
|
||||||
|
//// arm64
|
||||||
|
//// C:\Users\wddsh\go\bin\gox.exe -osarch="linux/arm64" -output "build/netmonitor_{{.OS}}_{{.Arch}}"
|
||||||
|
//func main() {
|
||||||
|
// flag.Parse()
|
||||||
|
//
|
||||||
|
// // 初始化日志
|
||||||
|
// file, err := os.OpenFile(ReportFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Printf("无法创建日志文件: %v\n", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// defer file.Close()
|
||||||
|
//
|
||||||
|
// // 同时输出到控制台和文件
|
||||||
|
// multiWriter := io.MultiWriter(os.Stdout, file)
|
||||||
|
// logger = log.New(multiWriter, "", log.LstdFlags)
|
||||||
|
//
|
||||||
|
// if *mode == "server" {
|
||||||
|
// runServer()
|
||||||
|
// } else {
|
||||||
|
// runClient()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// ======================= 服务端逻辑 (Host B) =======================
|
||||||
|
//
|
||||||
|
//func runServer() {
|
||||||
|
// logger.Println("=== 启动主机 B (Server Mode) ===")
|
||||||
|
// var wg sync.WaitGroup
|
||||||
|
// wg.Add(2)
|
||||||
|
//
|
||||||
|
// // 1. 启动 TCP Echo Server (用于延迟测试和信令)
|
||||||
|
// go func() {
|
||||||
|
// defer wg.Done()
|
||||||
|
// addr := fmt.Sprintf("0.0.0.0:%s", *tcpPort)
|
||||||
|
// listener, err := net.Listen(ProtocolTCP, addr)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Fatalf("TCP 监听失败: %v", err)
|
||||||
|
// }
|
||||||
|
// logger.Printf("TCP 服务监听中: %s", addr)
|
||||||
|
//
|
||||||
|
// for {
|
||||||
|
// conn, err := listener.Accept()
|
||||||
|
// if err != nil {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// go handleTCPConnection(conn)
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
//
|
||||||
|
// // 2. 启动 UDP Server (用于丢包测试)
|
||||||
|
// go func() {
|
||||||
|
// defer wg.Done()
|
||||||
|
// addr := fmt.Sprintf("0.0.0.0:%s", *udpPort)
|
||||||
|
// udpAddr, err := net.ResolveUDPAddr(ProtocolUDP, addr)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Fatalf("UDP 地址解析失败: %v", err)
|
||||||
|
// }
|
||||||
|
// conn, err := net.ListenUDP(ProtocolUDP, udpAddr)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Fatalf("UDP 监听失败: %v", err)
|
||||||
|
// }
|
||||||
|
// logger.Printf("UDP 服务监听中: %s", addr)
|
||||||
|
// handleUDPConnection(conn)
|
||||||
|
// }()
|
||||||
|
//
|
||||||
|
// wg.Wait()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func handleTCPConnection(conn net.Conn) {
|
||||||
|
// defer conn.Close()
|
||||||
|
// // 简单的 Echo 服务:收到什么发回什么
|
||||||
|
// // 这样客户端可以通过计算发送时间和接收时间的差值来算出 RTT
|
||||||
|
// buf := make([]byte, 1024)
|
||||||
|
// for {
|
||||||
|
// conn.SetReadDeadline(time.Now().Add(5 * time.Second))
|
||||||
|
// n, err := conn.Read(buf)
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// // 原样写回
|
||||||
|
// conn.Write(buf[:n])
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func handleUDPConnection(conn *net.UDPConn) {
|
||||||
|
// // UDP 处理逻辑:
|
||||||
|
// // 1. 接收客户端发来的包(统计 A->B 丢包)
|
||||||
|
// // 2. 收到特定的 "PONG_REQUEST" 指令后,向客户端反向发送一组包(用于 B->A 测试)
|
||||||
|
//
|
||||||
|
// buf := make([]byte, 1024)
|
||||||
|
// for {
|
||||||
|
// n, remoteAddr, err := conn.ReadFromUDP(buf)
|
||||||
|
// if err != nil {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// data := string(buf[:n])
|
||||||
|
//
|
||||||
|
// // 如果收到的是反向测试请求
|
||||||
|
// if data == "TEST_B_TO_A" {
|
||||||
|
// go sendUDPBurst(conn, remoteAddr)
|
||||||
|
// }
|
||||||
|
// // 否则只是接收(用于客户端计算发送成功率,或者服务端不做处理,完全由客户端通过TCP信令协调)
|
||||||
|
// // 在本简化模型中,我们采用Echo模式来计算UDP RTT丢包,或者单向接收
|
||||||
|
// // 为了实现"B到A丢包",我们使用上面的 TEST_B_TO_A 触发器
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func sendUDPBurst(conn *net.UDPConn, addr *net.UDPAddr) {
|
||||||
|
// // 向客户端反向发送数据包
|
||||||
|
// for i := 0; i < LossTestCount; i++ {
|
||||||
|
// msg := []byte(fmt.Sprintf("SEQ:%d", i))
|
||||||
|
// conn.WriteToUDP(msg, addr)
|
||||||
|
// time.Sleep(10 * time.Millisecond) // 发送间隔,防止本地拥塞
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// ======================= 客户端逻辑 (Host A) =======================
|
||||||
|
//
|
||||||
|
//func runClient() {
|
||||||
|
// logger.Println("=== 启动主机 A (Client Mode) ===")
|
||||||
|
// logger.Printf("目标主机: %s, 周期: %d秒", *targetIP, *interval)
|
||||||
|
//
|
||||||
|
// ticker := time.NewTicker(time.Duration(*interval) * time.Second)
|
||||||
|
// defer ticker.Stop()
|
||||||
|
//
|
||||||
|
// // 立即执行一次
|
||||||
|
// performTest()
|
||||||
|
//
|
||||||
|
// for range ticker.C {
|
||||||
|
// performTest()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func performTest() {
|
||||||
|
// result := TestResult{
|
||||||
|
// Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
// Target: *targetIP,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// logger.Println("------------------------------------------------")
|
||||||
|
// logger.Printf("[%s] 开始新一轮测试...", result.Timestamp)
|
||||||
|
//
|
||||||
|
// // 1. 测试 TCP 延迟 (RTT)
|
||||||
|
// latency, jitter, err := testTCPLatency(*targetIP + ":" + *tcpPort)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Printf("TCP 连接失败: %v", err)
|
||||||
|
// } else {
|
||||||
|
// result.TCPLatencyMs = latency
|
||||||
|
// result.TCPJitterMs = jitter
|
||||||
|
// logger.Printf("TCP 延迟: %.2f ms, 抖动: %.2f ms", latency, jitter)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 2. 测试 丢包率 (双向)
|
||||||
|
// // 注意:为了精确测试 B->A,我们需要 B 配合发送
|
||||||
|
// lossA2B, lossB2A, err := testPacketLoss(*targetIP + ":" + *udpPort)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Printf("UDP 测试失败: %v", err)
|
||||||
|
// } else {
|
||||||
|
// result.LossRateAtoB = lossA2B
|
||||||
|
// result.LossRateBtoA = lossB2A
|
||||||
|
// logger.Printf("丢包率 A->B: %.1f%%, B->A: %.1f%%", lossA2B*100, lossB2A*100)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 3. (可选) 路由追踪
|
||||||
|
// if *doTrace {
|
||||||
|
// route := performTraceRoute(*targetIP, *tcpPort)
|
||||||
|
// result.TraceRoute = route
|
||||||
|
// logger.Println("路由追踪完成")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 4. 保存报告
|
||||||
|
// saveReport(result)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// testTCPLatency 发送多次 TCP 请求计算平均 RTT 和抖动
|
||||||
|
//func testTCPLatency(address string) (float64, float64, error) {
|
||||||
|
// conn, err := net.DialTimeout(ProtocolTCP, address, 3*time.Second)
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
// defer conn.Close()
|
||||||
|
//
|
||||||
|
// var rtts []float64
|
||||||
|
// count := 5 // 测试5次取平均
|
||||||
|
//
|
||||||
|
// payload := []byte("PING_PAYLOAD_DATA_CHECK_LATENCY")
|
||||||
|
// buf := make([]byte, 1024)
|
||||||
|
//
|
||||||
|
// for i := 0; i < count; i++ {
|
||||||
|
// start := time.Now()
|
||||||
|
//
|
||||||
|
// _, err := conn.Write(payload)
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// conn.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||||
|
// _, err = conn.Read(buf)
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// rtt := float64(time.Since(start).Microseconds()) / 1000.0 // ms
|
||||||
|
// rtts = append(rtts, rtt)
|
||||||
|
// time.Sleep(100 * time.Millisecond)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 计算平均值
|
||||||
|
// var sum float64
|
||||||
|
// for _, v := range rtts {
|
||||||
|
// sum += v
|
||||||
|
// }
|
||||||
|
// avg := sum / float64(len(rtts))
|
||||||
|
//
|
||||||
|
// // 计算抖动 (标准差 或 平均偏差)
|
||||||
|
// var varianceSum float64
|
||||||
|
// for _, v := range rtts {
|
||||||
|
// diff := v - avg
|
||||||
|
// varianceSum += diff * diff
|
||||||
|
// }
|
||||||
|
// jitter := varianceSum / float64(len(rtts)) // 简单方差作为抖动参考
|
||||||
|
//
|
||||||
|
// return avg, jitter, nil
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// testPacketLoss 测试 UDP 丢包
|
||||||
|
//func testPacketLoss(address string) (float64, float64, error) {
|
||||||
|
// udpAddr, err := net.ResolveUDPAddr(ProtocolUDP, address)
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
// conn, err := net.DialUDP(ProtocolUDP, nil, udpAddr)
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
// defer conn.Close()
|
||||||
|
//
|
||||||
|
// // --- A -> B 测试 ---
|
||||||
|
// // 客户端发送 N 个包,我们假设如果服务端不报错且网络通畅,这里主要测试发送端的出口和路径
|
||||||
|
// // 严格的 A->B 需要服务端计数并通过 TCP 返回结果。
|
||||||
|
// // 这里简化逻辑:我们使用 "Echo" 模式来近似 A->B->A 的丢包,或者依赖应用层超时。
|
||||||
|
// // 但为了满足"双向"需求,我们采用以下策略:
|
||||||
|
//
|
||||||
|
// // 1. 发送触发指令,让 B 发数据给 A (测试 B->A)
|
||||||
|
// // 先开启监听准备接收
|
||||||
|
// localListener, err := net.ListenUDP(ProtocolUDP, nil) // 随机端口
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, fmt.Errorf("无法开启本地 UDP 监听: %v", err)
|
||||||
|
// }
|
||||||
|
// defer localListener.Close()
|
||||||
|
//
|
||||||
|
// // 告诉服务器:请发包给我 (TEST_B_TO_A)
|
||||||
|
// // 注意:由于 NAT 存在,服务器直接回发可能需要打洞。
|
||||||
|
// // 这里假设 A 和 B 之间是连通的(如专线或公网 IP),直接发给原来的连接通常可行
|
||||||
|
// _, err = conn.Write([]byte("TEST_B_TO_A"))
|
||||||
|
// if err != nil {
|
||||||
|
// return 0, 0, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 接收 B 发来的包
|
||||||
|
// //receivedCountBtoA := 0
|
||||||
|
// localListener.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||||
|
// readBuf := make([]byte, 1024)
|
||||||
|
//
|
||||||
|
// // 快速循环读取
|
||||||
|
// startTime := time.Now()
|
||||||
|
// for time.Since(startTime) < 2*time.Second {
|
||||||
|
// // 这里有个技巧:真正的 P2P UDP 穿透较复杂。
|
||||||
|
// // 在此我们假设复用 conn 对象读取(如果这是 Connected UDP)
|
||||||
|
// // 或者 B 发回给 conn 的源端口。
|
||||||
|
// // 简单起见,我们复用 conn 来读取 echo (如果 B 是 echo server) 或者 trigger result.
|
||||||
|
// // **修正策略**:为了保证代码极简且能跑,我们将 B 设计为:收到什么回什么 (Echo)。
|
||||||
|
// // 丢包率 = (发送总数 - 接收回显总数) / 发送总数
|
||||||
|
// // 这计算的是 A->B->A 的总丢包。
|
||||||
|
// // 如果必须拆分 A->B 和 B->A,需要复杂的序列号协议。
|
||||||
|
//
|
||||||
|
// // 让我们回退到最稳健的 Echo 模式测试总丢包率,并在报告中标记为 "RTT Packet Loss"
|
||||||
|
// // 这通常足够反映链路质量。
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // --- 重新实现的稳健丢包测试 (基于 Echo) ---
|
||||||
|
// // 发送 Count 个包,看收回多少个
|
||||||
|
// successCount := 0
|
||||||
|
// for i := 0; i < LossTestCount; i++ {
|
||||||
|
// seqMsg := []byte(fmt.Sprintf("SEQ:%d", i))
|
||||||
|
// _, err := conn.Write(seqMsg)
|
||||||
|
// if err == nil {
|
||||||
|
// conn.SetReadDeadline(time.Now().Add(200 * time.Millisecond))
|
||||||
|
// n, _, err := conn.ReadFromUDP(readBuf)
|
||||||
|
// // 如果 B 实现了 TEST_B_TO_A 的特殊逻辑,这里可能会冲突。
|
||||||
|
// // 所以我们在 B 端代码里,对于非指令包,应该不回或者回显。
|
||||||
|
// // 修改 B 端:如果不是 "TEST_B_TO_A",则不做操作(单向) 或者 回显(RTT)。
|
||||||
|
// // 为了代码简单有效:我们假定 B->A 丢包率 ≈ A->B 丢包率 ≈ (1 - RTT回包率)/2
|
||||||
|
// if err == nil && n > 0 {
|
||||||
|
// successCount++
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// time.Sleep(10 * time.Millisecond)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// lossRate := 1.0 - (float64(successCount) / float64(LossTestCount))
|
||||||
|
//
|
||||||
|
// // 在简单 UDP 模型下,A->B 和 B->A 往往是对称的,或者难以区分。
|
||||||
|
// // 这里我们将结果同时赋值给两者,代表链路质量
|
||||||
|
// return lossRate, lossRate, nil
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// performTraceRoute 应用层简易路由追踪
|
||||||
|
//func performTraceRoute(target string, port string) []string {
|
||||||
|
// var hops []string
|
||||||
|
//
|
||||||
|
// // 真正的 traceroute 需要构造 IP 包并修改 TTL (需要 root 权限)。
|
||||||
|
// // 此处实现一个 "伪" traceroute 占位符,
|
||||||
|
// // 或者如果环境允许,可以调用系统命令。
|
||||||
|
// // 为了保持 Go 程序独立性,这里只做简单的连通性检查并记录。
|
||||||
|
// // 注意:非 Root 无法设置 socket IP_TTL 选项在某些系统上。
|
||||||
|
//
|
||||||
|
// hops = append(hops, "Traceroute 需要 Raw Socket 权限,在此模式下仅显示端到端跳跃")
|
||||||
|
// hops = append(hops, fmt.Sprintf("1. Local -> %s:%s (Direct/NAT)", target, port))
|
||||||
|
//
|
||||||
|
// return hops
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func saveReport(result TestResult) {
|
||||||
|
// data, err := json.Marshal(result)
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Printf("JSON 序列化失败: %v", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// // 写入文件,JSON Lines 格式
|
||||||
|
// logger.Println("保存报告到文件...")
|
||||||
|
// // logger 已经配置了 MultiWriter,所以上面的输出已经写入文件了
|
||||||
|
// // 这里我们只把纯 JSON 再次追加进去以便机器读取?
|
||||||
|
// // 为了避免日志混乱,建议只保留日志形式的报告。
|
||||||
|
// // 或者我们可以专门写一个 data 文件。
|
||||||
|
//
|
||||||
|
// f, err := os.OpenFile("net_report_data.jsonl", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
// if err == nil {
|
||||||
|
// defer f.Close()
|
||||||
|
// f.Write(data)
|
||||||
|
// f.WriteString("\n")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// 辅助工具:Int 转 Bytes
|
||||||
|
//func itob(v int) []byte {
|
||||||
|
// b := make([]byte, 8)
|
||||||
|
// binary.BigEndian.PutUint64(b, uint64(v))
|
||||||
|
// return b
|
||||||
|
//}
|
||||||
50
1-代理Xray/99-网络质量分析/使用说明.md
Normal file
50
1-代理Xray/99-网络质量分析/使用说明.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
go build -o netmonitor net_quality_monitor.go
|
||||||
|
|
||||||
|
#### 2. 部署与运行
|
||||||
|
|
||||||
|
|
||||||
|
**第一步:在主机 B 上启动服务端**
|
||||||
|
服务端将监听 TCP 28080 和 UDP 28081 端口,等待 A 的连接。
|
||||||
|
```bash
|
||||||
|
# Linux/Mac
|
||||||
|
./netmonitor -mode server -tcp 28080 -udp 28081
|
||||||
|
|
||||||
|
|
||||||
|
**第二步:在主机 A 上启动客户端**
|
||||||
|
客户端将每隔 5 秒测试一次到 140.238.52.228 的网络质量。
|
||||||
|
```bash
|
||||||
|
|
||||||
|
# 开启测试
|
||||||
|
./netmonitor -mode client -target 140.238.52.228 -tcp 28080 -udp 28081 -duration 10 -interval 60
|
||||||
|
|
||||||
|
# 德国
|
||||||
|
./netmonitor -mode client -target 43.154.83.213 -tcp 28080 -udp 28081 -duration 15 -interval 600
|
||||||
|
|
||||||
|
### 功能特点详解
|
||||||
|
|
||||||
|
1. **真实 TCP 交互**:
|
||||||
|
* 代码中的 `testTCPLatency` 函数不使用 ICMP Ping,而是通过 `net.DialTimeout` 建立完整的三次握手,并发送 Payload 数据。服务端接收并回写(Echo)。
|
||||||
|
* 计算的时间包含了:`TCP握手时间` + `数据传输时间` + `ACK时间`。这比普通的 Ping 更能反映应用程序(如 HTTP/RPC)的真实感受。
|
||||||
|
|
||||||
|
2. **UDP 丢包监测**:
|
||||||
|
* `testPacketLoss` 采用 UDP 协议。UDP 是无连接的,不保证到达。
|
||||||
|
* 客户端连续快速发送 `LossTestCount` (默认20个) 包。如果接收端(Echo模式下)没有及时返回,则判定为丢包。
|
||||||
|
* 这种方法能有效检测线路拥塞或防火墙限流情况。
|
||||||
|
|
||||||
|
3. **定时与报告**:
|
||||||
|
* 程序使用 `time.Ticker` 保证精准的执行周期。
|
||||||
|
* 结果会同时输出到 **控制台** 和 **net_quality_report.log**。
|
||||||
|
* 另外生成 **net_report_data.jsonl**,每行一个 JSON 对象,方便后续通过脚本(如 Python/ELK)进行图表分析。
|
||||||
|
|
||||||
|
4. **关于 Traceroute 的说明**:
|
||||||
|
* 我在代码中预留了 `TraceRoute` 接口。
|
||||||
|
* *注意*:在 Go 语言中实现真正的 Traceroute(修改 TTL)需要引入 `golang.org/x/net/ipv4` 包并使用 Raw Socket,这要求程序必须以 **root/管理员** 权限运行。为了保持代码作为一个简洁的“单文件”工具,且能保证在普通用户权限下运行,我没有包含 Raw Socket 代码。目前的实现是应用层层面的连通性检查。
|
||||||
|
|
||||||
|
### 报告样本
|
||||||
|
|
||||||
|
日志文件 (`net_report_data.jsonl`) 内容示例:
|
||||||
|
```json
|
||||||
|
{"timestamp":"2023-10-27 10:00:00","target":"192.168.1.200","tcp_latency_ms":12.5,"tcp_jitter_ms":1.2,"loss_rate_a_to_b":0.0,"loss_rate_b_to_a":0.0}
|
||||||
|
{"timestamp":"2023-10-27 10:00:10","target":"192.168.1.200","tcp_latency_ms":12.8,"tcp_jitter_ms":0.9,"loss_rate_a_to_b":0.05,"loss_rate_b_to_a":0.05}
|
||||||
|
|
||||||
|
你可以直接用 Excel 或 Python 读取这个文件来生成网络质量波动图。
|
||||||
@@ -30,6 +30,9 @@ export DOMAIN_NAME=xx.p2.vl.s4.107421.xyz
|
|||||||
# BitsFlow-USA-LosAngles-CN2GIA
|
# BitsFlow-USA-LosAngles-CN2GIA
|
||||||
export DOMAIN_NAME=xx.l4.ca.bg.107421.xyz
|
export DOMAIN_NAME=xx.l4.ca.bg.107421.xyz
|
||||||
|
|
||||||
|
# seoul-arm-01
|
||||||
|
export DOMAIN_NAME=office.107421.xyz
|
||||||
|
|
||||||
export CF_Token="y-OqT1Gan37vBUC1YaedmkKbsH6Kf84RH6Ve2b5x"
|
export CF_Token="y-OqT1Gan37vBUC1YaedmkKbsH6Kf84RH6Ve2b5x"
|
||||||
export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191"
|
export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191"
|
||||||
export CF_Zone_ID="511894a4f1357feb905e974e16241ebb"
|
export CF_Zone_ID="511894a4f1357feb905e974e16241ebb"
|
||||||
@@ -41,4 +44,4 @@ acme.sh --install-cert -d ${DOMAIN_NAME} --ecc \
|
|||||||
--fullchain-file /etc/nginx/conf.d/ssl_key/${DOMAIN_NAME}.cert.pem \
|
--fullchain-file /etc/nginx/conf.d/ssl_key/${DOMAIN_NAME}.cert.pem \
|
||||||
--reloadcmd "systemctl restart nginx --force"
|
--reloadcmd "systemctl restart nginx --force"
|
||||||
|
|
||||||
acme.sh --renew -d ${DOMAIN_NAME}--ecc
|
acme.sh --renew -d ${DOMAIN_NAME} --ecc
|
||||||
57
4-初始化/a-所有主机IP-host.txt
Normal file
57
4-初始化/a-所有主机IP-host.txt
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
127.0.0.1 localhost
|
||||||
|
127.0.0.1 $(hostname)
|
||||||
|
|
||||||
|
# The following lines are desirable for IPv6 capable hosts
|
||||||
|
::1 ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
ff00::0 ip6-mcastprefix
|
||||||
|
ff02::1 ip6-allnodes
|
||||||
|
ff02::2 ip6-allrouters
|
||||||
|
|
||||||
|
132.145.87.10 arm-s-1 s0
|
||||||
|
10.0.0.91 arm-s-1 s0
|
||||||
|
|
||||||
|
146.56.159.175 arm-s-2 s5
|
||||||
|
10.0.0.173 arm-s-2 s5
|
||||||
|
|
||||||
|
140.238.8.73 seoul-1 s1
|
||||||
|
10.0.0.3 seoul-1 s1
|
||||||
|
|
||||||
|
140.238.30.110 seoul-2 s2
|
||||||
|
10.0.0.14 seoul-2 s2
|
||||||
|
|
||||||
|
140.238.29.102 seoul-3 s3
|
||||||
|
10.0.0.2 seoul-3 s3
|
||||||
|
|
||||||
|
140.238.14.103 seoul-4 s4
|
||||||
|
10.0.0.3 seoul-4 s4
|
||||||
|
|
||||||
|
150.230.198.103 tokyo-0 t0
|
||||||
|
|
||||||
|
140.238.63.37 tokyo-1 t1
|
||||||
|
|
||||||
|
140.238.52.228 tokyo-2 t2
|
||||||
|
|
||||||
|
140.83.84.142 osaka-1 o1
|
||||||
|
|
||||||
|
140.83.58.96 osaka-2 o2
|
||||||
|
|
||||||
|
129.146.249.37 p1
|
||||||
|
|
||||||
|
129.146.171.163 p2
|
||||||
|
|
||||||
|
129.146.65.80 p3 arm-p-1
|
||||||
|
|
||||||
|
129.146.57.94 p4 arm-p-2
|
||||||
|
|
||||||
|
42.192.52.227 tc-sh
|
||||||
|
|
||||||
|
43.154.83.213 tc-hk
|
||||||
|
|
||||||
|
114.117.165.222 tc-cd
|
||||||
|
|
||||||
|
154.40.34.106 los-1 bits cn2-1
|
||||||
|
|
||||||
|
45.134.50.233 de-1 rare
|
||||||
|
|
||||||
|
64.69.32.106 cc-1 los-2
|
||||||
66
4-初始化/b-wdd-super-agent-初始化.sh
Normal file
66
4-初始化/b-wdd-super-agent-初始化.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
rm -f /usr/local/bin/agent-wdd
|
||||||
|
rm -f /usr/local/bin/test-shell.sh
|
||||||
|
|
||||||
|
# 支持arm64 修改即可 2025年9月2日
|
||||||
|
wget https://pan.107421.xyz/d/oracle-seoul-2/agent-wdd_linux_amd64 -O /usr/local/bin/agent-wdd
|
||||||
|
|
||||||
|
chmod +x /usr/local/bin/agent-wdd
|
||||||
|
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd info all
|
||||||
|
cat /usr/local/etc/wdd/agent-wdd-config.yaml
|
||||||
|
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base firewall
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base ssh config
|
||||||
|
/usr/local/bin/agent-wdd base ssh key
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd proxy xray install
|
||||||
|
/usr/local/bin/agent-wdd proxy vmess 22443
|
||||||
|
|
||||||
|
|
||||||
|
#bash /usr/local/bin/test-shell.sh
|
||||||
|
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd info network
|
||||||
|
/usr/local/bin/agent-wdd info cpu
|
||||||
|
/usr/local/bin/agent-wdd info mem
|
||||||
|
/usr/local/bin/agent-wdd info swap
|
||||||
|
/usr/local/bin/agent-wdd info disks
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base docker local
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd info os
|
||||||
|
/usr/local/bin/agent-wdd base docker online
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd info os
|
||||||
|
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd zsh
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base tools
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base swap
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base firewall
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base selinux
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd base sysconfig
|
||||||
|
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd download https://pan.107421.xyz/d/oracle-osaka-1/docker-amd64-20.10.15.tgz /root/wdd
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd proxy xray install
|
||||||
|
|
||||||
|
/usr/local/bin/agent-wdd proxy vmess 22443
|
||||||
|
|
||||||
|
|
||||||
|
wget https://pan.107421.xyz/d/oracle-seoul-2/test-shell.sh -qO /usr/local/bin/test-shell.sh
|
||||||
|
|
||||||
|
chmod +x /usr/local/bin/test-shell.sh
|
||||||
|
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ rm -rf /var/snap/
|
|||||||
rm -rf /var/lib/snapd/
|
rm -rf /var/lib/snapd/
|
||||||
rm -rf /snap/
|
rm -rf /snap/
|
||||||
rm -rf ~/.snap/
|
rm -rf ~/.snap/
|
||||||
|
rm -rf /root/snap/
|
||||||
|
|
||||||
# 更新软件包列表
|
# 更新软件包列表
|
||||||
apt update
|
apt update
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
剑哥你好,关于雄安交流的工作,我做了一定的工作和理解
|
|
||||||
|
|
||||||
背景是:雄安政策对于低空经济的支持还是相当大的,详见PPT;已经有竞品公司,中国电信成立团队,中国邮政的无人机快递,中国通号的低空监视防护网等各家公司的进驻;
|
|
||||||
|
|
||||||
关于工作的理解和安排,总结如下:
|
|
||||||
1. 低空经济政策顶规:我已请教何博,对于相关的工作内容有了一定的了解。
|
|
||||||
2. 市场扩展:雄安移动的资源力度,能否考虑构建北方的示范基地
|
|
||||||
3. 工作及个人安排:可以外驻交流,脱离目前工作的“舒适圈”。主体工作交由技术支撑交付团队完成
|
|
||||||
|
|
||||||
还望剑哥批评指正,一切服从组织安排。
|
|
||||||
Reference in New Issue
Block a user