OCI NLB Reserved IP Incident: May 24, 2026
This page is a troubleshooting retrospective for the second reserved-IP ingress failure on Lumie's OCI app NLB. Unlike the earlier May 5 outage, this investigation ended with a checked-in root cause and a repo-managed fix that now applies to both public NLBs.
Source paths
todo/incidents/trouble/oci-nlb-reserved-ip-incident-2026-05-24.mdlumie-infra/provision/terraform/nlb_0214.tflumie-infra/provision/terraform/nlb_teleport_0213.tflumie-infra/provision/terraform/outputs.tf
Verified failure signature
The decisive test kept the same NLB shape and healthy backends, but swapped only the public IP type:
| Public IP on the NLB | Backend health | External TCP/443 | Outcome |
|---|---|---|---|
| Ephemeral public IP | healthy | succeeded | Real backend response reached Traefik |
| Reserved public IP | healthy | timed out | No ingress reached the NLB edge |
That ruled out the shared pieces of the path, including the backend pool, private subnet routing, and the cross-tenancy worker reachability used by nlb_0214.tf.
Root cause now encoded in Terraform
The current repo records the fix directly on the reserved public IP resource:
resource "oci_core_public_ip" "nlb_public_ip_0214" {
lifetime = "RESERVED"
lifecycle {
ignore_changes = [private_ip_id]
}
}
Source: lumie-infra/provision/terraform/nlb_0214.tf
The file comment is explicit about the contract: OCI assigns the reserved public IP to the NLB's floating private IP, and later Terraform runs must not reset private_ip_id to null. If that association is stripped, the NLB can keep reporting healthy backends while the public edge times out on TCP/443.
The same safeguard is duplicated for the Teleport NLB in lumie-infra/provision/terraform/nlb_teleport_0213.tf, which is the clearest sign that this was not a one-off patch on the app ingress path.
Why the backends still looked healthy
The backend set in nlb_0214.tf uses TCP health checks against port 443 on worker private IPs. Those checks validate the private NLB-to-worker path:
- they do not prove that the reserved public IP is still attached to the NLB's floating private IP
- they do not prove that Cloudflare-to-origin ingress can reach the edge
That is why this incident produced the confusing but repeatable state of "green backends, dead public ingress."
Recovery pattern that survived into the docs
- Restore service on a known-good path first, such as an ephemeral NLB IP or a temporary Cloudflare bypass, before attempting more NLB recreates.
- If an NLB recreate partially succeeds and Terraform reports an object already exists, prefer importing the existing OCI object into state over deleting it from the control plane.
Representative shape:
terraform import oci_network_load_balancer_backend_set.nlb_backend_set_0214 <nlb_ocid>/<backend_set_name>
The original incident note used that recovery to reconcile a partially created backend set without throwing away working server-side resources.
Verification
cd lumie-infra/provision/terraform
rg -n "ignore_changes = \\[private_ip_id\\]" nlb_0214.tf nlb_teleport_0213.tf
terraform output nlb_public_ip
terraform output nlb_teleport_public_ip
terraform output nlb_backend_targets
terraform plan
Success means both reserved-IP NLB resources still protect private_ip_id, the applied state exposes the expected public addresses, and terraform plan does not try to undo the OCI-managed IP association.
Related pages
- OCI NLB Reserved IP Incident: May 5, 2026
- Terraform infrastructure reference