Skip to content

release: v0.1.2.2 — coturn validation works on more provider topologies (closes #15, #16)#17

Merged
vnykmshr merged 4 commits intomainfrom
release/v0.1.2.2-coturn-and-script
Apr 26, 2026
Merged

release: v0.1.2.2 — coturn validation works on more provider topologies (closes #15, #16)#17
vnykmshr merged 4 commits intomainfrom
release/v0.1.2.2-coturn-and-script

Conversation

@vnykmshr
Copy link
Copy Markdown
Contributor

@vnykmshr vnykmshr commented Apr 26, 2026

Bundles #15 and #16. v0.1.2.2 patch tag; no code or JSON schema delta.

What this changes

File Why
examples/coturn-natcheck.conf Replaces v0.1.2.1's external-ip=PUBLIC/PRIVATE (only works on AWS/GCP-style topology where the two IPs differ) with explicit two-listening-ip + two-external-ip-pair form. Honest about the topology requirement.
docs/coturn-setup.md New per-provider topology table (AWS/GCP / DO basic / bare metal / others); worked DO Reserved IP example with ip addr add; verification step references the two specific coturn warning lines; cross-references the script.
scripts/validate-coturn.sh Three bugs fixed (#16): IPv4 detection (curl -4), log-file path (log-file=stdout so tee captures real content), CHANGE_REQUEST grep wording portable across coturn 4.5/4.6/4.10. New SECOND_IP env var: aliases the IP to the NIC, writes the multi-IP conf form. Honest failure on misconfigured single-IP droplets.
CHANGELOG.md [0.1.2.2] entry.

Why two issues bundled

#16's script fix is correct standalone (false-positive verification was a real bug), but merging it alone leaves users following docs/coturn-setup.md on a basic single-IP droplet in a worse state than today: the script correctly fails closed, but they have no path forward. #15 provides the path. Shipping both as v0.1.2.2 ships one user-visible message ("coturn validation now works end-to-end across more provider topologies") with a single tag.

Verification (Jordan)

Both behavioural branches confirmed against a real DO basic droplet (coturn 4.6, Ubuntu 24.04, primary public IP 168.144.121.96, Reserved IP 168.144.1.58):

  • Single-public-IP, no SECOND_IP (the misconfigured case):
    ==> Verifying coturn config — grepping log for misconfig signals...
        FAIL: 'only one IP address is provided' in log — coturn needs 2 distinct routable IPs to honor CHANGE_REQUEST
    exit=1
    
  • SECOND_IP=168.144.1.58 (the documented path-forward):
    Script aliases the Reserved IP, writes multi-IP conf, coturn starts clean (no warning), exits 0. natcheck reports the canonical filtering verdict end-to-end:
    {
      "nat_type": "ADM",
      "filtering": {"behavior": "address-and-port-dependent", "tested_against": "168.144.121.96:3478"},
      "webrtc_forecast": {"direct_p2p": "unlikely", "turn_required": true}
    }

Verdict reproduces across runs (mapped ports + RTTs vary as expected; classification + warnings + exit code stable).

Out of scope

Linus disposition

4 files, 136 insertions / 65 deletions. Each commit is one concern (conf+docs / script / changelog). No drive-by refactors. No new dependencies. No code touched.

Test plan

  • make test (race, count=1) — green (no code change but sanity)
  • make lint — 0 issues
  • gofmt -l . — clean
  • Both script branches verified end-to-end against real DO droplet
  • natcheck filtering verdict reproduces post-fix
  • CI green on this PR
  • Merge → tag v0.1.2.2 on merge commit → Pages auto-deploys → gh release create v0.1.2.2
  • Bump Homebrew tap formula to v0.1.2.2 (so brew upgrade natcheck lands the corrected examples/ and docs/ and the new scripts/)

…e verification

Closes #16.

Three bugs fixed during validation against a real DO droplet (coturn 4.6,
Ubuntu 24.04):

1. IPv4 detection — curl was following the system's preferred address family
   and returning the v6 address on dual-stack droplets. Fixed with curl -4.

2. log-file path — coturn 4.5/4.6 with no log-file directive detects non-TTY
   stdout (the tee pipe) and writes only to PID-named files
   (/var/log/turn_<pid>_<date>.log), so the bare-path file the script
   greps stays at 0 bytes. log-file=stdout in the conf forces stdout
   emission; tee captures it as a flat file.

3. CHANGE_REQUEST grep wording — script was matching coturn 4.10's text
   ("STUN CHANGE_REQUEST not supported: only one IP") which doesn't match
   coturn 4.6's ("cannot support STUN CHANGE_REQUEST functionality because
   only one IP address is provided"). Match the stable substring "only one IP"
   instead. Combined with bug 2's fix, verification is now real on both
   coturn versions.

Verified: on a single-public-IP droplet the script now correctly exits 1
with a printed FAIL line + log tail. On a multi-IP setup (Reserved IP
aliased to eth0 — see #15) the script exits 0 and natcheck reports the
expected filtering classification.
Closes #15.

v0.1.2.1 shipped `external-ip=PUBLIC/PRIVATE` as the universal fix. That
form only works on AWS/GCP-style topology where the public IP is NAT'd
to a separate private NIC IP — the two values differ naturally. On
single-public-IP providers (DO basic droplet, Linode Nanode, Hetzner
single-IP), eth0's IP IS the public IP; `external-ip=A/A` doesn't
satisfy coturn's "two distinct IPs" requirement and coturn refuses to
participate in §4.4.

Conf now uses two `listening-ip` + two `external-ip` pairs explicitly.
Docs add a per-provider topology table with the worked DO Reserved IP
example (alias second IP to eth0 with `ip addr add`, reference both as
listening-ip + as external-ip pairs). Verification step + automated
path (validate-coturn.sh) cross-referenced.

Verified: with two distinct routable IPs configured per the new conf
shape, coturn 4.6 emits no "only one IP" warning and natcheck reports
the canonical filtering verdict end-to-end.
…logies

Single-public-IP providers (DO basic, Linode Nanode, Hetzner single-IP)
need a second routable IP attached and aliased to eth0 before coturn can
honor §4.4. Script now accepts SECOND_IP env var: aliases the IP to the
default-route NIC if not already present, writes the conf in multi-IP
form (two listening-ip + two external-ip pairs).

Behaviour matrix:
- SECOND_IP set         → multi-IP form, aliases the IP, writes both pairs
- public != private     → AWS/GCP-style, uses both directly
- public == private     → writes degenerate single-IP conf that will fail
                          verification, so user gets the FAIL line and a
                          pointer to docs/coturn-setup.md instead of
                          silently producing filtering: untested samples

Top-of-file usage block now shows both the no-env (AWS/GCP) and
SECOND_IP=... (single-public-IP) invocation forms.
Bundles #16 (validate-coturn.sh provisioner with version-portable
verification) and #15 (multi-IP conf form + per-provider topology docs).
No code or schema delta.
@vnykmshr vnykmshr changed the title fix(scripts): add validate-coturn.sh provisioner — closes #16 release: v0.1.2.2 — coturn validation works on more provider topologies (closes #15, #16) Apr 26, 2026
@vnykmshr vnykmshr merged commit 30a0f5e into main Apr 26, 2026
5 checks passed
@vnykmshr vnykmshr deleted the release/v0.1.2.2-coturn-and-script branch April 26, 2026 10:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant