How to run a http server which serves a specific path?
Asked Answered
I

8

128

this is my Python3 project hiearchy:

projet
  \
  script.py
  web
    \
    index.html

From script.py, I would like to run a http server which serve the content of the web folder.

Here is suggested this code to run a simple http server:

import http.server
import socketserver

PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()

but this actually serve project, not web. How can I specify the path of the folder I want to serve?

Initial answered 1/10, 2016 at 0:13 Comment(3)
Have you considered running python3 -m http.server -d /path/to/web/dir on command line to do the job? Props to @kyle-barron who gave this perfect solution in a comment deep below.Unreason
I suggest this is the best answer: https://mcmap.net/q/81086/-how-to-run-a-http-server-which-serves-a-specific-pathGuacin
@AkseliPalén I get server.py: error: argument port: invalid int value: '/media/EHD/web_root' error when I run that in Ubuntu 18.04 Terminal (with python3.6.9)Maurits
I
109

In Python 3.7 SimpleHTTPRequestHandler can take a directory argument:

import http.server
import socketserver

PORT = 8000
DIRECTORY = "web"


class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=DIRECTORY, **kwargs)


with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()

and from the command line:

python -m http.server --directory web

To get a little crazy... you could make handlers for arbitrary directories:

def handler_from(directory):
    def _init(self, *args, **kwargs):
        return http.server.SimpleHTTPRequestHandler.__init__(self, *args, directory=self.directory, **kwargs)
    return type(f'HandlerFrom<{directory}>',
                (http.server.SimpleHTTPRequestHandler,),
                {'__init__': _init, 'directory': directory})


with socketserver.TCPServer(("", PORT), handler_from("web")) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()
Innocent answered 27/9, 2018 at 7:12 Comment(3)
Better to use http.server.HTTPServer (in exactly the same way as socketserver.TCPServer)Ripe
Similar: https://mcmap.net/q/82206/-how-to-run-cgi-quot-hello-world-quot-with-python-http-serverRipe
Note that if you're calling this from a Windows shortcut, then the "Start in" property of the shortcut will define what's the current working directory where web will be searched for. That is, if the command line of your Windows shortcut is C:\Windows\System32\cmd.exe /k "python -m http.server --directory web", then in the shortcut properties, make sure to leave the "Start in" field empty so that it'll consider web as relative to the path of the shortcut file, rather than \System32\cmd.exe.Asymptote
H
88

If you just want serve static file you can do it by running SimpleHTTPServer module using python 2:

 python -m SimpleHTTPServer

Or with python 3:

 python3 -m http.server

This way you do not need to write any script.

Hiroshima answered 8/4, 2017 at 9:6 Comment(7)
Note that you can also add a port at the end to specify the port of the server.Guardado
further note; you have to have an index.html or index.htm file in the directory you're running the server from in order for it to be served; otherwise you get a directory list.Terbecki
OP asks how to run it at specific folder path, not from present working directory.Personalize
There's a directory argument to http.server. So you can do python3 -m http.server -d /path/to/web/dirUnclassical
While this answer was accepted by the owner of the question as being the best answer, I think it should not be the best answer. The question was asking for a way how to code this in python and not how to invoke it from the command line.Guacin
i wish to run a index.py or main.py as the default in a ./www folder. the file is www/index.py what do i do?Aquiver
This is completely different situation. Here we serve content of the files which you probably do not want. I guess you want to execute the file?Hiroshima
P
52

https://docs.python.org/3/library/http.server.html#http.server.SimpleHTTPRequestHandler

This class serves files from the current directory and below, directly mapping the directory structure to HTTP requests.

So you just need to change the current directory prior to starting the server - see os.chdir

eg:

import http.server
import socketserver
import os

PORT = 8000

web_dir = os.path.join(os.path.dirname(__file__), 'web')
os.chdir(web_dir)

Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
Productive answered 1/10, 2016 at 0:25 Comment(4)
Thank you! Note: I added try: httpd.serve_forever(); except KeyboardInterrupt: pass; httpd.server_close() to actually close the port.Initial
Thanks. Its worked. But how can I get the Host address for this? I mean to say that how can I get 0.0.0.0:8000 instead of my local router address 192.168.0.100:8000Ethyne
@Initial You rather should use with socketserver.TCPServer(("", PORT), Handler) as httpd:, this way it closes automatically after being usedOosphere
For future readers: Andy Hayden's solution below is less 'hacky', and probably preferred, since it doesn't rely on side-effects.Josiahjosias
E
32

You also can run the command line with

python3 -m http.server -d web 8000
Enki answered 21/6, 2020 at 15:56 Comment(1)
or to see all supported parameters try python3 -m http.server --helpProstatitis
P
27

There's a shorter method for Python 3+:

import functools
    
Handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory='/my/dir/goes/here')
Pals answered 3/10, 2019 at 11:9 Comment(4)
this is a very cool way to do this and it works for me. I'd definitively recommend this as the best answer!Guacin
TypeError: __init__() got an unexpected keyword argument 'directory'Ehlers
I get the same error in Python 2.7. It worked for me on Python 3.8.Broderic
Stop using Python 2 :)Pals
S
21

Just for completeness, here's how you can setup the actual server classes to serve files from an arbitrary directory:

try
    # python 2
    from SimpleHTTPServer import SimpleHTTPRequestHandler
    from BaseHTTPServer import HTTPServer as BaseHTTPServer
except ImportError:
    # python 3
    from http.server import HTTPServer as BaseHTTPServer, SimpleHTTPRequestHandler


class HTTPHandler(SimpleHTTPRequestHandler):
    """This handler uses server.base_path instead of always using os.getcwd()"""
    def translate_path(self, path):
        path = SimpleHTTPRequestHandler.translate_path(self, path)
        relpath = os.path.relpath(path, os.getcwd())
        fullpath = os.path.join(self.server.base_path, relpath)
        return fullpath


class HTTPServer(BaseHTTPServer):
    """The main server, you pass in base_path which is the path you want to serve requests from"""
    def __init__(self, base_path, server_address, RequestHandlerClass=HTTPHandler):
        self.base_path = base_path
        BaseHTTPServer.__init__(self, server_address, RequestHandlerClass)

Then you can set any arbitrary path in your code:

web_dir = os.path.join(os.path.dirname(__file__), 'web')
httpd = HTTPServer(web_dir, ("", 8000))
httpd.serve_forever()
Sunday answered 20/9, 2017 at 21:40 Comment(0)
B
8

Another easy method to serve from a specific directory.

Since you really only need to set the directory parameter for the SimpleHTTPRequestHandler, you can use functools.partial to prepare the handler class without instantiating the class.

from functools import partial
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path


def start_httpd(directory: Path, port: int = 8000):
    print(f"serving from {directory}...")
    handler = partial(SimpleHTTPRequestHandler, directory=directory)
    httpd = HTTPServer(('localhost', port), handler)
    httpd.serve_forever()
    
Briton answered 7/9, 2021 at 12:20 Comment(0)
G
-12

If you just need a modern web static server,
deno is an alternative file server without any code.

install deno with single line

https://github.com/denoland/deno_install#deno_install

install file server with single line

deno install --allow-net --allow-read https://deno.land/[email protected]/http/file_server.ts

use deno file-server

file_server . --port=<port>
# Downloading https://deno.land/[email protected]/http/file_server.ts...
# HTTP server listening on http://0.0.0.0:<port>/

read more https://deno.land/manual/examples/file_server#using-the-codestdhttpcode-file-server

Graduate answered 15/2, 2022 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.