Save this as app.py:
from flask import Flask, request, jsonify import logging app = Flask(__name__) # Configure logging to print to stdout (visible in docker logs) logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) @app.route('/') def index(): """Main route that logs headers and returns HTML.""" x_forwarded_for = request.headers.get('X-Forwarded-For', 'Not set') x_real_ip = request.headers.get('X-Real-IP', 'Not set') # Log to console logger.info(f"--- Request to / ---") logger.info(f"X-Forwarded-For: {x_forwarded_for}") logger.info(f"X-Real-IP: {x_real_ip}") return f""" <html> <head><title>Header Test</title></head> <body> <h1>Headers Received</h1> <p><strong>X-Forwarded-For:</strong> {x_forwarded_for}</p> <p><strong>X-Real-IP:</strong> {x_real_ip}</p> <p><a href="/testheaders">/testheaders</a> - JSON output</p> <p><a href="/allheaders">/allheaders</a> - All headers</p> <p><em>Check docker logs for detailed output.</em></p> </body> </html> """ @app.route('/testheaders') def testheaders(): """ Dedicated route for testing header propagation. Returns all headers as JSON for easy programmatic verification. """ # Capture all headers all_headers = dict(request.headers) # Specifically extract the ones we care about x_forwarded_for = request.headers.get('X-Forwarded-For', 'MISSING') x_real_ip = request.headers.get('X-Real-IP', 'MISSING') # Log the specific values logger.info(f"--- Request to /testheaders ---") logger.info(f"X-Forwarded-For: {x_forwarded_for}") logger.info(f"X-Real-IP: {x_real_ip}") # Return JSON response return jsonify({ "status": "success", "headers_received": { "X-Forwarded-For": x_forwarded_for, "X-Real-IP": x_real_ip, "Host": request.headers.get('Host'), "User-Agent": request.headers.get('User-Agent') }, "all_headers": all_headers }), 200 @app.route('/allheaders') def allheaders(): """ Route that displays ALL headers received. Useful for debugging what Nginx is actually forwarding. """ # Get all headers as a dictionary all_headers = dict(request.headers) # Log each header for debugging logger.info("--- Request to /allheaders ---") for key, value in all_headers.items(): logger.info(f"{key}: {value}") # Create HTML table for readability header_rows = ''.join([ f'<tr><td><strong>{key}</strong></td><td>{value}</td></tr>' for key, value in sorted(all_headers.items()) ]) return f""" <!DOCTYPE html> <html> <head> <title>All Headers</title> <style> body {{ font-family: monospace; margin: 20px; }} table {{ border-collapse: collapse; width: 100%; }} th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }} th {{ background-color: #4CAF50; color: white; }} tr:nth-child(even) {{ background-color: #f2f2f2; }} </style> </head> <body> <h1>All Headers Received</h1> <p><strong>Total Headers:</strong> {len(all_headers)}</p> <table> <tr><th>Header Name</th><th>Value</th></tr> {header_rows} </table> <p><a href="/">← Back to Home</a></p> <p><em>Check docker logs for timestamped output.</em></p> </body> </html> """ if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
Add Dockerfile:
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt ENV TZ=Europe/Malta COPY app.py . EXPOSE 8080 CMD ["python", "app.py"]
Build the image and run:
docker build -t header-test-app . docker run -d --name app-container -p 8080:8080 --network <your_network> header-test-app
Change ports and network if necessary.