From 77440c8f7525c6fa0b3ac6e6ba3b602426f1fb54 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Aug 2026 02:43:37 +0000 Subject: [PATCH] Live-scan Traccar's device-protocol range for collisions, not just Asterisk's ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 5000-5150 range was only ever checked against Asterisk's hardcoded fixed ports (5038/5060/5061) for a first instance — no live scan of the rest of the range, because the directory-count-based offset mechanism only triggers for an explicit additional instance. Confirmed live: this range sat unclaimed at the OS level while this Traccar instance's container had never actually started, so an unrelated service's own find_free_port scan found port 5007 genuinely free (nothing was listening there yet) and took it — invisible to any check until Traccar itself tried to bind its declared range for the first time, failing with "port is already allocated". Add a live scan across the whole intended range (skipping Asterisk's expected carve-outs at the base 5000-5150 range) and shift by 1000, same step the multi-instance path already uses, until genuinely clear. Also fixed the compose-block and README generation, which keyed off INSTANCE_SUFFIX being empty to decide whether Asterisk's exclusions were needed — now keyed off whether the range is still the unshifted default (PROTO_MIN -eq 5000), since a first instance can now end up shifted too. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/traccar.sh | 50 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/services/traccar.sh b/services/traccar.sh index 853cf96..1f0fa70 100644 --- a/services/traccar.sh +++ b/services/traccar.sh @@ -231,7 +231,8 @@ install_traccar() { echo " - Point Traccar at it via env vars (CONFIG_USE_ENVIRONMENT_VARIABLES) — no secrets in a config file" echo " - Deploy an autoheal container that restarts Traccar if its healthcheck fails" echo " - Expose port 8082 (web) and 5000-5150 (device protocols; 5038/5060/5061 skipped — Asterisk keeps" - echo " priority on those); an additional instance's device-protocol range shifts by 1000 instead" + echo " priority on those); shifts by 1000 instead, whether for an additional instance or because" + echo " something else already has a port in that range" echo " - No default login — register the first account at the web UI, it becomes admin" echo " - Offer optional ntfy push notifications (self-hosted anywhere, or ntfy.sh)" echo " - Offer a Caddy reverse proxy and to start the container" @@ -310,6 +311,36 @@ install_traccar() { # directory-count-based mechanism (not an ss scan) and is unaffected. find_free_port WEB_PORT "$WEB_PORT" + # Live-check the whole device-protocol range too — the directory-count + # offset above only avoids colliding with an *earlier Traccar instance*, + # not an unrelated single-port service. Confirmed live: this range sat + # unclaimed at the OS level while this Traccar instance's own container + # had never actually started (still `docker compose up`'d for the first + # time), so a completely unrelated service's own find_free_port scan + # found 5007 "free" (nothing was listening there yet) and took it — + # invisible to any check until Traccar itself actually tried to bind + # its declared range. Shift by 1000 (reusing the same offset step the + # multi-instance path uses) until the whole range is genuinely clear. + _traccar_range_conflict() { + local min="$1" max="$2" p + for ((p = min; p <= max; p++)); do + # The base 5000-5150 range's own carve-outs for Asterisk are + # expected occupants, not a conflict — only relevant at the + # unshifted range; a shifted range never overlaps them anyway. + if [ "$min" -eq 5000 ] && { [ "$p" -eq 5038 ] || [ "$p" -eq 5060 ] || [ "$p" -eq 5061 ]; }; then + continue + fi + port_in_use "$p" tcp && return 0 + port_in_use "$p" udp && return 0 + done + return 1 + } + while _traccar_range_conflict "$PROTO_MIN" "$PROTO_MAX"; do + log_warning "Device-protocol range $PROTO_MIN-$PROTO_MAX collides with something already running — shifting to $((PROTO_MIN + 1000))-$((PROTO_MAX + 1000))." + PROTO_MIN=$((PROTO_MIN + 1000)) + PROTO_MAX=$((PROTO_MAX + 1000)) + done + mkdir -p "$TRACCAR_DIR" # Non-recursive on purpose — a rerun already has a `db/` full of Postgres's # own data files, owned by whatever uid the postgres container runs as @@ -406,13 +437,16 @@ networks: " fi - # First instance keeps the exact existing Asterisk-exclusion port block - # (5000-5150 with 5038/5060/5061 carved out). An additional instance's - # range is shifted by 1000 per instance (computed above), which never - # lands on Asterisk's fixed ports, so it just publishes the plain range - # with no exclusions needed. + # Keyed on whether the range is still the unshifted default (5000), not + # on INSTANCE_SUFFIX — a first instance can also end up shifted now, if + # the live-collision check above moved it off 5000 (see that check's + # comment). Only the unshifted base range needs Asterisk's ports carved + # out; any shifted range (whether from a genuine additional instance or + # a first instance that got bumped for a live collision) never lands on + # Asterisk's fixed ports, so it just publishes the plain range with no + # exclusions needed. local _PROTO_PORT_BLOCK - if [ -z "$INSTANCE_SUFFIX" ]; then + if [ "$PROTO_MIN" -eq 5000 ]; then _PROTO_PORT_BLOCK=" # 5038 (AMI), 5060 (SIP, tcp+udp), and 5061 (SIP TLS, tcp) are skipped: # they're Asterisk's ports (services/asterisk.sh runs Asterisk with # network_mode: host, so it binds them directly on the host, not @@ -584,7 +618,7 @@ Traccar instance.") stays open to anyone who reaches this server until you turn it off, so do this right away, then go to Settings → Server → Permissions and uncheck Registration. -- Device protocols: ports ${PROTO_MIN}-${PROTO_MAX} (TCP + UDP$( [ -z "$INSTANCE_SUFFIX" ] && echo "; 5038/tcp, 5060/tcp+udp, and 5061/tcp are skipped — reserved for Asterisk's AMI and SIP if this box also runs Asterisk from this repo, which gets priority on those ports")) +- Device protocols: ports ${PROTO_MIN}-${PROTO_MAX} (TCP + UDP$( [ "$PROTO_MIN" -eq 5000 ] && echo "; 5038/tcp, 5060/tcp+udp, and 5061/tcp are skipped — reserved for Asterisk's AMI and SIP if this box also runs Asterisk from this repo, which gets priority on those ports")) - App data: \`data/\` and \`logs/\` - Database: PostgreSQL (\`$DB_CONTAINER\` container, data in \`db/\`) - All database settings (name, user, password) live in \`.env\` — Traccar