Skip to content

feat: optionally bind SIP signaling to a named interface (LIVEKIT_NODE_IP_IFACE)#744

Open
rililinx wants to merge 1 commit into
livekit:mainfrom
rililinx:feat/listen-ip-from-iface
Open

feat: optionally bind SIP signaling to a named interface (LIVEKIT_NODE_IP_IFACE)#744
rililinx wants to merge 1 commit into
livekit:mainfrom
rililinx:feat/listen-ip-from-iface

Conversation

@rililinx

@rililinx rililinx commented Jul 15, 2026

Copy link
Copy Markdown

What

Adds an optional LIVEKIT_NODE_IP_IFACE environment variable. When set, the first IPv4 address of the named network interface (e.g. eth0) is resolved at startup and used as the SIP signaling bind address (listen_ip).

It is a no-op when:

  • the variable is unset/empty, or
  • listen_ip is already set to a specific (non-wildcard) address in config — an explicit operator choice always wins.

Why

This is about the bind address only, and is complementary to — not a replacement for — the existing advertised-IP options (local_net, use_external_ip, nat_1_to_1_ip).

On a multi-homed host (e.g. EC2 with multiple ENIs, bare metal, or K8s pods with several interfaces), binding SIP to 0.0.0.0 lets the kernel choose the source IP of outbound responses based on the routing table. That source IP can differ from the interface the request arrived on and from the IP advertised in Contact/Via/SDP. Many SIP peers and NATs drop responses whose source IP doesn't match where they sent the request, so signaling breaks.

Binding to the same interface you advertise keeps the response source IP consistent. listen_ip already lets you pin a static address, but in dynamically-scheduled environments (ECS/EC2/K8s) the address isn't known when the config is authored, whereas the interface name (eth0) is stable. Resolving by interface name at startup makes this ergonomic and mirrors the interface/NODE_IP resolution already used by the LiveKit media server, giving operators one consistent deployment pattern across LiveKit components.

What this does not do

  • It does not change the advertised SignalingIP/MediaIP. Those remain governed by local_net / use_external_ip / nat_1_to_1_ip.
  • It is not required for single-ENI Fargate/awsvpc deployments, where a 0.0.0.0 bind plus local_net for the advertised IP is sufficient.

How

  • applyNodeIPIface runs right after config load in runService, resolving the interface into conf.ListenIP before the server starts.
  • ipv4FromIface / firstIPv4 do the lookup and pick the first IPv4 on the interface.

Tests

Unit tests in cmd/livekit-sip/main_test.go cover the address-selection logic and the skip/override/error paths.

Notes

The env-var name mirrors the LiveKit media server for cross-component consistency. Happy to rename, or to expose this as a listen_iface config field instead of an env var, if maintainers prefer.

@rililinx
rililinx requested a review from a team as a code owner July 15, 2026 13:45

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.13%. Comparing base (0460b40) to head (30172c8).
⚠️ Report is 324 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #744      +/-   ##
==========================================
+ Coverage   65.25%   66.13%   +0.87%     
==========================================
  Files          51       41      -10     
  Lines        6588     7863    +1275     
==========================================
+ Hits         4299     5200     +901     
- Misses       1915     2190     +275     
- Partials      374      473      +99     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rililinx rililinx closed this Jul 15, 2026
@rililinx rililinx reopened this Jul 15, 2026
@rililinx rililinx changed the title feat: resolve LIVEKIT_NODE_IP_IFACE to set listen_ip at startup feat: optionally bind SIP signaling to a named interface (LIVEKIT_NODE_IP_IFACE) Jul 15, 2026
If LIVEKIT_NODE_IP_IFACE is set, resolve the first IPv4 address of that
network interface and use it as conf.ListenIP for SIP signalling binding.

This mirrors the LiveKit media server behaviour and is useful in
ECS/Fargate/Kubernetes, where the container IP lives on a known interface
(e.g. eth0) and must be bound explicitly rather than falling back to the
0.0.0.0 wildcard.

The override is skipped when the env var is empty, or when listen_ip is
already set to a specific (non-wildcard) address in config.

Co-Authored-By: Claude <noreply@anthropic.com>
@rililinx
rililinx force-pushed the feat/listen-ip-from-iface branch from 30172c8 to 7a04a75 Compare July 15, 2026 14:30
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