From 3531671d3d73b2dfdb1b3d133a29369cd3a86328 Mon Sep 17 00:00:00 2001 From: esefxdz Date: Fri, 24 Jul 2026 21:03:18 +0300 Subject: [PATCH] =?UTF-8?q?Rebrand:=20PaladinVPN=20->=20ReVoltVPN=20?= =?UTF-8?q?=E2=80=94=20all=20references,=20package=20names,=20Android=20na?= =?UTF-8?q?mespace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +- PRIVACY_POLICY.md | 4 +- README.md | 10 +- XRAY_CONFIG_REFERENCE.md | 2 +- android/app/build.gradle.kts | 4 +- android/app/src/main/AndroidManifest.xml | 2 +- .../app/MainActivity.kt | 2 +- lib/components/bottom_bar.dart | 10 +- lib/components/clock_display.dart | 2 +- lib/components/connect_button.dart | 12 +- lib/components/gdpr_button.dart | 2 +- lib/components/header.dart | 6 +- lib/components/info_button.dart | 4 +- lib/components/notification.dart | 6 +- lib/components/privacy_policy_button.dart | 2 +- lib/components/status_text.dart | 2 +- lib/components/watch_ad_button.dart | 4 +- lib/logic/ad_manager.dart | 6 +- lib/logic/hivemind_service.dart | 6 +- lib/logic/session_timer.dart | 8 +- lib/logic/vpn_connection.dart | 6 +- lib/main.dart | 20 +- lib/screens/intro.dart | 4 +- lib/screens/main_screen.dart | 16 +- pubspec.yaml | 4 +- server_picture.sh | 200 ------------------ 26 files changed, 75 insertions(+), 274 deletions(-) rename android/app/src/main/kotlin/com/{paladinvpn => revoltvpn}/app/MainActivity.kt (77%) delete mode 100644 server_picture.sh diff --git a/.gitignore b/.gitignore index 4075193..c4ef68e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,9 @@ local_packages/*/.dart_tool/ # Crashlytics cache **/android/app/crashlytics-build.properties +# Shell scripts (dev only, not for public) +server_picture.sh + # Secrets android/key.properties android/admob.properties @@ -75,5 +78,3 @@ server full picture.txt technical_debt_*.md server_full_picture_2.txt hivemind_backup.py -AGENTS.md -00-FULL-REPORT.md diff --git a/PRIVACY_POLICY.md b/PRIVACY_POLICY.md index a37c01d..8a11dc0 100644 --- a/PRIVACY_POLICY.md +++ b/PRIVACY_POLICY.md @@ -1,6 +1,6 @@ Privacy Policy Last updated: July 2025 -PaladinVPN is a free VPN service built and operated by a solo developer. +ReVoltVPN is a free VPN service built and operated by a solo developer. What we collect We collect the minimum required to operate the service: @@ -14,7 +14,7 @@ We do not log your internet traffic or browsing history. We do not sell or share any data with third parties. Ads & Consent -PaladinVPN uses Google AdMob to display rewarded video ads. On first launch, users in the European Economic Area (EEA) and United Kingdom are shown a consent dialog (provided by Google's User Messaging Platform) that lets them choose whether to allow personalized ads. This consent choice is stored on your device and can be changed at any time by reinstalling the app. Google may collect data as part of ad delivery. Please refer to Google's Privacy Policy for details. +ReVoltVPN uses Google AdMob to display rewarded video ads. On first launch, users in the European Economic Area (EEA) and United Kingdom are shown a consent dialog (provided by Google's User Messaging Platform) that lets them choose whether to allow personalized ads. This consent choice is stored on your device and can be changed at any time by reinstalling the app. Google may collect data as part of ad delivery. Please refer to Google's Privacy Policy for details. Your traffic Your internet traffic is routed through our server located in Finland. We do not inspect, log, or store your traffic. Contact diff --git a/README.md b/README.md index 6bd0fe3..0f8d0e4 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ ---

- PaladinVPN banner + ReVoltVPN banner

-# PaladinVPN +# ReVoltVPN A free VPN app I built in my spare time as a student with basically no prior experience.

