19 Commits

Author SHA1 Message Date
andrey271192
b23ac29e87 contact: personal Telegram -> group @PCAdministration 2026-05-30 18:27:48 +03:00
andrey271192
23212a8b01 contact: personal Telegram -> group @PCAdministration 2026-05-30 18:27:46 +03:00
andrey271192
48d20a08b7 contact: personal Telegram -> group @PCAdministration 2026-05-30 18:27:44 +03:00
andrey271192
8beee2f067 contact: personal Telegram -> group @PCAdministration 2026-05-30 18:27:43 +03:00
andrey271192
6624b8127e contact: personal Telegram -> group @PCAdministration 2026-05-30 18:26:43 +03:00
Андрей Бобырев
9792bbccb6 docs: живее README, скрины и понятнее вступление
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 06:59:42 +03:00
Андрей Бобырев
156a02fa32 docs: polish wording for public audience
Rename informal quickstart headings to neutral Quickstart.
2026-04-27 04:19:12 +03:00
Андрей Бобырев
8fe0a09684 docs: add beginner steps and fix SSH port example
Add simple step-by-step guidance, troubleshooting notes, and align SSH port example to 22.
2026-04-27 04:14:18 +03:00
Андрей Бобырев
aae52e86ef docs: add Entware install snippet
Document Entware installation (mipsel/aarch64 + KeeneticOS 4.2 browser method) and SSH defaults for router access.
2026-04-27 03:16:39 +03:00
Андрей Бобырев
ee031b09dd docs: больше наглядности (схемы + скриншот)
Made-with: Cursor
2026-04-26 17:06:24 +03:00
andrey271192
bf504f4b28 README.md 2026-04-26 16:51:36 +03:00
Андрей Бобырев
a671c1556f docs: объяснить имя роутера (peer) и --dnat для разных портов
Made-with: Cursor
2026-04-26 16:22:31 +03:00
Андрей Бобырев
c6db82bd2e tunnel: per-peer DNAT ports via kssh-tun add --dnat
Made-with: Cursor
2026-04-26 16:19:59 +03:00
Андрей Бобырев
90006b6149 tunnel: печатать DNAT_PORTS=81,79 в ENV-блоке
Made-with: Cursor
2026-04-26 16:14:50 +03:00
Андрей Бобырев
10852b61b3 tunnel: DNAT_PORTS для разных портов (81/79/...)
Made-with: Cursor
2026-04-26 16:05:59 +03:00
Андрей Бобырев
4e9f413521 tunnel: авто-DNAT для NDM/81 через wg0 (fix connection refused)
Made-with: Cursor
2026-04-26 16:02:41 +03:00
Андрей Бобырев
858ff8b6ef docs: README для новичков (без доменов, безопасное удаление)
Made-with: Cursor
2026-04-26 15:44:32 +03:00
Андрей Бобырев
7dbd2b43d0 docs: серый IP — 2 команды + Caddy/Nginx пример
Made-with: Cursor
2026-04-26 15:36:40 +03:00
Андрей Бобырев
7866cc22d5 docs: переписать README (простая установка) + скриншоты
Made-with: Cursor
2026-04-26 15:33:31 +03:00
15 changed files with 461 additions and 273 deletions

View File

@@ -24,7 +24,7 @@ PORT=2001
CMD_TIMEOUT=300
# Подпись и Telegram внизу страницы (без @)
AUTHOR_TELEGRAM_USERNAME=Iot_andrey
AUTHOR_TELEGRAM_USERNAME=PCAdministration
# Ограничение по IP клиента (через запятую, без масок). Пусто = все IP.
# Пример: ALLOWED_IPS=192.168.1.100,10.0.0.5

482
README.md
View File

