Skip to content

Instantly share code, notes, and snippets.

@xjoker
Last active May 20, 2025 03:14
Show Gist options
  • Save xjoker/5fe9fdc7f08b2bb48ff4dac4245920ba to your computer and use it in GitHub Desktop.
Save xjoker/5fe9fdc7f08b2bb48ff4dac4245920ba to your computer and use it in GitHub Desktop.
xray_auto_install
#!/bin/bash
# 函数:显示绿色信息
log_info() {
echo -e "\033[32m[INFO] $1\033[0m"
}
# 函数:显示黄色警告
log_warn() {
echo -e "\033[33m[WARN] $1\033[0m"
}
# 函数:显示红色错误并退出
log_error_exit() {
echo -e "\033[31m[ERROR] $1\033[0m" >&2
exit 1
}
# 检查是否为 root 用户
if [ "$(id -u)" -ne 0 ]; then
log_error_exit "此脚本需要 root 权限运行。请使用 sudo 执行。"
fi
# --- 用户输入 ---
DEFAULT_REALITY_DEST_DOMAIN="www.yahoo.com" # 一个常见且高可用的域名
echo "欢迎使用 Xray (VLESS + Reality) 服务端部署脚本。"
echo "-----------------------------------------------------"
read -r -p "请输入 Xray 监听的端口 (范围 1-65535,留空则随机生成 10000-65535 之间的端口): " LISTENING_PORT
if [[ -z "$LISTENING_PORT" ]]; then
LISTENING_PORT=$(shuf -i 10000-65535 -n 1)
log_info "未指定端口,已随机生成端口: $LISTENING_PORT"
else
if ! [[ "$LISTENING_PORT" =~ ^[0-9]+$ ]] || [ "$LISTENING_PORT" -lt 1 ] || [ "$LISTENING_PORT" -gt 65535 ]; then
log_error_exit "无效的端口号: $LISTENING_PORT. 必须是 1-65535 之间的数字。"
fi
log_info "将使用端口: $LISTENING_PORT"
fi
read -r -p "请输入 Reality 'dest' 和 'serverNames' 使用的目标域名 (例如: one.one.one.one, 默认: ${DEFAULT_REALITY_DEST_DOMAIN}): " REALITY_DOMAIN
if [[ -z "$REALITY_DOMAIN" ]]; then
REALITY_DOMAIN="$DEFAULT_REALITY_DEST_DOMAIN"
fi
# Reality 'dest' 通常包含端口 443
REALITY_DEST="${REALITY_DOMAIN}:443"
# Reality 'serverNames' (用于SNI)
REALITY_SERVER_NAME="$REALITY_DOMAIN"
log_info "Reality 'dest' 将设置为: $REALITY_DEST"
log_info "Reality 'serverName' (SNI) 将设置为: $REALITY_SERVER_NAME"
echo "-----------------------------------------------------"
# --- 安装依赖 ---
log_info "正在更新软件包列表并安装依赖 (curl, unzip, jq, openssl, uuid-runtime)..."
export DEBIAN_FRONTEND=noninteractive
if ! apt-get update -y > /dev/null 2>&1; then
log_warn "apt-get update 失败,请检查网络或软件源。"
fi
if ! apt-get install -y curl unzip jq openssl uuid-runtime > /dev/null 2>&1; then
log_error_exit "依赖安装失败。请检查错误信息并手动安装 curl, unzip, jq, openssl, uuid-runtime。"
fi
log_info "依赖安装完成。"
echo "-----------------------------------------------------"
# --- 安装 Xray-core ---
log_info "正在安装/更新 Xray-core..."
# 使用 --without-logfiles 参数,让 Xray 使用 journald 记录日志
if bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) install --without-logfiles; then
log_info "Xray-core 安装/更新成功。"
else
log_error_exit "Xray-core 安装失败。"
fi
echo "-----------------------------------------------------"
# --- 生成 Xray Keys 和 IDs ---
log_info "正在生成 Reality 密钥对和客户端 ID..."
XRAY_BIN="/usr/local/bin/xray" # 确认 xray 执行文件路径
if [ ! -f "$XRAY_BIN" ]; then
log_error_exit "Xray 执行文件未找到: $XRAY_BIN"
fi
xray_key_output=$("$XRAY_BIN" x25519)
XRAY_PRIVATE_KEY=$(echo "$xray_key_output" | grep 'Private key:' | awk '{print $3}')
XRAY_PUBLIC_KEY=$(echo "$xray_key_output" | grep 'Public key:' | awk '{print $3}')
if [[ -z "$XRAY_PRIVATE_KEY" || -z "$XRAY_PUBLIC_KEY" ]]; then
log_error_exit "生成 Reality 密钥对失败。请确保 Xray 命令 ($XRAY_BIN x25519) 能正常工作。"
fi
CLIENT_UUID=$(uuidgen)
# 生成两个 shortId (16进制字符串)
SHORT_ID_1=$(openssl rand -hex 4) # 8 字符
SHORT_ID_2=$(openssl rand -hex 4) # 8 字符
SHORT_ID_3=$(openssl rand -hex 4) # 8 字符
log_info "密钥和 ID 生成完毕。"
log_info " 公钥 (Public Key): $XRAY_PUBLIC_KEY"
log_info " 客户端 UUID: $CLIENT_UUID"
log_info " Short ID 1: $SHORT_ID_1"
log_info " Short ID 2: $SHORT_ID_2"
log_info " Short ID 3: $SHORT_ID_3"
# 私钥不直接显示给用户,只写入配置文件
echo "-----------------------------------------------------"
# --- 创建 Xray 配置 ---
log_info "正在创建 Xray 配置文件..."
XRAY_CONFIG_DIR="/usr/local/etc/xray"
XRAY_CONFIG_PATH="${XRAY_CONFIG_DIR}/config.json"
mkdir -p "$XRAY_CONFIG_DIR"
# 使用 cat 和 EOF 创建 JSON 配置文件
cat > "$XRAY_CONFIG_PATH" <<EOL
{
"log": {
"loglevel": "warning"
},
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "blocked"
},
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "blocked"
}
]
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": ${LISTENING_PORT},
"protocol": "vless",
"settings": {
"clients": [
{
"id": "${CLIENT_UUID}",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none"
},
"tag":"inbound-${LISTENING_PORT}",
"mux": {
"enabled": true,
"concurrency": 8
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "${REALITY_DEST}",
"xver": 0,
"serverNames": ["${REALITY_SERVER_NAME}"],
"privateKey": "${XRAY_PRIVATE_KEY}",
"minClientVer": "",
"maxClientVer": "",
"maxTimeDiff": 0,
"shortIds": ["${SHORT_ID_1}", "${SHORT_ID_2}", "${SHORT_ID_3}"]
}
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"metadataOnly": false
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
]
}
EOL
# 验证 JSON 配置文件格式 (需要 jq)
if command -v jq > /dev/null && jq . "$XRAY_CONFIG_PATH" > /dev/null 2>&1; then
log_info "Xray 配置文件创建成功: $XRAY_CONFIG_PATH"
else
# 如果 jq 不可用或 JSON 无效,给出警告,但不一定退出,Xray 自身也会校验
log_warn "Xray 配置文件已创建,但无法使用 jq进行 JSON 格式校验。"
log_warn "请在启动服务后检查 Xray 日志确认配置是否正确。"
cat "$XRAY_CONFIG_PATH" # 打印配置内容供检查
fi
echo "-----------------------------------------------------"
# --- 重启并设置 Xray 服务 ---
log_info "正在启动/重启 Xray 服务并设置为开机自启..."
systemctl enable xray > /dev/null 2>&1
if systemctl restart xray; then
log_info "Xray 服务启动/重启成功。"
# 等待服务稳定
sleep 3
if systemctl is-active --quiet xray; then
log_info "Xray 服务当前状态: active (running)"
else
log_warn "Xray 服务启动后未能保持运行状态。请检查日志:"
log_warn " systemctl status xray -l --no-pager"
log_warn " journalctl -u xray --no-pager -l -n 50" # 显示最近50条日志
# 不要在此处退出,允许用户查看输出的配置信息
fi
else
log_warn "Xray 服务启动/重启失败。请检查配置文件和日志。"
log_warn " 配置文件路径: $XRAY_CONFIG_PATH"
log_warn " 查看 Xray 状态: systemctl status xray -l --no-pager"
log_warn " 查看 Xray 日志: journalctl -u xray --no-pager -l -n 50"
# 不要在此处退出,允许用户查看输出的配置信息
fi
echo "-----------------------------------------------------"
# --- 输出客户端连接参数 ---
# 尝试自动获取服务器公网 IP
SERVER_IP=$(curl -s https://api.ipify.org || curl -s https://checkip.amazonaws.com || curl -s http://v4.ident.me || hostname -I | awk '{print $1}')
if [[ -z "$SERVER_IP" ]]; then
log_warn "未能自动获取服务器公网 IP 地址。请手动替换下面的 <服务器IP地址>。"
SERVER_IP="<服务器IP地址>"
fi
# TLS 指纹,'chrome' 是一个常见的 Reality 默认值
CLIENT_FINGERPRINT="chrome"
# 构建 VLESS URI
# 格式: vless://<uuid>@<address>:<port>?type=tcp&security=reality&sni=<serverName>&fp=<fingerprint>&pbk=<publicKey>&sid=<shortId>&flow=xtls-rprx-vision
VLESS_LINK_1="vless://${CLIENT_UUID}@${SERVER_IP}:${LISTENING_PORT}?type=tcp&security=reality&sni=${REALITY_SERVER_NAME}&fp=${CLIENT_FINGERPRINT}&pbk=${XRAY_PUBLIC_KEY}&sid=${SHORT_ID_1}&flow=xtls-rprx-vision"
VLESS_LINK_2="vless://${CLIENT_UUID}@${SERVER_IP}:${LISTENING_PORT}?type=tcp&security=reality&sni=${REALITY_SERVER_NAME}&fp=${CLIENT_FINGERPRINT}&pbk=${XRAY_PUBLIC_KEY}&sid=${SHORT_ID_2}&flow=xtls-rprx-vision"
VLESS_LINK_3="vless://${CLIENT_UUID}@${SERVER_IP}:${LISTENING_PORT}?type=tcp&security=reality&sni=${REALITY_SERVER_NAME}&fp=${CLIENT_FINGERPRINT}&pbk=${XRAY_PUBLIC_KEY}&sid=${SHORT_ID_3}&flow=xtls-rprx-vision"
echo ""
echo -e "\033[1;32m==================================================================\033[0m"
echo -e "\033[1;32m ✅ Xray 服务端部署完成! \033[0m"
echo -e "\033[1;32m==================================================================\033[0m"
echo ""
echo -e "\033[1;34m📋 客户端连接参数:\033[0m"
echo "------------------------------------------------------------------"
echo -e " \033[33m协议 (Protocol):\033[0m VLESS"
echo -e " \033[33m地址 (Address):\033[0m $SERVER_IP"
echo -e " \033[33m端口 (Port):\033[0m $LISTENING_PORT"
echo -e " \033[33m用户 ID (UUID):\033[0m $CLIENT_UUID"
echo -e " \033[33m流控 (Flow):\033[0m xtls-rprx-vision"
echo -e " \033[33m传输方式 (Network):\033[0m tcp"
echo -e " \033[33m安全类型 (Security):\033[0m reality"
echo -e " \033[33mSNI (Server Name):\033[0m $REALITY_SERVER_NAME"
echo -e " \033[33m公钥 (PublicKey/pbk):\033[0m $XRAY_PUBLIC_KEY"
echo -e " \033[33mShort ID (sid):\033[0m $SHORT_ID_1 or $SHORT_ID_2 or $SHORT_ID_3"
echo -e " \033[33m指纹 (Fingerprint/fp):\033[0m $CLIENT_FINGERPRINT (客户端可选: chrome, firefox, safari, ios, android, random等)"
echo -e " \033[33m目标域名 (SpiderX/dest):\033[0m $REALITY_DEST (此参数通常在客户端的 Reality 设置中填写,而不是直接在链接中)"
echo "------------------------------------------------------------------"
echo ""
echo -e "\033[1;34m🔗 VLESS 链接 (使用 Short ID: ${SHORT_ID_1}):\033[0m"
echo -e "\033[36m$VLESS_LINK_1\033[0m"
echo ""
echo -e "\033[1;34m🔗 VLESS 链接 (使用 Short ID: ${SHORT_ID_2}):\033[0m"
echo -e "\033[36m$VLESS_LINK_2\033[0m"
echo ""
echo -e "\033[1;34m🔗 VLESS 链接 (使用 Short ID: ${SHORT_ID_3}):\033[0m"
echo -e "\033[36m$VLESS_LINK_3\033[0m"
echo ""
echo "------------------------------------------------------------------"
echo -e "\033[1;31m⚠️ 重要提示:\033[0m"
echo -e "1. 如果您启用了防火墙 (如 ufw), 请确保开放 TCP 端口 \033[33m${LISTENING_PORT}\033[0m。"
echo -e " 例如: \033[33msudo ufw allow ${LISTENING_PORT}/tcp\033[0m 然后 \033[33msudo ufw reload\033[0m"
echo -e "2. Reality 的 'dest' (目标域名) 设置为 \033[33m${REALITY_DEST}\033[0m,'serverNames' (SNI) 设置为 \033[33m${REALITY_SERVER_NAME}\033[0m。"
echo " 客户端的 SNI、PublicKey、ShortID 必须与服务器配置严格匹配。"
echo "3. 客户端的 TLS 指纹 (Fingerprint) 可以根据需要选择,如 'chrome', 'firefox', 'safari', 'ios', 'random'。"
echo "4. 如果服务启动失败或运行不正常,请检查 Xray 日志:"
echo -e " \033[33msystemctl status xray -l --no-pager\033[0m"
echo -e " \033[33mjournalctl -u xray --no-pager -l -n 100\033[0m (查看最近100条日志)"
echo -e "\033[1;32m==================================================================\033[0m"
echo ""
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment