Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c1c82afec | ||
|
|
0f98c074c8 | ||
|
|
286142bd7a | ||
|
|
cf4b5f79b5 | ||
|
|
5f97c6c6d7 | ||
|
|
14bb6ae589 | ||
|
|
51712310f6 | ||
|
|
6ec1782d8b | ||
|
|
e61ec09b18 |
70
CHANGELOG.md
Normal file
70
CHANGELOG.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Changelog — PCA Phobos
|
||||
|
||||
Каналы: **stable** (публичный, без токена) · **beta** / **dev** (приватный repo, токен подписчика).
|
||||
Обновление: `phobos-update stable` · `GH_TOKEN=… phobos-update beta|dev` · из панели → «Версия и обновления».
|
||||
|
||||
---
|
||||
|
||||
## Как обновиться после фиксов
|
||||
|
||||
```bash
|
||||
# stable (открытый)
|
||||
phobos-update stable
|
||||
|
||||
# beta/dev (токен уже сохранён в /opt/phobos-panel/.gh_token)
|
||||
phobos-update beta # или: phobos-update dev
|
||||
```
|
||||
Затем **пересоздать клиентов** в панели (старые конфиги могли содержать неверный порт обфускатора).
|
||||
Обновляются: панель, скрипты онбординга, агент, updater. Ключи WireGuard, `server.env`, клиенты — НЕ трогаются.
|
||||
|
||||
---
|
||||
|
||||
## stable
|
||||
|
||||
### v1.2.7
|
||||
- **fix:** импорт `phobos://` в PhobosWG. Конфиги дополняются `= none` для недостающих полей (`PresharedKey` и др.) перед base64 — иначе приложение писало «невозможно импортировать туннель».
|
||||
|
||||
### v1.2.6
|
||||
- **fix:** бинарники wg-obfuscator для роутеров. Keenetic = aarch64, а Ground-Zerro раздаёт только x86_64. Теперь install.sh и сборка пакета клиента авто-качают aarch64/mipsel/armv7 из ClusterM/wg-obfuscator releases.
|
||||
|
||||
### v1.2.5
|
||||
- **feat:** поле токена подписчика + кнопки каналов (stable/beta/dev) прямо в карточке «Версия и обновления». Подписчик вставляет токен в панель и переключается на beta/dev без консоли.
|
||||
|
||||
### v1.2.4
|
||||
- **feat:** установка по умолчанию стабильная; beta/dev — опционально (`CHANNEL=`).
|
||||
|
||||
### v1.2.3
|
||||
- **fix:** дебаунс DOWN-алертов (3 цикла + повтор) — убирает ложный флап серверов.
|
||||
- **fix:** `phobos-update` отменяет обновление на несуществующую версию (текущая не трогается).
|
||||
- **feat:** `--check` / `--versions`, кнопка «Проверить обновления».
|
||||
|
||||
### v1.2.2
|
||||
- контакт во всех местах → группа `@PCAdministration`.
|
||||
|
||||
---
|
||||
|
||||
## Критичные фиксы (общие, во всех каналах)
|
||||
|
||||
| Версия | Проблема | Решение |
|
||||
|--------|----------|---------|
|
||||
| 1.2.7 / 1.3.x | PhobosWG: «невозможно импортировать туннель» | `phobos://` дополняется `= none` для всех обязательных полей (`PresharedKey`) по спеке формата |
|
||||
| 1.2.6 / 1.3.x | Роутер aarch64: «бинарник не найден в архиве» | авто-загрузка aarch64/mipsel/armv7 из ClusterM releases |
|
||||
| (внутр.) | Клиент не подключается, «НЕТ СОЕДИНЕНИЯ», handshake не встаёт | клиентский обфускатор целился в порт 51821 (никто не слушал); теперь берёт первый из `OBFUSCATOR_PORTS` (2083) |
|
||||
| (внутр.) | агент secondary не обновлялся через `phobos-update` | `server/api.py` добавлен в managed_files |
|
||||
|
||||
---
|
||||
|
||||
## beta (приватный)
|
||||
|
||||
### v1.3.0-beta
|
||||
- скачивание `.conf` для телефона (Android `phobos://` + QR, iOS обычный WireGuard + QR);
|
||||
- кнопка скачивания приложения **PhobosWG (APK)** — авто-загрузка из GitHub Release приватного repo;
|
||||
- все критичные фиксы выше.
|
||||
|
||||
---
|
||||
|
||||
## dev (приватный, активная разработка)
|
||||
|
||||
### v1.3.1-dev
|
||||
- **баланс по трафику:** агенты отдают пропускную способность канала (rx/tx NIC), `server_load = 0.45·cpu + 0.30·mem + 0.25·bw`; карточки серверов показывают ↕ Mbps;
|
||||
- все фиксы и фичи из beta.
|
||||
22
README.md
22
README.md
@@ -113,7 +113,7 @@ bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main
|
||||
> Для каждого устройства создавай **отдельного клиента** (свой ключ и IP). Один конфиг на двух устройствах = конфликт ключей.
|
||||
|
||||
**Приложения:**
|
||||
- **Android (PhobosWG):** автор пока не публикует APK официально. Положи `.apk` на сервер в `/opt/Phobos/www/app/PhobosWG.apk` — панель сама покажет кнопку «Скачать приложение PhobosWG» на странице Android-клиента (раздаётся по `http://<сервер>/app/PhobosWG.apk`).
|
||||
- **Android (PhobosWG):** на странице Android-клиента в панели есть кнопка **«Скачать приложение PhobosWG (APK)»** — приложение скачивается автоматически (доступно в каналах beta/dev). Установи APK, затем импортируй `phobos://`-ссылку или QR.
|
||||
- **iPhone (iOS):** официальный [WireGuard из App Store](https://apps.apple.com/app/wireguard/id1441195209) — кнопка есть на странице iOS-клиента.
|
||||
|
||||
---
|
||||
@@ -138,6 +138,22 @@ phobos-update --list # список бэкапов
|
||||
|
||||
---
|
||||
|
||||
## Полное удаление сервера
|
||||
|
||||
Одной командой (спросит подтверждение):
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/uninstall.sh)
|
||||
```
|
||||
|
||||
Без подтверждения: `PURGE=1 bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/uninstall.sh)`
|
||||
|
||||
Удаляет: веб-панель, обфускатор-сервисы, WireGuard `wg0`, агент, nginx-сайт, watchdog-cron, iptables-правила, бинарники (`wg-obfuscator`, `phobos-update`) и каталоги `/opt/Phobos`, `/opt/phobos-panel`. Общие пакеты (wireguard, nginx, cron) НЕ трогает.
|
||||
|
||||
**Удаление с роутера** (на самом роутере): `/opt/etc/Phobos/phobos-uninstall.sh`
|
||||
|
||||
---
|
||||
|
||||
## Возможные проблемы и решения
|
||||
|
||||
| Симптом | Причина | Решение |
|
||||
@@ -152,6 +168,10 @@ phobos-update --list # список бэкапов
|
||||
| **Смена сервера применяется не сразу** | роутер тянет конфиг по cron | Применяется за ~12–15 сек, не мгновенно |
|
||||
| **Забыл порт панели** | случайный порт | `cat /opt/phobos-panel/.port` |
|
||||
| **Забыл API key** | | `grep server_api_key /opt/phobos-panel/settings.json` |
|
||||
| **PhobosWG: «невозможно импортировать туннель»** | старая панель генерила неполный `phobos://` (без `PresharedKey`) | Обнови панель, заново скопируй `phobos://`-ссылку или пересканируй QR. Исправлено в v1.2.7 |
|
||||
| **Роутер aarch64: «бинарник не найден в архиве»** | Ground-Zerro раздаёт только x86_64 | Обнови (`phobos-update`) — aarch64/mipsel/armv7 авто-качаются из ClusterM, затем пересоздай клиента. Исправлено в v1.2.6 |
|
||||
| **Клиент не подключается, «НЕТ СОЕДИНЕНИЯ»** | клиентский обфускатор целился в неверный порт (51821) | Обнови панель → **пересоздай клиента** → переустанови на роутере. Порт берётся из `OBFUSCATOR_PORTS` |
|
||||
| **Удалить сервер полностью** | | `bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/uninstall.sh)` |
|
||||
|
||||
Логи: `journalctl -u phobos-panel -n 50` · сторож: `/opt/Phobos/server/watchdog.log` · роутер: `/opt/etc/Phobos/health.log`.
|
||||
|
||||
|
||||
48
app.py
48
app.py
@@ -721,16 +721,56 @@ def build_phone_config(cid, mode="android"):
|
||||
if os.path.exists(instpath):
|
||||
inst = open(instpath).read().strip()
|
||||
conf = wg + "\n\n" + inst + "\n"
|
||||
b64 = base64.urlsafe_b64encode(conf.encode()).decode().rstrip("=")
|
||||
link = "phobos://" + b64 + "#" + urllib.parse.quote(cid)
|
||||
# PhobosWG requires ALL fields present; missing -> "= none" before base64
|
||||
# (spec 2.3). Ground-Zerro configs lack PresharedKey -> import fails otherwise.
|
||||
padded = _pad_conf_with_none(conf)
|
||||
b64 = base64.urlsafe_b64encode(padded.encode()).decode().rstrip("=")
|
||||
link = "phobos://" + b64 + "#" + urllib.parse.quote(cid or "none")
|
||||
return conf, link
|
||||
|
||||
|
||||
def _pad_conf_with_none(conf):
|
||||
"""Insert '<key> = none' for every missing mandatory PhobosWG field
|
||||
(phobos:// spec 2.3). Only for phobos:// payload, NOT raw .conf."""
|
||||
mandatory = {
|
||||
"[interface]": ["PrivateKey", "Address", "MTU", "DNS"],
|
||||
"[peer]": ["PublicKey", "PresharedKey", "AllowedIPs", "PersistentKeepalive", "Endpoint"],
|
||||
"[instance]": ["source-if", "source-lport", "target", "key", "masking",
|
||||
"verbose", "idle-timeout", "max-dummy"],
|
||||
}
|
||||
sections = []
|
||||
cur = None
|
||||
for ln in conf.split("\n"):
|
||||
s = ln.strip()
|
||||
if s.startswith("[") and s.endswith("]"):
|
||||
cur = [s, []]
|
||||
sections.append(cur)
|
||||
elif cur is not None:
|
||||
cur[1].append(ln)
|
||||
out = []
|
||||
for header, lines in sections:
|
||||
keys = {ln.split("=", 1)[0].strip().lower() for ln in lines if "=" in ln}
|
||||
while lines and lines[-1].strip() == "":
|
||||
lines.pop()
|
||||
for req in mandatory.get(header.lower(), []):
|
||||
if req.lower() not in keys:
|
||||
lines.append("%s = none" % req)
|
||||
out.append(header)
|
||||
out.extend(lines)
|
||||
out.append("")
|
||||
return "\n".join(out).rstrip("\n") + "\n"
|
||||
|
||||
|
||||
def qr_datauri(data):
|
||||
try:
|
||||
import qrcode, io, base64
|
||||
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_L,
|
||||
box_size=4, border=3)
|
||||
qr.add_data(data)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
buf = io.BytesIO()
|
||||
qrcode.make(data).save(buf, format="PNG")
|
||||
img.save(buf, format="PNG")
|
||||
return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
|
||||
except Exception:
|
||||
return ""
|
||||
@@ -1654,7 +1694,7 @@ def client_phone(cid, mode):
|
||||
{nav('clients')}
|
||||
<div class="card" style="text-align:center">
|
||||
<h2>{cid} — {title}</h2>
|
||||
<img src="{qr}" alt="QR" style="width:300px;height:300px;background:#fff;padding:10px;border-radius:10px"><br>
|
||||
<img src="{qr}" alt="QR" style="max-width:340px;width:100%;background:#fff;padding:10px;border-radius:10px;image-rendering:pixelated"><br>
|
||||
<p style="margin-top:10px">{tr("Отсканируй QR в приложении или импортируй конфиг:", "Scan the QR in the app or import the config:")}</p>
|
||||
{extra}
|
||||
<textarea readonly onclick="this.select()" style="width:100%;height:250px;font-family:monospace;font-size:.78em">{conf}</textarea>
|
||||
|
||||
@@ -98,7 +98,7 @@ for _am in "aarch64:linux-arm64" "mipsel:linux-mipsel-mips32" "mips:linux-mips-m
|
||||
_t=$(mktemp -d)
|
||||
curl -fsSL -m30 "${_CB}/wg-obfuscator-${_OBF_TAG}-${_ss}.tar.gz" -o "$_t/o.tgz" 2>/dev/null &&
|
||||
tar -xzf "$_t/o.tgz" -C "$_t" 2>/dev/null &&
|
||||
_b=$(find "$_t" -name "wg-obfuscator" | head -1) &&
|
||||
_b=$(find "$_t" -name "wg-obfuscator" -type f | head -1) &&
|
||||
[ -n "$_b" ] && cp "$_b" "$PHOBOS_DIR/bin/wg-obfuscator-${_da}" && chmod +x "$PHOBOS_DIR/bin/wg-obfuscator-${_da}" && echo " +wg-obfuscator-${_da} (ClusterM ${_OBF_TAG})"
|
||||
rm -rf "$_t"
|
||||
fi
|
||||
|
||||
@@ -6,6 +6,12 @@ check_root
|
||||
load_env
|
||||
ensure_dirs
|
||||
|
||||
# server.env stores OBFUSCATOR_PORTS (plural, comma list). Client obfuscator
|
||||
# must target an ACTUAL listening port. lib-core load_env defaults OBFUSCATOR_PORT
|
||||
# to 51821 (NOT listened on) -> handshake failed. Override unconditionally from
|
||||
# the real port list when present.
|
||||
[ -n "${OBFUSCATOR_PORTS:-}" ] && export OBFUSCATOR_PORT="$(echo "$OBFUSCATOR_PORTS" | cut -d',' -f1)"
|
||||
|
||||
CMD="${1:-help}"
|
||||
CLIENT_ARG="${2:-}"
|
||||
EXTRA_ARG="${3:-}"
|
||||
@@ -209,8 +215,21 @@ action_package() {
|
||||
cp "$dir/${id}.conf" "$pkg_root/${id}.conf"
|
||||
cp "$dir/wg-obfuscator.conf" "$pkg_root/wg-obfuscator.conf"
|
||||
|
||||
for arch in mipsel mips aarch64 armv7 x86_64; do
|
||||
[[ -f "$PHOBOS_DIR/bin/wg-obfuscator-$arch" ]] && cp "$PHOBOS_DIR/bin/wg-obfuscator-$arch" "$pkg_root/bin/"
|
||||
# Fetch missing router-arch binaries from ClusterM on-demand
|
||||
local _tag; _tag=$(curl -fsSL -m10 https://api.github.com/repos/ClusterM/wg-obfuscator/releases/latest 2>/dev/null | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\(.*\)".*//')
|
||||
local _cb="https://github.com/ClusterM/wg-obfuscator/releases/download/${_tag}"
|
||||
declare -A _am=([aarch64]="linux-arm64" [mipsel]="linux-mipsel-mips32" [mips]="linux-mips-mips32" [armv7]="linux-armv7-hf" [x86_64]="linux-x64")
|
||||
for _arch in aarch64 mipsel mips armv7 x86_64; do
|
||||
if [[ ! -f "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" ]] && [[ -n "$_tag" ]]; then
|
||||
local _t; _t=$(mktemp -d)
|
||||
if curl -fsSL -m30 "${_cb}/wg-obfuscator-${_tag}-${_am[$_arch]}.tar.gz" -o "$_t/o.tgz" 2>/dev/null; then
|
||||
tar -xzf "$_t/o.tgz" -C "$_t" 2>/dev/null || true
|
||||
local _b; _b=$(find "$_t" -name "wg-obfuscator" -type f | head -1)
|
||||
[[ -n "$_b" ]] && cp "$_b" "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" && chmod +x "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" && log_info "+wg-obfuscator-$_arch (ClusterM ${_tag})"
|
||||
fi
|
||||
rm -rf "$_t"
|
||||
fi
|
||||
[[ -f "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" ]] && cp "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" "$pkg_root/bin/"
|
||||
done
|
||||
|
||||
local tpl_dir="$REPO_DIR/client/templates"
|
||||
@@ -249,7 +268,7 @@ action_package() {
|
||||
source "$PHOBOS_DIR/server/server.env"
|
||||
cat > "$pkg_root/failover.conf" <<FAILEOF
|
||||
# Phobos Failover Configuration
|
||||
SERVER_1=${SERVER_PUBLIC_IP_V4}:51821,51822,51823
|
||||
SERVER_1=${SERVER_PUBLIC_IP_V4}:${OBFUSCATOR_PORTS:-51821,51822,51823}
|
||||
KEY_1=${OBFUSCATOR_KEY}
|
||||
FAILEOF
|
||||
|
||||
|
||||
70
uninstall.sh
Executable file
70
uninstall.sh
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# PCA Phobos — полное удаление сервера (primary / panel node)
|
||||
#
|
||||
# bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/uninstall.sh)
|
||||
#
|
||||
# Останавливает и удаляет: панель, обфускатор-сервисы, WireGuard wg0,
|
||||
# nginx-сайт, watchdog-cron, бинарники, iptables-правила, каталоги Phobos.
|
||||
# По умолчанию спрашивает подтверждение. PURGE=1 — без вопросов.
|
||||
# ============================================================
|
||||
set -u
|
||||
PHOBOS_DIR="/opt/Phobos"
|
||||
PANEL_DIR="/opt/phobos-panel"
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || { echo "Запусти от root"; exit 1; }
|
||||
|
||||
echo "=================================================="
|
||||
echo " PCA Phobos — УДАЛЕНИЕ сервера"
|
||||
echo " Будут удалены: панель, obfuscator, wg0, nginx-сайт,"
|
||||
echo " watchdog, бинарники, $PHOBOS_DIR, $PANEL_DIR"
|
||||
echo "=================================================="
|
||||
if [ "${PURGE:-0}" != "1" ]; then
|
||||
printf "Точно удалить ВСЁ? [yes/NO]: "
|
||||
read ans
|
||||
[ "$ans" = "yes" ] || { echo "Отменено."; exit 0; }
|
||||
fi
|
||||
|
||||
IFACE=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<NF;i++) if($i=="dev") print $(i+1)}' | head -1)
|
||||
IFACE="${IFACE:-eth0}"
|
||||
|
||||
echo "[1/8] stop + disable services..."
|
||||
# obfuscator services (any port)
|
||||
for svc in $(systemctl list-units --all --plain --no-legend 'wg-obfuscator-*' 2>/dev/null | awk '{print $1}'); do
|
||||
systemctl stop "$svc" 2>/dev/null; systemctl disable "$svc" 2>/dev/null
|
||||
done
|
||||
for svc in phobos-panel phobos-api wg-quick@wg0; do
|
||||
systemctl stop "$svc" 2>/dev/null; systemctl disable "$svc" 2>/dev/null
|
||||
done
|
||||
|
||||
echo "[2/8] remove systemd units..."
|
||||
rm -f /etc/systemd/system/wg-obfuscator-*.service 2>/dev/null
|
||||
rm -f /etc/systemd/system/phobos-panel.service /etc/systemd/system/phobos-api.service 2>/dev/null
|
||||
systemctl daemon-reload 2>/dev/null
|
||||
|
||||
echo "[3/8] remove WireGuard wg0..."
|
||||
rm -f /etc/wireguard/wg0.conf 2>/dev/null
|
||||
|
||||
echo "[4/8] remove iptables rules..."
|
||||
iptables -t nat -D POSTROUTING -o "$IFACE" -j MASQUERADE 2>/dev/null || true
|
||||
iptables -D FORWARD -i wg0 -j ACCEPT 2>/dev/null || true
|
||||
iptables -D FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||
iptables -D INPUT -p udp --dport 51820 ! -s 127.0.0.1 -j DROP 2>/dev/null || true
|
||||
|
||||
echo "[5/8] remove nginx site..."
|
||||
rm -f /etc/nginx/sites-enabled/phobos /etc/nginx/sites-available/phobos 2>/dev/null
|
||||
nginx -t >/dev/null 2>&1 && systemctl reload nginx 2>/dev/null || true
|
||||
|
||||
echo "[6/8] remove watchdog cron..."
|
||||
( crontab -l 2>/dev/null | grep -v 'phobos-router-watchdog' | grep -v '/opt/Phobos' || true ) | crontab - 2>/dev/null || true
|
||||
|
||||
echo "[7/8] remove binaries / symlinks..."
|
||||
rm -f /usr/local/bin/wg-obfuscator /usr/local/bin/phobos-update 2>/dev/null
|
||||
|
||||
echo "[8/8] remove directories..."
|
||||
rm -rf "$PHOBOS_DIR" "$PANEL_DIR" 2>/dev/null
|
||||
|
||||
echo "=================================================="
|
||||
echo " Phobos удалён."
|
||||
echo " (WireGuard/nginx/cron-пакеты НЕ удалены — общие; убрать вручную при желании)"
|
||||
echo "=================================================="
|
||||
Reference in New Issue
Block a user