Writing a Custom HTTP Server from Scratch in Python
4 min readBy Isoftke Software Solutions

Creating an HTTP server from scratch in Python is a great way to understand how web servers handle client requests and responses. Instead of using Python's built-in http.server module, we will build a basic HTTP server using sockets that can process requests, serve static files, and respond to different HTTP methods.
Step 1: Setting Up the Server Socket
The first step is to create a socket that listens for incoming connections. The socket will bind to a specific IP address and port, allowing clients (such as web browsers) to connect and send requests.
Implementation:
import socket
# Server Configuration
HOST = '127.0.0.1' # Localhost
PORT = 8080 # Port to listen on
# Create a socket object
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the address and port
server_socket.bind((HOST, PORT))
# Listen for incoming connections
server_socket.listen(5)
print(f"Server is running on http://{HOST}:{PORT}")
# Accept and handle client connections
while True:
client_socket, client_address = server_socket.accept()
print(f"Connection from {client_address}")
request_data = client_socket.recv(1024).decode()
print("Request Data:\n", request_data)
# Close the client connection
client_socket.close()
Explanation:
- A TCP socket is created using
socket.AF_INET(IPv4) andsocket.SOCK_STREAM(TCP). - The socket binds to
127.0.0.1:8080and listens for connections. - When a client connects, it receives the HTTP request and prints it.

Run the script and open http://127.0.0.1:8080 in a browser. You will see the raw HTTP request printed in the terminal.


Step 2: Handling HTTP Requests
Now, we need to parse the HTTP request to extract the requested resource (e.g., /index.html) and respond accordingly.
Implementation:
import socket
# Server Configuration
HOST = '127.0.0.1'
PORT = 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
print(f"Server is running on http://{HOST}:{PORT}")
while True:
client_socket, client_address = server_socket.accept()
request_data = client_socket.recv(1024).decode()
request_lines = request_data.split("\n")
if request_lines:
request_line = request_lines[0] # Example: "GET /index.html HTTP/1.1"
print("Request:", request_line)
# Extract the requested file
request_path = request_line.split(" ")[1]
# Default file if no specific file is requested
if request_path == "/":
request_path = "/index.html"
try:
with open("www" + request_path, "r") as file:
response_body = file.read()
response_header = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"
except FileNotFoundError:
response_body = "<h1>404 Not Found</h1>"
response_header = "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n"
response = response_header + response_body
client_socket.sendall(response.encode())
client_socket.close()
Explanation:
- The server extracts the requested file path from the HTTP request.
- If the requested path is
/, it defaults to/index.html. - The server attempts to read the requested file from a
wwwdirectory. - If the file exists, it sends an
HTTP 200 OKresponse with the file content. - If the file is missing, it sends an
HTTP 404 Not Foundresponse.
Testing the Server:
- Create a folder named
wwwin the same directory as the script. - Inside
www, create a file namedindex.htmlwith some sample content:
<!DOCTYPE html>
<html>
<head><title>My Custom HTTP Server</title></head>
<body>
<h1>Welcome to My Custom HTTP Server!</h1>
</body>
</html>
- Start the server and open
http://127.0.0.1:8080in a browser. - Try visiting
http://127.0.0.1:8080/hello.html(which doesn’t exist) to trigger a 404 error.

Step 3: Handling Different HTTP Methods
A full-featured web server should handle different HTTP methods like GET and POST.
Enhancing the Server to Handle GET and POST Requests:
import socket
HOST = '127.0.0.1'
PORT = 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
print(f"Server running at http://{HOST}:{PORT}")
while True:
client_socket, client_address = server_socket.accept()
request_data = client_socket.recv(1024).decode()
request_lines = request_data.split("\n")
if request_lines:
request_line = request_lines[0]
method, path, _ = request_line.split(" ")
if method == "GET":
if path == "/":
path = "/index.html"
try:
with open("www" + path, "r") as file:
response_body = file.read()
response_header = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"
except FileNotFoundError:
response_body = "<h1>404 Not Found</h1>"
response_header = "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n"
elif method == "POST":
response_body = "<h1>POST Request Received</h1>"
response_header = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"
else:
response_body = "<h1>405 Method Not Allowed</h1>"
response_header = "HTTP/1.1 405 Method Not Allowed\nContent-Type: text/html\n\n"
response = response_header + response_body
client_socket.sendall(response.encode())
client_socket.close()
Explanation:
- The server checks the HTTP method.
- If it’s
GET, it serves static files. - If it’s
POST, it sends a simple response acknowledging the request. - If the method is unsupported, it returns a
405 Method Not Allowedresponse.
Testing the POST Request:
Use curl or a tool like Postman to send a POST request:
curl -X POST http://127.0.0.1:8080
This will return POST Request Received.

Step 4: Improving the Server with Multi-threading
A single-threaded server processes one request at a time, making it slow under heavy traffic. Using multi-threading, the server can handle multiple clients simultaneously.
Adding Multi-threading:
import socket
import threading
HOST = '127.0.0.1'
PORT = 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
print(f"Server running at http://{HOST}:{PORT}")
def handle_client(client_socket):
request_data = client_socket.recv(1024).decode()
request_lines = request_data.split("\n")
if request_lines:
request_line = request_lines[0]
method, path, _ = request_line.split(" ")
response_body = f"<h1>Request Received: {method} {path}</h1>"
response_header = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"
response = response_header + response_body
client_socket.sendall(response.encode())
client_socket.close()
while True:
client_socket, client_address = server_socket.accept()
thread = threading.Thread(target=handle_client, args=(client_socket,))
thread.start()
This allows the server to process multiple requests in parallel, improving performance.
Conclusion
We built a simple HTTP server from scratch using sockets in Python. It can:
- Handle GET and POST requests.
- Serve static HTML files.
- Process multiple clients simultaneously with threading.
Keep reading
What is Domain-Driven Development?
Software development thrives on approaches that bridge the gap between complex business requirements and technical implementation. Domain-Driven Design (DDD) is one such…
10 Mistakes Developers Make When Building an API (and How to Avoid Them)
APIs (Application Programming Interfaces) are the backbone of modern web development, enabling communication between different software systems. Whether you’re building a RESTful…
How to Build an API using Node.js and Express
Building an API is a fundamental aspect of modern web development, allowing different applications to communicate with each other. In this blog, we'll explore how to build a…
Need A Consultation?
We are here to answer your questions 24/7

