feat: Добавлены веб-интерфейс управления и скрипт для генерации клиентских конфигураций VLESS из URL.
This commit is contained in:
28
README.md
28
README.md
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
- Пользователи, которым нужен VPN для работы или доступа к заблокированным ресурсам
|
- Пользователи, которым нужен VPN для работы или доступа к заблокированным ресурсам
|
||||||
- Разработчики, которые хотят направить трафик VS Code или других программ через VPN
|
- Разработчики, которые хотят направить трафик VS Code или других программ через VPN
|
||||||
- Люди, которые получили "ссылку подписки" от VPN-провайдера
|
- Люди, которые получили VLESS ссылку от VPN-провайдера
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -57,9 +57,7 @@
|
|||||||
|
|
||||||
### Что вам понадобится
|
### Что вам понадобится
|
||||||
|
|
||||||
1. **VPN-ссылка** — получите её от вашего VPN-провайдера. Бывает двух видов:
|
1. **VLESS-ссылка** — получите её от вашего VPN-провайдера. Она начинается с `vless://...`
|
||||||
- **Прямая ссылка**: начинается с `vless://...`
|
|
||||||
- **Ссылка подписки**: обычный URL (начинается с `https://...`), который содержит список серверов
|
|
||||||
|
|
||||||
2. **Docker** — программа для запуска изолированных приложений
|
2. **Docker** — программа для запуска изолированных приложений
|
||||||
- [Скачать Docker Desktop](https://www.docker.com/products/docker-desktop/) (бесплатно)
|
- [Скачать Docker Desktop](https://www.docker.com/products/docker-desktop/) (бесплатно)
|
||||||
@@ -90,7 +88,7 @@ docker compose up -d
|
|||||||
### После запуска
|
### После запуска
|
||||||
|
|
||||||
1. **Откройте веб-интерфейс**: http://localhost:3456
|
1. **Откройте веб-интерфейс**: http://localhost:3456
|
||||||
2. **Вставьте вашу VPN-ссылку** (vless:// или https://)
|
2. **Вставьте вашу VLESS-ссылку** (vless://)
|
||||||
3. **Нажмите "Применить"**
|
3. **Нажмите "Применить"**
|
||||||
4. Готово! Прокси работает на порту **8082**
|
4. Готово! Прокси работает на порту **8082**
|
||||||
|
|
||||||
@@ -174,24 +172,14 @@ http.proxy: http://127.0.0.1:8082
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔄 Смена сервера
|
|
||||||
|
|
||||||
### Через веб-интерфейс (рекомендуется)
|
|
||||||
|
### Через веб-интерфейс
|
||||||
|
|
||||||
1. Откройте http://localhost:3456
|
1. Откройте http://localhost:3456
|
||||||
2. Вставьте новую ссылку
|
2. Вставьте новую VLESS ссылку
|
||||||
3. Нажмите "Применить"
|
3. Нажмите "Применить"
|
||||||
|
|
||||||
### Через консоль (если нужен выбор из списка)
|
|
||||||
|
|
||||||
Если у вас ссылка подписки с несколькими серверами:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker exec -it sing-proxy ./menu.sh "https://ваша-ссылка-подписки..."
|
|
||||||
```
|
|
||||||
|
|
||||||
Появится список серверов для выбора.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Управление контейнером
|
## 📋 Управление контейнером
|
||||||
@@ -250,7 +238,7 @@ docker compose up -d
|
|||||||
**Решение**:
|
**Решение**:
|
||||||
|
|
||||||
- Попробуйте другой сервер — вставьте другую ссылку в веб-интерфейсе
|
- Попробуйте другой сервер — вставьте другую ссылку в веб-интерфейсе
|
||||||
- Проверьте, что ссылка подписки актуальна
|
- Проверьте, что VLESS ссылка актуальна
|
||||||
|
|
||||||
### Как узнать, работает ли VPN?
|
### Как узнать, работает ли VPN?
|
||||||
|
|
||||||
@@ -311,7 +299,7 @@ environment:
|
|||||||
| **Контейнер** | Изолированное приложение со всеми необходимыми компонентами |
|
| **Контейнер** | Изолированное приложение со всеми необходимыми компонентами |
|
||||||
| **VLESS** | Современный протокол VPN-соединения |
|
| **VLESS** | Современный протокол VPN-соединения |
|
||||||
| **Reality** | Технология маскировки VPN-трафика под обычный интернет-трафик |
|
| **Reality** | Технология маскировки VPN-трафика под обычный интернет-трафик |
|
||||||
| **Ссылка подписки** | URL, который содержит список VPN-серверов и их настройки |
|
|
||||||
| **Порт** | "Номер двери" для сетевых соединений. Прокси: 8082, Веб-интерфейс: 3456 |
|
| **Порт** | "Номер двери" для сетевых соединений. Прокси: 8082, Веб-интерфейс: 3456 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -19,60 +19,12 @@ if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect if input is a subscription link (HTTP/HTTPS)
|
# Check if input starts with vless://
|
||||||
if [[ "$URL_INPUT" =~ ^http ]]; then
|
if [[ "$URL_INPUT" != vless://* ]]; then
|
||||||
echo "Detecting subscription link..."
|
echo "Error: Only vless:// URLs are supported." >&2
|
||||||
|
|
||||||
# Build URL with client parameter for APIs that require it
|
|
||||||
SUB_URL="$URL_INPUT"
|
|
||||||
|
|
||||||
# Try fetching as-is first
|
|
||||||
SUB_CONTENT=$(curl -sSL "$SUB_URL")
|
|
||||||
|
|
||||||
# If empty, try adding client parameter (some APIs require this)
|
|
||||||
if [[ -z "$SUB_CONTENT" ]]; then
|
|
||||||
echo "Empty response, trying with client=v2rayng parameter..."
|
|
||||||
if [[ "$SUB_URL" == *"?"* ]]; then
|
|
||||||
SUB_URL="${URL_INPUT}&client=v2rayng"
|
|
||||||
else
|
|
||||||
SUB_URL="${URL_INPUT}?client=v2rayng"
|
|
||||||
fi
|
|
||||||
SUB_CONTENT=$(curl -sSL "$SUB_URL")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$SUB_CONTENT" ]]; then
|
|
||||||
echo "Error: Failed to download subscription from $SUB_URL" >&2
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if base64 encoded (simple check: no spaces, looks like b64)
|
|
||||||
# Trying to decode. If fails, assume it's plain text lists
|
|
||||||
if DECODED=$(echo "$SUB_CONTENT" | base64 -d 2>/dev/null); then
|
|
||||||
echo "Decoded base64 subscription."
|
|
||||||
RAW_CONFIGS="$DECODED"
|
|
||||||
else
|
|
||||||
echo "Using plain text subscription."
|
|
||||||
RAW_CONFIGS="$SUB_CONTENT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Find first vless reality link (vless://... + security=reality or just vless://)
|
|
||||||
# We try to find one that explicitly has reality, if not, pick ANY vless
|
|
||||||
TARGET_URL=$(echo "$RAW_CONFIGS" | grep -o 'vless://[^[:space:]]*' | grep 'security=reality' | head -n 1)
|
|
||||||
|
|
||||||
if [[ -z "$TARGET_URL" ]]; then
|
|
||||||
echo "No VLESS Reality link found, trying any VLESS..."
|
|
||||||
TARGET_URL=$(echo "$RAW_CONFIGS" | grep -o 'vless://[^[:space:]]*' | head -n 1)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$TARGET_URL" ]]; then
|
|
||||||
echo "Error: No VLESS URL found in subscription." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Selected URL from subscription: ${TARGET_URL:0:30}..."
|
|
||||||
URL_INPUT="$TARGET_URL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Strip scheme
|
# Strip scheme
|
||||||
URL_NOSCHEME=${URL_INPUT#vless://}
|
URL_NOSCHEME=${URL_INPUT#vless://}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@@ -113,8 +114,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.6; }
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
@@ -223,7 +231,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
@@ -242,6 +252,7 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-8px);
|
transform: translateY(-8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@@ -346,6 +357,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -365,17 +377,12 @@
|
|||||||
|
|
||||||
<form id="proxyForm">
|
<form id="proxyForm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="urlInput">VLESS / Subscription URL</label>
|
<label for="urlInput">VLESS Key</label>
|
||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
<input
|
<input type="text" id="urlInput" placeholder="vless://..." autocomplete="off"
|
||||||
type="text"
|
spellcheck="false">
|
||||||
id="urlInput"
|
|
||||||
placeholder="vless://... или https://subscription.link"
|
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="hint">Вставьте VLESS ссылку или URL подписки</p>
|
<p class="hint">Вставьте VLESS ссылку</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary" id="submitBtn">
|
<button type="submit" class="btn btn-primary" id="submitBtn">
|
||||||
@@ -513,4 +520,5 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -115,8 +115,8 @@ class ProxyControlHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.send_json({"success": False, "error": "URL не указан"}, 400)
|
self.send_json({"success": False, "error": "URL не указан"}, 400)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not (url.startswith("vless://") or url.startswith("http://") or url.startswith("https://")):
|
if not url.startswith("vless://"):
|
||||||
self.send_json({"success": False, "error": "Неверный формат URL. Ожидается vless:// или http(s):// ссылка"}, 400)
|
self.send_json({"success": False, "error": "Неверный формат. Поддерживаются только vless:// ссылки"}, 400)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Run gen-client-from-url.sh
|
# Run gen-client-from-url.sh
|
||||||
|
|||||||
Reference in New Issue
Block a user