NodePort not reachable externally — cloud firewall or security group blocking
NodePort service works internally but not from outside the cluster
Focused incident mode — strips away everything but this runbook.
Symptoms
- NodePort service works internally but not from outside the cluster
- curl from external machine times out on the node IP + NodePort
- Internal pod-to-NodePort works but public IP:port does not respond
NodePort requires the cloud provider's firewall to allow traffic in the 30000-32767 range. This is the most common reason NodePort works internally but not externally.
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
NodePort assignment
kubectl get svc <svc> -n <namespace> -o jsonpath='{.spec.ports[*].nodePort}'Node external IP
kubectl get nodes -o wide | awk '{print $1, $6}'
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- curl from the node works but from external machine times out
- Security group has no ingress rule for 30000-32767
Confirm before fixing
aws ec2 describe-security-groups --group-ids <sg-id> --query 'SecurityGroups[*].IpPermissions'Check security group rules
Fix
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 30000-32767 --cidr 0.0.0.0/0Open the NodePort range in the security group
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
kubectl get svc <svc> -n <namespace> -o wideConfirm NodePort and endpoints
ssh <node> curl -s http://localhost:<nodeport>/healthzTest from the node itself
aws ec2 describe-security-groups --group-ids <sg-id> --query 'SecurityGroups[*].IpPermissions'Check security group rules
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 30000-32767 --cidr 0.0.0.0/0Open the NodePort range
Prevention
- Document required security group rules for NodePort in the cluster runbook.
- Use LoadBalancer or Ingress instead of NodePort for production external access.
- Test NodePort reachability after any security group or NACL change.
- Restrict NodePort CIDR to known IP ranges instead of 0.0.0.0/0.
Related runbooks
Same stack, same failure family — worth a skim.
kubectl get svc shows <pending> for EXTERNAL-IP
curl to ClusterIP from a pod returns connection refused or timeout
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.