feat: Добавлена нативная установка Singbox и обновлены скрипты прокси и документация.
This commit is contained in:
40
README.md
40
README.md
@@ -26,7 +26,7 @@
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Ваш браузер │────▶│ VPN Proxy │────▶│ VPN Сервер │────▶ Интернет
|
||||
│ или VS Code │ │ (порт 8082) │ │ (в другой стране)│
|
||||
│ или VS Code │ │ (порт 8080) │ │ (в другой стране)│
|
||||
└─────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
▲
|
||||
│
|
||||
@@ -44,6 +44,7 @@
|
||||
| --------------------------- | ------------------------------------------------------------------ |
|
||||
| `install-docker-proxy.ps1` | 🚀 **Автоустановщик** — скачайте и запустите, всё сделает сам |
|
||||
| `discord-windows-hack.ps1` | 🎮 Установка ProxiFyre для Discord/Vesktop |
|
||||
| `setup-singbox-native.ps1` | 🎯 Нативный sing-box для Discord UDP (голосовые) |
|
||||
| `web/server.py` | Веб-интерфейс для управления через браузер |
|
||||
| `web/index.html` | Страница с красивым интерфейсом |
|
||||
| `docker/entrypoint.sh` | Главный скрипт запуска контейнера |
|
||||
@@ -120,7 +121,7 @@ docker compose up -d
|
||||
2. **Выберите режим**:
|
||||
- **📡 Подписка**: вставьте URL подписки, нажмите «Загрузить серверы», выберите сервер и нажмите «Применить»
|
||||
- **🔑 VLESS Ключ**: вставьте VLESS-ссылку и нажмите «Применить»
|
||||
3. Готово! Прокси работает на порту **8082**
|
||||
3. Готово! Прокси работает на порту **8080**
|
||||
|
||||
> 💡 **Подписка сохраняется** между перезагрузками контейнера — URL и выбранный сервер хранятся в папке `data/`
|
||||
|
||||
@@ -153,7 +154,7 @@ docker compose up -d
|
||||
| Порт | Для чего | URL |
|
||||
| ------ | ------------------------------------------------- | ----------------------- |
|
||||
| `3456` | **Веб-интерфейс** — управление через браузер | http://localhost:3456 |
|
||||
| `2412` | **Прокси** — сюда подключаются браузер/приложения | `http://127.0.0.1:8082` |
|
||||
| `8080` | **Прокси** — сюда подключаются браузер/приложения | `http://127.0.0.1:8080` |
|
||||
| `9090` | Внутренний порт управления (обычно не нужен) | — |
|
||||
|
||||
---
|
||||
@@ -168,7 +169,7 @@ docker compose up -d
|
||||
|
||||
```bash
|
||||
# Через прокси — должен показать IP VPN-сервера
|
||||
curl -x http://127.0.0.1:8082 https://ipinfo.io/json
|
||||
curl -x http://127.0.0.1:8080 https://ipinfo.io/json
|
||||
```
|
||||
|
||||
Если показывает IP другой страны — VPN работает! 🎉
|
||||
@@ -182,14 +183,14 @@ curl -x http://127.0.0.1:8082 https://ipinfo.io/json
|
||||
Откройте настройки (Cmd+, на Mac или Ctrl+, на Windows), найдите "proxy" и добавьте:
|
||||
|
||||
```
|
||||
http.proxy: http://127.0.0.1:8082
|
||||
http.proxy: http://127.0.0.1:8080
|
||||
```
|
||||
|
||||
Или добавьте в `settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"http.proxy": "http://127.0.0.1:8082",
|
||||
"http.proxy": "http://127.0.0.1:8080",
|
||||
"http.proxyStrictSSL": true
|
||||
}
|
||||
```
|
||||
@@ -200,7 +201,7 @@ http.proxy: http://127.0.0.1:8082
|
||||
|
||||
- **Тип**: HTTP или SOCKS5
|
||||
- **Адрес**: `127.0.0.1`
|
||||
- **Порт**: `8082`
|
||||
- **Порт**: `8080`
|
||||
|
||||
### Для Discord / Vesktop (Windows)
|
||||
|
||||
@@ -215,7 +216,26 @@ Discord не поддерживает системные настройки пр
|
||||
- Устанавливает драйвер Windows Packet Filter
|
||||
- Устанавливает ProxiFyre как службу Windows
|
||||
- Настраивает перехват трафика для Discord/Vesktop
|
||||
- Направляет его через прокси `127.0.0.1:8082`
|
||||
- Направляет его через прокси `127.0.0.1:8080`
|
||||
|
||||
> ⚠️ **Важно:** Docker Desktop на Windows **не поддерживает UDP**. Голосовые звонки Discord могут не работать.
|
||||
> Для полной поддержки голоса используйте `setup-singbox-native.ps1`.
|
||||
|
||||
### 🎯 Нативный sing-box для Discord (голосовые звонки)
|
||||
|
||||
Если Docker запущен локально на Windows и голосовые звонки Discord не работают:
|
||||
|
||||
```powershell
|
||||
# Запустите от имени Администратора
|
||||
.\setup-singbox-native.ps1
|
||||
```
|
||||
|
||||
**Что делает скрипт:**
|
||||
- Спрашивает режим работы (удалённый прокси или локальный Docker)
|
||||
- Загружает sing-box v1.11.4 для Windows
|
||||
- Работает с подписками (как веб-интерфейс)
|
||||
- Создаёт задачу автозапуска в Планировщике Windows
|
||||
- Настраивает ProxiFyre на локальный SOCKS5 (порт 1080)
|
||||
|
||||
**Если ProxiFyre уже установлен:**
|
||||
При повторном запуске скрипт покажет:
|
||||
@@ -300,7 +320,7 @@ docker compose up -d
|
||||
curl https://ipinfo.io/json
|
||||
|
||||
# Через прокси — должен показать IP VPN-сервера
|
||||
curl -x http://127.0.0.1:8082 https://ipinfo.io/json
|
||||
curl -x http://127.0.0.1:8080 https://ipinfo.io/json
|
||||
```
|
||||
|
||||
Если IP-адреса разные — VPN работает! 🎉
|
||||
@@ -333,7 +353,7 @@ curl -x http://127.0.0.1:8082 https://ipinfo.io/json
|
||||
| **VLESS** | Современный протокол VPN-соединения |
|
||||
| **Reality** | Технология маскировки VPN-трафика под обычный интернет-трафик |
|
||||
|
||||
| **Порт** | "Номер двери" для сетевых соединений. Прокси: 8082, Веб-интерфейс: 3456 |
|
||||
| **Порт** | "Номер двери" для сетевых соединений. Прокси: 8080, Веб-интерфейс: 3456 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# ==========================================
|
||||
param(
|
||||
[switch]$Force, # Принудительная переустановка
|
||||
[string]$Proxy = "", # Адрес прокси (для неинтерактивного режима), например "127.0.0.1:8082"
|
||||
[string]$Proxy = "", # Адрес прокси (для неинтерактивного режима), например "127.0.0.1:8080"
|
||||
[string[]]$Apps = @(), # Приложения (для неинтерактивного режима), например @("Discord", "Vesktop")
|
||||
[switch]$Silent # Тихий режим (без лишнего вывода, для вызова из других скриптов)
|
||||
)
|
||||
@@ -44,9 +44,11 @@ if ($proxifyreExists -and -not $Force) {
|
||||
Write-Host "📊 Статус службы: " -NoNewline -ForegroundColor Yellow
|
||||
if ($proxifyreService -and $proxifyreService.Status -eq 'Running') {
|
||||
Write-Host "РАБОТАЕТ" -ForegroundColor Green
|
||||
} elseif ($proxifyreService) {
|
||||
}
|
||||
elseif ($proxifyreService) {
|
||||
Write-Host "$($proxifyreService.Status)" -ForegroundColor Red
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host "НЕ ЗАРЕГИСТРИРОВАНА" -ForegroundColor Red
|
||||
}
|
||||
|
||||
@@ -68,7 +70,8 @@ if ($proxifyreExists -and -not $Force) {
|
||||
Write-Host " Прокси: $proxy" -ForegroundColor White
|
||||
Write-Host " Приложения: $apps" -ForegroundColor White
|
||||
Write-Host ""
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Write-Host " ⚠️ Не удалось прочитать конфиг" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
@@ -114,14 +117,90 @@ if ($proxifyreExists -and -not $Force) {
|
||||
}
|
||||
"4" {
|
||||
Write-Host "`n⚙️ Изменение настроек..." -ForegroundColor Cyan
|
||||
# Продолжаем выполнение скрипта для настройки
|
||||
|
||||
# Выбор режима
|
||||
Write-Host ""
|
||||
Write-Host "📡 Где работает VPN-прокси?" -ForegroundColor Yellow
|
||||
Write-Host " [1] Удалённый сервер (Docker на VPS/другом ПК)" -ForegroundColor White
|
||||
Write-Host " [2] Локальный Docker Desktop (на этом ПК)" -ForegroundColor White
|
||||
$modeChoice = Read-Host "👉 Выбор (1-2)"
|
||||
|
||||
if ($modeChoice -eq "2") {
|
||||
# Локальный Docker — нужен sing-box
|
||||
$singboxTask = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue
|
||||
if ($singboxTask -and $singboxTask.State -eq "Running") {
|
||||
Write-Host "`n✅ Нативный sing-box работает!" -ForegroundColor Green
|
||||
$NewProxy = "127.0.0.1:1080"
|
||||
}
|
||||
else {
|
||||
Write-Host "`n⚠️ Нативный sing-box не запущен!" -ForegroundColor Yellow
|
||||
Write-Host " Запустите: .\setup-singbox-native.ps1" -ForegroundColor Cyan
|
||||
$runSetup = Read-Host " Запустить сейчас? (y/n)"
|
||||
if ($runSetup -eq "y") {
|
||||
$setupScript = Join-Path $PSScriptRoot "setup-singbox-native.ps1"
|
||||
if (Test-Path $setupScript) { & $setupScript }
|
||||
}
|
||||
$NewProxy = "127.0.0.1:1080"
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Удалённый прокси
|
||||
Write-Host "`n🌐 SOCKS5 Прокси (IP:PORT):" -ForegroundColor Yellow
|
||||
$NewProxy = Read-Host " [Enter] для 127.0.0.1:8080"
|
||||
if ([string]::IsNullOrWhiteSpace($NewProxy)) { $NewProxy = "127.0.0.1:8080" }
|
||||
}
|
||||
|
||||
# Запрос приложений
|
||||
Write-Host "`n🎮 Что проксируем?" -ForegroundColor Yellow
|
||||
Write-Host " [1] Vesktop"
|
||||
Write-Host " [2] Discord"
|
||||
Write-Host " [3] Vesktop + Discord"
|
||||
$AppChoice = Read-Host "👉 Выбор (1-3)"
|
||||
|
||||
switch ($AppChoice) {
|
||||
"2" { $NewApps = @("Discord") }
|
||||
"3" { $NewApps = @("Vesktop", "Discord") }
|
||||
Default { $NewApps = @("Vesktop") }
|
||||
}
|
||||
|
||||
# Генерируем новый конфиг
|
||||
Write-Host "`n📝 Обновляем конфиг..." -ForegroundColor Cyan
|
||||
$ConfigData = @{
|
||||
logLevel = "Info"
|
||||
proxies = @(
|
||||
@{
|
||||
appNames = $NewApps
|
||||
socks5ProxyEndpoint = $NewProxy
|
||||
username = ""
|
||||
password = ""
|
||||
supportedProtocols = @("TCP", "UDP")
|
||||
}
|
||||
)
|
||||
excludes = @()
|
||||
} | ConvertTo-Json -Depth 4
|
||||
Set-Content -Path $configPath -Value $ConfigData -Encoding UTF8
|
||||
|
||||
Write-Host " ✅ Конфиг обновлён:" -ForegroundColor Green
|
||||
Write-Host " Прокси: $NewProxy" -ForegroundColor White
|
||||
Write-Host " Приложения: $($NewApps -join ', ')" -ForegroundColor White
|
||||
|
||||
# Перезапуск службы
|
||||
Write-Host "`n🔄 Перезапуск службы для применения..." -ForegroundColor Cyan
|
||||
Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "stop" -Wait -NoNewWindow
|
||||
Start-Sleep -s 1
|
||||
Start-Process -FilePath "$InstallPath\ProxiFyre.exe" -ArgumentList "start" -Wait -NoNewWindow
|
||||
Start-Sleep -s 2
|
||||
$svc = Get-Service -Name "ProxiFyreService" -ErrorAction SilentlyContinue
|
||||
Write-Host " Статус: $($svc.Status)" -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
"5" {
|
||||
Write-Host "`n📋 Логи ProxiFyre:" -ForegroundColor Cyan
|
||||
$logFiles = Get-ChildItem "$InstallPath\logs\*.log" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
if ($logFiles) {
|
||||
Get-Content $logFiles.FullName -Tail 50
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host " Лог-файлы не найдены" -ForegroundColor Yellow
|
||||
}
|
||||
exit 0
|
||||
@@ -130,14 +209,16 @@ if ($proxifyreExists -and -not $Force) {
|
||||
Write-Host "`n📄 Конфиг ProxiFyre:" -ForegroundColor Cyan
|
||||
if (Test-Path $configPath) {
|
||||
Get-Content $configPath
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host " Конфиг не найден" -ForegroundColor Yellow
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
"7" {
|
||||
Write-Host "`n🔧 Переустановка..." -ForegroundColor Cyan
|
||||
# Продолжаем выполнение скрипта
|
||||
$Force = $true
|
||||
# Продолжаем выполнение скрипта для полной переустановки
|
||||
}
|
||||
default {
|
||||
Write-Host "`n ℹ️ Выход" -ForegroundColor Gray
|
||||
@@ -157,11 +238,77 @@ if ($Proxy -and $Apps.Count -gt 0) {
|
||||
Write-Host " Прокси: $UserProxy" -ForegroundColor White
|
||||
Write-Host " Приложения: $($TargetApps -join ', ')" -ForegroundColor White
|
||||
}
|
||||
} else {
|
||||
# Интерактивный режим
|
||||
}
|
||||
else {
|
||||
# Интерактивный режим — сначала выбор режима
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host " 📡 ГДЕ РАБОТАЕТ ВАШ VPN-ПРОКСИ? " -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " [1] 🌐 УДАЛЁННЫЙ СЕРВЕР" -ForegroundColor White
|
||||
Write-Host " Docker на VPS или другом ПК в сети" -ForegroundColor Gray
|
||||
Write-Host " (UDP работает, просто укажите адрес)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] 💻 ЛОКАЛЬНЫЙ DOCKER НА WINDOWS" -ForegroundColor White
|
||||
Write-Host " Docker Desktop на этом компьютере" -ForegroundColor Gray
|
||||
Write-Host " (UDP НЕ работает, нужен нативный sing-box)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
$modeChoice = Read-Host "👉 Выбор (1-2)"
|
||||
|
||||
if ($modeChoice -eq "2") {
|
||||
# Локальный Docker — нужен нативный sing-box
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Yellow
|
||||
Write-Host " ⚠️ ЛОКАЛЬНЫЙ DOCKER DESKTOP " -ForegroundColor Yellow
|
||||
Write-Host "==========================================" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Docker Desktop на Windows НЕ поддерживает UDP!" -ForegroundColor Red
|
||||
Write-Host "Для голосовых звонков Discord нужен нативный sing-box." -ForegroundColor Red
|
||||
Write-Host ""
|
||||
|
||||
# Проверяем, установлен ли уже нативный sing-box
|
||||
$singboxInstalled = Test-Path "C:\Tools\sing-box\sing-box.exe"
|
||||
$singboxTask = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue
|
||||
|
||||
if ($singboxInstalled -and $singboxTask -and $singboxTask.State -eq "Running") {
|
||||
Write-Host "✅ Нативный sing-box уже установлен и работает!" -ForegroundColor Green
|
||||
Write-Host " Прокси: 127.0.0.1:1080" -ForegroundColor White
|
||||
$UserProxy = "127.0.0.1:1080"
|
||||
}
|
||||
else {
|
||||
Write-Host "Для установки нативного sing-box запустите:" -ForegroundColor Yellow
|
||||
Write-Host " .\setup-singbox-native.ps1" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$runSetup = Read-Host "Запустить setup-singbox-native.ps1 сейчас? (y/n)"
|
||||
if ($runSetup -eq "y") {
|
||||
$setupScript = Join-Path $PSScriptRoot "setup-singbox-native.ps1"
|
||||
if (Test-Path $setupScript) {
|
||||
& $setupScript
|
||||
# После установки используем порт 1080
|
||||
$UserProxy = "127.0.0.1:1080"
|
||||
}
|
||||
else {
|
||||
Write-Host "❌ Скрипт setup-singbox-native.ps1 не найден!" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
Write-Host "Установите sing-box вручную и повторите." -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Удалённый прокси — просто спрашиваем адрес
|
||||
Write-Host "`n🌐 SOCKS5 Прокси (IP:PORT):" -ForegroundColor Yellow
|
||||
$UserProxy = Read-Host " [Enter] для 127.0.0.1:8082"
|
||||
if ([string]::IsNullOrWhiteSpace($UserProxy)) { $UserProxy = "127.0.0.1:8082" }
|
||||
Write-Host " Примеры: 192.168.1.100:8080, myserver.com:8080" -ForegroundColor Gray
|
||||
$UserProxy = Read-Host " [Enter] для 127.0.0.1:8080"
|
||||
if ([string]::IsNullOrWhiteSpace($UserProxy)) { $UserProxy = "127.0.0.1:8080" }
|
||||
}
|
||||
|
||||
Write-Host "`n🎮 Что проксируем?" -ForegroundColor Yellow
|
||||
Write-Host " [1] Vesktop"
|
||||
@@ -193,7 +340,8 @@ try {
|
||||
$Proc = Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$MsiFile`" /qn /norestart" -Wait -PassThru
|
||||
if ($Proc.ExitCode -eq 0) { Write-Host " ✅ Успешно." -ForegroundColor Green }
|
||||
elseif ($Proc.ExitCode -eq 1603) { Write-Host " ⚠️ Уже установлен." -ForegroundColor Yellow }
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Write-Error "❌ Ошибка скачивания драйвера: $_"; Exit
|
||||
}
|
||||
|
||||
@@ -209,7 +357,8 @@ try {
|
||||
Invoke-WebRequest -Uri $AppUrl -OutFile $ZipFile -ErrorAction Stop
|
||||
Expand-Archive -Path $ZipFile -DestinationPath $InstallPath -Force
|
||||
Write-Host " ✅ Распаковано." -ForegroundColor Green
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
Write-Error "❌ Ошибка скачивания ProxiFyre: $_"; Exit
|
||||
}
|
||||
|
||||
@@ -263,7 +412,8 @@ if ($Service -and $Service.Status -eq 'Running') {
|
||||
Write-Host "🎉 УСПЕХ! Служба работает в фоне." -ForegroundColor Green
|
||||
Write-Host "📁 Логи тут: $InstallPath\logs"
|
||||
Write-Host "=========================================="
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host "`n⚠️ Служба установлена, но статус: $($Service.Status). Проверь логи." -ForegroundColor Red
|
||||
Write-Host "Попробуй вручную: net start ProxiFyreService"
|
||||
}
|
||||
@@ -50,7 +50,8 @@ if ($existingContainer -and -not $Force) {
|
||||
Write-Host "РАБОТАЕТ" -ForegroundColor Green
|
||||
Write-Host " Контейнер: sing-proxy" -ForegroundColor Gray
|
||||
Write-Host " Uptime: $containerRunning" -ForegroundColor Gray
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host "📊 Статус: " -NoNewline -ForegroundColor Yellow
|
||||
Write-Host "ОСТАНОВЛЕН" -ForegroundColor Red
|
||||
$containerStatus = docker ps -a --filter "name=sing-proxy" --format "{{.Status}}" 2>$null
|
||||
@@ -60,7 +61,7 @@ if ($existingContainer -and -not $Force) {
|
||||
Write-Host ""
|
||||
Write-Host "📡 Адреса подключения:" -ForegroundColor Yellow
|
||||
Write-Host " Веб-интерфейс: http://localhost:3456" -ForegroundColor White
|
||||
Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8082" -ForegroundColor White
|
||||
Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8080" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "📁 Расположение:" -ForegroundColor Yellow
|
||||
Write-Host " Проект: $ScriptDir" -ForegroundColor White
|
||||
@@ -84,7 +85,8 @@ if ($existingContainer -and -not $Force) {
|
||||
$proxy = $config.proxies[0].socks5ProxyEndpoint
|
||||
Write-Host " Прокси: $proxy" -ForegroundColor White
|
||||
Write-Host " Приложения: $apps" -ForegroundColor White
|
||||
} catch {}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
@@ -155,7 +157,8 @@ try {
|
||||
Write-Success "Docker установлен: $dockerVersion"
|
||||
$DockerInstalled = $true
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$DockerInstalled = $false
|
||||
}
|
||||
|
||||
@@ -186,7 +189,8 @@ if ($DockerInstalled) {
|
||||
Write-Success "Docker daemon запущен"
|
||||
$DockerRunning = $true
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
catch {
|
||||
$DockerRunning = $false
|
||||
}
|
||||
|
||||
@@ -214,17 +218,20 @@ if ($DockerInstalled) {
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$DockerRunning = $true
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
if ($DockerRunning) {
|
||||
Write-Success "Docker запустился!"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Error "Таймаут ожидания Docker. Запустите Docker Desktop вручную."
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -238,7 +245,8 @@ if ($DockerRunning) {
|
||||
Write-Success "Docker Compose доступен: $composeVersion"
|
||||
$DockerComposeAvailable = $true
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
catch {}
|
||||
|
||||
if (-not $DockerComposeAvailable) {
|
||||
# Пробуем старый формат docker-compose
|
||||
@@ -248,7 +256,8 @@ if ($DockerRunning) {
|
||||
Write-Success "Docker Compose (legacy) доступен: $composeVersion"
|
||||
$DockerComposeAvailable = $true
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
if (-not $DockerComposeAvailable -and -not $SkipDockerCheck) {
|
||||
@@ -316,7 +325,8 @@ try {
|
||||
}
|
||||
Write-Success "Контейнер запущен"
|
||||
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
@@ -328,7 +338,8 @@ Write-Step "Проверка статуса..."
|
||||
$containerStatus = docker ps --filter "name=sing-proxy" --format "{{.Status}}" 2>&1
|
||||
if ($containerStatus -match "Up") {
|
||||
Write-Success "Контейнер sing-proxy работает: $containerStatus"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Warning "Контейнер может ещё запускаться. Проверьте через: docker ps"
|
||||
}
|
||||
|
||||
@@ -342,7 +353,7 @@ Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "📡 Адреса подключения:" -ForegroundColor Yellow
|
||||
Write-Host " Веб-интерфейс: http://localhost:3456" -ForegroundColor White
|
||||
Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8082" -ForegroundColor White
|
||||
Write-Host " HTTP/SOCKS Прокси: 127.0.0.1:8080" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "📋 Следующие шаги:" -ForegroundColor Yellow
|
||||
Write-Host " 1. Откройте http://localhost:3456 в браузере" -ForegroundColor White
|
||||
@@ -381,7 +392,8 @@ if (-not $SkipDiscord) {
|
||||
Write-Host " cd `"$ScriptDir`"" -ForegroundColor Cyan
|
||||
Write-Host " .\discord-windows-hack.ps1" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
# Запускаем скрипт с параметрами для неинтерактивного режима
|
||||
$discordScript = Join-Path $ScriptDir "discord-windows-hack.ps1"
|
||||
|
||||
@@ -396,14 +408,31 @@ if (-not $SkipDiscord) {
|
||||
}
|
||||
|
||||
# Вызываем discord-windows-hack.ps1 с параметрами (без дублирования кода)
|
||||
& $discordScript -Proxy "127.0.0.1:8082" -Apps $targetApps -Force
|
||||
& $discordScript -Proxy "127.0.0.1:8080" -Apps $targetApps -Force
|
||||
|
||||
} else {
|
||||
# Предупреждение о UDP
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Yellow
|
||||
Write-Host " ⚠️ ВАЖНО: ГОЛОСОВЫЕ ЗВОНКИ DISCORD " -ForegroundColor Yellow
|
||||
Write-Host "==========================================" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Docker Desktop на Windows НЕ ПОДДЕРЖИВАЕТ UDP!" -ForegroundColor Red
|
||||
Write-Host "Голосовые звонки Discord могут не работать." -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Для полной поддержки голоса запустите:" -ForegroundColor Cyan
|
||||
Write-Host " .\setup-singbox-native.ps1" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "Этот скрипт установит нативный sing-box," -ForegroundColor Gray
|
||||
Write-Host "который поддерживает UDP трафик." -ForegroundColor Gray
|
||||
|
||||
}
|
||||
else {
|
||||
Write-Warning "Скрипт discord-windows-hack.ps1 не найден"
|
||||
Write-Info "Скачайте его или создайте вручную"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Info "Установка Discord прокси пропущена"
|
||||
}
|
||||
}
|
||||
|
||||
439
setup-singbox-native.ps1
Normal file
439
setup-singbox-native.ps1
Normal file
@@ -0,0 +1,439 @@
|
||||
# ==========================================
|
||||
# 🎯 SING-BOX NATIVE INSTALLER FOR WINDOWS
|
||||
# ==========================================
|
||||
# Устанавливает нативный sing-box для поддержки UDP (Discord голосовые)
|
||||
# Используется когда Docker запущен ЛОКАЛЬНО на Windows
|
||||
# (Docker Desktop не поддерживает UDP)
|
||||
# ==========================================
|
||||
|
||||
param(
|
||||
[switch]$Force, # Принудительная переустановка
|
||||
[string]$SubscriptionUrl = "" # URL подписки (для неинтерактивного режима)
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# КОНФИГУРАЦИЯ
|
||||
# ==========================================
|
||||
$SingboxVersion = "1.11.4"
|
||||
$InstallDir = "C:\Tools\sing-box"
|
||||
$LocalProxyPort = 1080
|
||||
|
||||
# Ссылки для скачивания
|
||||
$SingboxUrl = "https://github.com/SagerNet/sing-box/releases/download/v$SingboxVersion/sing-box-$SingboxVersion-windows-amd64.zip"
|
||||
|
||||
# App Info (для заголовков подписки)
|
||||
$AppName = "VPN-Proxy-Control by Dokril"
|
||||
|
||||
# ==========================================
|
||||
# ЦВЕТА И ВЫВОД
|
||||
# ==========================================
|
||||
function Write-Step { param($msg) Write-Host "`n📦 $msg" -ForegroundColor Cyan }
|
||||
function Write-Success { param($msg) Write-Host " ✅ $msg" -ForegroundColor Green }
|
||||
function Write-Warning { param($msg) Write-Host " ⚠️ $msg" -ForegroundColor Yellow }
|
||||
function Write-Error { param($msg) Write-Host " ❌ $msg" -ForegroundColor Red }
|
||||
function Write-Info { param($msg) Write-Host " ℹ️ $msg" -ForegroundColor Gray }
|
||||
|
||||
# ==========================================
|
||||
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
|
||||
# ==========================================
|
||||
|
||||
function Get-HWID {
|
||||
$hwidFile = "$InstallDir\hwid"
|
||||
if (Test-Path $hwidFile) {
|
||||
return (Get-Content $hwidFile -Raw).Trim()
|
||||
}
|
||||
|
||||
$hwid = [System.Guid]::NewGuid().ToString("N").Substring(0, 16)
|
||||
|
||||
if (!(Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Set-Content -Path $hwidFile -Value $hwid
|
||||
return $hwid
|
||||
}
|
||||
|
||||
function Get-SystemInfo {
|
||||
return @{
|
||||
os = "windows"
|
||||
version = [System.Environment]::OSVersion.Version.Major.ToString()
|
||||
}
|
||||
}
|
||||
|
||||
function Get-SubscriptionData {
|
||||
param([string]$Url)
|
||||
|
||||
Write-Info "Загружаю подписку..."
|
||||
|
||||
$hwid = Get-HWID
|
||||
$sysInfo = Get-SystemInfo
|
||||
|
||||
$headers = @{
|
||||
"User-Agent" = "singbox"
|
||||
"x-hwid" = $hwid
|
||||
"x-device-os" = $sysInfo.os
|
||||
"x-ver-os" = $sysInfo.version
|
||||
"x-device-model" = $AppName
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri $Url -Headers $headers -TimeoutSec 15 -UseBasicParsing
|
||||
$config = $response.Content | ConvertFrom-Json
|
||||
|
||||
$userInfo = @{}
|
||||
$userInfoHeader = $response.Headers["subscription-userinfo"]
|
||||
if ($userInfoHeader) {
|
||||
$parts = $userInfoHeader -split ";"
|
||||
foreach ($part in $parts) {
|
||||
if ($part -match "(\w+)=(\d+)") {
|
||||
$userInfo[$matches[1]] = [int64]$matches[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @{
|
||||
success = $true
|
||||
config = $config
|
||||
userInfo = $userInfo
|
||||
}
|
||||
}
|
||||
catch {
|
||||
return @{
|
||||
success = $false
|
||||
error = $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Select-Server {
|
||||
param($Config)
|
||||
|
||||
$outbounds = $Config.outbounds
|
||||
$servers = @()
|
||||
|
||||
foreach ($outbound in $outbounds) {
|
||||
if ($outbound.type -in @("vless", "vmess", "trojan", "shadowsocks", "hysteria2")) {
|
||||
$servers += @{
|
||||
tag = $outbound.tag
|
||||
type = $outbound.type
|
||||
server = $outbound.server
|
||||
server_port = $outbound.server_port
|
||||
outbound = $outbound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($servers.Count -eq 0) {
|
||||
Write-Error "Серверы не найдены в подписке!"
|
||||
return $null
|
||||
}
|
||||
|
||||
Write-Host "`n🌐 Доступные серверы:" -ForegroundColor Yellow
|
||||
for ($i = 0; $i -lt $servers.Count; $i++) {
|
||||
$s = $servers[$i]
|
||||
Write-Host " [$($i+1)] $($s.tag) ($($s.type)) - $($s.server):$($s.server_port)"
|
||||
}
|
||||
|
||||
$choice = Read-Host "`n👉 Выберите сервер (1-$($servers.Count))"
|
||||
$index = [int]$choice - 1
|
||||
|
||||
if ($index -lt 0 -or $index -ge $servers.Count) {
|
||||
Write-Error "Неверный выбор!"
|
||||
return $null
|
||||
}
|
||||
|
||||
return $servers[$index]
|
||||
}
|
||||
|
||||
function New-SingboxConfig {
|
||||
param($Outbound, $Port)
|
||||
|
||||
$config = @{
|
||||
log = @{
|
||||
level = "info"
|
||||
timestamp = $true
|
||||
}
|
||||
dns = @{
|
||||
independent_cache = $true
|
||||
}
|
||||
inbounds = @(
|
||||
@{
|
||||
type = "socks"
|
||||
tag = "socks-in"
|
||||
listen = "127.0.0.1"
|
||||
listen_port = $Port
|
||||
}
|
||||
)
|
||||
outbounds = @(
|
||||
$Outbound,
|
||||
@{
|
||||
type = "direct"
|
||||
tag = "direct"
|
||||
}
|
||||
)
|
||||
route = @{
|
||||
final = $Outbound.tag
|
||||
auto_detect_interface = $true
|
||||
}
|
||||
}
|
||||
|
||||
return $config
|
||||
}
|
||||
|
||||
function Install-SingboxTask {
|
||||
Write-Step "Установка sing-box через Task Scheduler..."
|
||||
|
||||
$exePath = "$InstallDir\sing-box.exe"
|
||||
$configPath = "$InstallDir\config.json"
|
||||
$taskName = "SingBoxProxy"
|
||||
|
||||
# Удаляем старую задачу
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
|
||||
# Создаём новую
|
||||
$action = New-ScheduledTaskAction -Execute "$exePath" -Argument "run -c `"$configPath`"" -WorkingDirectory $InstallDir
|
||||
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
|
||||
|
||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null
|
||||
|
||||
# Запускаем сразу
|
||||
Start-ScheduledTask -TaskName $taskName
|
||||
|
||||
Write-Success "Задача создана и запущена!"
|
||||
return $true
|
||||
}
|
||||
|
||||
function Stop-SingboxTask {
|
||||
Stop-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue
|
||||
Stop-Process -Name "sing-box" -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# ==========================================
|
||||
# ПРОВЕРКА ПРАВ АДМИНИСТРАТОРА
|
||||
# ==========================================
|
||||
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
|
||||
Write-Host "⛔ Запустите скрипт от имени АДМИНИСТРАТОРА!" -ForegroundColor Red
|
||||
Start-Sleep -Seconds 3
|
||||
Exit 1
|
||||
}
|
||||
|
||||
Clear-Host
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host " 🎯 SING-BOX NATIVE INSTALLER " -ForegroundColor Cyan
|
||||
Write-Host " для Discord UDP поддержки " -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Этот скрипт нужен когда Docker запущен" -ForegroundColor Gray
|
||||
Write-Host "ЛОКАЛЬНО на Windows (Docker Desktop)." -ForegroundColor Gray
|
||||
Write-Host "Docker Desktop не поддерживает UDP." -ForegroundColor Gray
|
||||
|
||||
# ==========================================
|
||||
# ПРОВЕРКА СУЩЕСТВУЮЩЕЙ УСТАНОВКИ
|
||||
# ==========================================
|
||||
$singboxExists = Test-Path "$InstallDir\sing-box.exe"
|
||||
$taskExists = Get-ScheduledTask -TaskName "SingBoxProxy" -ErrorAction SilentlyContinue
|
||||
|
||||
if ($singboxExists -and $taskExists -and -not $Force) {
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host " ✅ SING-BOX УЖЕ УСТАНОВЛЕН! " -ForegroundColor Green
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
$taskInfo = Get-ScheduledTask -TaskName "SingBoxProxy"
|
||||
$taskState = $taskInfo.State
|
||||
|
||||
Write-Host "📊 Статус: " -NoNewline -ForegroundColor Yellow
|
||||
if ($taskState -eq "Running") {
|
||||
Write-Host "РАБОТАЕТ" -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
Write-Host "$taskState" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "📁 Расположение: $InstallDir" -ForegroundColor Yellow
|
||||
Write-Host "🔌 Локальный SOCKS5: 127.0.0.1:$LocalProxyPort" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Что вы хотите сделать?" -ForegroundColor Yellow
|
||||
Write-Host " [1] Запустить" -ForegroundColor White
|
||||
Write-Host " [2] Остановить" -ForegroundColor White
|
||||
Write-Host " [3] Показать конфиг" -ForegroundColor White
|
||||
Write-Host " [4] Переустановить" -ForegroundColor White
|
||||
Write-Host " [q] Выход" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
$choice = Read-Host "👉 Выбор (1-4/q)"
|
||||
|
||||
switch ($choice) {
|
||||
"1" {
|
||||
Start-ScheduledTask -TaskName "SingBoxProxy"
|
||||
Start-Sleep -Seconds 2
|
||||
Write-Success "Запущено!"
|
||||
exit 0
|
||||
}
|
||||
"2" {
|
||||
Stop-SingboxTask
|
||||
Write-Success "Остановлено!"
|
||||
exit 0
|
||||
}
|
||||
"3" {
|
||||
Write-Host "`n📄 Конфигурация:" -ForegroundColor Cyan
|
||||
Get-Content "$InstallDir\config.json" | ConvertFrom-Json | ConvertTo-Json -Depth 10
|
||||
exit 0
|
||||
}
|
||||
"4" {
|
||||
Write-Info "Переустановка..."
|
||||
}
|
||||
default {
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ==========================================
|
||||
# УСТАНОВКА
|
||||
# ==========================================
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
# ШАГ 1: Скачиваем sing-box
|
||||
Write-Step "Скачиваю sing-box v$SingboxVersion..."
|
||||
|
||||
if (!(Test-Path $InstallDir)) {
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
}
|
||||
|
||||
$zipFile = "$env:TEMP\sing-box.zip"
|
||||
|
||||
try {
|
||||
Invoke-WebRequest -Uri $SingboxUrl -OutFile $zipFile -UseBasicParsing
|
||||
Write-Success "Скачано!"
|
||||
}
|
||||
catch {
|
||||
Write-Error "Ошибка скачивания: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Info "Распаковываю..."
|
||||
Expand-Archive -Path $zipFile -DestinationPath $env:TEMP -Force
|
||||
|
||||
$extractedDir = Get-ChildItem "$env:TEMP\sing-box-*" -Directory | Select-Object -First 1
|
||||
Copy-Item "$($extractedDir.FullName)\sing-box.exe" "$InstallDir\sing-box.exe" -Force
|
||||
|
||||
Remove-Item $zipFile -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item $extractedDir.FullName -Recurse -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Success "sing-box установлен в $InstallDir"
|
||||
|
||||
# ШАГ 2: Получаем подписку
|
||||
Write-Step "Настройка подписки..."
|
||||
|
||||
$savedSubFile = Join-Path $PSScriptRoot "data\subscription.json"
|
||||
$subUrl = $SubscriptionUrl
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($subUrl) -and (Test-Path $savedSubFile)) {
|
||||
try {
|
||||
$savedSub = Get-Content $savedSubFile -Raw | ConvertFrom-Json
|
||||
if ($savedSub.url) {
|
||||
Write-Info "Найдена сохранённая подписка"
|
||||
Write-Host " URL: $($savedSub.url)" -ForegroundColor Gray
|
||||
$useSaved = Read-Host " Использовать? (y/n)"
|
||||
if ($useSaved -eq "y") {
|
||||
$subUrl = $savedSub.url
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($subUrl)) {
|
||||
Write-Host "`n🔗 Введите URL подписки:" -ForegroundColor Yellow
|
||||
$subUrl = Read-Host "👉"
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($subUrl)) {
|
||||
Write-Error "URL подписки не указан!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$subResult = Get-SubscriptionData -Url $subUrl
|
||||
|
||||
if (-not $subResult.success) {
|
||||
Write-Error "Ошибка загрузки подписки: $($subResult.error)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Success "Подписка загружена!"
|
||||
|
||||
if ($subResult.userInfo.Count -gt 0) {
|
||||
$ui = $subResult.userInfo
|
||||
if ($ui.upload -and $ui.download -and $ui.total) {
|
||||
$usedGB = [math]::Round(($ui.upload + $ui.download) / 1GB, 2)
|
||||
$totalGB = [math]::Round($ui.total / 1GB, 2)
|
||||
Write-Info "Трафик: $usedGB / $totalGB GB"
|
||||
}
|
||||
}
|
||||
|
||||
# ШАГ 3: Выбираем сервер
|
||||
$selectedServer = Select-Server -Config $subResult.config
|
||||
|
||||
if (-not $selectedServer) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Success "Выбран сервер: $($selectedServer.tag)"
|
||||
|
||||
# ШАГ 4: Генерируем конфиг
|
||||
Write-Step "Генерирую конфигурацию..."
|
||||
|
||||
$config = New-SingboxConfig -Outbound $selectedServer.outbound -Port $LocalProxyPort
|
||||
$configJson = $config | ConvertTo-Json -Depth 10
|
||||
|
||||
Set-Content -Path "$InstallDir\config.json" -Value $configJson -Encoding UTF8
|
||||
Write-Success "Конфиг сохранён: $InstallDir\config.json"
|
||||
|
||||
# ШАГ 5: Запускаем
|
||||
Stop-SingboxTask
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
$installed = Install-SingboxTask
|
||||
|
||||
if (-not $installed) {
|
||||
Write-Error "Не удалось установить задачу!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
# Проверяем порт
|
||||
Write-Info "Проверяю доступность порта..."
|
||||
$portCheck = Test-NetConnection -ComputerName 127.0.0.1 -Port $LocalProxyPort -WarningAction SilentlyContinue
|
||||
|
||||
if ($portCheck.TcpTestSucceeded) {
|
||||
Write-Success "Порт $LocalProxyPort доступен!"
|
||||
}
|
||||
else {
|
||||
Write-Warning "Порт $LocalProxyPort пока недоступен. Подождите несколько секунд."
|
||||
}
|
||||
|
||||
# Финал
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host " 🎉 SING-BOX УСТАНОВЛЕН! " -ForegroundColor Green
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "📡 Локальный SOCKS5: 127.0.0.1:$LocalProxyPort" -ForegroundColor Yellow
|
||||
Write-Host " Сервер: $($selectedServer.tag)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "Теперь запустите discord-windows-hack.ps1" -ForegroundColor Cyan
|
||||
Write-Host "и укажите прокси: 127.0.0.1:$LocalProxyPort" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "📋 Полезные команды:" -ForegroundColor Gray
|
||||
Write-Host " Статус: Get-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray
|
||||
Write-Host " Запустить: Start-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray
|
||||
Write-Host " Остановить: Stop-ScheduledTask -TaskName SingBoxProxy" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Reference in New Issue
Block a user