Skip to content

Instantly share code, notes, and snippets.

@bhagman
Created December 7, 2025 02:59
Show Gist options
  • Select an option

  • Save bhagman/d1ab9770a4c337594cafe80e7479c112 to your computer and use it in GitHub Desktop.

Select an option

Save bhagman/d1ab9770a4c337594cafe80e7479c112 to your computer and use it in GitHub Desktop.
Serve pages locally, ala Cloudflare Pages (no .html extension)
#!/usr/bin/env python3
"""
Serves files from the current directory, allowing access to HTML files
without requiring the .html extension in the URL.
For example, accessing '/login' will serve 'login.html'.
Accessing the root '/' will serve 'index.html'.
Files with other extensions will not be served without their extensions.
"""
import http.server
import socketserver
import os
from urllib.parse import urlparse
class NoExtensionHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
parsed_url = urlparse(self.path)
path = parsed_url.path.lstrip('/')
if path.endswith(".html"):
new_path = "/" + path[:-5]
if path == "index.html":
new_path = "/"
if parsed_url.query:
new_path += "?" + parsed_url.query
self.send_response(301)
self.send_header("Location", new_path)
self.end_headers()
return
if not path:
# Handle the base URL case for index.html
index_file = os.path.join(os.getcwd(), "index.html")
if os.path.exists(index_file) and os.path.isfile(index_file):
self.path = "/index.html" + (parsed_url.query and "?" + parsed_url.query) + (parsed_url.fragment and "#" + parsed_url.fragment)
return http.server.SimpleHTTPRequestHandler.do_GET(self)
else:
self.send_error(404, "Default index.html not found")
return
if not os.path.splitext(path)[1] or path.endswith(".html"):
# Only try to serve .html without extension if there's no extension
# or if the user explicitly requested .html
potential_file = os.path.join(os.getcwd(), path + ".html")
if os.path.exists(potential_file) and os.path.isfile(potential_file):
self.path = "/" + path + ".html" + (parsed_url.query and "?" + parsed_url.query) + (parsed_url.fragment and "#" + parsed_url.fragment)
return http.server.SimpleHTTPRequestHandler.do_GET(self)
# If it's not a potential extension-less .html file, let the default handler try
return http.server.SimpleHTTPRequestHandler.do_GET(self)
if __name__ == "__main__":
PORT = 8000
with socketserver.TCPServer(("", PORT), NoExtensionHandler) as httpd:
print(f"Serving at port {PORT}")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nShutting down server...")
finally:
httpd.server_close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment