Skip to content

feat: add WithHostIP option to bind exposed ports to a host IP - #3844

Open
shyim wants to merge 2 commits into
testcontainers:mainfrom
shyim:feat/bind-ports-to-host-ip
Open

feat: add WithHostIP option to bind exposed ports to a host IP#3844
shyim wants to merge 2 commits into
testcontainers:mainfrom
shyim:feat/bind-ports-to-host-ip

Conversation

@shyim

@shyim shyim commented Aug 10, 2026

Copy link
Copy Markdown

What does this PR do?

Disclaimer AI used

Adds a first-class WithHostIP option (and a matching HostIP field on ContainerRequest) to control the IP address to which a container's exposed ports are bound on the host.

By default, testcontainers binds exposed ports to all host interfaces (0.0.0.0). With this PR:

ctr, err := testcontainers.Run(ctx, "nginx:alpine",
    testcontainers.WithExposedPorts("80/tcp"),
    testcontainers.WithHostIP("127.0.0.1"),
)

restricts the binding to 127.0.0.1 only (the WithHostConfigModifier dance is no longer needed).

Implementation notes:

  • WithHostIP(ip string) validates the address with netip.ParseAddr at request-customization time and stores it as req.HostIP.
  • preCreateContainerHook applies the IP to all port bindings after mergePortBindings, so it covers both the default ephemeral bindings and per-port bindings set via WithHostConfigModifier (the HostIP is overridden while the HostPort is preserved).
  • Direct ContainerRequest users get the same validation, returning an error for invalid IPs.

Why is it important?

Exposing containers on 0.0.0.0 is a security concern on shared/multi-tenant machines: any process on the host (or, depending on the network setup, other hosts) can reach the container. Binding to loopback was previously only possible by reaching into the internal HostConfig via a modifier, with no validation and no documentation.

My usecase is running agents on a remote host, and while testcontainer runs my postgres / and so on are publicly reachable in the Internet, without proper Firewall

Related issues

# unit tests
go test -run 'TestWithHostIP|TestPreCreateContainerHookAppliesHostIP' .

# integration test (requires Docker): verifies the container actually
# binds to 127.0.0.1 via Inspect().NetworkSettings.Ports
go test -run 'TestContainerWithHostIP' -v .

By default the exposed ports of a container are bound to all host
interfaces (0.0.0.0). Add a WithHostIP option and a matching HostIP
field on ContainerRequest so users can restrict the port bindings to
a specific IP address, e.g. localhost only.

The host IP is applied to all port bindings in the pre-create hook,
after the default ephemeral bindings are merged, so it covers both
the default bindings and per-port bindings set via
WithHostConfigModifier (overriding their HostIP while preserving
their HostPort). Invalid IPs are rejected at request customization
time and validated again for direct ContainerRequest users.
@shyim
shyim requested a review from a team as a code owner August 10, 2026 06:34
@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit b045b48
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/6a7971bec00b36000887a9d0
😎 Deploy Preview https://deploy-preview-3844--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c7a1e180-7f6f-4cbd-ad06-6fd476354e04

📥 Commits

Reviewing files that changed from the base of the PR and between 4523ada and b045b48.

📒 Files selected for processing (1)
  • host_ip_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • host_ip_test.go

Summary by CodeRabbit

  • New Features

    • Added support for configuring the host IP address used when binding exposed container ports.
    • Added the WithHostIP option with IPv4 and IPv6 support.
    • Defaults to 0.0.0.0 when no host IP is specified.
    • Configured host IP settings take precedence over per-port bindings.
  • Bug Fixes

    • Invalid host IP addresses now produce clear validation errors.
  • Documentation

    • Added usage guidance and examples for configuring host IP addresses.

Walkthrough

The change adds ContainerRequest.HostIP and the WithHostIP option. Validated host IP values are applied to all container host port bindings. Tests cover IPv4, IPv6, invalid input, modifier bindings, and integration behavior.

Changes

Host IP binding

Layer / File(s) Summary
Host IP request option
container.go, options.go, options_test.go
ContainerRequest now exposes HostIP. WithHostIP validates and stores canonical IPv4 or IPv6 addresses.
Port binding application
lifecycle.go, host_ip_test.go
preCreateContainerHook applies HostIP to every merged host port binding and returns an error for invalid values. Unit tests cover default, custom, invalid, and modifier-provided bindings.
Integration coverage and documentation
host_ip_test.go, docs/features/common_functional_options.md, docs/features/common_functional_options_list.md
Integration tests cover ContainerRequest.HostIP and WithHostIP. Documentation describes the option and its precedence.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant WithHostIP
  participant preCreateContainerHook
  participant Docker
  Caller->>WithHostIP: provide IP address
  WithHostIP->>Caller: store canonical HostIP
  Caller->>preCreateContainerHook: create container request
  preCreateContainerHook->>Docker: apply HostIP to port bindings
  Docker-->>Caller: expose ports on configured host IP
Loading

Possibly related PRs

Suggested labels: enhancement

Poem

I’m a rabbit with an IP to bind,
Ports now listen where you designed.
IPv4 and IPv6 pass the test,
Custom host ports remain at rest.
Hop, hop—localhost is set! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: adding the WithHostIP option for host IP port binding.
Description check ✅ Passed The description accurately explains the WithHostIP option, validation, binding behavior, tests, and motivation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@host_ip_test.go`:
- Around line 50-54: Update the HostConfigModifier binding in the host IP
precedence test to use a different valid address, such as 0.0.0.0, while keeping
req.HostIP and its expected assertion set to 127.0.0.1. This ensures the test
verifies that req.HostIP overrides the modifier address.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 923ecec9-0182-478f-a375-7f8be5fb9d9c

📥 Commits

Reviewing files that changed from the base of the PR and between 16cdc31 and 4523ada.

📒 Files selected for processing (7)
  • container.go
  • docs/features/common_functional_options.md
  • docs/features/common_functional_options_list.md
  • host_ip_test.go
  • lifecycle.go
  • options.go
  • options_test.go

Comment thread host_ip_test.go
The precedence test used the same address (127.0.0.1) for both
req.HostIP and the HostConfigModifier binding, so it passed even if
the override logic was removed. Use 0.0.0.0 in the modifier binding
while keeping req.HostIP and the assertion at 127.0.0.1, making the
test fail when the override is absent.
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