212 lines
7.0 KiB
Bash
Executable File
212 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# sdm-xray — установка сервера stealth-туннеля на свежую Ubuntu VPS.
|
|
# Использование:
|
|
# bash <(curl -fsSL https://git.my-handbook.ru/ded_ikar/sdm-xray/raw/main/install.sh) <domain>
|
|
# где <domain> — ваш домен, A-запись которого указывает на IP этой VPS.
|
|
set -euo pipefail
|
|
|
|
DOMAIN="${1:-}"
|
|
if [ -z "$DOMAIN" ]; then
|
|
echo "Usage: install.sh <domain>"
|
|
echo " domain — домен, указывающий на IP этой VPS (нужен для Let's Encrypt)"
|
|
exit 1
|
|
fi
|
|
|
|
GITEA="https://git.my-handbook.ru/ded_ikar/sdm-xray"
|
|
VERSION="v0.2.1"
|
|
BIN="xray-stealth-server-linux-amd64"
|
|
PANEL_BIN="sdm-panel-linux-amd64"
|
|
INSTALL_DIR="/usr/local/xray"
|
|
DATA_DIR="/etc/xray"
|
|
WEBROOT="/var/www/html"
|
|
VPS_IP="$(curl -fsSL --max-time 10 https://api.ipify.org 2>/dev/null || echo UNKNOWN)"
|
|
|
|
echo "=== sdm-xray installer ${VERSION} ==="
|
|
echo "domain: $DOMAIN vps-ip: $VPS_IP"
|
|
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
echo "=== apt: deps ==="
|
|
apt-get update -qq
|
|
apt-get install -y -qq curl openssl jq nginx certbot >/dev/null 2>&1
|
|
|
|
echo "=== download server binary + geo files ==="
|
|
mkdir -p "$INSTALL_DIR" "$DATA_DIR" "$WEBROOT"
|
|
curl -fsSL -o "$INSTALL_DIR/xray" "$GITEA/releases/download/$VERSION/$BIN"
|
|
curl -fsSL -o "$INSTALL_DIR/geoip.dat" "$GITEA/releases/download/$VERSION/geoip.dat"
|
|
curl -fsSL -o "$INSTALL_DIR/geosite.dat" "$GITEA/releases/download/$VERSION/geosite.dat"
|
|
chmod 755 "$INSTALL_DIR/xray"
|
|
"$INSTALL_DIR/xray" version | sed -n '1p'
|
|
|
|
echo "=== generate secrets ==="
|
|
UUID="$(cat /proc/sys/kernel/random/uuid)"
|
|
KEY="$(openssl rand -hex 8)"
|
|
echo "$UUID" > "$DATA_DIR/uuid"
|
|
echo "$KEY" > "$DATA_DIR/key"
|
|
|
|
echo "=== nginx on 80 (acme) ==="
|
|
mkdir -p "$WEBROOT/.well-known/acme-challenge"
|
|
cat > /etc/nginx/sites-available/sdm <<'NGX'
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name DOMAIN;
|
|
root /var/www/html;
|
|
index index.html;
|
|
location /.well-known/acme-challenge/ {
|
|
alias /var/www/html/.well-known/acme-challenge/;
|
|
}
|
|
location / {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
NGX
|
|
sed -i "s/DOMAIN/$DOMAIN/" /etc/nginx/sites-available/sdm
|
|
ln -sf /etc/nginx/sites-available/sdm /etc/nginx/sites-enabled/sdm
|
|
rm -f /etc/nginx/sites-enabled/default
|
|
nginx -t >/dev/null 2>&1 && systemctl reload nginx
|
|
|
|
echo "=== Let's Encrypt cert ==="
|
|
certbot certonly --webroot -w "$WEBROOT" -d "$DOMAIN" \
|
|
--register-unsafely-without-email --agree-tos --no-eff-email -n \
|
|
--cert-name "$DOMAIN" >/dev/null 2>&1 || true
|
|
CERT_DIR="/etc/letsencrypt/live/$DOMAIN"
|
|
if [ ! -f "$CERT_DIR/fullchain.pem" ]; then
|
|
echo "ERROR: сертификат не получен. Проверьте, что $DOMAIN -> $VPS_IP и порт 80 открыт."
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== xray config ==="
|
|
cat > "$DATA_DIR/config.json" <<EOF
|
|
{
|
|
"log": {"loglevel": "warning"},
|
|
"routing": {
|
|
"rules": [
|
|
{"port": "443", "network": "udp", "outboundTag": "block"},
|
|
{"ip": ["geoip:private"], "outboundTag": "block"}
|
|
]
|
|
},
|
|
"inbounds": [
|
|
{
|
|
"listen": "0.0.0.0",
|
|
"port": 443,
|
|
"protocol": "vless",
|
|
"settings": {"clients": [{"id": "$UUID", "level": 0}], "decryption": "none"},
|
|
"streamSettings": {
|
|
"network": "stealth",
|
|
"stealthSettings": {
|
|
"key": "$KEY", "padMax": 2048, "padProb": 50, "paceMs": 0, "paceJitterMs": 0,
|
|
"paths": ["/api/t04d12b46/", "/api/v2/telemetry/", "/collect/", "/ingest/"],
|
|
"ports": [443], "bps": 0, "target": "https://www.iana.org",
|
|
"padProfile": "browser", "retries": 3
|
|
},
|
|
"security": "tls",
|
|
"tlsSettings": {
|
|
"certificates": [
|
|
{"certificateFile": "$CERT_DIR/fullchain.pem", "keyFile": "$CERT_DIR/privkey.pem"}
|
|
]
|
|
}
|
|
},
|
|
"sniffing": {"enabled": true, "destOverride": ["http","tls","quic"]}
|
|
}
|
|
],
|
|
"outbounds": [
|
|
{"protocol": "freedom", "tag": "direct"},
|
|
{"protocol": "blackhole", "tag": "block"}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
echo "=== systemd ==="
|
|
cat > /etc/systemd/system/xray.service <<'UNIT'
|
|
[Unit]
|
|
Description=sdm-xray stealth tunnel
|
|
After=network.target nss-lookup.target
|
|
|
|
[Service]
|
|
ExecStart=/usr/local/xray/xray run -c /etc/xray/config.json
|
|
Restart=on-failure
|
|
RestartPreventExitStatus=23
|
|
LimitNOFILE=65535
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
UNIT
|
|
systemctl daemon-reload
|
|
systemctl enable xray >/dev/null 2>&1 || true
|
|
systemctl restart xray
|
|
sleep 1
|
|
if ! systemctl is-active xray >/dev/null 2>&1; then
|
|
echo "ERROR: xray не запустился:"; journalctl -u xray -n 20 --no-pager || true; exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "=== INSTALLED OK ==="
|
|
echo "uuid: $UUID"
|
|
echo "key: $KEY"
|
|
|
|
# --- panel ---
|
|
echo
|
|
echo "=== control panel (sdm-panel) ==="
|
|
curl -fsSL -o "$INSTALL_DIR/sdm-panel" "$GITEA/releases/download/$VERSION/$PANEL_BIN"
|
|
chmod 755 "$INSTALL_DIR/sdm-panel"
|
|
PANEL_PASS="$(openssl rand -hex 8)"
|
|
cat > "$DATA_DIR/panel.json" <<EOF
|
|
{
|
|
"bind": "127.0.0.1:8080",
|
|
"password": "$PANEL_PASS"
|
|
}
|
|
EOF
|
|
chmod 600 "$DATA_DIR/panel.json"
|
|
cat > /etc/systemd/system/sdm-panel.service <<'PANEL'
|
|
[Unit]
|
|
Description=sdm-xray control panel
|
|
After=network.target xray.service
|
|
|
|
[Service]
|
|
ExecStart=/usr/local/xray/sdm-panel
|
|
Restart=on-failure
|
|
RestartSec=3
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
PANEL
|
|
systemctl daemon-reload
|
|
systemctl enable sdm-panel >/dev/null 2>&1 || true
|
|
systemctl restart sdm-panel
|
|
sleep 1
|
|
echo "panel password: $PANEL_PASS (запомни его — больше не покажем)"
|
|
echo "Доступ к панели (SSH-туннель, шифрованный):"
|
|
echo " ssh -L 8080:127.0.0.1:8080 root@<vps-ip>"
|
|
echo " затем открой в браузере http://localhost:8080 (login: admin / пароль выше)"
|
|
|
|
echo
|
|
echo "=== client config (client-stealth.json) ==="
|
|
cat <<CFG
|
|
{
|
|
"log": {"loglevel": "warning"},
|
|
"inbounds": [
|
|
{"listen": "127.0.0.1", "port": 10808, "protocol": "socks"},
|
|
{"listen": "127.0.0.1", "port": 10809, "protocol": "http"}
|
|
],
|
|
"outbounds": [
|
|
{
|
|
"protocol": "vless",
|
|
"settings": {"vnext": [{"address": "$DOMAIN", "port": 443, "users": [{"id": "$UUID", "encryption": "none"}]}]},
|
|
"streamSettings": {
|
|
"network": "stealth",
|
|
"stealthSettings": {"key": "$KEY", "padMax": 2048, "padProb": 50, "paceMs": 0, "paceJitterMs": 0, "paths": ["/api/t04d12b46/", "/api/v2/telemetry/", "/collect/", "/ingest/"], "ports": [443], "bps": 0},
|
|
"security": "tls",
|
|
"tlsSettings": {"serverName": "$DOMAIN", "fingerprint": "chrome"}
|
|
}
|
|
},
|
|
{"protocol": "freedom", "tag": "direct"}
|
|
]
|
|
}
|
|
CFG
|
|
echo
|
|
echo "=== client binaries ==="
|
|
echo " Windows: $GITEA/releases/download/$VERSION/xray-stealth-client-windows-amd64.exe"
|
|
echo " Router: $GITEA/releases/download/$VERSION/xray-stealth-client-linux-arm64"
|
|
echo " Panel: $GITEA/releases/download/$VERSION/sdm-panel-linux-amd64"
|