From d7fb869783767f3c23a16ca5166af4099f20d163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Sun, 8 Nov 2026 09:55:44 +0100 Subject: [PATCH] v0.36.5 --- CHANGELOG.md | 1 + SHA256SUMS | 6 +++--- scripts/deploy/deploy_core.py | 28 +++++++++++++++++++++++++++- scripts/deploy/deploy_runtime.py | 12 ++++++++++-- 4 files changed, 41 insertions(+), 6 deletions(-) mode change 100755 => 100644 scripts/deploy/deploy_core.py mode change 100755 => 100644 scripts/deploy/deploy_runtime.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e42759..39ec4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Release history focused on **features, settings, default behavior, compatibility - **Certificate auto-selection:** when creating a vhost, redirect or 404 host, RustProxy picks the stored certificate that covers every host name you enter (an exact name beats a wildcard, the narrowest certificate wins). A hint names the chosen certificate and the selector still lets you pick another one or the global default. Existing entries are never changed. - **Clearer host conflicts:** the "overlapping frontend bindings for hostname …" error now names the entry that already uses the host (`vhost`, `redirect` or `404 host` plus its ID) and the conflicting listener address. - **Clearer validation errors:** duplicate or invalid IDs, repeated hostnames, missing hostnames or listeners, invalid location IDs, regular expressions, exact paths and duplicate location matchers now say which value or location is wrong and how to fix it. +- **Deploy script:** `update.sh` / `install.sh` retry the GeoIP download (transient 502/503/504, timeouts) up to four times and, if it still fails, warn and continue with the installed GeoIP data instead of aborting the update with `HTTP Error 504`. ## 0.36.4 — cache readability and editor UX polish diff --git a/SHA256SUMS b/SHA256SUMS index c6d3042..f3f96ce 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -2,7 +2,7 @@ 4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/.env.example e76e688874828e3743d03693b1d2872b9633b4db09909673786caf30f7cfe489 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/.gitignore 875fa17d64e0cf8f097cd4635ca801686c256d556680a39a9259dcdb1155ed6c /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/AGENTS.md -a544bba6a7558f7aa780ddd3e1c9e67aae58e371dddb99e8b277455f2d4cb46b /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/CHANGELOG.md +7619bfb852154916eaec3f84ecae54cc58b2ab1607c8a38f158524a5e388a542 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/CHANGELOG.md eae2405a396e300ca4f2997a36239648b74acebf9e724b8c8d095c11969e3fd9 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/Cargo.lock 202e5377c7875ef538d420ccb563c26d4cb010dbcd49ce80ca1a1555d267b038 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/Cargo.toml 25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/Dockerfile @@ -120,8 +120,8 @@ fd1c34599f725ad5f7c3c0cc89e08b11917baef02c83af054ac8528b2e01dd8e /sessions/rcw- c3066f40f152a2655f88314fd9cf784eddbfa6c3238a494da13d972ef9ad930c /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/build/panel_css.py 5e98d6c30047512825f5dc1c42709b82f0f6342fc0db8346a67ae85ffeb40c90 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/build/swagger_assets.py e4d15aa6aa864d04b9b30aca33826b833632af02ca643f8b23e219a5ea1298dd /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/deploy.py -618603239b000bbe4af36a6a6ee268758af632c761fc53fc6b7f44a4a818bdf1 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/deploy_core.py -992c9a806464fa10902de5be102f1609469986331fc0ae223a5b5f8507153574 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/deploy_runtime.py +f0edbdca3af49cfa8f9c118d3eb0977c99569264dc5d74a85c4610234ea1fe88 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/deploy_core.py +f26297284e0ad9fb4e4317deac24b25de819c10d04fed551134ddb6debc41837 /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/deploy_runtime.py a59587ce8ad41b1bbb431356b58398f9c8ff7cb96a613a91752e907a70e10c2e /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/deploy/upgrade.py 2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/migration/migrate_npm.py a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c /sessions/rcw-01mmsgszuju6d7f2h8egrxc4/mnt/RustProxy/scripts/migration/migrate_npm_api.py diff --git a/scripts/deploy/deploy_core.py b/scripts/deploy/deploy_core.py old mode 100755 new mode 100644 index ec96fb9..a03440b --- a/scripts/deploy/deploy_core.py +++ b/scripts/deploy/deploy_core.py @@ -28,6 +28,7 @@ import subprocess import sys import time import uuid +import urllib.error import urllib.request import urllib.parse @@ -41,6 +42,12 @@ GEOIP_SOURCES = { 'user-country-ipv6.csv': 'https://github.com/sapics/ip-location-db/releases/download/latest/user-country-ipv6.csv', } GEOIP_MAX_BYTES = 256 * 1024 * 1024 +GEOIP_FETCH_ATTEMPTS = 4 +GEOIP_RETRY_DELAYS = (3, 6, 12) + + +class GeoipUnavailable(RuntimeError): + """The GeoIP CSV download failed after retries; the deployment itself can continue.""" def run(args: list[str], **kwargs) -> subprocess.CompletedProcess: @@ -93,7 +100,7 @@ def digest(path: Path) -> str: return result.hexdigest() -def fetch_https(url: str, max_bytes: int) -> bytes: +def _fetch_https_once(url: str, max_bytes: int) -> bytes: if urllib.parse.urlparse(url).scheme != 'https': raise ValueError('GeoIP downloads require HTTPS.') request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer'}) @@ -114,6 +121,25 @@ def fetch_https(url: str, max_bytes: int) -> bytes: return bytes(result) +def fetch_https(url: str, max_bytes: int) -> bytes: + """Download with retries; transient gateway/network failures (502/503/504, timeouts) are retried.""" + last: BaseException | None = None + for attempt in range(GEOIP_FETCH_ATTEMPTS): + try: + return _fetch_https_once(url, max_bytes) + except urllib.error.HTTPError as error: + last = error + if error.code not in (408, 425, 429) and error.code < 500: + break + except (urllib.error.URLError, TimeoutError, ConnectionError, ssl.SSLError) as error: + last = error + if attempt + 1 < GEOIP_FETCH_ATTEMPTS: + delay = GEOIP_RETRY_DELAYS[min(attempt, len(GEOIP_RETRY_DELAYS) - 1)] + print(f'GeoIP download failed ({last}); retrying in {delay}s ({attempt + 1}/{GEOIP_FETCH_ATTEMPTS - 1}).', file=sys.stderr) + time.sleep(delay) + raise GeoipUnavailable(f'GeoIP download from {url} failed: {last}') + + def acquire_geoip_update_lock(data: Path, uid: int | None = None, gid: int | None = None) -> int: """Serialize installer/manual GeoIP refresh with the in-process worker.""" path = data / '.geoip-update.lock' diff --git a/scripts/deploy/deploy_runtime.py b/scripts/deploy/deploy_runtime.py old mode 100755 new mode 100644 index 5d835ad..25db7dc --- a/scripts/deploy/deploy_runtime.py +++ b/scripts/deploy/deploy_runtime.py @@ -365,7 +365,12 @@ def update(record: dict, binary: Path, sha: str, start: bool, refresh_geoip: boo if refresh_geoip: # Shared lock with the runtime worker prevents concurrent upgrades. geoip_lock_fd = acquire_geoip_update_lock(data, account.pw_uid, account.pw_gid) - geoip_stage, geoip_names = prepare_geoip_update(data, prefix) + try: + geoip_stage, geoip_names = prepare_geoip_update(data, prefix) + except GeoipUnavailable as error: + # GeoIP is refreshed best-effort: the update must not be blocked by a flaky download. + print(f'WARNING: GeoIP refresh skipped, keeping the installed country data: {error}', file=sys.stderr) + geoip_stage, geoip_names = None, [] active = subprocess.run(['systemctl', 'is-active', '--quiet', SERVICE], check=False, stdout=subprocess.DEVNULL).returncode == 0 stop_for_managed_update(data) try: @@ -434,7 +439,10 @@ def install(record: dict, binary: Path, sha: str, start: bool, install_geoip: bo prefix.mkdir(parents=True, mode=0o755, exist_ok=True); os.chmod(prefix, 0o755) data.mkdir(parents=True, mode=0o700, exist_ok=True); os.chmod(data, 0o700); os.chown(data, account.pw_uid, account.pw_gid) if install_geoip: - download_geoip(data, account.pw_uid, account.pw_gid) + try: + download_geoip(data, account.pw_uid, account.pw_gid) + except GeoipUnavailable as error: + print(f'WARNING: GeoIP download skipped ({error}). Country allow/block lists will use data fetched later by the GeoIP updater, or rerun update.sh.', file=sys.stderr) release, version = stage(binary, prefix, record['user'], sha) record.update(release=release, version=version, sha256=sha) switch(prefix, release)