How to Create a Python Web Server

Python remains one of the best programming languages to learn for 2026. From back-end web development and machine learning to scientific modeling and system operations, its versatility is unmatched. It is generally considered one of the most approachable languages due to its English-like syntax and vast library ecosystem.

That accessibility extends to creating a Python web server. Unlike other languages that may require complex environment setups (like Apache or Nginx) just to view a static file, Python allows you to launch a local server in seconds.

In this guide, we will cover:

  • The Basics: Understanding the HTTP Protocol.
  • Quick Start: Launching a server in one line of code.
  • Advanced CLI: Binding addresses and changing directories.
  • Custom Scripts: Writing your own request handlers.
  • Troubleshooting: Common errors and behaviors.

Understanding the HTTP Protocol

Before launching a server, it helps to understand what the server is actually speaking. HTTP (HyperText Transfer Protocol) is the foundation of data communication on the web.

When you create a Python web server, you are creating a program that listens for Requests and sends back Responses.

Key Concepts

  • Verbs (Methods): The action the client wants to perform.
    • GET: Retrieve data (e.g., viewing a page).
    • POST: Submit data (e.g., filling out a form).
    • HEAD: Similar to GET, but asks only for headers (no body data).
  • Status Codes: The server's way of saying "Success" or "Failure".
    • 200 OK: The request succeeded.
    • 404 Not Found: The file requested doesn't exist.
    • 500 Internal Server Error: The server crashed while trying to process the request.

The Quick Method: Python's Built-in HTTP Server

If you just need to view an HTML file in web browsers, you do not need to write a script. You can run Python's built-in http.server module directly from your terminal.

Prerequisites

Ensure Python 3 is installed on your system. You can verify this by opening your terminal (or command prompt) and typing:

python --version

Basic Command

Navigate to the folder containing your web files and run the following command:

python -m http.server

You should see a message confirming the server has started:

Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Command Line Arguments & Behavior

The http.server module is more powerful than it looks. You can control its behavior using specific command-line arguments (flags).

1. Changing the Port

By default, Python listens on port 8000. If this port is busy, specify a different one at the end of the command:

python -m http.server 8080

2. Serving a Specific Directory

By default, the server serves files from the current directory you are in. If you want to run the server from one folder but serve files from another, use the --directory or -d flag:

python -m http.server --directory /tmp/

3. Binding to a Specific Address

By default, the server binds to all interfaces (0.0.0.0), meaning it is accessible to other computers on your network. To restrict it to only your computer (for security), use the --bind or -b flag:

python -m http.server --bind 127.0.0.1

Default Server Behavior

When you visit the local URL, the server follows a specific logic:

  1. Index File Check: It looks for a file named index.html (or index.htm). If found, it renders that page.
  2. Directory Listing: If no index file is found, it generates a "Directory Listing," showing all files and folders in that directory as clickable links.

Under the Hood: Handlers

When you run the command above, Python is using a "Handler" class to manage the work. Understanding handlers is key if you move to advanced Python web development.

The http.server module provides two main request handlers:

1. SimpleHTTPRequestHandler

This is the default. It maps the request structure to your local file system. It handles the headers, parses the request, and returns the file contents. It is perfect for serving static content.

2. CGIHTTPRequestHandler

This is an older standard used to run scripts (like Python or PHP files) on the server rather than just serving text. While less common in modern web development (replaced by WSGI frameworks like Django), it allows the server to execute code and return the output of that code.


Creating a Custom Web Server Script

To go beyond static files, you can extend the BaseHTTPRequestHandler class. This allows you to define exactly what happens when a user visits your page.

The Python Script

from http.server import HTTPServer, BaseHTTPRequestHandler
import time

# Configuration
HOST_NAME = "localhost"
SERVER_PORT = 8080

class MyServer(BaseHTTPRequestHandler):
    """
    A custom handler to process HTTP requests.
    Inherits from BaseHTTPRequestHandler to override standard methods.
    """
    def do_GET(self):
        # 1. Send the HTTP Status Code (200 = OK)
        self.send_response(200)
        
        # 2. Define the Content Type (HTML)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        
        # 3. Write the HTML content to the page
        # Note: Content must be encoded to bytes using "utf-8"
        self.wfile.write(bytes("<html><head><title>Python Server</title></head>", "utf-8"))
        self.wfile.write(bytes("<body>", "utf-8"))
        self.wfile.write(bytes("<h1>Request Received!</h1>", "utf-8"))
        self.wfile.write(bytes(f"<p>You accessed path: {self.path}</p>", "utf-8"))
        self.wfile.write(bytes("</body></html>", "utf-8"))

if __name__ == "__main__":        
    web_server = HTTPServer((HOST_NAME, SERVER_PORT), MyServer)
    print(f"Server started http://{HOST_NAME}:{SERVER_PORT}")

    try:
        # Keep the server running until user stops it (Ctrl+C)
        web_server.serve_forever()
    except KeyboardInterrupt:
        pass

    web_server.server_close()
    print("Server stopped.")

Python's "Batteries Included" Philosophy

You might wonder why Python includes a web server in its standard library when specialized tools like Nginx or Apache exist. This stems from Python's "Batteries Included" philosophy.

This means that Python comes pre-packaged with useful tools and modules so you can be productive immediately, without downloading separate packages. The http.server module is one of these "batteries." It allows any Python user to share files instantly, even in an offline environment.


Static vs. Dynamic Content

