NGINX Traffic Capture

This guide shows you how to use Qtap to capture HTTP traffic flowing through NGINX, one of the most popular web servers and reverse proxies. You'll learn how to observe both incoming client requests and outgoing upstream connections, all without proxies or code changes.

What You'll Learn

  • Capture NGINX ingress traffic (client requests coming in)

  • Capture NGINX egress traffic (upstream service requests going out)

  • Monitor both sides of a reverse proxy simultaneously

  • Apply conditional capture rules for specific endpoints

  • Set up NGINX + Qtap in Docker for testing

  • Deploy production-ready configurations with S3 storage

Use Cases

Why capture NGINX traffic?

  • Reverse Proxy Visibility: See both client requests and upstream responses in one place

  • Performance Analysis: Measure latency between client→nginx and nginx→upstream

  • API Gateway Monitoring: Track all API calls flowing through your gateway

  • Security Auditing: Detect malicious requests or data exfiltration attempts

  • Troubleshooting: Debug issues with request/response transformations

  • Compliance: Audit all traffic for regulatory requirements

  • Load Balancer Analytics: Understand traffic distribution patterns


Prerequisites

  • Linux system with kernel 5.10+ and eBPF support

  • Docker installed (for this guide's examples)

  • Root/sudo access

  • Basic understanding of NGINX configuration


Part 1: Simple NGINX Web Server

Let's start with a basic NGINX setup serving static content and reverse proxying to an upstream service.

Step 1: Create NGINX Configuration

Create a directory for our demo:

Create nginx.conf:

Step 2: Create Qtap Configuration

Create qtap.yaml:

Key Configuration Points:

  • direction: all - Captures both incoming (client→nginx) AND outgoing (nginx→upstream) traffic

  • ignore_loopback: false - Important! NGINX often communicates via localhost

  • level: full - Captures complete requests/responses including bodies

Step 3: Create Docker Compose Setup

Create docker-compose.yaml:


Part 2: Running and Testing

Step 1: Start the Services

Step 2: Generate Test Traffic

Step 3: View Captured Traffic

What you should see:

Key indicators that it's working:

  • "exe": "/usr/sbin/nginx" - NGINX process identified

  • Direction: INGRESS - Client to NGINX

  • Direction: EGRESS - NGINX to upstream

  • Two transactions for proxied requests (one ingress, one egress)

  • ✅ Custom headers visible (X-Custom-Header, X-Real-IP)

  • ✅ Full request/response bodies captured

  • ✅ Latency tracked for both hops


Part 3: Advanced Configurations

Configuration 1: Capture Only Errors

Reduce volume by capturing only failed requests (4xx/5xx status codes):

Test it:

Configuration 2: Separate Ingress and Egress Stacks

Apply different capture levels to ingress vs. egress traffic:

Configuration 3: Filter by API Endpoint

Capture only specific API paths using Rulekit:

Configuration 4: Production Setup with S3

For production, store sensitive data in your own S3 bucket:

Update docker-compose.yaml to pass S3 credentials:

See Storage Configuration for complete S3 setup.


Part 4: Real-World Use Cases

Use Case 1: API Gateway Monitoring

Monitor all API traffic flowing through NGINX as an API gateway:

Use Case 2: Debugging Reverse Proxy Issues

Capture both sides of a reverse proxy to debug transformation issues:

This configuration lets you compare:

  • What the client sent to NGINX (ingress)

  • What NGINX forwarded to the upstream (egress)

  • What the upstream returned (egress response)

  • What NGINX sent back to the client (ingress response)

Use Case 3: Load Balancer Analytics

Track traffic distribution across multiple upstreams:

nginx.conf (simplified):

qtap.yaml:

Analyze the logs to see which backend server received each request.


Understanding the Output

Dual Capture for Reverse Proxy

When NGINX proxies a request, Qtap captures two separate HTTP transactions:

Transaction 1: INGRESS (Client → NGINX)

Transaction 2: EGRESS (NGINX → Upstream)

This dual capture lets you:

  • Measure end-to-end latency vs. upstream latency

  • See how NGINX transforms requests (headers, paths, bodies)

  • Debug issues on either side of the proxy

Capture Levels Explained

  • none: No capture (use with rules for conditional capture)

  • summary: Basic metadata (method, URL, status, duration) - no headers/bodies

  • details: Includes headers - no bodies

  • full: Everything (headers + bodies)

For high-traffic NGINX servers, start with summary or details to control volume.


Troubleshooting

Not Seeing NGINX Traffic?

Check 1: Is Qtap running before you made requests?

Check 2: Is ignore_loopback set correctly?

Check 3: Is NGINX actually processing requests?

Check 4: Verify Qtap is hooking NGINX

Seeing "l7Protocol": "other"?

This means Qtap captured the connection but couldn't parse HTTP:

  • NGINX might be using HTTPS internally (check TLS configuration)

  • Traffic might not be HTTP

  • Qtap may not have fully initialized (wait 6+ seconds after starting)

Too Much Traffic Captured?

Option 1: Use conditional rules

Option 2: Filter specific paths

Option 3: Capture summary only

Duplicate Transactions?

If you see the same request captured multiple times, this is expected for reverse proxies:

  • One INGRESS capture (client → nginx)

  • One EGRESS capture (nginx → upstream)

To capture only one direction:


Performance Considerations

NGINX + Qtap Performance Impact

Qtap operates out-of-band using eBPF, with minimal impact:

  • CPU overhead: ~1-3% for typical HTTP traffic

  • Memory: ~50-200MB depending on traffic volume

  • Latency: No additional latency (passive observation)

Best practices for high-traffic NGINX:

  1. Use level: summary or details (avoid full with large bodies)

  2. Apply conditional rules to reduce captured volume

  3. Filter out health checks and monitoring endpoints

  4. Send data to S3 in batches (use Fluent Bit for buffering)

  5. Set TTL policies on storage (90 days recommended)

Scaling Recommendations

Traffic Volume

Recommended Level

Storage

< 100 req/sec

full

stdout or S3

100-1000 req/sec

details

S3 with batching

1000-10000 req/sec

summary

S3 + Fluent Bit

> 10000 req/sec

conditional rules

S3 + Fluent Bit + aggressive filtering


Next Steps

Learn More About Qtap:

Production Deployment:

Related Guides:

Alternative: Cloud Management:


Cleanup


This guide uses validated configurations. All examples are tested and guaranteed to work with NGINX and Qtap.

Last updated