Ingress Not Reachable¶
1. Summary¶
Symptom¶
HTTP requests to your Container App's FQDN fail with timeout, 502 Bad Gateway, or 504 Gateway Timeout errors. DNS may resolve correctly, but the application is not serving traffic. Errors can be intermittent or sustained.
Why this scenario is confusing¶
Ingress failures have many possible causes spanning DNS, networking, revision health, and probe configuration. A working revision doesn't guarantee reachability—ingress mode, target port, and backend health all contribute to the final outcome.
Troubleshooting decision flow¶
graph TD
A[Symptom: Endpoint unreachable] --> B{DNS resolves to correct IP?}
B -->|No| H1[H1: DNS/Environment misconfiguration]
B -->|Yes| C{Ingress enabled and mode correct?}
C -->|No| H2[H2: Ingress mode mismatch]
C -->|Yes| D{Healthy replicas running?}
D -->|No| H3[H3: No healthy backend]
D -->|Yes| E{Target port matches app?}
E -->|No| H4[H4: Target port mismatch]
E -->|Yes| F{Network path clear?}
F -->|No| H5[H5: Firewall/NSG blocking]
F -->|Yes| G[Investigate app-level issues] 2. Common Misreadings¶
- "DNS is broken" — Many reachability issues are actually unhealthy replicas or wrong target port, not DNS.
- "Ingress external means always public" — NSGs, firewalls, and private environment routing still apply.
- "The revision is running, so ingress should work" — Revision running ≠ healthy replicas passing probes.
- "502 means platform issue" — Often indicates backend unhealthy or probe failures, not platform bugs.
- "It works from my machine" — Different network paths (VNet, internet, private endpoint) have different reachability.
3. Competing Hypotheses¶
| Hypothesis | Typical Evidence For | Typical Evidence Against |
|---|---|---|
| H1: DNS/Environment misconfiguration | NXDOMAIN, wrong IP resolved, environment domain mismatch | DNS resolves to correct environment IP |
| H2: Ingress mode mismatch | external=false but tested from internet, or vice versa | Internal caller succeeds from same VNet |
| H3: No healthy backend replicas | HealthState=Unhealthy, 0 running replicas, probe failures | Multiple healthy replicas serving requests |
| H4: Target port mismatch | 502 with app logs showing no incoming requests, app listening on different port | App and target port aligned, health probes pass |
| H5: Firewall/NSG blocking | Timeout from specific networks, works from others | Same behavior from all network locations |
4. What to Check First¶
Metrics¶
- Request count with 5xx spikes and low success ratio
- Replica count over time (should be > 0)
- Ingress latency percentiles (P50, P95, P99)
Logs¶
let AppName = "ca-myapp";
ContainerAppSystemLogs_CL
| where ContainerAppName_s == AppName
| where TimeGenerated > ago(1h)
| where Log_s has_any ("ingress", "502", "503", "504", "connection refused", "timeout", "upstream", "gateway")
| project TimeGenerated, RevisionName_s, Reason_s, Log_s
| order by TimeGenerated desc
Platform Signals¶
# Check ingress configuration
az containerapp show --name "$APP_NAME" --resource-group "$RG" \
--query "properties.configuration.ingress" --output json
# Check revision health and traffic weights
az containerapp revision list --name "$APP_NAME" --resource-group "$RG" \
--query "[].{name:name,active:properties.active,replicas:properties.replicas,health:properties.healthState,traffic:properties.trafficWeight}" \
--output table
# Check replica status
az containerapp replica list --name "$APP_NAME" --resource-group "$RG" --output table
| Command | Purpose |
|---|---|
az containerapp show --name "$APP_NAME" --resource-group "$RG" --query "properties.configuration.ingress" --output json | Reads the Container App resource and extracts the effective ingress configuration in structured form for operator review, which is the specific surface this troubleshooting step needs to confirm. |
az containerapp revision list --name "$APP_NAME" --resource-group "$RG" --query "[].{name:name,active:properties.active,replicas:properties.replicas,health:properties.healthState,traffic:properties.trafficWeight}" --output table | Lists revisions and filters them to the health, traffic, or timing fields needed for this hypothesis, so you can see whether rollout state matches the failure pattern. |
az containerapp replica list --name "$APP_NAME" --resource-group "$RG" --output table | Lists live replicas so you can confirm how many instances exist and whether the platform is creating, restarting, or recycling them. |
5. Evidence to Collect¶
Required Evidence¶
| Evidence | Command/Query | Purpose |
|---|---|---|
| Ingress config | az containerapp show ... --query ingress | Verify mode, port, transport |
| Revision list | az containerapp revision list | Check health state and traffic weights |
| Replica list | az containerapp replica list | Confirm running replicas exist |
| System logs | KQL on ContainerAppSystemLogs_CL | Find ingress/probe errors |
| DNS resolution | nslookup <fqdn> or dig <fqdn> | Verify DNS resolves correctly |
Useful Context¶
- Environment networking mode (VNet-integrated or consumption-only)
- Custom domain configuration (if applicable)
- Recent deployment or configuration changes
- Network path of the caller (internet, VNet, private endpoint)
6. Validation and Disproof by Hypothesis¶
H1: DNS/Environment misconfiguration¶
Signals that support:
nslookupreturns NXDOMAIN or unexpected IP- Environment default domain doesn't match expected pattern
- Custom domain verification incomplete
Signals that weaken:
- DNS resolves to correct environment IP
- Same FQDN works from other clients
What to verify:
# Check DNS resolution
nslookup $(az containerapp show --name "$APP_NAME" --resource-group "$RG" \
--query "properties.configuration.ingress.fqdn" --output tsv)
# Check environment domain
az containerapp env show --name "$ACA_ENV_NAME" --resource-group "$RG" \
--query "properties.defaultDomain" --output tsv
| Command | Why it is used |
|---|---|
az containerapp show --name ... | Reads the Container App configuration so the documented setting can be verified. |
H2: Ingress mode mismatch¶
Signals that support:
external: falsebut testing from public internet- Works from VNet but not from internet (or vice versa)
- 404 or timeout only from specific network locations
Signals that weaken:
- Ingress mode matches test scenario
- Same error from both internal and external callers
What to verify:
# Check ingress external setting
az containerapp show --name "$APP_NAME" --resource-group "$RG" \
--query "properties.configuration.ingress.external" --output tsv
# Expected: true for public access, false for VNet-only
| Command | Why it is used |
|---|---|
az containerapp show --name ... | Reads the Container App configuration so the documented setting can be verified. |
H3: No healthy backend replicas¶
Signals that support:
HealthState: UnhealthyorDegradedin revision list- Replica count is 0 or replicas show
Terminatedstatus - System logs show
ProbeFailed,ContainerTerminated,CrashLoopBackOff - 502/503 errors with backend probe failure messages
Signals that weaken:
- Multiple
Healthyreplicas inRunningstate - Successful responses intermixed with failures
What to verify:
# Check revision health
az containerapp revision list --name "$APP_NAME" --resource-group "$RG" \
--query "[?properties.active].{name:name,health:properties.healthState,replicas:properties.replicas}" \
--output table
# Check replica status
az containerapp replica list --name "$APP_NAME" --resource-group "$RG" --output table
| Command | Why it is used |
|---|---|
az containerapp revision list ... | Lists revisions so rollout state, traffic, and health can be verified. |
KQL for probe failures:
let AppName = "ca-myapp";
ContainerAppSystemLogs_CL
| where ContainerAppName_s == AppName
| where TimeGenerated > ago(1h)
| where Reason_s in ("ProbeFailed", "ContainerTerminated", "Unhealthy")
| summarize count() by Reason_s, RevisionName_s
| order by count_ desc
H4: Target port mismatch¶
Signals that support:
- 502 errors but no incoming requests in app console logs
- App configured to listen on port 3000 but
targetPort: 8000 - Probe failures with "connection refused"
Signals that weaken:
- App console logs show incoming requests
- Target port matches
EXPOSEin Dockerfile and app bind
What to verify:
# Check target port
az containerapp show --name "$APP_NAME" --resource-group "$RG" \
--query "properties.configuration.ingress.targetPort" --output tsv
# Check app's actual listening port (from container config or Dockerfile)
az containerapp show --name "$APP_NAME" --resource-group "$RG" \
--query "properties.template.containers[0].env[?name=='PORT' || name=='CONTAINER_APP_PORT']" \
--output table
| Command | Purpose |
|---|---|
az containerapp show --name "$APP_NAME" --resource-group "$RG" --query "properties.configuration.ingress.targetPort" --output tsv | Reads the Container App resource and extracts the ingress target port as plain text for reuse in later commands, which is the specific surface this troubleshooting step needs to confirm. |
az containerapp show --name "$APP_NAME" --resource-group "$RG" --query "properties.template.containers[0].env[?name=='PORT' || name=='CONTAINER_APP_PORT']" --output table | Reads the Container App resource and extracts the container environment-variable mapping, which is the specific surface this troubleshooting step needs to confirm. |
| Command | Why it is used |
|---|---|
az containerapp show --name ... | Reads the Container App configuration so the documented setting can be verified. |
H5: Firewall/NSG blocking¶
Signals that support:
- Timeout from specific source networks only
- Works from Azure Cloud Shell but not corporate network
- VNet has NSG rules blocking inbound 443/80
Signals that weaken:
- Same behavior from all network locations
- NSG logs show traffic allowed
What to verify:
# For VNet-integrated environments, check NSG rules
az network nsg rule list --resource-group "$RG" --nsg-name "$NSG_NAME" --output table
# Test from different network locations
curl --verbose --connect-timeout 10 "https://${APP_FQDN}/health"
| Command | Purpose |
|---|---|
az network nsg rule list --resource-group "$RG" --nsg-name "$NSG_NAME" --output table | Lists the NSG rules on the ingress path so you can confirm whether a network policy block explains why only certain caller networks time out. |
curl --verbose --connect-timeout 10 "https://${APP_FQDN}/health" | Tests the app endpoint from the current client path and shows connection, TLS, and HTTP details, which helps separate network blocking from application failures. |
7. Likely Root Cause Patterns¶
| Pattern | Frequency | First Signal | Typical Resolution |
|---|---|---|---|
| Probe failure cascade | Very common | System logs: ProbeFailed | Fix probe config or app startup |
| Target port mismatch | Common | 502 + no app traffic | Align targetPort with app |
| Ingress disabled | Common | 404 or connection refused | Enable ingress |
| Revision not activated | Occasional | 0 traffic weight | Set traffic weight > 0 |
| VNet routing issues | Occasional | Timeout from VNet only | Check UDR and private DNS |
8. Immediate Mitigations¶
- If no healthy replicas: Roll back to previous healthy revision
| Command | Why it is used |
|---|---|
az containerapp ingress traffic ... | Runs the Azure CLI operation required by the documented step. |
- If target port mismatch: Update ingress target port
| Command | Why it is used |
|---|---|
az containerapp ingress update ... | Updates ingress settings on an existing Container App. |
- If probe too aggressive: Relax probe settings temporarily
| Command | Why it is used |
|---|---|
az containerapp update --name ... | Updates the existing Container App configuration without recreating the app. |
- If ingress disabled: Enable ingress
| Command | Why it is used |
|---|---|
az containerapp ingress enable ... | Enables ingress for workloads that must receive inbound traffic. |
9. Prevention¶
- Include endpoint smoke tests in release pipeline
- Alert on sustained 5xx increase and zero healthy replicas
- Validate ingress config in IaC templates before deployment
- Use health check endpoints that verify actual app readiness
- Document expected ingress mode and FQDN in runbooks
See Also¶
- Container Start Failure
- Probe Failure and Slow Start
- Service-to-Service Connectivity Failure
- AppGW to Internal Azure Container Apps NSG Destination — use this playbook when Application Gateway fronts an internal environment and the container app subnet NSG has Destination =
staticIpor is missing31443/31080/AzureLoadBalancer - Application Gateway Integration with an Internal Container Apps Environment
- Ingress Error Analysis KQL
- Target Port Mismatch Detection KQL — directly resolves H4 ("Target port mismatch") in the decision flow above with the verbatim
Reason_s: TargetPortMismatchsystem log - HTTP Query Pack
- Ingress Target Port Mismatch Lab