Table of contents
Part of nurago, a collection of independent Go packages for backend services.
import "github.com/tecnickcom/nurago/pkg/ipify"
Asks ipify.org what address the outside world sees this process as having.
c, err := ipify.New()
ip, err := c.GetPublicIP(ctx)
Defaults: endpoint https://api.ipify.org, timeout 4 seconds.
Why a process cannot answer this itself
A service behind NAT, in a container, on a cloud instance, or behind a load balancer has local interface addresses that bear no relation to the address its outbound traffic appears to come from. Reading net.Interfaces() gives you 10.0.x.x or 172.17.x.x, which is not the answer to “what should I tell a partner to allowlist”.
The only way to learn the public address is to ask something outside the network. That makes this package a network call with all a network call’s failure modes, rather than a lookup.
It appears in service status endpoints, where operators want the egress address visible next to the other diagnostics, and in startup logs for allowlist-based integrations.
Construction validates, calls fall back
New rejects a URL that is missing, unparseable, or not http/https with a host. A non-positive timeout is clamped to the default, rather than meaning “no timeout” as a bare zero would to http.Client.
Catching a bad endpoint at construction means a misconfiguration surfaces at startup rather than the first time the status endpoint is hit.
At request time the behaviour is the opposite. When request creation, transport, status-code validation, or body reading fails, GetPublicIP returns the configured error IP alongside the error rather than an empty string. WithErrorIP sets that value.
Returning a usable sentinel and an error lets a status handler render something rather than nothing, while a caller that checks the error still sees the failure. Code that ignores the error gets a marker value it can recognise instead of an empty field.
Options
| Option | Effect |
|---|---|
WithURL | a different endpoint, validated |
WithTimeout | request timeout, non-positive clamped to 4s |
WithHTTPClient | inject a transport or a mock |
WithErrorIP | the value returned alongside an error |
WithURL matters more than it looks. ipify is a free third-party service with no availability commitment, and it is a dependency in your request path if you call it on demand. Several compatible endpoints exist, and WithURL points the client at one you control.
HealthCheck
Client.HealthCheck probes endpoint reachability, matching the method every other nurago client exposes so it can be registered with healthcheck alongside the rest.
Consider whether a third-party lookup belongs in a readiness probe: a service that is otherwise healthy will be marked unready when ipify has an outage.
Caching
The public address of a running instance changes rarely. GetPublicIP performs a request every call and does no caching of its own.
Resolve once at startup, or wrap the call in sfcache with a long TTL, which also collapses concurrent lookups into one request.
Example
c, err := ipify.New(ipify.WithTimeout(2 * time.Second))
if err != nil {
log.Fatal(err)
}
ip, err := c.GetPublicIP(context.Background())
fmt.Println(ip, err)
Full source is in example_ipify_test.go. More runnable examples are on pkg.go.dev.
Dependencies
This package reaches no external module: it uses only the Go standard library.
Links
- Reference documentation
- Source code
- Caching the result: sfcache
- Registering the probe: healthcheck
- All nurago packages