You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two new feature areas + hardening + install/UX polish.
New: Servers (managed VPS inventory)
Separate page from Nodes — tracks the remote VPS hosts that may
carry one or more proxy outbounds, with their SSH connection,
provider/region metadata, tags, and a Deployments tab listing which
protocols/ports are currently set up on each box. Async-SSH probe
via asyncssh==2.18.0. Optional manual provisioning scripts (Caddy +
forwardproxy for naive, xray, SSH hardening) over the same SSH link.
3 new alembic migrations: 008 (server table), 009 (deployments), 010
(geo URL defaults).
New: full-fidelity JSON Export/Import for Nodes and Servers
Versioned bundle envelope ({kind, version, exported_at,
pitun_version, count, items}). Append (default) or replace mode;
dedup by natural keys (Nodes: protocol+address+port+uuid; Servers:
name+host+port). Server export defaults to no-secrets, with an
opt-in checkbox to include passwords/keys for migrations between
trusted hosts. Distinct from URI/subscription import which only
carries a single node.
NodeCircle pre-ping with retry + Failover<->Circle integration
Before switching the active outbound to a candidate, the scheduler
now TCP-probes it (SO_MARK=0xFF to bypass TPROXY) with a single
retry to absorb transient SYN drops. Disabled or removed nodes are
skipped automatically; if every candidate fails, the rotation
aborts and the active node stays put. Each circle gets its own
asyncio.Lock and a 20s hard deadline so scheduler ticks and
manual rotate-now never race.
When the active node fails its health check repeatedly AND it
belongs to an enabled circle, the failover handler delegates
recovery to circle_scheduler.rotate_circle() instead of walking the
fallback list — reusing the pre-ping logic to skip dead siblings.
If no circle owns the node (or all siblings are dead), Tier-2
fallback is the existing list-based path. New "Auto-failover" toggle
on the NodeCircles page is the master switch.
Comprehensive geo profiles
Three switchable upstream profiles for geoip.dat / geosite.dat:
Loyalsoldier (CN-focused, largest geosite:cn coverage), runetfreedom
(Russian-internet curated, geosite:ru-blocked + clean geosite:ru),
v2fly (vanilla baseline). UI lets you select + Update; PiTun fetches
into the xray asset directory and reloads.
Routing rules: comprehensive Proxy streaming preset
Quick Add 'Proxy streaming' grew from a handful of entries to a
curated list of 50 (Netflix, Disney+, HBO, Hulu, Spotify, YouTube
Premium, Twitch, Steam, Epic Games, BBC iPlayer, ChatGPT/OpenAI,
Anthropic Claude, etc.). Backend auto-prefixes bare domain entries
with `domain:` on save so users don't have to type the prefix.
Install: autodetect LAN_CIDR + host IP from default-route interface
install.sh now writes correct INTERFACE, LAN_CIDR, GATEWAY_IP,
VITE_API_BASE_URL, VITE_WS_BASE_URL, and CORS_ORIGINS into the
freshly generated .env, derived from the host's primary interface
(python3 ipaddress for CIDR math, pure-bash bitwise fallback).
Previously only INTERFACE was autodetected — users on subnets other
than 192.168.1.0/24 had to edit four places by hand.
Backend gains a parallel _detect_cidr() runtime fallback in
GET /settings, mirroring the existing _detect_ip() behavior. Stays
read-only (does not overwrite a deliberate manual lan_cidr in DB).
README.md / README.ru.md / .env.example: clarified that GATEWAY_IP
is a misnomer for the PiTun host's own LAN IP (not the home
router's IP), and documented the new autodetect + runtime fallback.
UI polish
- NodeCircles page InfoTips now open downward (position="bottom") to
avoid clipping at the top of the viewport on narrow screens.
- Knowledge Base updated: Servers, Geo profiles, JSON Export/Import,
NodeCircle pre-ping/retry, Failover<->Circle integration, Routing
Quick Add presets details all documented. Two new sections:
"Servers (VPS Inventory)" and "Geo Data Profiles".
Routing rules JSON Export/Import (v2ray-style)
Round-trip rule sets as v2ray routing JSON for backups and migrating
curated rules between PiTun instances.
Backend versioning is now a single source of truth (APP_VERSION in
config.py); surfaced in /health, /system/status, and the OpenAPI
metadata. 284 backend tests pass. No breaking changes; 3 alembic
migrations apply automatically on first start.
|`INTERFACE`|`eth0`| LAN interface name on the host |
381
-
|`LAN_CIDR`|`192.168.1.0/24`| Your LAN subnet |
382
-
|`GATEWAY_IP`|`192.168.1.1`|Your home router's IP (used for `direct` traffic)|
405
+
|`LAN_CIDR`|`192.168.1.0/24`| Your LAN subnet (autodetected by `install.sh`) |
406
+
|`GATEWAY_IP`|`192.168.1.100`|**The PiTun host's own LAN IP** — devices set this as their default gateway. (Misnomer kept for backward compat; *not* the router's IP.) Autodetected by `install.sh`.|
383
407
|`BACKEND_PORT`|`8000`| Backend listen port (behind nginx) |
384
408
|`TPROXY_PORT_TCP`|`7893`| TPROXY TCP listener |
385
409
|`DNS_PORT`|`5353`| Internal DNS forwarder port |
@@ -388,6 +412,13 @@ must be set before first start, via `.env`:
388
412
389
413
Full annotated example: [`.env.example`](.env.example).
390
414
415
+
> **About `GATEWAY_IP`:** the variable name predates the LAN-gateway
416
+
> feature and refers to the PiTun host itself, not your home router.
417
+
> If the .env value disagrees with the actual interface IP, the backend
418
+
> auto-syncs the live IP into the database on the first `GET /settings`,
419
+
> so the UI always shows the truth. `LAN_CIDR` has the same runtime
|`GATEWAY_IP`|`192.168.1.100`|**LAN-IP самого PiTun** — устройства задают это как default gateway. (Имя оставлено для обратной совместимости; это *не* IP роутера.) Автодетектится `install.sh`.|
378
406
|`BACKEND_PORT`|`8000`| Порт бэкенда (за nginx) |
379
407
|`TPROXY_PORT_TCP`|`7893`| TCP-листенер TPROXY |
380
408
|`DNS_PORT`|`5353`| Внутренний DNS-форвардер |
@@ -383,6 +411,13 @@ docker compose up -d
383
411
384
412
Полный аннотированный пример: [`.env.example`](.env.example).
385
413
414
+
> **О `GATEWAY_IP`:** имя переменной осталось с тех времён когда LAN-
415
+
> gateway фичи ещё не было, и относится к самому PiTun-хосту, а не к
416
+
> роутеру. Если в .env лежит несовпадающий с реальным IP интерфейса —
417
+
> бэкенд автоматически синкнет живой IP в БД при первом `GET /settings`,
418
+
> так что в UI всегда будет правда. У `LAN_CIDR` такой же runtime-
0 commit comments