When developing IoT firmware, testing REST API client libraries, or validating webhooks in a local staging environment, backend engineers often need a lightweight HTTP server capable of receiving POST payloads and returning immediate, custom HTTP responses without deploying full web frameworks like Express or Flask.

Netcat (nc) paired with Unix Named Pipes (FIFOs) provides an elegant solution. It allows you to simulate a full HTTP/1.1 server on any specified port number, inspect incoming POST headers and body payloads, and respond with customized status codes, JSON objects, or XML data. In this article, we demonstrate how to set up a bi-directional Netcat HTTP server and send test requests using curl and Python.

Client/Server Setup Quick Cheatsheet

Run the Netcat server on port 9090 and transmit an HTTP POST request from a client terminal:

Terminal 1: Netcat Server (Port 9090)bash
# 1. Create a temporary named pipe (FIFO)
rm -f /tmp/netcat_pipe && mkfifo /tmp/netcat_pipe
 
# 2. Start Netcat HTTP server returning an HTTP 200 JSON payload
while true; do
  { printf "HTTP/1.1 200 OK

Content-Type: application/json
Connection: close

{"status":"SUCCESS","code":200}
"; } | nc -l 9090 > /tmp/netcat_pipe
  cat /tmp/netcat_pipe
done
Terminal 2: Client Request (curl)bash
# Send an HTTP POST request containing JSON data to port 9090
curl -i -X POST http://localhost:9090/v1/telemetry \
     -H "Content-Type: application/json" \
     -d '{"device_id": "sensor-09", "temperature": 24.8}'
 
# Expected Response Received by Client:
# HTTP/1.1 200 OK
# Content-Type: application/json
# Connection: close
#
# {"status":"SUCCESS","code":200}

Step-by-Step Implementation: Bi-Directional HTTP Server

1. Why Named Pipes (FIFOs) Are Required

A standard Netcat command (nc -l 9090) opens a one-way socket. To receive client request data on stdout while simultaneously piping back an HTTP response on stdin, Unix named pipes (mkfifo) connect the input and output streams of Netcat asynchronously without blocking.

2. Writing a Robust Netcat HTTP Server Script

Create a standalone executable bash script (http_server_netcat.sh) that logs incoming requests and returns custom headers:

http_server_netcat.shbash
#!/usr/bin/env bash
# Production-ready Netcat Mock HTTP Server
 
PORT=9090
PIPE="/tmp/http_fifo"
 
# Cleanup existing pipe on exit
trap 'rm -f "${PIPE}"' EXIT
rm -f "${PIPE}"
mkfifo "${PIPE}"
 
echo "=================================================="
echo " Netcat Mock HTTP Server active on port ${PORT}"
echo "=================================================="
 
while true; do
  # Write custom HTTP 200 OK response header and JSON body to FIFO pipe
  cat << 'EOF' > "${PIPE}" &
HTTP/1.1 200 OK
Server: Netcat-Mock-Server/1.0
Content-Type: application/json
Access-Control-Allow-Origin: *
Connection: close
 
{
  "message": "HTTP POST payload processed successfully",
  "timestamp": "$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
}
EOF
 
  echo -e "
[$(date '+%Y-%m-%d %H:%M:%S')] Incoming Request:"
  nc -l "${PORT}" < "${PIPE}"
done

Client Testing: Python and Shell POST Workflows

Testing with Python requests

Verify your Netcat mock server against a Python HTTP client script:

post_client.pypython
import requests
import json
 
url = "http://localhost:9090/api/event"
payload = {
    "app": "Lynxbee-Client",
    "status": "active",
    "metrics": {"cpu": 12.5, "mem_mb": 512}
}
 
headers = {"Content-Type": "application/json"}
 
try:
    print(f"Sending POST request to {url}...")
    response = requests.post(url, data=json.dumps(payload), headers=headers, timeout=5)
    
    print("
--- Server Response ---")
    print(f"Status Code: {response.status_code}")
    print(f"Headers: {dict(response.headers)}")
    print(f"Body: {response.text}")
 
except Exception as e:
    print(f"Request failed: {e}")

Troubleshooting & Advanced Netcat Flags

  • `Address already in use` (`EADDRINUSE`): Occurs if another service is using port 9090. Find and terminate the process using sudo lsof -i :9090 or fuser -k 9090/tcp.

  • OpenBSD vs Nmap `ncat` Variant: On Fedora/RedHat or systems with Nmap installed, ncat supports multi-client handling natively: ncat -l 9090 --keep-open --exec "/bin/cat response.http".

  • Port Binding Permissions: Remember that binding to ports below 1024 (e.g. port 80 or 443) requires sudo privileges on Linux.