Although, we aren’t gonna need it in this article but it’s always good to setup a virtual environment when working with Python. Check out my article on how to create a virtual environment for Python: /blog/python/how-to-create-a-python-virtual-environment/.
To create a simple Python HTTP Server, we are going to use two modules called
socketserver. They both are part of Python’s Standard Library, we don’t need to install them.
Important! This material is made for learning purposes. DO NOT use it in production.
http.server is not recommended for production. It only implements basic security checks.
Let’s create a file called
server.py and define our
Server class there.
The preceding code-block will create a running server, listening, by default, on a port chosen by your OS and serving the current working directory.
How it works
On lines 8,9 the
Server class initiates with two arguments -
server_address is a tuple taking two values. The first value is the host, which is
localhost. The second value is the port number, which by default is
0, this allows the operating system to choose itself on which port to serve. The
handler, by default, accepts
SimpleHTTPRequestHandler is part of the
http.server module and is responsible for handling the client requests.
You can see how the handler is used by a
TCPServer instance on line 14.
TCPServer itself is part of the
socketserver module and instantiates with 3 arguments:
bind_and_activate. We’ll skip the
bind_and_activate argument in this article. For the other two, you already understand what they do.
On line 15, we call
server_address from the newly created
TCPServer instance to print the server information on line 17. Here, the port number is set by the OS, already. We set
serving_at as the variable name here to escape confusion with the variable on line 10.
On line 18, we call the
serve_forever() method. It runs the server in a loop and never exits unless the program gets terminated.
Finally, on lines 21, 22 we instantiate the
Server class and call its
Creating a custom handler
You can create a custom handler to be used by the
TCPServer instead of
SimpleHTTPRequestHandler. For simplicity, let’s define our handler in the same server.py file.
Handler class inherits from
SimpleHTTPRequestHandler. We keep it empty for now. You’ll see soon how we can customize it. Since we’ve defined a custom handler, the
Server class instantiates with the handler attribute equal to our custom
Handler class on line 25.
Serving a custom directory
Now, what if we want to serve on a different directory. Let’s say we have a directory called
public containing a few HTML files and images. To serve that directory we must modify the
Handler class defined in the previous passage.
Here, we initiate our
Handler class by calling the
__init__ of the parent class and modifying the
directory argument of it. All other non-keyword and keyword arguments remain the same with
**kwargs called. It worths mentioning that in Python3.9 the
directory argument accepts a path-like object.
SimpleHTTPRequestHandler class allows us to manage the requests coming from a client via
do_HEAD() methods. Since our
Handler class inherits from
SimpleHTTPRequestHandler, we can define custom routes by overriding these methods. In this article, we do so only to
do_GET() method and define custom routes for
On lines 11-15, we say that if the root path (
/) is requested then the server should look for the
index.html file. And if the requested path is
/lyrics, then the server should look for the
return statement at the end:
Since we override the
do_GET() method, we must call the default one from the parent class at the end so the handler knows how to process the
We can do more with
do_GET() and even create automatic routing to look for the corresponding
HTML files for each path, etc. But that’s a topic for another article or for you to experiment and find it out yourself. 🙂
The code in this article is available in my repo here: github.com/oorkan/a-simple-python-http-server.
I hope you enjoyed it. Cheers! 🍻
ReferencesPython *args and **kwargs by Programiz