- PaladinVPN splash screen + ReVoltVPN splash screen     - PaladinVPN connected — 60 min session active + ReVoltVPN connected — 60 min session active

There are hundreds of free VPN apps on the Play Store. Most of them are fine honestly — some are genuinely good. But a lot of them are vague about how they work, who runs them, and what happens to your traffic. I wanted to build something where the answer to all of those questions is just... public. @@ -58,6 +58,6 @@ You can read the server code yourself, it's in this repo. --- -*PaladinVPN is not affiliated with any VPN company.* +*ReVoltVPN is not affiliated with any VPN company.* --- diff --git a/XRAY_CONFIG_REFERENCE.md b/XRAY_CONFIG_REFERENCE.md index 70a9445..cf92a30 100644 --- a/XRAY_CONFIG_REFERENCE.md +++ b/XRAY_CONFIG_REFERENCE.md @@ -1,4 +1,4 @@ -# Xray Configuration Reference — PaladinVPN +# Xray Configuration Reference — ReVoltVPN > Minimal production config with annotated explanations and optional upgrades. > File lives at `/usr/local/etc/xray/config.json` on the Hetzner box. diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 4543fde..12f2823 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } android { - namespace = "com.paladinvpn.app" + namespace = "com.revoltvpn.app" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -34,7 +34,7 @@ android { } defaultConfig { - applicationId = "com.paladinvpn.app" + applicationId = "com.revoltvpn.app" minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2b444fb..347fa8c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ title: const Text('VPN Permission Required', style: TextStyle(color: Colors.white)), content: const Text( - 'PaladinVPN needs permission to set up a VPN connection.\n\n' + 'ReVoltVPN needs permission to set up a VPN connection.\n\n' 'Since the permission was denied once, Android won\'t ask again. ' 'To grant it manually:\n\n' '1. Open your device Settings\n' - '2. Go to Apps → PaladinVPN\n' + '2. Go to Apps → ReVoltVPN\n' '3. Tap "VPN" and enable it\n' - '4. Return to PaladinVPN and tap connect', + '4. Return to ReVoltVPN and tap connect', style: TextStyle(color: Color(0xFFA0AEC0)), ), actions: [ diff --git a/lib/components/gdpr_button.dart b/lib/components/gdpr_button.dart index a1b8059..61c25e3 100644 --- a/lib/components/gdpr_button.dart +++ b/lib/components/gdpr_button.dart @@ -72,7 +72,7 @@ class GdprButton extends StatelessWidget { void _fallbackToPrivacyPolicy() async { final Uri url = Uri.parse( - 'https://github.com/esefxdz/PaladinVPN/blob/main/PRIVACY_POLICY.md', + 'https://github.com/esefxdz/ReVoltVPN/blob/main/PRIVACY_POLICY.md', ); if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { debugPrint('Could not launch $url'); diff --git a/lib/components/header.dart b/lib/components/header.dart index 608bc68..0695d08 100644 --- a/lib/components/header.dart +++ b/lib/components/header.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -/// Header displays the Paladin brand logo, title, and subtitle. +/// Header displays the ReVolt brand logo, title, and subtitle. /// /// It represents the top branding portion of the main dashboard and is designed /// with clean proportions, consistent typography, and a modern cyberpunk-inspired color scheme. class Header extends StatelessWidget { const Header({super.key}); - // Cyber-paladin cyan glow accent color used as a fallback for the shield icon + // cyber-revolt cyan glow accent color used as a fallback for the shield icon static const Color _cyanGlow = Color(0xFF00E5FF); @override @@ -30,7 +30,7 @@ class Header extends StatelessWidget { // Brand primary name const Text( - 'Paladin', + 'ReVolt', style: TextStyle( fontSize: 22, fontWeight: FontWeight.w800, diff --git a/lib/components/info_button.dart b/lib/components/info_button.dart index 300e146..cceba48 100644 --- a/lib/components/info_button.dart +++ b/lib/components/info_button.dart @@ -5,7 +5,7 @@ class InfoButton extends StatelessWidget { const InfoButton({super.key}); Future _launchGitHub() async { - final Uri url = Uri.parse('https://github.com/esefxdz/PaladinVPN'); + final Uri url = Uri.parse('https://github.com/esefxdz/ReVoltVPN'); if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { debugPrint('Could not launch $url'); } @@ -16,7 +16,7 @@ class InfoButton extends StatelessWidget { return IconButton( icon: const Icon(Icons.help_outline, color: Colors.white, size: 28), onPressed: _launchGitHub, - tooltip: 'About PaladinVPN', + tooltip: 'About ReVoltVPN', splashRadius: 24, ); } diff --git a/lib/components/notification.dart b/lib/components/notification.dart index 4f188ad..3c154b5 100644 --- a/lib/components/notification.dart +++ b/lib/components/notification.dart @@ -46,7 +46,7 @@ class VpnNotificationManager { // the old channel was created without 'ongoing: true', users would be // stuck with a swipeable notification forever. const androidDetails = AndroidNotificationDetails( - 'paladin_vpn_status_v2', + 'revolt_vpn_status_v2', 'VPN Status', channelDescription: 'Shown while VPN is active — non-dismissable', importance: Importance.low, @@ -72,7 +72,7 @@ class VpnNotificationManager { try { await _plugin.show( 888, // Fixed ID — always updates the same notification - 'Paladin VPN Active', + 'REVOLT VPN Active', 'Time: $timeLeft • $speedKbps', notificationDetails, ); @@ -84,7 +84,7 @@ class VpnNotificationManager { await init(); await _plugin.show( 888, - 'Paladin VPN Active', + 'REVOLT VPN Active', 'Time: $timeLeft • $speedKbps', notificationDetails, ); diff --git a/lib/components/privacy_policy_button.dart b/lib/components/privacy_policy_button.dart index a98abd2..b26eae3 100644 --- a/lib/components/privacy_policy_button.dart +++ b/lib/components/privacy_policy_button.dart @@ -5,7 +5,7 @@ class PrivacyPolicyButton extends StatelessWidget { const PrivacyPolicyButton({super.key}); Future _launchPrivacyPolicy() async { - final Uri url = Uri.parse('https://github.com/esefxdz/PaladinVPN/blob/main/PRIVACY_POLICY.md'); + final Uri url = Uri.parse('https://github.com/esefxdz/ReVoltVPN/blob/main/PRIVACY_POLICY.md'); if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { debugPrint('Could not launch $url'); } diff --git a/lib/components/status_text.dart b/lib/components/status_text.dart index 1146b40..69b8fb8 100644 --- a/lib/components/status_text.dart +++ b/lib/components/status_text.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:paladinvpn/logic/vpn_connection.dart'; +import 'package:revoltvpn/logic/vpn_connection.dart'; /// StatusText displays the status of the VPN tunnel. /// diff --git a/lib/components/watch_ad_button.dart b/lib/components/watch_ad_button.dart index bd74b0e..f5e4738 100644 --- a/lib/components/watch_ad_button.dart +++ b/lib/components/watch_ad_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:paladinvpn/logic/session_timer.dart'; -import 'package:paladinvpn/logic/ad_manager.dart'; +import 'package:revoltvpn/logic/session_timer.dart'; +import 'package:revoltvpn/logic/ad_manager.dart'; /// WatchAdButton is a voluntary option allowing the user to watch a rewarded video ad /// and extend their active VPN tunnel session by 30 minutes as a reward. diff --git a/lib/logic/ad_manager.dart b/lib/logic/ad_manager.dart index 6693a26..be6cc6d 100644 --- a/lib/logic/ad_manager.dart +++ b/lib/logic/ad_manager.dart @@ -3,9 +3,9 @@ import 'dart:convert'; import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; -import 'package:paladinvpn/logic/crypto_service.dart'; -import 'package:paladinvpn/logic/hivemind_service.dart'; -import 'package:paladinvpn/logic/app_config.dart'; +import 'package:revoltvpn/logic/crypto_service.dart'; +import 'package:revoltvpn/logic/hivemind_service.dart'; +import 'package:revoltvpn/logic/app_config.dart'; /// AdManager manages the lifecycle of rewarded video ads. /// diff --git a/lib/logic/hivemind_service.dart b/lib/logic/hivemind_service.dart index 41a59d5..cc62362 100644 --- a/lib/logic/hivemind_service.dart +++ b/lib/logic/hivemind_service.dart @@ -3,8 +3,8 @@ import 'dart:convert'; import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import 'package:paladinvpn/logic/app_config.dart'; -import 'package:paladinvpn/logic/crypto_service.dart'; +import 'package:revoltvpn/logic/app_config.dart'; +import 'package:revoltvpn/logic/crypto_service.dart'; class HivemindService { /// Nonce generated at the start of a connect cycle. @@ -76,7 +76,7 @@ class HivemindService { '&security=${AppConfig.vlessSecurity}' '&type=${AppConfig.vlessType}' '&flow=${AppConfig.vlessFlow}' - '#PaladinVPN'; + '#ReVoltVPN'; _expectedNonce = null; // consumed successfully return vlessUrl; diff --git a/lib/logic/session_timer.dart b/lib/logic/session_timer.dart index 91ef9a5..d4dfbb8 100644 --- a/lib/logic/session_timer.dart +++ b/lib/logic/session_timer.dart @@ -2,10 +2,10 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import 'package:paladinvpn/logic/app_config.dart'; -import 'package:paladinvpn/logic/vpn_connection.dart'; -import 'package:paladinvpn/logic/crypto_service.dart'; -import 'package:paladinvpn/components/notification.dart'; +import 'package:revoltvpn/logic/app_config.dart'; +import 'package:revoltvpn/logic/vpn_connection.dart'; +import 'package:revoltvpn/logic/crypto_service.dart'; +import 'package:revoltvpn/components/notification.dart'; /// SessionTimer is the client-side session authority for the VPN tunnel. /// diff --git a/lib/logic/vpn_connection.dart b/lib/logic/vpn_connection.dart index 1a839ec..dae2339 100644 --- a/lib/logic/vpn_connection.dart +++ b/lib/logic/vpn_connection.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter_vless/flutter_vless.dart'; -import 'package:paladinvpn/logic/hivemind_service.dart'; +import 'package:revoltvpn/logic/hivemind_service.dart'; // ── VPN States ──────────────────────────────────────────────────────────────── enum VpnStatus { @@ -50,7 +50,7 @@ class VpnConnection extends ChangeNotifier { try { await _vless.initializeVless( - providerBundleIdentifier: 'com.paladinvpn.app', + providerBundleIdentifier: 'com.revoltvpn.app', ); _initialized = true; } catch (e) { @@ -148,7 +148,7 @@ class VpnConnection extends ChangeNotifier { final config = parsed.getFullConfiguration(); await _vless.startVless( - remark: parsed.remark.isNotEmpty ? parsed.remark : 'PaladinVPN', + remark: parsed.remark.isNotEmpty ? parsed.remark : 'ReVoltVPN', config: config, ); diff --git a/lib/main.dart b/lib/main.dart index 44b94bf..7d23457 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,13 +3,13 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; -import 'package:paladinvpn/logic/vpn_connection.dart'; -import 'package:paladinvpn/logic/session_timer.dart'; -import 'package:paladinvpn/logic/ad_manager.dart'; -import 'package:paladinvpn/logic/consent_manager.dart'; -import 'package:paladinvpn/screens/intro.dart'; +import 'package:revoltvpn/logic/vpn_connection.dart'; +import 'package:revoltvpn/logic/session_timer.dart'; +import 'package:revoltvpn/logic/ad_manager.dart'; +import 'package:revoltvpn/logic/consent_manager.dart'; +import 'package:revoltvpn/screens/intro.dart'; -/// The entry point for the Paladin VPN application. +/// The entry point for the REVOLT VPN application. void main() async { // Ensure that the Flutter engine is fully initialized before using platform channels // (e.g., for SystemChrome or MobileAds). @@ -39,12 +39,12 @@ void main() async { await MobileAds.instance.initialize(); // Inflate the root widget - runApp(const PaladinApp()); + runApp(const ReVoltApp()); } /// The root application widget wrapping the app in necessary state providers and themes. -class PaladinApp extends StatelessWidget { - const PaladinApp({super.key}); +class ReVoltApp extends StatelessWidget { + const ReVoltApp({super.key}); @override Widget build(BuildContext context) { @@ -69,7 +69,7 @@ class PaladinApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => AdManager()), ], child: MaterialApp( - title: 'Paladin VPN', + title: 'ReVolt VPN', debugShowCheckedModeBanner: false, theme: _buildDarkTheme(), home: const IntroScreen(), diff --git a/lib/screens/intro.dart b/lib/screens/intro.dart index 8812c6c..d355461 100644 --- a/lib/screens/intro.dart +++ b/lib/screens/intro.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:paladinvpn/screens/main_screen.dart'; +import 'package:revoltvpn/screens/main_screen.dart'; class IntroScreen extends StatefulWidget { const IntroScreen({super.key}); @@ -77,7 +77,7 @@ class _IntroScreenState extends State with WidgetsBindingObserver { ), const SizedBox(height: 30), const Text( - 'PALADIN VPN', + 'REVOLT VPN', style: TextStyle( color: Colors.white, fontSize: 28, diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 5f46f4d..6bf94fa 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:paladinvpn/components/header.dart'; -import 'package:paladinvpn/components/status_text.dart'; -import 'package:paladinvpn/components/connect_button.dart'; -import 'package:paladinvpn/components/bottom_bar.dart'; -import 'package:paladinvpn/components/info_button.dart'; -import 'package:paladinvpn/components/privacy_policy_button.dart'; -import 'package:paladinvpn/components/gdpr_button.dart'; +import 'package:revoltvpn/components/header.dart'; +import 'package:revoltvpn/components/status_text.dart'; +import 'package:revoltvpn/components/connect_button.dart'; +import 'package:revoltvpn/components/bottom_bar.dart'; +import 'package:revoltvpn/components/info_button.dart'; +import 'package:revoltvpn/components/privacy_policy_button.dart'; +import 'package:revoltvpn/components/gdpr_button.dart'; -/// MainScreen serves as the primary home screen for Paladin VPN. +/// MainScreen serves as the primary home screen for REVOLT VPN. /// /// It provides a dark mode, cyberpunk-inspired visual layout displaying: /// - Logo and Branding at the top (`Header`) diff --git a/pubspec.yaml b/pubspec.yaml index 0785c70..a4897dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ -name: paladinvpn -description: Paladin VPN — Secure VLESS tunnel for Android +name: revoltvpn +description: ReVolt VPN — Secure VLESS tunnel for Android # The following line prevents the package from being accidentally published to # pub.dev using `pub publish`. This is preferred for private packages. diff --git a/server_picture.sh b/server_picture.sh deleted file mode 100644 index d8160b5..0000000 --- a/server_picture.sh +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash -# PaladinVPN — Full Server Picture (VLESS era) -# Copy-paste this entire block into your SSH terminal on the Hetzner Debian box. -# Read-only — makes no changes to the system. -# Run as root or with sudo. - -bash <<'REPORT' -echo "============================================================" -echo " PaladinVPN — Server State Report" -echo " $(date '+%Y-%m-%d %H:%M:%S %Z')" -echo "============================================================" - -# ── 1. System ──────────────────────────────────────────────── -echo ""; echo "=== SYSTEM ===" -echo "Hostname : $(hostname)" -echo "Uptime : $(uptime -p)" -echo "Debian : $(cat /etc/debian_version 2>/dev/null || echo 'N/A')" -echo "Kernel : $(uname -r)" -echo "Arch : $(uname -m)" -echo "Load : $(uptime | awk -F'load average:' '{print $2}' | xargs)" -echo "" -echo "CPU:" -echo "$(lscpu | grep -E 'Model name|CPU\(s\)|Thread' | sed 's/^/ /')" 2>/dev/null -echo "" -echo "Memory:" -free -h | grep -E '^Mem:|^Swap:' | sed 's/^/ /' -echo "" -echo "Disk:" -df -h / | tail -1 | awk '{print " Root: " $3 "/" $2 " (" $5 ")"}' - -# ── 2. Network Interfaces ──────────────────────────────────── -echo ""; echo "=== NETWORK INTERFACES ===" -ip -br addr 2>/dev/null || ifconfig -a 2>/dev/null -echo "" -echo "Routes:" -ip route show 2>/dev/null | grep -v '^fe80' || route -n -echo "" -echo "DNS:" -cat /etc/resolv.conf 2>/dev/null | grep -v '^#' | grep -v '^$' | sed 's/^/ /' - -# ── 3. Open Ports ──────────────────────────────────────────── -echo ""; echo "=== LISTENING PORTS ===" -ss -tlnp 2>/dev/null | head -30 || netstat -tlnp 2>/dev/null | head -30 - -# ── 4. IPv6 Status ─────────────────────────────────────────── -echo ""; echo "=== IPv6 ===" -echo "Forwarding:" -sysctl net.ipv6.conf.all.forwarding 2>/dev/null -echo "" -echo "IPv6 routes:" -ip -6 route show 2>/dev/null | head -10 -echo "" -echo "IPv6 NAT (ip6tables):" -ip6tables -t nat -L POSTROUTING -n 2>/dev/null | head -10 || echo " ip6tables not available" - -# ── 5. Firewall (iptables) ─────────────────────────────────── -echo ""; echo "=== IPTABLES NAT ===" -iptables -t nat -L POSTROUTING -n -v 2>/dev/null | head -20 || echo " iptables not available" - -# ── 6. Services ────────────────────────────────────────────── -echo ""; echo "=== SERVICES ===" -for svc in hivemind xray nginx docker certbot; do - if systemctl is-enabled "$svc" &>/dev/null; then - printf " %-12s : %s (enabled)\n" "$svc" "$(systemctl is-active "$svc")" - elif systemctl is-active "$svc" &>/dev/null; then - printf " %-12s : %s (not enabled)\n" "$svc" "$(systemctl is-active "$svc")" - else - printf " %-12s : not found\n" "$svc" - fi -done -echo "" -echo "Certbot timer:" -systemctl list-timers --all 2>/dev/null | grep -i certbot || echo " No certbot timer found" - -# ── 7. Xray ────────────────────────────────────────────────── -echo ""; echo "=== XRAY ===" -if command -v xray &>/dev/null; then - echo "Binary : $(which xray)" - echo "Version : $(xray version 2>&1 | head -1)" - echo "Status : $(systemctl is-active xray 2>/dev/null || echo 'N/A')" - echo "" - echo "Config file exists?" - if [ -f /usr/local/etc/xray/config.json ]; then - echo " YES — $(wc -c < /usr/local/etc/xray/config.json) bytes" - echo " Clients: $(python3 -c "import json; c=json.load(open('/usr/local/etc/xray/config.json')); print(len(c['inbounds'][0]['settings']['clients']))" 2>/dev/null || echo 'ERROR reading config')" - else - echo " NO — /usr/local/etc/xray/config.json not found" - fi - echo "" - echo "Stats API:" - curl -s --max-time 3 http://127.0.0.1:10085/stats/query -d '{"pattern":"","reset":false}' 2>/dev/null | python3 -m json.tool 2>/dev/null | head -10 || echo " Stats API unreachable" - echo "" - echo "Last 5 Xray log lines:" - journalctl -u xray --no-pager -n 5 2>/dev/null | sed 's/^/ /' || echo " No journal entries" -else - echo " Xray NOT INSTALLED" -fi - -# ── 8. Hivemind ────────────────────────────────────────────── -echo ""; echo "=== HIVEMIND ===" -echo "Status : $(systemctl is-active hivemind 2>/dev/null || echo 'N/A')" -echo "Config : $(systemctl cat hivemind 2>/dev/null | grep -i execstart | sed 's/^/ /')" -echo "" -echo "Active sessions:" -python3 -c " -import sys; sys.path.insert(0, '/root') -try: - from server_hivemind_5_0 import active_sessions, sessions_lock - with sessions_lock: - count = len(active_sessions) - throttled = sum(1 for s in active_sessions.values() if s.get('is_throttled')) - print(f' Total: {count} Throttled: {throttled}') -except Exception as e: - print(f' Could not read sessions: {e}') -" 2>/dev/null || echo " Could not import hivemind module" -echo "" -echo "Hivemind script:" -if [ -f /root/server_hivemind_5_0.py ]; then - echo " /root/server_hivemind_5_0.py — $(wc -l < /root/server_hivemind_5_0.py) lines" -elif [ -f /root/server_hivemind_* ]; then - ls -la /root/server_hivemind_* 2>/dev/null | sed 's/^/ /' -else - echo " No hivemind script found in /root" -fi -echo "" -echo "Last 10 Hivemind log lines:" -journalctl -u hivemind --no-pager -n 10 2>/dev/null | sed 's/^/ /' || echo " No journal entries" - -# ── 9. Nginx ───────────────────────────────────────────────── -echo ""; echo "=== NGINX ===" -if command -v nginx &>/dev/null; then - echo "Binary : $(which nginx)" - echo "Version : $(nginx -v 2>&1)" - echo "Status : $(systemctl is-active nginx 2>/dev/null || echo 'N/A')" - echo "" - echo "Config test:" - nginx -t 2>&1 | sed 's/^/ /' - echo "" - echo "Sites enabled:" - ls -la /etc/nginx/sites-enabled/ 2>/dev/null | sed 's/^/ /' - echo "" - echo "/tunnel location block exists?" - grep -r "location /tunnel" /etc/nginx/sites-enabled/ 2>/dev/null | sed 's/^/ /' || echo " NOT FOUND" - echo "" - echo "/api location block exists?" - grep -r "location /api" /etc/nginx/sites-enabled/ 2>/dev/null | sed 's/^/ /' || echo " NOT FOUND" -else - echo " NGINX NOT INSTALLED" -fi - -# ── 10. SSL ────────────────────────────────────────────────── -echo ""; echo "=== SSL CERTIFICATES ===" -if command -v certbot &>/dev/null; then - certbot certificates 2>/dev/null | sed 's/^/ /' || echo " No certificates found" - echo "" - echo "Certificate files:" - ls -la /etc/letsencrypt/live/ 2>/dev/null | sed 's/^/ /' || echo " /etc/letsencrypt/live/ not found" -else - echo " certbot not installed" -fi - -# ── 11. Docker ──────────────────────────────────────────────── -echo ""; echo "=== DOCKER ===" -if command -v docker &>/dev/null; then - echo "Running containers:" - docker ps --format ' {{.Names}} {{.Image}} {{.Status}} {{.Ports}}' 2>/dev/null || echo " None" -else - echo " Docker not installed" -fi - -# ── 12. Traffic Control (tc) ───────────────────────────────── -echo ""; echo "=== TRAFFIC CONTROL (tc) ===" -if command -v tc &>/dev/null; then - for iface in $(ip -br link 2>/dev/null | awk '{print $1}'); do - rules=$(tc qdisc show dev "$iface" 2>/dev/null | grep -v "noqueue\|fq_codel\|pfifo_fast" | head -5) - if [ -n "$rules" ]; then - echo " Interface $iface:" - echo "$rules" | sed 's/^/ /' - fi - done - echo " (no custom tc rules found unless listed above)" -else - echo " tc not available" -fi - -# ── 13. AWG leftovers ──────────────────────────────────────── -echo ""; echo "=== AWG LEFTOVERS ===" -echo "awg0 interface : $([ -d /sys/class/net/awg0 ] && echo 'STILL EXISTS' || echo 'gone ✓')" -echo "awg binary : $(command -v awg 2>/dev/null && echo 'STILL INSTALLED' || echo 'gone ✓')" -echo "wg-easy docker : $(docker ps -a --filter 'name=wg-easy' --format '{{.Names}}' 2>/dev/null || echo 'gone ✓')" -echo "iptables 10.8.x: $(iptables -t nat -L POSTROUTING 2>/dev/null | grep '10\.8\.' | head -3 || echo 'gone ✓')" - -# ── 14. Recent Errors ──────────────────────────────────────── -echo ""; echo "=== RECENT ERRORS (last 50 journal lines, filtered) ===" -journalctl -u hivemind -u xray -u nginx --no-pager -n 50 --since "1 hour ago" 2>/dev/null | grep -iE 'error|fail|warn|exception|cannot|denied|timeout' | tail -10 | sed 's/^/ /' || echo " No recent errors" - -echo ""; echo "============================================================" -echo " Report complete — $(date '+%H:%M:%S')" -echo "============================================================" -REPORT