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
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
Linux system with kernel 5.10+ and eBPF support
Docker installed (for this guide's examples)
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:
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:
Use level: summary or details (avoid full with large bodies)
Apply conditional rules to reduce captured volume
Filter out health checks and monitoring endpoints
Send data to S3 in batches (use Fluent Bit for buffering)
Set TTL policies on storage (90 days recommended)
Scaling Recommendations
S3 + Fluent Bit + aggressive filtering
Learn More About Qtap:
Production Deployment:
Related Guides:
Alternative: Cloud Management:
Qplane - Manage Qtap with visual dashboards
This guide uses validated configurations. All examples are tested and guaranteed to work with NGINX and Qtap.