feat: v1.9.1 — operator quality-of-life: tunable auto-blacklist, configurable batch timeout, MHRV_AUTH_KEY hint, run.bat CLI fallback

Four small fixes that address recurring user-issue patterns:

- src/config.rs / src/domain_fronter.rs: auto_blacklist_strikes,
  auto_blacklist_window_secs, auto_blacklist_cooldown_secs config fields
  (#391, #444). Previously 3 strikes / 30s window / 120s cooldown were
  hard-coded. Single-deployment users on flaky networks hit this too
  aggressively; multi-deployment users want tighter fail-fast. Defaults
  preserve historical behavior. Power-user file edit only — no UI
  control yet. Clamps to [1, 86400] for durations.

- src/config.rs / src/domain_fronter.rs / src/tunnel_client.rs:
  request_timeout_secs config field (#430, masterking32 PR #25).
  Replaces hard-coded BATCH_TIMEOUT 30s. DomainFronter::batch_timeout()
  exposes the value, fire_batch reads it. Clamped to [5s, 300s].

- tunnel-node/src/main.rs: detect MHRV_AUTH_KEY env var being set
  while TUNNEL_AUTH_KEY is unset, and emit a specific warning pointing
  at the right env var name. Catches the recurring #391/#444 docker
  run typo that made users chase phantom AUTH_KEY-mismatch decoys.

- assets/launchers/run.bat: when both UI renderers (glow + wgpu)
  fail on older Windows / RDP / VM-without-GPU, fall back to launching
  mhrv-rs.exe (CLI) instead of just printing "open an issue".
  Addresses #417 / #426 / #487. CLI has the same proxy functionality
  on 127.0.0.1:8085 (HTTP) / :8086 (SOCKS5).

169 mhrv-rs lib tests + 33 tunnel-node tests still passing. UI build
clean. ConfigWire round-trips the new fields with skip-default-on-write
so unchanged configs stay clean.
This commit is contained in:
therealaleph
2026-04-30 08:33:53 +03:00
parent 58fb141cf7
commit cd6ff8d381
9 changed files with 193 additions and 35 deletions
Generated
+1 -1
View File
@@ -2222,7 +2222,7 @@ dependencies = [
[[package]]
name = "mhrv-rs"
version = "1.9.0"
version = "1.9.1"
dependencies = [
"base64 0.22.1",
"bytes",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "mhrv-rs"
version = "1.9.0"
version = "1.9.1"
edition = "2021"
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
license = "MIT"
+14 -3
View File
@@ -60,10 +60,21 @@ if not "%UI_EXIT%"=="0" (
echo - running inside RDP or a VM without GPU acceleration
echo - antivirus blocking the exe — whitelist the folder and retry
echo.
echo Copy everything above and open an issue on:
echo https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues
echo You can still use mhrv-rs without the UI. Run the CLI directly:
echo.
echo mhrv-rs.exe
echo.
echo Set your config in %%APPDATA%%\mhrv-rs\config\config.json (or
echo place a config.json next to mhrv-rs.exe in this folder), then
echo point your browser proxy at 127.0.0.1:8085 (HTTP) or
echo 127.0.0.1:8086 (SOCKS5). The CLI is the same proxy without
echo the UI shell, so all functionality is available.
echo.
echo Falling back to the CLI now so you can keep using the proxy.
echo Press Ctrl+C in the CLI window to stop it.
echo ---------------------------------------------------
pause
echo.
mhrv-rs.exe
)
)
+10
View File
@@ -0,0 +1,10 @@
<!-- see docs/changelog/v1.1.0.md for the file format: Persian, then `---`, then English. -->
• tunable کردن آستانه auto-blacklist با ۳ field config جدید: `auto_blacklist_strikes` (default 3)، `auto_blacklist_window_secs` (default 30)، `auto_blacklist_cooldown_secs` (default 120) ([#391](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/391)، [#444](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/444)): تا قبل، threshold روی ۳ timeout در ۳۰ ثانیه = ۱۲۰ ثانیه cooldown hard-coded بود. کاربران single-deployment گزارش دادن این threshold روی شبکه‌های flaky too aggressive هست — یک cold-start stall + دو network blip → فقط deployment آن‌ها lockout می‌شه. حالا قابل تنظیم: single-deployment users می‌تونن `auto_blacklist_strikes: 5` یا `auto_blacklist_cooldown_secs: 30` بزارن. کاربران multi-deployment با ۱۰+ alternatives می‌تونن `auto_blacklist_strikes: 2` بزارن برای fail-fast. defaults رفتار قدیمی رو حفظ می‌کنن — هیچ کاربری چیزی notice نمی‌کنه مگر در config صریح override کنه. کاربر در UI form expose نشده — power-user file edit در config.json. clamp [1, 86400] برای جلوگیری از مقادیر غیرمعقول.
`request_timeout_secs` config (default 30) برای تنظیم batch HTTP timeout ([#430](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/430)، masterking32 PR #25): تا قبل `BATCH_TIMEOUT = 30s` hard-coded. شبکه‌های Iran ISP slow ممکنه `45` یا `60` بخوان تا Apps Script پیغام ارسال کنه past throttle window. شبکه‌های با fail-fast preference ممکنه `15` بخوان برای retry سریع‌تر هنگام hang. clamp [5s, 300s]. برای کاربر در UI form expose نشده.
• warning روشن‌تر در tunnel-node startup برای recurring `MHRV_AUTH_KEY` typo ([#391](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/391)، [#444](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/444)): چندین قدیمی copy-paste guide از `MHRV_AUTH_KEY` به‌جای `TUNNEL_AUTH_KEY` در docker run استفاده می‌کرد. tunnel-node اون env var رو هرگز نمی‌خوند + silently default `changeme` رو fallback می‌کرد، که باعث AUTH_KEY-mismatch decoy می‌شد در client. حالا اگر `MHRV_AUTH_KEY` set باشه ولی `TUNNEL_AUTH_KEY` نباشه، tunnel-node پیغام specific می‌ده: "MHRV_AUTH_KEY is set but TUNNEL_AUTH_KEY is not — tunnel-node only reads TUNNEL_AUTH_KEY (uppercase, with underscores). Rename your env var: docker run ... -e TUNNEL_AUTH_KEY=...". این به کاربر مستقیم کمک می‌کنه به‌جای ساعت‌ها debug.
• run.bat fallback به CLI بعد از UI failure ([#417](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/417)، [#426](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/426)، [#487](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/487)): قبلاً وقتی هر دو UI renderer (glow + wgpu) fail می‌گرفتن (روی ماشین‌های قدیمی Windows / RDP / VM بدون GPU)، script پیغام "open issue" می‌داد + exit. حالا بعد از پیغام error، CLI `mhrv-rs.exe` رو خود اجرا می‌کنه + کاربر می‌تونه به استفاده از proxy ادامه دهد. CLI همان full functionality رو داره بدون UI shell — proxy روی `127.0.0.1:8085` (HTTP) و `127.0.0.1:8086` (SOCKS5).
---
• Tunable auto-blacklist threshold via three new config fields: `auto_blacklist_strikes` (default 3), `auto_blacklist_window_secs` (default 30), `auto_blacklist_cooldown_secs` (default 120) ([#391](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/391), [#444](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/444)): previously hard-coded at "3 timeouts in 30s = 120s cooldown". Single-deployment users reported this threshold was too aggressive on flaky networks — one cold-start stall plus two transient network blips would lock them out of their only relay path. Now tunable: single-deployment users can set `auto_blacklist_strikes: 5` or `auto_blacklist_cooldown_secs: 30` to be more forgiving. Multi-deployment users with 10+ healthy alternatives can set `auto_blacklist_strikes: 2` to fail-fast. Defaults preserve existing behavior — no user notices a change unless they explicitly tune in `config.json`. Not exposed in the UI form yet — power-user file edit. Clamped to [1, 86400] for the duration fields to prevent absurd values.
`request_timeout_secs` config field (default 30) to tune the batch HTTP timeout ([#430](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/430), masterking32 PR #25): previously the hard-coded `BATCH_TIMEOUT = 30s` constant. Slow Iran ISP networks may want `45` or `60` to give Apps Script time to respond past throttle windows. Networks preferring fail-fast may want `15` to retry sooner when a deployment hangs. Clamped to [5s, 300s] (anything beyond exceeds Apps Script's 6-min hard cap with no benefit). Not in the UI form.
• Clearer tunnel-node startup warning for the recurring `MHRV_AUTH_KEY` typo ([#391](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/391), [#444](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/444)): several older copy-paste guides used `MHRV_AUTH_KEY` instead of `TUNNEL_AUTH_KEY` in `docker run`. tunnel-node never read that env var and silently fell back to default `changeme`, producing baffling AUTH_KEY-mismatch decoys on the client. Now if `MHRV_AUTH_KEY` is set but `TUNNEL_AUTH_KEY` is not, tunnel-node emits a specific warning: `"MHRV_AUTH_KEY is set but TUNNEL_AUTH_KEY is not — tunnel-node only reads TUNNEL_AUTH_KEY (uppercase, with underscores). Rename your env var: docker run ... -e TUNNEL_AUTH_KEY=<your-secret>"`. Saves users hours of debugging the wrong layer.
`run.bat` falls back to CLI after UI renderer failure ([#417](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/417), [#426](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/426), [#487](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/487)): when both UI renderers (glow + wgpu) fail on older Windows machines, RDP sessions, or VMs without GPU acceleration, the script previously printed an "open an issue on GitHub" message and exited. Now it prints the diagnostic info AND launches `mhrv-rs.exe` (CLI) so the user can keep using the proxy without the UI shell. CLI has the same proxy functionality on `127.0.0.1:8085` (HTTP) and `127.0.0.1:8086` (SOCKS5); only the visual UI is missing.
+47
View File
@@ -272,6 +272,14 @@ struct FormState {
/// there is no UI editor for these yet, only file-edited config.
/// See config.rs `fronting_groups`.
fronting_groups: Vec<FrontingGroup>,
/// Auto-blacklist tuning + per-batch timeout. Config-only knobs (no UI
/// fields yet — power-user file edit). Round-tripped through FormState
/// so Save preserves the user's hand-edited values. See config.rs
/// `auto_blacklist_*` and `request_timeout_secs`.
auto_blacklist_strikes: u32,
auto_blacklist_window_secs: u64,
auto_blacklist_cooldown_secs: u64,
request_timeout_secs: u64,
}
#[derive(Clone, Debug)]
@@ -369,6 +377,10 @@ fn load_form() -> (FormState, Option<String>) {
tunnel_doh: c.tunnel_doh,
bypass_doh_hosts: c.bypass_doh_hosts.clone(),
fronting_groups: c.fronting_groups.clone(),
auto_blacklist_strikes: c.auto_blacklist_strikes,
auto_blacklist_window_secs: c.auto_blacklist_window_secs,
auto_blacklist_cooldown_secs: c.auto_blacklist_cooldown_secs,
request_timeout_secs: c.request_timeout_secs,
}
} else {
FormState {
@@ -401,6 +413,12 @@ fn load_form() -> (FormState, Option<String>) {
tunnel_doh: true,
bypass_doh_hosts: Vec::new(),
fronting_groups: Vec::new(),
// Defaults match `default_auto_blacklist_*` and
// `default_request_timeout_secs` in src/config.rs.
auto_blacklist_strikes: 3,
auto_blacklist_window_secs: 30,
auto_blacklist_cooldown_secs: 120,
request_timeout_secs: 30,
}
};
(form, load_err)
@@ -567,6 +585,14 @@ impl FormState {
// batch alongside the system-proxy toggle (#432).
coalesce_step_ms: 0,
coalesce_max_ms: 0,
// Auto-blacklist + batch timeout: config-only knobs (#391,
// #444, #430). Round-trip through FormState so Save doesn't
// drop hand-edited values. UI editor planned alongside the
// v1.8.x desktop UI batch.
auto_blacklist_strikes: self.auto_blacklist_strikes,
auto_blacklist_window_secs: self.auto_blacklist_window_secs,
auto_blacklist_cooldown_secs: self.auto_blacklist_cooldown_secs,
request_timeout_secs: self.request_timeout_secs,
})
}
}
@@ -626,8 +652,25 @@ struct ConfigWire<'a> {
bypass_doh_hosts: &'a Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
fronting_groups: &'a Vec<FrontingGroup>,
/// Auto-blacklist tuning + batch timeout (#391, #444, #430). Skip
/// serialization when matching the historical defaults so unchanged
/// configs stay clean — only emitted when the user has explicitly
/// tuned them.
#[serde(skip_serializing_if = "is_default_strikes")]
auto_blacklist_strikes: u32,
#[serde(skip_serializing_if = "is_default_window_secs")]
auto_blacklist_window_secs: u64,
#[serde(skip_serializing_if = "is_default_cooldown_secs")]
auto_blacklist_cooldown_secs: u64,
#[serde(skip_serializing_if = "is_default_timeout_secs")]
request_timeout_secs: u64,
}
fn is_default_strikes(v: &u32) -> bool { *v == 3 }
fn is_default_window_secs(v: &u64) -> bool { *v == 30 }
fn is_default_cooldown_secs(v: &u64) -> bool { *v == 120 }
fn is_default_timeout_secs(v: &u64) -> bool { *v == 30 }
fn is_false(b: &bool) -> bool {
!*b
}
@@ -677,6 +720,10 @@ impl<'a> From<&'a Config> for ConfigWire<'a> {
tunnel_doh: c.tunnel_doh,
bypass_doh_hosts: &c.bypass_doh_hosts,
fronting_groups: &c.fronting_groups,
auto_blacklist_strikes: c.auto_blacklist_strikes,
auto_blacklist_window_secs: c.auto_blacklist_window_secs,
auto_blacklist_cooldown_secs: c.auto_blacklist_cooldown_secs,
request_timeout_secs: c.request_timeout_secs,
}
}
}
+51
View File
@@ -291,6 +291,47 @@ pub struct Config {
/// to the DoH bypass. Empty / missing = feature off.
#[serde(default)]
pub fronting_groups: Vec<FrontingGroup>,
/// Auto-blacklist tuning — how many timeouts within the window
/// trip a per-deployment cooldown.
///
/// Default `3` matches the historical behavior. Single-deployment
/// users who hit transient network blips have reported (#391, #444)
/// that 3 strikes are too few — one cold-start stall plus two
/// network glitches lock out their only relay path. Bumping to
/// `5` or `6` is a reasonable workaround for that case.
///
/// Multi-deployment users with 10+ healthy alternatives can lower
/// this (e.g. `2`) to fail-fast off a flaky deployment without
/// burning latency on retries.
#[serde(default = "default_auto_blacklist_strikes")]
pub auto_blacklist_strikes: u32,
/// Window (seconds) for the auto-blacklist strike counter. Strikes
/// older than this are dropped. Default `30`. Larger windows make
/// the heuristic less twitchy at the cost of holding state longer
/// for deployments that have already recovered.
#[serde(default = "default_auto_blacklist_window_secs")]
pub auto_blacklist_window_secs: u64,
/// Cooldown (seconds) when the strike threshold trips. Default
/// `120`. Single-deployment users who can't afford a 2-min lockout
/// when their only relay misbehaves can drop to `30` or `60`. Multi-
/// deployment users with healthy alternatives can extend to `600`
/// to keep a known-bad deployment out of rotation longer.
#[serde(default = "default_auto_blacklist_cooldown_secs")]
pub auto_blacklist_cooldown_secs: u64,
/// Per-batch HTTP round-trip timeout (seconds). Default `30` —
/// matches Apps Script's typical response cliff and historical
/// `BATCH_TIMEOUT` constant. Slow Iran ISP networks may want `45`
/// or `60` to give Apps Script time to respond past throttle
/// windows. Networks with fail-fast preference may want `15` to
/// retry sooner when a deployment hangs. Floor `5`, ceiling `300`
/// (anything beyond exceeds Apps Script's hard 6-min cap with
/// no benefit).
#[serde(default = "default_request_timeout_secs")]
pub request_timeout_secs: u64,
}
/// One multi-edge fronting group. Edge CDNs like Vercel and Fastly
@@ -342,6 +383,16 @@ fn default_google_ip_validation() -> bool {true}
/// opt back in with `tunnel_doh: false`.
fn default_tunnel_doh() -> bool { true }
/// Defaults for the auto-blacklist tuning knobs (#391, #444). These
/// preserve historical behavior — `3 strikes / 30s window / 120s cooldown`.
fn default_auto_blacklist_strikes() -> u32 { 3 }
fn default_auto_blacklist_window_secs() -> u64 { 30 }
fn default_auto_blacklist_cooldown_secs() -> u64 { 120 }
/// Default for `request_timeout_secs`: 30s, matching the historical
/// hard-coded `BATCH_TIMEOUT` and Apps Script's typical response cliff.
fn default_request_timeout_secs() -> u64 { 30 }
fn default_google_ip() -> String {
"216.239.38.120".into()
}
+37 -18
View File
@@ -140,6 +140,17 @@ pub struct DomainFronter {
/// payloads. Mirrors `Config::disable_padding` (#391). Default false
/// (padding active = stronger DPI defense at +25% bandwidth cost).
disable_padding: bool,
/// Per-instance auto-blacklist tuning. Mirrors `Config::auto_blacklist_*`
/// (#391, #444). Cached here so the hot path in `record_timeout_strike`
/// doesn't have to reach back through the Config (which we don't keep
/// a reference to).
auto_blacklist_strikes: u32,
auto_blacklist_window: Duration,
auto_blacklist_cooldown: Duration,
/// Per-batch HTTP timeout. Mirrors `Config::request_timeout_secs`
/// (#430, masterking32 PR #25). Read by `tunnel_client::fire_batch`
/// so a single config field tunes the timeout used everywhere.
batch_timeout: Duration,
}
/// Aggregated stats for one remote host.
@@ -163,20 +174,11 @@ impl HostStat {
const BLACKLIST_COOLDOWN_SECS: u64 = 600;
/// Sliding window for the timeout-strike blacklist heuristic. Three
/// timeouts within this window on a single deployment trip the
/// blacklist. Tuned so a single cold-start stall plus one transient
/// network blip won't false-trigger, but a deployment that's actually
/// dead (stale `TUNNEL_SERVER_URL`, paused project, dropped script)
/// fails fast instead of poisoning round-robin until the user notices.
const TIMEOUT_STRIKE_WINDOW: Duration = Duration::from_secs(30);
const TIMEOUT_STRIKE_LIMIT: u32 = 3;
/// Cooldown for a deployment blacklisted via the timeout-strike path.
/// Distinct from `BLACKLIST_COOLDOWN_SECS` (10 min) because timeouts
/// are a much noisier signal than quota errors — if the deployment
/// recovers, we want to rejoin in minutes, not after a 10-min penalty.
const TIMEOUT_BLACKLIST_COOLDOWN_SECS: u64 = 120;
/// Auto-blacklist defaults are now per-instance fields on `DomainFronter`,
/// driven by `Config::auto_blacklist_strikes` / `_window_secs` /
/// `_cooldown_secs` (#391, #444). The constants below are gone — see the
/// `Config` doc comments for tuning guidance and `default_auto_blacklist_*`
/// for the historical defaults (3 strikes / 30s window / 120s cooldown).
/// Request payload sent to Apps Script (single, non-batch).
#[derive(Serialize)]
@@ -299,9 +301,26 @@ impl DomainFronter {
today_bytes: AtomicU64::new(0),
today_key: std::sync::Mutex::new(current_pt_day_key()),
disable_padding: config.disable_padding,
auto_blacklist_strikes: config.auto_blacklist_strikes.max(1),
auto_blacklist_window: Duration::from_secs(
config.auto_blacklist_window_secs.clamp(1, 3600),
),
auto_blacklist_cooldown: Duration::from_secs(
config.auto_blacklist_cooldown_secs.clamp(1, 86400),
),
batch_timeout: Duration::from_secs(
config.request_timeout_secs.clamp(5, 300),
),
})
}
/// Per-batch HTTP round-trip timeout. Read by `tunnel_client` so the
/// `BATCH_TIMEOUT` constant doesn't have to be touched on every config
/// change. Clamped to `[5s, 300s]` at construction.
pub(crate) fn batch_timeout(&self) -> Duration {
self.batch_timeout
}
/// Record one relay call toward the daily budget. Called once per
/// outbound Apps Script fetch. Rolls over both daily counters at
/// 00:00 Pacific Time, matching Apps Script's quota reset cadence
@@ -483,22 +502,22 @@ impl DomainFronter {
let entry = counts
.entry(script_id.to_string())
.or_insert((now, 0));
if now.duration_since(entry.0) > TIMEOUT_STRIKE_WINDOW {
if now.duration_since(entry.0) > self.auto_blacklist_window {
*entry = (now, 1);
} else {
entry.1 += 1;
}
let strikes = entry.1;
if strikes >= TIMEOUT_STRIKE_LIMIT {
if strikes >= self.auto_blacklist_strikes {
counts.remove(script_id);
drop(counts);
self.blacklist_script_for(
script_id,
Duration::from_secs(TIMEOUT_BLACKLIST_COOLDOWN_SECS),
self.auto_blacklist_cooldown,
&format!(
"{} timeouts in {}s",
strikes,
TIMEOUT_STRIKE_WINDOW.as_secs()
self.auto_blacklist_window.as_secs()
),
);
}
+14 -11
View File
@@ -38,10 +38,11 @@ const MAX_BATCH_PAYLOAD_BYTES: usize = 4 * 1024 * 1024;
/// serializing too many sessions behind a single HTTP round-trip.
const MAX_BATCH_OPS: usize = 50;
/// Timeout for a single batch HTTP round-trip. If the tunnel-node or Apps
/// Script takes longer than this, the batch fails and sessions get error
/// replies rather than hanging forever.
const BATCH_TIMEOUT: Duration = Duration::from_secs(30);
// Per-batch HTTP round-trip timeout is now read from
// `DomainFronter::batch_timeout()`, sourced from `Config::request_timeout_secs`
// (#430, masterking32 PR #25). The historical default — 30 s, matching Apps
// Script's typical response cliff — lives in `default_request_timeout_secs`
// in `config.rs`.
/// Timeout for a session waiting for its batch reply. If the batch task
/// is slow (e.g. one op in the batch has a dead target on the tunnel-node
@@ -820,10 +821,12 @@ async fn fire_batch(
let t0 = std::time::Instant::now();
let n_ops = data_ops.len();
// Bounded-wait: if the batch takes longer than BATCH_TIMEOUT,
// all sessions in this batch get an error and can retry.
// Bounded-wait: if the batch takes longer than the configured
// batch timeout (Config::request_timeout_secs), all sessions in
// this batch get an error and can retry.
let batch_timeout = f.batch_timeout();
let result = tokio::time::timeout(
BATCH_TIMEOUT,
batch_timeout,
f.tunnel_batch_request_to(&script_id, &data_ops),
)
.await;
@@ -930,14 +933,14 @@ async fn fire_batch(
}
}
Err(_) => {
// Whole-batch budget (`BATCH_TIMEOUT`, 30 s) elapsed. Even
// stronger signal than a per-read timeout — count it the same
// way so a truly-stuck deployment exits round-robin fast.
// Whole-batch budget elapsed. Even stronger signal than a
// per-read timeout — count it the same way so a truly-stuck
// deployment exits round-robin fast.
f.record_timeout_strike(&script_id);
let sid_short = &script_id[..script_id.len().min(8)];
tracing::warn!(
"batch timed out after {:?} (script {}, {} ops)",
BATCH_TIMEOUT,
batch_timeout,
sid_short,
n_ops
);
+18 -1
View File
@@ -1405,7 +1405,24 @@ async fn main() {
.init();
let auth_key = std::env::var("TUNNEL_AUTH_KEY").unwrap_or_else(|_| {
tracing::warn!("TUNNEL_AUTH_KEY not set — using default (INSECURE)");
// Catch the recurring `MHRV_AUTH_KEY` typo (#391, #444). Several old
// copy-paste guides used `MHRV_AUTH_KEY` for the docker run; tunnel-node
// never read that name and silently fell through to `changeme`,
// producing baffling AUTH_KEY-mismatch decoys on the client. If
// `MHRV_AUTH_KEY` is set, point at it specifically so the user sees
// why their value isn't taking effect.
if std::env::var("MHRV_AUTH_KEY").is_ok() {
tracing::warn!(
"MHRV_AUTH_KEY is set but TUNNEL_AUTH_KEY is not — \
tunnel-node only reads TUNNEL_AUTH_KEY (uppercase, with \
underscores). Rename your env var: \
`docker run ... -e TUNNEL_AUTH_KEY=<your-secret>`. Falling \
back to default `changeme` for now (INSECURE clients will \
fail with AUTH_KEY mismatch decoys until this is fixed)."
);
} else {
tracing::warn!("TUNNEL_AUTH_KEY not set — using default (INSECURE)");
}
"changeme".into()
});
let port: u16 = std::env::var("PORT")