Files
amnezia_web-PRO/scripts/warp-amnezia.sh
Андрей Бобырев 6f6fb5f9b9 feat: Cloudflare WARP routing for AmneziaWG
Web toggles per IPv4 peer; wgcf install script on host (no Telegram/QR).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 18:00:39 +03:00

253 lines
7.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Cloudflare WARP внутри контейнера AmneziaWG (wgcf → warp.conf → wg-quick).
# Запускать на хосте VPS от root. Без Telegram и без QR — только установка и обслуживание туннеля WARP.
# После install управление «кто выходит через WARP» — в веб-панели Amnezia Admin (раздел WARP).
set -euo pipefail
WGCF_VERSION="${WGCF_VERSION:-2.2.30}"
WGCF_BIN="${WGCF_BIN:-/root/wgcf}"
WGCF_ACCOUNT="${WGCF_ACCOUNT:-/root/wgcf-account.toml}"
WGCF_PROFILE="${WGCF_PROFILE:-/root/wgcf-profile.conf}"
usage() {
echo "Использование: $0 {install|start|stop|status|rekey} [имя_контейнера]"
echo "Переменные: AWG_CONTAINER, WARP_DIR (по умолчанию /opt/warp)"
exit 1
}
need_root() {
if [[ "${EUID:-0}" -ne 0 ]]; then
echo "Запустите от root."
exit 1
fi
}
pick_container() {
local c="${2:-${AWG_CONTAINER:-}}"
if [[ -n "$c" ]] && docker exec "$c" true 2>/dev/null; then
CONTAINER="$c"
return 0
fi
local -a found=()
while IFS= read -r n; do found+=("$n"); done < <(docker ps --format '{{.Names}}' | grep -E '^amnezia-awg2$|^amnezia-awg$' || true)
if [[ ${#found[@]} -eq 1 ]]; then
CONTAINER="${found[0]}"
return 0
fi
if [[ ${#found[@]} -gt 1 ]]; then
echo "Несколько контейнеров: ${found[*]}. Укажите вторым аргументом или AWG_CONTAINER="
exit 1
fi
echo "Не найден контейнер amnezia-awg / amnezia-awg2."
exit 1
}
load_paths() {
AWG_WARP_DIR="${WARP_DIR:-/opt/warp}"
AWG_WARP_CONF="${AWG_WARP_DIR}/warp.conf"
AWG_VPN_CONF=""
if docker exec "$CONTAINER" test -f /opt/amnezia/awg/awg0.conf 2>/dev/null; then
AWG_VPN_CONF="/opt/amnezia/awg/awg0.conf"
elif docker exec "$CONTAINER" test -f /opt/amnezia/awg/wg0.conf 2>/dev/null; then
AWG_VPN_CONF="/opt/amnezia/awg/wg0.conf"
else
for f in /opt/amnezia/awg/wg0.conf /opt/amnezia/awg/awg0.conf /etc/wireguard/wg0.conf; do
if docker exec "$CONTAINER" test -f "$f" 2>/dev/null; then
AWG_VPN_CONF="$f"
break
fi
done
fi
[[ -n "$AWG_VPN_CONF" ]] || {
echo "Не найден конфиг WireGuard/AWG в контейнере."
exit 1
}
}
install_wgcf() {
[[ -x "$WGCF_BIN" ]] && return 0
local arch wa
arch="$(uname -m)"
case "$arch" in
x86_64) wa="amd64" ;;
aarch64 | arm64) wa="arm64" ;;
armv7l) wa="armv7" ;;
*) echo "Архитектура не поддерживается: $arch"; exit 1 ;;
esac
wget -q -O "$WGCF_BIN" "https://github.com/ViRb3/wgcf/releases/download/v${WGCF_VERSION}/wgcf_${WGCF_VERSION}_linux_${wa}"
chmod +x "$WGCF_BIN"
}
ensure_account() {
if [[ ! -f "$WGCF_ACCOUNT" ]]; then
echo "Регистрация WARP (wgcf register)…"
(cd /root && yes | "$WGCF_BIN" register >/dev/null 2>&1 || true)
fi
[[ -f "$WGCF_ACCOUNT" ]] || {
echo "Не создан $WGCF_ACCOUNT"
exit 1
}
}
generate_profile() {
(cd /root && yes | "$WGCF_BIN" generate >/dev/null 2>&1 || true)
[[ -f "$WGCF_PROFILE" ]] || {
echo "Не создан $WGCF_PROFILE"
exit 1
}
}
resolve_endpoint() {
local ep
ep="$(getent ahostsv4 engage.cloudflareclient.com 2>/dev/null | awk 'NR==1{print $1}')"
[[ -n "$ep" ]] || {
echo "Не удалось резолвить engage.cloudflareclient.com"
exit 1
}
echo "$ep"
}
build_warp_conf() {
local endpoint_ip="$1"
local pk pub addr
pk="$(awk -F' = ' '/^PrivateKey = /{print $2}' "$WGCF_PROFILE")"
pub="$(awk -F' = ' '/^PublicKey = /{print $2}' "$WGCF_PROFILE")"
addr="$(awk -F' = ' '/^Address = /{print $2}' "$WGCF_PROFILE" | cut -d',' -f1)"
docker exec "$CONTAINER" sh -c "mkdir -p '$AWG_WARP_DIR'"
docker cp "$WGCF_PROFILE" "${CONTAINER}:${AWG_WARP_DIR}/wgcf-profile.conf" 2>/dev/null || true
docker exec "$CONTAINER" sh -c "cat > '$AWG_WARP_CONF' <<WARPEOF
[Interface]
PrivateKey = ${pk}
Address = ${addr}
MTU = 1280
Table = off
[Peer]
PublicKey = ${pub}
AllowedIPs = 0.0.0.0/0
Endpoint = ${endpoint_ip}:2408
PersistentKeepalive = 25
WARPEOF
chmod 600 '$AWG_WARP_CONF'"
}
warp_up() {
docker exec "$CONTAINER" sh -c "wg-quick down '$AWG_WARP_CONF' >/dev/null 2>&1 || true"
docker exec "$CONTAINER" sh -c "wg-quick up '$AWG_WARP_CONF'"
docker exec "$CONTAINER" ip addr show warp >/dev/null 2>&1 || {
echo "Интерфейс warp не поднялся."
exit 1
}
}
warp_down() {
docker exec "$CONTAINER" sh -c "wg-quick down '$AWG_WARP_CONF' 2>/dev/null || true"
}
is_installed() {
docker exec "$CONTAINER" test -f "$AWG_WARP_CONF" 2>/dev/null
}
is_running() {
docker exec "$CONTAINER" ip addr show warp >/dev/null 2>&1
}
cmd_install() {
echo "Бэкап конфигов в контейнере…"
docker exec "$CONTAINER" sh -c "
ts=\$(date +%Y%m%d-%H%M%S)
cp '$AWG_VPN_CONF' '${AWG_VPN_CONF}.bak-warp-'\$ts 2>/dev/null || true
cp /opt/amnezia/start.sh /opt/amnezia/start.sh.bak-warp-\$ts 2>/dev/null || true
true
"
install_wgcf
ensure_account
generate_profile
local ep
ep="$(resolve_endpoint)"
echo "Endpoint: $ep"
build_warp_conf "$ep"
warp_up
echo "Готово: WARP установлен. Управление клиентами — в веб-панели (раздел WARP)."
}
cmd_status() {
if is_installed; then
echo "warp.conf: есть ($AWG_WARP_CONF)"
else
echo "warp.conf: нет — выполните: $0 install"
exit 1
fi
if is_running; then
echo "Интерфейс warp: поднят"
docker exec "$CONTAINER" wg show warp 2>/dev/null || true
echo -n "Внешний IP через WARP: "
docker exec "$CONTAINER" sh -c "curl -fsS --interface warp --connect-timeout 4 https://ifconfig.me 2>/dev/null || echo '?'"
echo
else
echo "Интерфейс warp: опущен ($0 start)"
fi
}
cmd_rekey() {
is_installed || {
echo "Сначала install."
exit 1
}
warp_down || true
rm -f "$WGCF_ACCOUNT"
ensure_account
generate_profile
local ep
ep="$(resolve_endpoint)"
build_warp_conf "$ep"
warp_up
echo "Ключ WARP перевыпущен. Заново отметьте клиентов в веб-панели и примените маршрутизацию."
}
[[ "${1:-}" ]] || usage
need_root
command -v docker >/dev/null || {
echo "Нужен docker в PATH."
exit 1
}
CMD="$1"
pick_container "$@"
load_paths
case "$CMD" in
install)
if is_installed && is_running; then
echo "Уже установлен и работает."
exit 0
fi
if is_installed && ! is_running; then
echo "Конфиг есть — поднимаю интерфейс…"
warp_up
exit 0
fi
cmd_install
;;
start)
is_installed || {
echo "Нет warp.conf — сначала install."
exit 1
}
is_running && {
echo "Уже работает."
exit 0
}
warp_up
echo "WARP поднят."
;;
stop)
is_installed || exit 0
warp_down
echo "WARP остановлен."
;;
status) cmd_status ;;
rekey) cmd_rekey ;;
*) usage ;;
esac