So far, we have built a Static Web Server. It simply retrieves a file from your hard drive and sends it to the browser. The content never changes unless you manually edit the file.

Modern websites, however, run on Dynamic Content. This means the HTML is generated on the fly based on data.

  • Static: "Here is about.html."
  • Dynamic: "User logged in as 'Alice'. Query the database for Alice's photos. Generate a custom HTML page showing only her photos."

To handle dynamic content efficiently, writing raw Python code using BaseHTTPRequestHandler becomes messy and difficult. This is where Web Frameworks come in.


The Next Step: Using Flask

If you want to build a real web application, you should move away from the built-in server and use a framework. The most popular "micro-framework" for beginners is Flask.

Compare the complexity of the custom script we wrote earlier to this Flask equivalent:

Flask Example

First, you would install it (pip install flask). Then, the code is much simpler:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "<h1>Hello! This is dynamic.</h1>"

@app.route("/user/<name>")
def user_profile(name):
    # This generates a different page depending on the URL!
    return f"<h1>Welcome back, {name}!</h1>"

if __name__ == "__main__":
    app.run(port=8080)

Notice how Flask handles the routing logic (@app.route) and dynamic variables (<name>) automatically. This is why professional Python developers use frameworks like Flask or Django rather than the standard http.server.


Securing Your Local Server (HTTPS)

By default, the Python web server runs on HTTP, which is unencrypted. If you are developing features that require secure contexts (like accessing a webcam or microphone in the browser), you need HTTPS.

To do this locally, you can use a Self-Signed Certificate. This involves two steps:

1. Generate the Certificate

Run this command in your terminal (requires OpenSSL, which is standard on Linux/Mac and available for Windows):

openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes

2. Python Script with SSL

You must wrap the server socket with Python's ssl module. Here is the modified script:

from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl

# Configuration
HOST_NAME = "localhost"
SERVER_PORT = 4443

httpd = HTTPServer((HOST_NAME, SERVER_PORT), SimpleHTTPRequestHandler)

# Wrap the socket with SSL
httpd.socket = ssl.wrap_socket(httpd.socket, 
                               certfile='./server.pem', 
                               server_side=True)

print(f"Secure server started https://{HOST_NAME}:{SERVER_PORT}")
httpd.serve_forever()

Note: When you visit this site, your browser will warn you that the certificate is not trusted. This is normal for self-signed certificates; you can proceed safely.


Moving to Production: Full-Fledged Web Servers

We cannot stress this enough: Do not use `http.server` in production. It is single-threaded and insecure.

In a professional environment, the architecture changes. You typically use a WSGI Server (to run Python) behind a Reverse Proxy (to handle traffic).

The Stack

  • The Web Server (Nginx/Apache): Handles incoming traffic, SSL encryption, and static files (images/CSS). It is very fast.
  • The Application Server (Gunicorn/uWSGI): Translates requests from Nginx into something Python can understand. It creates multiple "workers" to handle many users at once.
  • The Application (Flask/Django): Your actual Python code.

Professional Workflow: GitHub & Environment Variables

As your project grows, you need to manage your code and configuration professionally.

1. Handling Secrets with Environment Variables

Never hard-code sensitive information (like API keys or specific ports) directly into your script. Use Environment Variables instead.

import os

# Get the PORT from the environment, default to 8080 if not found
# This is crucial for cloud hosting (like AWS or Heroku)
SERVER_PORT = int(os.environ.get("PORT", 8080))

2. Version Control with GitHub

When uploading your code to GitHub, you want to keep your repository clean. Create a file named .gitignore in your folder and add the following lines:

# .gitignore
__pycache__/
*.pem
.env

This ensures you don't accidentally upload your compiled Python files, your security certificates, or your configuration secrets to the public web.


Summary: Best Practices

To wrap up, here is a checklist for running Python web servers effectively:

  • Use the Right Tool: Use http.server for quick local testing. Use Flask/Django for building apps. Use Gunicorn/Nginx for deploying to the public.
  • Security First: Never expose the built-in server to the public internet using port forwarding. It is easy to crash and easy to hack.
  • Clean Code: Use a requirements.txt file to list your dependencies (e.g., flask==2.0.1) so other developers can install them easily.
  • Structure: Keep your HTML files in a folder named templates and your static files (CSS/JS) in a folder named static. This is the standard convention for Python web frameworks.

Frequently Asked Questions (FAQ)

How do I stop the Python web server?

Return to your terminal or command prompt window and press Ctrl + C. This sends a keyboard interrupt signal that terminates the process.

Is Python http.server secure?

No. It is designed for local development only. It has not been audited for security vulnerabilities and should never be used in a production environment (public internet). For production, look into Gunicorn or uWSGI.

What does "Address already in use" mean?

This means another program (or a previous instance of your server) is already using that port. Change the port number (e.g., 8081) or kill the process occupying the port.


Resources & References

For further reading and official documentation, check out these resources:


People are also reading:

By Ramya Shankar

A cheerful, full of life and vibrant person, I hold a lot of dreams that I want to fulfill on my own. My passion for writing started with small diary entries and travel blogs, after which I have moved on to writing well-researched technical content. I find it fascinating to blend thoughts and research and shape them into something beautiful through my writing.

View all post by the author

Subscribe to our Newsletter for Articles, News, & Jobs.

I accept the Terms and Conditions.

Disclosure: Hackr.io is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission.

In this article

Featured Resources

Learn More

Please login to leave comments