@@ -1,329 +1,279 @@
# keenetic_ssh-web
> Локальная веб-панель для **Keenetic + Entware**: shell-команды на роутере, расписание, ручной запуск, просмотр stdout/stderr. Слушает порт **2001**. Авторизация — логин/пароль от веб-админки роутера.
>
> + опциональный модуль **`tunnel/`** — WireGuard VPS↔роутер, чтобы дотянуться до панели и SSH с **серого IP**, без проброса портов.
Веб‑панель, которая **выполняет команды прямо на роутере Keenetic** (Entware) и показывает вывод. Подходит для обновления пакетов, перезапусков сервисов, диагностики, и т. п.
Репозиторий: [github.com/andrey271192/keenetic_ssh-web](https://github.com/andrey271192/keenetic_ssh-web)
- **Порт панели:** `2001`
- **Где работает:** на самом роутере (Entware)
- **Вход:** логин/пароль **от веб‑админки Keenetic** (NDM `/auth`)
(есть запасной «мастер‑пароль» `WEB_PASSWORD`, если нужно)
- **Опционально:** модуль `tunnel/`**WireGuardтуннель VPS ↔ роутер**, чтобы открыть доступ к панели и SSH, даже если у роутера **серый IP** (без проброса портов).
![Интерфейс](docs/ui.png)
![Схема туннеля (через VPS)](docs/tunnel-diagram.svg)
---
## В репозитории два независимых пакета
## Самое главное (чтобы было безопасно)
| Пакет | Куда ставится | Зачем | Обязателен |
|---|---|---|---|
| **A. keenetic_ssh-web** | роутер (Entware) | веб-панель команд на 2001 | да |
| **B. tunnel** | VPS (Ubuntu) + роутер | WG-туннель для серого IP | нет, по желанию |
**Ставятся и удаляются отдельно**. Пакет B нужен только если у роутера серый IP и вы хотите управлять им из интернета через свой VPS. Если у вас белый IP / KeenDNS Cloud / достаточно LAN — ставьте только A.
> ⚠️ **Скрипты установки/удаления НЕ трогают** `hrneo`/`hrweb` (HydraRoute Neo), XKeen, Domain Hydra и любые ваши кастомные пакеты Entware. Не правят `/opt/etc/opkg.conf`, не сбрасывают чужие правила iptables, не ставят/удаляют пакеты, не относящиеся к данным двум пакетам.
- Эта панель запускает **любые команды** в Linux на роутере. Это мощно, но опасно.
- **Не открывайте порт 2001 в интернет для всех.** Минимум — включите `ALLOWED_IPS` или используйте туннель (вариант 2).
---
## Сценарии и что ставить
## Быстрый старт
| Сценарий | Доступ | Что ставить |
|---|---|---|
| Управляю только из дома (LAN) | `http://192.168.X.1:2001` | только **A** |
| Серый IP, нужен доступ из любой точки | `https://имя.домен` через ваш VPS | **A** + **B** + reverse-proxy на VPS |
| Белый IP / KeenDNS Cloud | проброс портов или KeenDNS на 2001 | только **A** (B не нужен) |
1. **Entware** на роутере — блок «📦 Установка Entware» ниже.
2. **Панель** — вариант 1, если хватает доступа из домашней сети.
3. **Серый IP** и нужен доступ откуда угодно — вариант 2 с туннелем через VPS.
Рядом с [Keenetic Unified](https://github.com/andrey271192/keenetic-unified) этот проект **не мешает**: другой порт (`2001`), всё крутится на самом роутере.
### Ещё скриншоты
| | |
|---|---|
| Список файлов на роутере | ![Файлы](docs/files.png) |
| Проверка DNS-маршрутов | ![DNS routes](docs/dns-routes-test.png) |
### 📦 Установка Entware на Keenetic
━━━━━━━━━━━━━━━━━━━━━━
⚠️ Определи свою архитектуру
- Mipsel — роутеры на чипе MT7628/MT7621
- Aarch64 — роутеры на чипе MT7622/MT7981/MT7988 (ARM)
━━━━━━━━━━━━━━━━━━━━━━
💡 Совет
Начиная с KeeneticOS 4.2 Entware можно установить прямо через браузер — просто открой `192.168.1.1/a` и следуй инструкции.
━━━━━━━━━━━━━━━━━━━━━━
🚀 Установка онлайн — одной командой
🔵 Mipsel (MT7628/MT7621)
```sh
opkg disk storage:/ https://bin.entware.net/mipselsf-k3.4/installer/mipsel-installer.tar.gz
```
🟢 Aarch64 (MT7622/MT7981/MT7988)
```sh
opkg disk storage:/ https://bin.entware.net/aarch64-k3.10/installer/aarch64-installer.tar.gz
```
⏳ Дождись окончания установки — это займёт пару минут. После этого Entware готов к работе.
🔌 Подключение по SSH
📋 Данные для входа
- Логин: `root`
- Пароль: `keenetic`
- Порт: `22` (если вы не меняли порт SSH вручную)
### Вариант 1. Панель нужна только дома (LAN)
На роутере (в Entware shell по SSH):
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/setup-router.sh | sh
```
Откройте в браузере:
- `http://IP_РОУТЕРА:2001`
Вход — **как в веб‑админку Keenetic**.
---
# A. keenetic_ssh-web — установка
### Вариант 2. Серый IP, нужен доступ из любой точки (через VPS)
## A.1. Требования
#### 2 команды “с нуля” (самый простой путь)
- Keenetic с **Entware** (`opkg` доступен)
- `python3` — установится автоматически из `bin.entware.net`
- Свободный порт **2001** (можно переопределить в `.env`)
![2 шага установки (VPS → роутер)](docs/steps.svg)
## A.2. Установка одной командой (на роутере)
**Команда 1 — на VPS (Ubuntu):** поставить туннель и сразу добавить роутер.
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/bootstrap.sh | sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/setup-vps.sh | sudo bash -s -- add my-router
```
Что делает:
- скачивает архив ветки `main`, кладёт в `/opt/share/keenetic_ssh-web`
- ставит **только** `python3`, `python3-pip`, `python3-venv` (если их нет)
- кладёт init-скрипт `/opt/etc/init.d/S99keenetic-ssh-web` и rc.d-симлинк
- стартует сервис на порту 2001
- создаёт `.env` из примера и подставляет в `ROUTER_HOST` LAN-IP роутера
Где `my-router`**имя этого роутера на VPS** (можете назвать `home`, `dacha`, `office1`).
В конце выведет адрес панели: `http://<LAN-IP>:2001`. Логин/пароль — от веб-админки роутера.
> Другая ветка/форк: `KSSH_BRANCH=dev KSSH_REPO=user/repo curl … | sh`.
## A.3. Конфиг — `/opt/share/keenetic_ssh-web/.env`
| Переменная | Описание | По умолчанию |
|---|---|---|
| `ROUTER_HOST` | HTTP-адреса админки Keenetic для проверки логина (через запятую — пробуем по очереди). Установщик сам подставит LAN-IP. | `http://127.0.0.1` |
| `ROUTER_LOGIN` | Логин по умолчанию в форме входа | `admin` |
| `ROUTER_TIMEOUT` | Таймаут запроса к `/auth`, сек | `5` |
| `WEB_PASSWORD` | Запасной мастер-пароль (если админка недоступна) | пусто |
| `PORT` | HTTP-порт панели | `2001` |
| `CMD_TIMEOUT` | Таймаут одной shell-команды, сек | `300` |
| `ALLOWED_IPS` | Белый список IP клиентов (через запятую). Пусто = всех. | пусто |
| `AUTHOR_TELEGRAM_USERNAME` | username для ссылки в шапке | `Iot_andrey` |
После правки:
```sh
/opt/etc/init.d/S99keenetic-ssh-web restart
tail -f /opt/var/log/keenetic-ssh-web.log
```
> ⚠️ **Безопасность.** Панель выполняет произвольные shell-команды с правами процесса (на Entware часто root). Не открывайте порт 2001 в интернет напрямую. Используйте `ALLOWED_IPS` или туннель + reverse-proxy с HTTPS (см. пакет B).
## A.4. Управление сервисом
Если у конкретного роутера «прокси/админка» сидит на другом порту (например `777`), задайте порт **для этого роутера**:
```sh
/opt/etc/init.d/S99keenetic-ssh-web start
/opt/etc/init.d/S99keenetic-ssh-web stop
/opt/etc/init.d/S99keenetic-ssh-web restart
tail -f /opt/var/log/keenetic-ssh-web.log
vi /opt/share/keenetic_ssh-web/.env
sudo kssh-tun add my-router --dnat 777
```
## A.5. Удаление keenetic_ssh-web
Что делает `--dnat`: туннель на роутере автоматически прокидывает вход на `wg0:<порт>``LAN_IP:<порт>`.
Это нужно, потому что некоторые сервисы Keenetic слушают **только на LANIP**, и через `wg0` иначе будет `Connection refused`.
Команда на VPS выведет **готовый блок** (несколько строк `export ...` + `curl ... | sh`).
**Команда 2 — на роутере (Entware shell):** вставьте выданный блок **как есть**.
Он поднимет `wg0`, а затем установит панель на `2001`.
Проверка с VPS:
```sh
curl http://10.99.0.X:2001
ssh root@10.99.0.X
```
Можно **вообще без домена и без Caddy/Nginx**: просто открывайте панель по IP из туннеля:
- `http://10.99.0.X:2001`
Reverseproxy нужен только если вы хотите **красивый адрес** `https://router-домен` и HTTPS.
**Caddy (3 строки):**
```caddy
router.example.com {
reverse_proxy 10.99.0.X:2001
}
```
**Nginx (минимальный server block):**
```nginx
server {
server_name router.example.com;
location / { proxy_pass http://10.99.0.X:2001; }
}
```
Рекомендация: в `.env` панели выставить **`ALLOWED_IPS=10.99.0.1`**, чтобы к роутеру мог обращаться **только VPS**.
---
### Вариант 3. Белый IP — без туннеля
Ставьте как в варианте 1 (LAN), а доступ снаружи делайте как вам удобно: проброс порта/файрвол/домен.
Важно: **не открывайте 2001 в интернет без ограничений** (см. безопасность ниже).
---
## Как пользоваться панелью
### 1) Добавьте команду
- **Название** — как вам удобно (например: `opkg update`)
- **Команда** — обычная shellкоманда (например: `opkg update`)
- **Примечание** — необязательно
### 2) Запуск
- **Выполнить** — запускает одну команду и показывает результат
- **Выполнить все команды** — запускает все строки с галочкой **«ВКЛ»**
### 3) Расписание
- Поставьте интервал (в минутах) и нажмите **Сохранить**
- У нужных строк включите **«Распис.»**
По расписанию выполняются только строки: **ВКЛ + Распис.**
### 4) Просмотр вывода
Кнопка **«Вывод»** раскрывает полный лог последнего запуска (stdout + stderr).
---
## Примеры полезных команд (можно копировать)
- Обновить пакеты: `opkg update && opkg list-upgradable | head`
- Обновить всё: `opkg update && opkg upgrade`
- Проверить место: `df -h`
- Процессы: `top -b -n 1 | head -60`
- WireGuard: `wg show`
- Логи: `logread | tail -200`
---
## Безопасность (важно)
Это **не песочница**: команда выполняется с правами процесса (на Entware часто **root**).
- Не публикуйте порт **2001** в интернет «как есть».
- Используйте минимум: **туннель + reverseproxy** или **`ALLOWED_IPS`**.
---
## Удаление (одной командой)
### удаления (под ключ, без поломок)
Скрипты **удаляют только то, что сами ставили** и **не трогают**:
- HydraRoute Neo (`hrneo` / `hrweb`)
- другие Entwareпакеты и ваши сервисы
- ваши конфиги (кроме своих файлов)
- чужие правила firewall/iptables (удаляются только наши вставки, связанные с wg0)
Если хотите сохранить настройки панели (`.env`) и список команд (`data/store.json`) — скажите, добавлю отдельную “удалить, но оставить данные” команду в `setup-router.sh` (сейчас это есть для панели через `KEEP_DATA=1`, но не вынесено в быстрый блок).
---
Панель (на роутере):
С GitHub:
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/uninstall.sh | sh
```
Сохранить `data/store.json` и `.env`:
Панель (на роутере), **сохранить команды и настройки**:
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/uninstall.sh | env KEEP_DATA=1 sh
```
Удаляет ровно: `/opt/share/keenetic_ssh-web/`, `/opt/etc/init.d/S99keenetic-ssh-web`, `/opt/etc/rc.d/S99keenetic-ssh-web`, pid-файл.
**Не удаляет:** `python3`, `wireguard-tools`, `hrneo`, `hrweb`, любые другие пакеты Entware, лог `/opt/var/log/keenetic-ssh-web.log`.
---
# B. tunnel — установка (опционально, для серых IP)
```
[твой ПК] → https://router.домен (VPS, белый IP)
│ Caddy/Nginx reverse-proxy
wg0 10.99.0.1 (VPS)
⇅ WireGuard, UDP/51820
wg0 10.99.0.X (роутер за NAT провайдера)
127.0.0.1:2001 keenetic_ssh-web
127.0.0.1:22 SSH
```
Туннель **инициирует роутер** наружу — серый IP / NAT провайдера не мешает.
## B.1. На VPS (Ubuntu) — один раз
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/server-install.sh | sudo sh
```
Что делает:
- `apt install wireguard wireguard-tools curl`
- генерит серверные ключи (`/etc/wireguard/server_{private,public}.key`)
- создаёт `/etc/wireguard/wg0.conf` (UDP 51820, IP `10.99.0.1/24`)
- ставит утилиту `kssh-tun` в `/usr/local/bin/`
- открывает `51820/udp` и `wg0` в `ufw`/`iptables`, если активны
- запускает `wg-quick@wg0` и ставит на автозапуск
В конце печатает Endpoint и серверный PublicKey.
## B.2. На VPS — добавить роутер (peer)
```sh
sudo kssh-tun add router-name
```
Утилита:
- генерит ключи клиента, выделяет IP `10.99.0.X`
- сохраняет `/etc/wireguard/peers/<name>.peer`
- регенерирует `wg0.conf` и применяет (`systemctl restart wg-quick@wg0`)
- **выводит готовую команду для роутера** — четыре `export` + `curl … | sh`
Прочие команды:
```sh
sudo kssh-tun list # список peer-ов
sudo kssh-tun show <name> # повторно вывести ENV-блок
sudo kssh-tun remove <name> # удалить peer
sudo kssh-tun status # wg show wg0
```
## B.3. На роутере — поднять клиент
Скопируйте блок из `kssh-tun add` и выполните на роутере (через SSH/Entware shell):
```sh
export VPS_ENDPOINT=SERVER_IP:51820
export VPS_PUBKEY='...'
export CLIENT_IP=10.99.0.X
export CLIENT_PRIVKEY='...'
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/tunnel-install.sh | sh
```
Что делает:
- `opkg install wireguard-tools` (если нет)
- пишет `/opt/etc/wireguard/wg0.conf`
- поднимает интерфейс `wg0` с адресом `CLIENT_IP/24`
- ставит init-скрипт `/opt/etc/init.d/S50kssh-tunnel` + rc.d-симлинк
- **разрешает входящий трафик с туннеля** (`iptables -I INPUT -i wg0 -j ACCEPT` + `rp_filter=2`) — без этого Keenetic режет ответы из VPS, handshake пройдёт, а ping/HTTP — нет
- пингует `10.99.0.1` для проверки
После этого с VPS:
```sh
ping -c 3 10.99.0.X
ssh root@10.99.0.X # если на роутере включён SSH
curl http://10.99.0.X:2001 # панель keenetic_ssh-web (если установлена)
```
## B.4. Reverse-proxy на VPS (доступ снаружи)
Caddyfile:
```
router.example.com {
reverse_proxy 10.99.0.X:2001
}
```
Caddy выдаст HTTPS, и `https://router.example.com` отдаёт панель роутера. В `.env` keenetic_ssh-web укажите `ALLOWED_IPS=10.99.0.1` — только VPS будет иметь право заходить.
## B.5. Параметры (ENV)
`server-install.sh` (VPS):
| Переменная | По умолчанию | Описание |
|---|---|---|
| `WG_PORT` | `51820` | UDP-порт сервера |
| `WG_SUBNET_PREFIX` | `10.99.0` | Первые три октета `/24` |
| `WG_SERVER_LAST_OCTET` | `1` | Адрес сервера в туннеле |
| `KSSH_REPO`/`KSSH_BRANCH` | `andrey271192/keenetic_ssh-web` / `main` | Источник `kssh-tun` и `tunnel-install.sh` |
`tunnel-install.sh` (роутер):
| Переменная | Обязательная | Описание |
|---|---|---|
| `VPS_ENDPOINT` | да | `<публичный IP>:<порт>` |
| `VPS_PUBKEY` | да | PublicKey сервера |
| `CLIENT_IP` | да | IP роутера в туннеле |
| `CLIENT_PRIVKEY` | да | PrivateKey роутера (выдаёт `kssh-tun add`) |
| `WG_IF` | `wg0` | Имя интерфейса |
| `WG_SUBNET` | `10.99.0.1/32` | AllowedIPs клиента. По умолчанию только VPS, чтобы не ломать существующие WG-маршруты Keenetic. Поставьте `10.99.0.0/24` для peer-to-peer. |
| `WG_KEEPALIVE` | `25` | `PersistentKeepalive`, сек (нужен из-за NAT провайдера) |
## B.6. Удаление tunnel
### B.6.1. На роутере (только клиент)
Туннель‑клиент (на роутере, если ставили):
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/tunnel-uninstall.sh | sh
```
Удаляет: интерфейс `wg0`, `/opt/etc/wireguard/wg0.conf`, init-скрипт `S50kssh-tunnel`, rc.d-симлинк, наши правила `iptables ACCEPT для wg0`.
**Не удаляет:** `wireguard-tools`, общие правила iptables, чужие WG-конфиги, `keenetic_ssh-web`, HydraRoute Neo и др.
### B.6.2. На VPS (сервер)
Туннель‑сервер (на VPS, если ставили):
```sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/server-uninstall.sh | sudo sh
```
Удаляет: `wg-quick@wg0` (stop+disable), `/etc/wireguard/{wg0.conf,server_*.key,peers/,.kssh-tun.env}`, `/usr/local/bin/kssh-tun`, наши правила ufw/iptables.
**Не удаляет:** apt-пакеты `wireguard`/`wireguard-tools`, чужие правила ufw/iptables, ваши приложения и Docker.
---
Если потом захотите снести и сами apt-пакеты — вручную:
```sh
sudo apt remove --purge wireguard wireguard-tools
```
## Туннель как отдельный сервис (по желанию)
Туннель — это **дополнительный сервис для всей вашей экосистемы** (keeneticunified, domen_hydra и т. д.). Он просто делает так, что VPS «видит» роутер по адресу `10.99.0.X`.
Полная документация (для тех, кому нужно больше деталей): `tunnel/README.md`.
---
## Полный «с нуля» — пример
## Частые ошибки (и решения)
Допустим, на роутере уже стоит HydraRoute Neo, и его трогать **нельзя**. Хотим чистую установку обоих пакетов.
### `Connection refused` через туннель (RCI/админка/порт)
Некоторые сервисы Keenetic слушают **только LANIP**, и если вы ходите на `wg0`, будет `Connection refused`.
- **Решение**: включить автоDNAT на нужный порт:
**1. На VPS:**
```sh
# (если что-то стояло раньше)
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/server-uninstall.sh | sudo sh
# свежая установка сервера туннеля
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/server-install.sh | sudo sh
# завести роутер
sudo kssh-tun add my-router
# → скопировать выданный 5-строчный блок
sudo kssh-tun add my-router --dnat 81
```
**2. На роутере:**
```sh
# (если что-то стояло раньше — оба пакета по отдельности)
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/tunnel-uninstall.sh | sh
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/uninstall.sh | sh
или задать несколько портов: `--dnat 81,79`.
# панель
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/bootstrap.sh | sh
### Нельзя открывать панель в интернет
# туннель — вставить выданный с VPS блок (4 export + curl)
export VPS_ENDPOINT=...
export VPS_PUBKEY='...'
export CLIENT_IP=10.99.0.X
export CLIENT_PRIVKEY='...'
curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/tunnel/tunnel-install.sh | sh
```
Порт `2001` — это выполнение команд. **Не публикуйте его “как есть”**.
**3. Проверка с VPS:**
```sh
ping -c 3 10.99.0.X
curl -I http://10.99.0.X:2001/
```
- **Решение**: `ALLOWED_IPS` (например, только IP вашего VPS) или туннель + reverseproxy.
`hrneo`/`hrweb` (HydraRoute Neo) и любые ваши кастомные репозитории на обоих хостах остаются нетронутыми.
## Поддержка проекта
---
## Что лежит где
### keenetic_ssh-web (на роутере)
| Путь | |
|---|---|
| `/opt/share/keenetic_ssh-web/` | приложение, `.env`, `data/store.json`, venv/lib |
| `/opt/etc/init.d/S99keenetic-ssh-web` | init-скрипт |
| `/opt/etc/rc.d/S99keenetic-ssh-web` | автозапуск |
| `/opt/var/log/keenetic-ssh-web.log` | лог |
| `/opt/var/run/keenetic-ssh-web.pid` | pid |
### tunnel — клиент (на роутере)
| Путь | |
|---|---|
| `/opt/etc/wireguard/wg0.conf` | конфиг туннеля |
| `/opt/etc/init.d/S50kssh-tunnel` | init-скрипт |
| `/opt/etc/rc.d/S50kssh-tunnel` | автозапуск |
### tunnel — сервер (на VPS)
| Путь | |
|---|---|
| `/etc/wireguard/wg0.conf` | конфиг сервера (регенерируется `kssh-tun`) |
| `/etc/wireguard/server_{private,public}.key` | серверные ключи |
| `/etc/wireguard/peers/<name>.peer` | данные peer-а (имя/IP/ключи) |
| `/etc/wireguard/.kssh-tun.env` | параметры запуска |
| `/usr/local/bin/kssh-tun` | утилита |
| `systemctl status wg-quick@wg0` | сервис |
---
## Поддержка
- **GitHub:** [andrey271192](https://github.com/andrey271192)
- **Boosty:** [донат](https://boosty.to/andrey27/donate)
- **Telegram:** [@Iot_andrey](https://t.me/Iot_andrey)
- **Boosty:** `https://boosty.to/andrey27/donate`
- **Ozon Bank (СБП):** `https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798`
- **Telegram:** `https://t.me/PCAdministration`
Кнопка **Sponsor** на GitHub ведёт на варианты из `.github/FUNDING.yml`.
## Лицензия
MIT — см. [LICENSE](LICENSE).

2
app.py
View File

@@ -21,7 +21,7 @@ log = logging.getLogger("kssh")
APP_DIR = Path(__file__).resolve().parent
WEB_PASSWORD = os.environ.get("WEB_PASSWORD", "").strip()
AUTHOR_TG = os.environ.get("AUTHOR_TELEGRAM_USERNAME", "Iot_andrey").strip().lstrip("@") or "Iot_andrey"
AUTHOR_TG = os.environ.get("AUTHOR_TELEGRAM_USERNAME", "PCAdministration").strip().lstrip("@") or "PCAdministration"
ALLOWED_IPS_RAW = os.environ.get("ALLOWED_IPS", "").strip()
ALLOWED_IPS = {x.strip() for x in ALLOWED_IPS_RAW.split(",") if x.strip()} if ALLOWED_IPS_RAW else set()
CMD_TIMEOUT = int(os.environ.get("CMD_TIMEOUT", "300"))

View File

@@ -29,7 +29,7 @@ _DOT = "color:#86868b;user-select:none"
def brand_bar_html(telegram_username: str) -> str:
u = (telegram_username or "Iot_andrey").lstrip("@")
u = (telegram_username or "PCAdministration").lstrip("@")
tg = f"https://t.me/{u}"
safe_u = html.escape(u, quote=True)
return (

BIN
docs/dns-routes-test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/files.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

56
docs/steps.svg Normal file
View File

@@ -0,0 +1,56 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="520" viewBox="0 0 1200 520">
<defs>
<style>
.bg{fill:#0d1117}
.card{fill:#161b22;stroke:#30363d;stroke-width:2}
.txt{fill:#e6edf3;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif}
.mut{fill:#8b949e;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif}
.ttl{font-size:26px;font-weight:800}
.h{font-size:18px;font-weight:800}
.p{font-size:15px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace}
.accent{fill:#1f6feb}
.ok{fill:#3fb950}
.pill{fill:#0b1220;stroke:#30363d;stroke-width:2}
.arrow{stroke:#3fb950;stroke-width:4;fill:none;marker-end:url(#m)}
</style>
<marker id="m" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#3fb950"/>
</marker>
</defs>
<rect class="bg" x="0" y="0" width="1200" height="520"/>
<text class="txt ttl" x="40" y="60">Установка «серый IP через VPS» — всего 2 шага</text>
<text class="mut p" x="40" y="92">Выполняете одну команду на VPS, получаете блок — вставляете его на роутере.</text>
<!-- Step 1 -->
<rect class="card" x="40" y="140" rx="16" ry="16" width="520" height="320"/>
<circle cx="80" cy="190" r="18" class="accent"/>
<text class="txt h" x="110" y="197">Шаг 1 (на VPS)</text>
<text class="mut p" x="70" y="235">Ставим туннель и добавляем роутер:</text>
<rect class="pill" x="70" y="255" rx="12" ry="12" width="460" height="110"/>
<text class="txt p mono" x="90" y="295">curl -fsSL https://raw.githubusercontent.com/</text>
<text class="txt p mono" x="90" y="320">andrey271192/keenetic_ssh-web/main/setup-vps.sh</text>
<text class="txt p mono" x="90" y="345">| sudo bash -s -- add home --dnat 777</text>
<text class="mut p" x="70" y="400">Результат: VPS печатает блок <tspan class="mono">export ...</tspan> для роутера.</text>
<!-- Step 2 -->
<rect class="card" x="640" y="140" rx="16" ry="16" width="520" height="320"/>
<circle cx="680" cy="190" r="18" class="ok"/>
<text class="txt h" x="710" y="197">Шаг 2 (на роутере)</text>
<text class="mut p" x="670" y="235">Вставляем блок, который выдал VPS:</text>
<rect class="pill" x="670" y="255" rx="12" ry="12" width="460" height="140"/>
<text class="txt p mono" x="690" y="295">export VPS_ENDPOINT=...</text>
<text class="txt p mono" x="690" y="320">export VPS_PUBKEY='...'</text>
<text class="txt p mono" x="690" y="345">export CLIENT_IP=10.99.0.X</text>
<text class="txt p mono" x="690" y="370">export DNAT_PORTS='777'</text>
<text class="txt p mono" x="690" y="395">curl -fsSL .../tunnel-install.sh | sh</text>
<text class="mut p" x="670" y="445">Готово: открываете <tspan class="mono">http://10.99.0.X:2001</tspan></text>
<path class="arrow" d="M 560 300 C 600 300, 610 300, 640 300"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

69
docs/tunnel-diagram.svg Normal file
View File

@@ -0,0 +1,69 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="520" viewBox="0 0 1200 520">
<defs>
<style>
.bg{fill:#0d1117}
.card{fill:#161b22;stroke:#30363d;stroke-width:2}
.txt{fill:#e6edf3;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif}
.mut{fill:#8b949e;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif}
.ttl{font-size:26px;font-weight:800}
.h{font-size:18px;font-weight:700}
.p{font-size:15px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace}
.accent{fill:#1f6feb}
.ok{fill:#3fb950}
.arrow{stroke:#1f6feb;stroke-width:4;fill:none;marker-end:url(#m)}
.arrow2{stroke:#3fb950;stroke-width:4;fill:none;marker-end:url(#m2)}
</style>
<marker id="m" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#1f6feb"/>
</marker>
<marker id="m2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#3fb950"/>
</marker>
</defs>
<rect class="bg" x="0" y="0" width="1200" height="520"/>
<text class="txt ttl" x="40" y="60">Схема работы (серый IP → доступ через VPS)</text>
<text class="mut p" x="40" y="92">Роутер сам подключается к VPS по WireGuard, и VPS видит роутер как «локальный» IP 10.99.0.X.</text>
<!-- PC -->
<rect class="card" x="40" y="150" rx="16" ry="16" width="320" height="260"/>
<text class="txt h" x="70" y="195">Ваш ПК / телефон</text>
<text class="mut p" x="70" y="225">Открываете панель:</text>
<text class="txt p mono" x="70" y="255">http://10.99.0.X:2001</text>
<text class="mut p" x="70" y="290">(если туннель включён)</text>
<text class="mut p" x="70" y="335">Или дома в LAN:</text>
<text class="txt p mono" x="70" y="365">http://192.168.88.1:2001</text>
<!-- VPS -->
<rect class="card" x="440" y="150" rx="16" ry="16" width="320" height="260"/>
<text class="txt h" x="470" y="195">VPS (белый IP)</text>
<text class="mut p" x="470" y="225">WireGuard сервер:</text>
<text class="txt p mono" x="470" y="255">wg0 10.99.0.1</text>
<text class="mut p" x="470" y="295">Порт:</text>
<text class="txt p mono" x="520" y="295">UDP 51820</text>
<text class="mut p" x="470" y="335">Проверка:</text>
<text class="txt p mono" x="470" y="365">ping 10.99.0.X</text>
<!-- Router -->
<rect class="card" x="840" y="150" rx="16" ry="16" width="320" height="260"/>
<text class="txt h" x="870" y="195">Роутер Keenetic (Entware)</text>
<text class="mut p" x="870" y="225">WireGuard клиент:</text>
<text class="txt p mono" x="870" y="255">wg0 10.99.0.X</text>
<rect x="870" y="285" rx="12" ry="12" width="260" height="44" fill="#0b1220" stroke="#30363d" stroke-width="2"/>
<circle cx="892" cy="307" r="8" class="ok"/>
<text class="txt p" x="910" y="312">keenetic_ssh-web :2001</text>
<rect x="870" y="342" rx="12" ry="12" width="260" height="44" fill="#0b1220" stroke="#30363d" stroke-width="2"/>
<circle cx="892" cy="364" r="8" class="accent"/>
<text class="txt p" x="910" y="369">SSH :22</text>
<!-- Arrows -->
<path class="arrow" d="M 360 280 C 400 280, 410 280, 440 280"/>
<path class="arrow2" d="M 760 280 C 800 280, 810 280, 840 280"/>
<text class="mut p" x="505" y="140">WireGuard туннель</text>
<text class="mut p mono" x="515" y="118">10.99.0.0/24</text>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
docs/ui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -4,6 +4,7 @@
# Запуск (любой из вариантов):
# curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/setup-vps.sh | sudo bash
# curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/setup-vps.sh | sudo bash -s -- add <peer-name>
# curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/setup-vps.sh | sudo bash -s -- add <peer-name> --dnat 777
#
# Что делает (одной командой):
# 1) сносит предыдущий kssh-tunnel сервер (если был)
@@ -33,7 +34,8 @@ curl -fsSL "$RAW/tunnel/server-install.sh" | bash
if [ "${1:-}" = "add" ] && [ -n "${2:-}" ]; then
echo
echo "==> [3/3] Добавление peer '$2'…"
/usr/local/bin/kssh-tun add "$2"
shift 2
/usr/local/bin/kssh-tun add "$@"
else
echo
echo "==> [3/3] Сервер готов. Добавьте роутер командой:"

View File

@@ -82,7 +82,7 @@
</div>
<div class="links">
<a class="lnk" href="https://github.com/andrey271192/keenetic_ssh-web" target="_blank" rel="noopener noreferrer">GitHub</a>
<a class="lnk" id="lnk-tg" href="https://t.me/Iot_andrey" target="_blank" rel="noopener noreferrer">Telegram</a>
<a class="lnk" id="lnk-tg" href="https://t.me/PCAdministration" target="_blank" rel="noopener noreferrer">Telegram</a>
<a class="lnk" href="https://boosty.to/andrey27/donate" target="_blank" rel="noopener noreferrer">Boosty</a>
<a class="lnk donate" href="https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798" target="_blank" rel="noopener noreferrer" title="Поддержать проекта (Ozon Bank, СБП)">Поддержать ❤</a>
</div>

View File

@@ -2,6 +2,14 @@
Решает задачу: у вас на роутере **серый IP** (нет публичного), но есть **VPS с белым IP**. Поднимаем WireGuard, и любой сервис на VPS обращается к роутеру по адресу из туннельной подсети (`10.99.0.X`), как если бы они были в одной LAN. SSH, HTTP, что угодно — без проброса портов и без переписывания других сервисов (`Domain Hydra`, `keenetic-unified`, `keenetic_ssh-web`, …).
## Quickstart
- На VPS выполни “1 раз” (раздел 1).
- На VPS добавь роутер (раздел 2) — команда напечатает блок `export ...`.
- Этот блок вставь на роутере (раздел 3).
После этого на VPS роутер будет доступен по `10.99.0.X` (SSH/HTTP/панели).
```
[VPS, белый IP] [Роутер, серый IP]
:443 Caddy/Nginx → wg0 10.99.0.1 ⇄ wg0 10.99.0.X → 127.0.0.1:2001 (kssh-web)
@@ -9,6 +17,8 @@
…и т. д.
```
![Схема (коротко)](../docs/tunnel-diagram.svg)
UDP `51820`, подсеть `10.99.0.0/24`. Параметры можно поменять через ENV.
---
@@ -40,7 +50,15 @@ PublicKey: <SERVER_PUB>
## 2. На VPS — добавление каждого роутера
```sh
sudo kssh-tun add router-andrey-1
sudo kssh-tun add home
```
`home` — это **имя роутера на VPS** (название peer-а). Можно любое: `dacha`, `office1`, `keenetic_andrey`.
Если у конкретного роутера сервис слушает на нестандартном порту (например `777`) и нужен автоDNAT `wg0:777 → LAN_IP:777`, добавьте:
```sh
sudo kssh-tun add home --dnat 777
```
Утилита:
@@ -64,6 +82,36 @@ sudo kssh-tun status # wg show wg0
## 3. На роутере (Keenetic + Entware)
### 📦 Установка Entware на Keenetic
━━━━━━━━━━━━━━━━━━━━━━
⚠️ Определи свою архитектуру
- Mipsel — роутеры на чипе MT7628/MT7621
- Aarch64 — роутеры на чипе MT7622/MT7981/MT7988 (ARM)
━━━━━━━━━━━━━━━━━━━━━━
💡 Совет
Начиная с KeeneticOS 4.2 Entware можно установить прямо через браузер — просто открой `192.168.1.1/a` и следуй инструкции.
━━━━━━━━━━━━━━━━━━━━━━
🚀 Установка онлайн — одной командой
🔵 Mipsel (MT7628/MT7621)
```sh
opkg disk storage:/ https://bin.entware.net/mipselsf-k3.4/installer/mipsel-installer.tar.gz
```
🟢 Aarch64 (MT7622/MT7981/MT7988)
```sh
opkg disk storage:/ https://bin.entware.net/aarch64-k3.10/installer/aarch64-installer.tar.gz
```
⏳ Дождись окончания установки — это займёт пару минут. После этого Entware готов к работе.
🔌 Подключение по SSH
📋 Данные для входа
- Логин: `root`
- Пароль: `keenetic`
- Порт: `22` (если вы не меняли порт SSH вручную)
Скопируйте блок из `kssh-tun add` и выполните на роутере (5 строк, можно блоком, можно по одной):
```sh
@@ -81,6 +129,7 @@ curl -fsSL https://raw.githubusercontent.com/andrey271192/keenetic_ssh-web/main/
- поднимает интерфейс `wg0` с адресом `CLIENT_IP/24`
- маршрутизирует `10.99.0.0/24` через `wg0`
- ставит init-скрипт `/opt/etc/init.d/S50kssh-tunnel` ({start|stop|restart|status}) и rc.d-симлинк автозапуска
- автоматически добавляет DNAT для портов из `DNAT_PORTS`: вход на `wg0:port``LAN_IP:port` (помогает Keeneticадминке/HTTP Proxy открываться через туннель; удаляется uninstallскриптом)
- в конце пингует `10.99.0.1` (VPS) для проверки
Если ping не прошёл — почти всегда дело в фаерволе VPS: `sudo ufw allow 51820/udp` (или эквивалент для iptables/firewalld).
@@ -127,6 +176,7 @@ ssh root@10.99.0.5
| `WG_IF` | `wg0` | Имя интерфейса. |
| `WG_SUBNET` | `10.99.0.1/32` | AllowedIPs клиента (что маршрутизировать в туннель). По умолчанию только VPS, чтобы не конфликтовать с существующими WG-маршрутами Keenetic. Поставьте `10.99.0.0/24` если нужно общение peer-to-peer. |
| `WG_KEEPALIVE` | `25` | `PersistentKeepalive` в секундах (нужен из-за NAT провайдера). |
| `DNAT_PORTS` | `81` | Порты через запятую, для которых делаем автоDNAT `wg0:port → LAN_IP:port` (исправляет `Connection refused`, когда сервис слушает только на LANIP). Пример: `DNAT_PORTS=81,79`. |
---

View File

@@ -91,6 +91,7 @@ export VPS_ENDPOINT=$PUB_IP:$WG_PORT
export VPS_PUBKEY='$SERVER_PUB'
export CLIENT_IP=$CLIENT_IP
export CLIENT_PRIVKEY='$CLIENT_PRIV'
export DNAT_PORTS='${DNAT_PORTS:-81,79}'
curl -fsSL https://raw.githubusercontent.com/${KSSH_REPO}/${KSSH_BRANCH}/tunnel/tunnel-install.sh | sh
EOF
echo "============================================================"
@@ -104,6 +105,25 @@ case "$cmd" in
require_root
NAME="${1:-}"
[ -z "$NAME" ] && { echo "usage: kssh-tun add <name>" >&2; exit 1; }
shift || true
DNAT_PORTS_ARG=""
while [ $# -gt 0 ]; do
case "$1" in
--dnat)
DNAT_PORTS_ARG="${2:-}"
shift 2 || true
;;
--dnat=*)
DNAT_PORTS_ARG="${1#--dnat=}"
shift || true
;;
*)
echo "Неизвестный аргумент: $1" >&2
echo "usage: kssh-tun add <name> [--dnat 81,79]" >&2
exit 1
;;
esac
done
case "$NAME" in *[!a-zA-Z0-9_-]*) echo "Имя: только [a-zA-Z0-9_-]" >&2; exit 1;; esac
mkdir -p "$PEERS_DIR"
PEER_FILE="$PEERS_DIR/$NAME.peer"
@@ -119,6 +139,7 @@ NAME="$NAME"
CLIENT_IP="$CLIENT_IP"
CLIENT_PRIV="$CLIENT_PRIV"
CLIENT_PUB="$CLIENT_PUB"
DNAT_PORTS="$DNAT_PORTS_ARG"
EOF
chmod 600 "$PEER_FILE"
regen_conf
@@ -164,7 +185,7 @@ EOF
cat <<EOF
kssh-tun — управление WireGuard-клиентами для keenetic_ssh-web tunnel.
kssh-tun add <name> добавить peer, вывести ENV-блок для роутера
kssh-tun add <name> [--dnat 81,79] добавить peer, вывести ENV-блок для роутера
kssh-tun show <name> повторно вывести ENV-блок
kssh-tun list список peer-ов
kssh-tun remove <name> удалить peer

View File

@@ -20,6 +20,11 @@ WG_SUBNET="${WG_SUBNET:-10.99.0.1/32}"
WG_KEEPALIVE="${WG_KEEPALIVE:-25}"
WG_DIR="/opt/etc/wireguard"
INIT="/opt/etc/init.d/S50kssh-tunnel"
# DNAT для сервисов, которые слушают только на LAN-IP, но не на wg0.
# Пример: Keenetic NDM/HTTP Proxy часто на :81 или :79.
# Порты через запятую, например: DNAT_PORTS=81,79
DNAT_PORTS="${DNAT_PORTS:-81}"
NAT_TAG_PREFIX="kssh-tunnel:dnat"
[ -z "$VPS_ENDPOINT" ] && { echo "VPS_ENDPOINT обязателен" >&2; exit 1; }
[ -z "$VPS_PUBKEY" ] && { echo "VPS_PUBKEY обязателен" >&2; exit 1; }
@@ -68,6 +73,8 @@ WG_DIR="$WG_DIR"
CONF="\$WG_DIR/\$WG_IF.conf"
ADDR="$CLIENT_IP/24"
SUBNET="$WG_SUBNET"
DNAT_PORTS="$DNAT_PORTS"
NAT_TAG_PREFIX="$NAT_TAG_PREFIX"
up() {
ip link show "\$WG_IF" >/dev/null 2>&1 && ip link del "\$WG_IF" 2>/dev/null
@@ -87,6 +94,28 @@ up() {
if command -v iptables >/dev/null 2>&1; then
iptables -C INPUT -i "\$WG_IF" -j ACCEPT 2>/dev/null || iptables -I INPUT 1 -i "\$WG_IF" -j ACCEPT
iptables -C OUTPUT -o "\$WG_IF" -j ACCEPT 2>/dev/null || iptables -I OUTPUT 1 -o "\$WG_IF" -j ACCEPT
# Некоторые сервисы на Keenetic слушают только на LAN-IP:port, но не на wg0:port.
# Для доступа через туннель делаем DNAT wg0:port → LAN_IP:port для заданных портов.
LAN_IP=""
for IF in br0 br-lan; do
LAN_IP=\$(ip -4 -o addr show "\$IF" 2>/dev/null | awk '{print \$4}' | cut -d/ -f1 | head -n 1)
[ -n "\$LAN_IP" ] && break
done
if [ -z "\$LAN_IP" ]; then
LAN_IP=\$(ip -4 -o addr show 2>/dev/null | awk -v wg="\$WG_IF" '\$2!=wg && \$2!=\"lo\" {print \$4}' | cut -d/ -f1 | head -n 1)
fi
if [ -n "\$LAN_IP" ]; then
OLD_IFS="\$IFS"
IFS=","
for P in \$DNAT_PORTS; do
P=\$(echo "\$P" | tr -d ' ')
case "\$P" in ""|*[!0-9]*) continue ;; esac
TAG="\$NAT_TAG_PREFIX:\$WG_IF:\$P"
iptables -t nat -C PREROUTING -i "\$WG_IF" -p tcp --dport "\$P" -m comment --comment "\$TAG" -j DNAT --to-destination "\$LAN_IP:\$P" 2>/dev/null || \
iptables -t nat -I PREROUTING 1 -i "\$WG_IF" -p tcp --dport "\$P" -m comment --comment "\$TAG" -j DNAT --to-destination "\$LAN_IP:\$P" 2>/dev/null || true
done
IFS="\$OLD_IFS"
fi
fi
if ! wg show "\$WG_IF" | grep -q '^peer:'; then
echo "ВНИМАНИЕ: peer не появился в \$WG_IF — handshake не состоится."
@@ -103,6 +132,11 @@ down() {
while iptables -C OUTPUT -o "\$WG_IF" -j ACCEPT 2>/dev/null; do
iptables -D OUTPUT -o "\$WG_IF" -j ACCEPT 2>/dev/null || break
done
# удалить наши DNAT-правила (если были) — только с tag-prefix
while iptables -t nat -S PREROUTING 2>/dev/null | grep -q "\$NAT_TAG_PREFIX:\$WG_IF:"; do
RULE=\$(iptables -t nat -S PREROUTING | grep "\$NAT_TAG_PREFIX:\$WG_IF:" | head -n 1 | sed 's/^-A /-D /')
[ -n "\$RULE" ] && iptables -t nat \$RULE 2>/dev/null || break
done
fi
echo "stopped \$WG_IF"
}

View File

@@ -14,6 +14,7 @@ WG_IF="${WG_IF:-wg0}"
WG_DIR="/opt/etc/wireguard"
INIT="/opt/etc/init.d/S50kssh-tunnel"
RCD="/opt/etc/rc.d/S50kssh-tunnel"
NAT_TAG_PREFIX="kssh-tunnel:dnat"
echo "==> kssh-tunnel: удаление клиента ($WG_IF)"
@@ -33,6 +34,11 @@ if command -v iptables >/dev/null 2>&1; then
while iptables -C OUTPUT -o "$WG_IF" -j ACCEPT 2>/dev/null; do
iptables -D OUTPUT -o "$WG_IF" -j ACCEPT 2>/dev/null || break
done
# удалить наши DNAT-правила (только наши теги)
while iptables -t nat -S PREROUTING 2>/dev/null | grep -q "$NAT_TAG_PREFIX:$WG_IF:"; do
RULE="$(iptables -t nat -S PREROUTING | grep "$NAT_TAG_PREFIX:$WG_IF:" | head -n 1 | sed 's/^-A /-D /')"
[ -n "$RULE" ] && iptables -t nat $RULE 2>/dev/null || break
done
fi
# 3. Удалить файлы туннеля (НЕ трогаем чужие WG-конфиги в этой папке)