package acmecert import ( "context" "fmt" "io" "net/http" "strings" ) // wanIPServiceURL returns the caller's public IP as plain text. Overridden by tests. var wanIPServiceURL = "https://api.ipify.org" // DetectWANIP asks a public IP-echo service what address this host is reachable from, // for pre-filling the Let's Encrypt HTTP-01 "certificate for my IP" option. There's no // stdlib or local way to learn a WAN-facing IP from behind NAT/a cloud LB, so an // outbound HTTP call is the only option here. func DetectWANIP(ctx context.Context) (string, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, wanIPServiceURL, nil) if err != nil { return "", err } resp, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("detect WAN IP: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("detect WAN IP: unexpected status %s", resp.Status) } body, err := io.ReadAll(io.LimitReader(resp.Body, 256)) if err != nil { return "", fmt.Errorf("detect WAN IP: %w", err) } return strings.TrimSpace(string(body)), nil }