CryskuraHTTP is a lightweight, customizable HTTP(s) server implemented in Python that supports basic HTTP(s) functionalities, including serving files and handling errors, with support for custom services, API calls, and authentication.
CryskuraHTTP is an extension of Python's built-in http.server, with zero external dependencies. You can leverage it to implement Python HTTP services without needing to install large software or libraries. It can also be used as a file sharing tool, supporting file serving and uploading through the browser, and can be launched from the Windows right-click menu.
- Customizable Services: Easily add custom services by extending the
BaseServiceclass. - Customizable API Calls: Define custom API calls with the
APIServiceclass. - Error Handling: Customizable error handling via the
ErrorServiceclass. - File Serving: Serve files from a specified directory via the
FileServiceclass. - File Uploading: Handle file uploads via POST requests with the
FileServiceclass. - WebPage Serving: Serve web pages without allowing directory listing via the
PageServiceclass. - Customizable Routes: Define custom routes for your services with the
Routeclass. - Customizable Authentication: Implement custom authentication for your services.
- Auto uPnP Port Forwarding: Automatically forward ports using uPnP.
- Request Handling: Handle GET, POST, HEAD requests.
- Resumable Downloads: Supports resumable downloads for large files when serving files.
- Redirects: Supports 301 and 308 redirects.
- SSL Support: Optionally enable SSL by providing a certificate file.
- IPv6 & Dual-Stack: Full IPv6 support with dual-stack mode enabled by default.
- Multi-IP/Port Listening: Bind to multiple interfaces and ports simultaneously.
- Threaded Server: Supports multi-threaded request handling for better performance.
- Command-Line Interface: Run the server from the command line with custom settings.
- Right Click Support: Supports right-click context menu for launching the server on Windows.
This project is not designed to replace full-scale, production-grade HTTP servers. Instead, it is ideal for small-scale web UI development or for use alongside tools like pywebview and qtwebengine. So don't expect it to handle thousands of concurrent connections or to have advanced features like load balancing or caching.
- Python 3.7+ (no external dependencies)
-
Install the package using pip:
pip install cryskura
-
You can also download whl file from GitHub Releases and install it using pip:
pip install cryskura-1.0-py3-none-any.wh
-
Clone the repository and install manually if you want to modify the source code:
git clone https://github.com/HofNature/CryskuraHTTP.git cd CryskuraHTTP python setup.py install
To start the server with default settings:
from cryskura import Server
server = Server()
server.start()This starts on [::1]:8080 with dual-stack enabled, serving the current directory.
The CLI listens on :: (all interfaces, dual-stack) at port 8080 by default:
cryskuraYou can also specify a custom interface, port, and directory:
cryskura --interface ::1 --port 8080 --path /path/to/serveThis will start the server on localhost at port 8080 and serve files from /path/to/serve.
You can add the server to the right-click context menu on Windows by running:
cryskura --addRightClick # You can also use -ar as a short formNote: If arguments like
--interface,--port,--browser, etc., are provided, the server will start with the specified settings when launched from the right-click menu.
If you want to remove it from the right-click menu, run:
cryskura --removeRightClick # You can also use -rr as a short formNote: This feature is only available on Windows. For Windows 11 24h2 and above, if Sudo is enabled, it will be called automatically; otherwise, you need to run it manually with administrator privileges.
When using the Python API, you can stop the server by calling the stop() method:
server.stop()Note: Only the threaded server can be stopped using this method. The non-threaded server will block the thread, so it cannot be stopped by calling the
stop()method. You can stop the non-threaded server by pressingCtrl+Cin the terminal.
When using the command line, you can stop the server by pressing Ctrl+C in the terminal.
You can get help on the command-line interface by running:
cryskura --helpThis will show the available options:
-h, --help: Show help message and exit.-u, --uPnP: Enable uPnP port forwarding.-v, --version: Show program's version number and exit.-b, --browser: Open the browser after starting the server.-ba, --browserAddress: The address to open in the browser.-w, --webMode: Enable web mode, which means only files can be accessed, not directories.-f, --forcePort: Force to use the specified port even if it is already in use.-t, --allowUpload: Allow file upload.-r, --allowResume: Allow resume download.-ar, --addRightClick: Add to right-click menu.-rr, --removeRightClick: Remove from right-click menu.-d PATH, --path PATH: The path to the directory to serve.-n NAME, --name NAME: The name of the server.-p PORT, --port PORT: The port to listen on. Can be specified multiple times for multi-port listening.-c CERTFILE, --certfile CERTFILE: The path to the certificate file.-i INTERFACE, --interface INTERFACE: The interface to listen on. Can be specified multiple times for multi-IP listening. Accepts IPv4, IPv6 addresses, or hostnames. Default:::.-j HTTP_TO_HTTPS, --http_to_https HTTP_TO_HTTPS: Port to redirect HTTP requests to HTTPS.--single-stack: Disable dual-stack mode. IPv6 sockets will only accept IPv6 connections (sets IPV6_V6ONLY=1). Useful on platforms with broken dual-stack support.-tp, --trusted-proxy: Trusted reverse proxy IP or CIDR range. Can be specified multiple times.--cors-origin: CORS allowed origin. Can be specified multiple times (default:*).--cors-credentials: Enable CORS credentials support.--cors-max-age: CORS preflight max age in seconds (default: 86400).--log-dir: Directory path for log files. Disabled when not set.
The server supports listening on multiple interfaces and ports simultaneously. All combinations of the specified interfaces and ports are used. Dual-stack is enabled by default — binding to an IPv6 address accepts both IPv4 and IPv6 connections.
# Default: 127.0.0.1:8080, dual-stack enabled
server = Server()
server.start()# CLI default: [::]:8080 (all interfaces, dual-stack)
cryskuraserver = Server(interface="::", port=[8080, 8443])
server.start()Or from the command line:
cryskura -i :: -p 8080 -p 8443server = Server(interface=["192.168.1.5", "10.0.0.1"], port=8080)
server.start()Full IPv6 is supported. Use :: for all IPv6 interfaces, ::1 for IPv6 localhost:
# IPv6 + IPv4 via dual-stack (default)
server = Server(interface="::", port=8080)
# IPv6-only (no IPv4)
server = Server(interface="::", port=8080, dual_stack=False)
# IPv4-only
server = Server(interface="0.0.0.0", port=8080)From the command line:
# All interfaces, dual-stack (default)
cryskura
# IPv6 only, disable dual-stack
cryskura --single-stack
# IPv4 only
cryskura -i 0.0.0.0Note: Dual-stack is implemented by setting
IPV6_V6ONLY=0on IPv6 sockets. On platforms where this is unreliable, use--single-stackand explicitly bind to-i :: -i 0.0.0.0instead.
server = Server(interface=["127.0.0.1", "::1"], port=[8080])
server.start()This creates two separate sockets — one for IPv4 on 127.0.0.1:8080 and one for IPv6 on [::1]:8080.
You can customize the server by providing different parameters:
from cryskura import Server
from cryskura.Services import FileService,PageService,RedirectService,APIService
# Create services
fs=FileService(r"/path/to/file","/Files",allowResume=True,allowUpload=True)
rs=RedirectService("/Redirect","https://www.google.com")
ps1=PageService(r"/path/to/html/example.com","/",host="example.com")
ps2=PageService(r"/path/to/html/default","/")
# Define the API function
def APIFunc(request, path, args, headers, content, method):
"""
A sample API function for handling API requests.
Parameters:
- request: The HTTP request object.
- path: The sub-path of the request URL after the API endpoint.
- args: The query parameters from the URL as a dictionary.
- headers: The headers from the request as a dictionary.
- content: The body content of the request as bytes.
- method: The HTTP method used (e.g., "GET", "POST").
Returns:
- code: An integer HTTP status code (e.g., 200 for success).
- response_headers: A dictionary of headers to include in the response.
- response_content: The body content to send in the response as bytes.
"""
print(f"API {method} {path} {args}")
# Process the request and generate a response
code = 200 # HTTP status code
response_headers = {"Content-Type": "text/plain"} # Response headers
response_content = b"API Call" # Response body content
return code, response_headers, response_content
# Create API service
api=APIService("/API",func=APIFunc)
# Start the server
server=Server(services=[fs,rs,api,ps1,ps2],certfile="/path/to/cert.pem",uPnP=True)
server.start()This will start the server with the following services:
- FileService: Serves files from
/path/to/fileat the/Filesendpoint, allowing resumable downloads and file uploads. - RedirectService: Redirects requests from
/Redirecttohttps://www.google.com. - PageService 1: Hosts web pages located in
/path/to/html/example.comand serves them at the root endpoint/only when user requests with domainexample.com. - PageService 2: Hosts default web pages located in
/path/to/html/defaultand serves them at the root endpoint/for all other requests. - APIService: Handles API calls at the
/APIendpoint, printing request details and responding with a plain text message.
And with the following settings:
- SSL Support: Uses the certificate file located at
/path/to/cert.pemfor SSL encryption. - uPnP Port Forwarding: Automatically forwards ports using uPnP.
If multiple services have conflicting routes, the priority is determined by the order in which the services are listed in the services parameter. The service listed first will have the highest priority, and so on.
For example:
from cryskura import Server
from cryskura.Services import FileService, PageService
fs = FileService(r"/path/to/files", "/files")
ps = PageService(r"/path/to/pages", "/")
server = Server(services=[fs,ps])
server.start()In this case, FileService will have priority over PageService for routes that conflict between the two services. So if a request is made to /files/index.html, it will be handled by FileService and not PageService.
To implement custom authentication, you need to define an authentication function and pass it to the service that requires authentication. The authentication function should accept four parameters: cookies, path, args, and operation. It should return True if the authentication is successful, and False otherwise.
Here is an example of how to implement custom authentication:
from cryskura import Server
from cryskura.Services import FileService
# Define authentication function
def AUTHFunc(cookies, path, args, operation):
print(f"AUTH {operation} {path} {args}")
if args.get('passwd') == "passwd" and operation == "GET":
return True
elif args.get('passwd') == "admin" and operation == "POST":
return True
return False
# Create a file service with authentication
fs = FileService(r"/path/to/files", "/files", allowResume=True, auth_func=AUTHFunc)
# Start the server
server = Server(services=[fs])
server.start()In this example, the AUTHFunc function checks the passwd parameter in the request arguments to authenticate GET and POST requests. If the passwd parameter is passwd for GET requests or admin for POST requests, the authentication is successful. Otherwise, the authentication fails.
You can customize the AUTHFunc function to implement your own authentication logic, such as checking cookies, headers, or other request parameters.
CryskuraHTTP also provides a built-in cookie-based authentication service with a login page.
from cryskura import Server
from cryskura.Services import FileService, AuthService, AuthVerify
# 1) Define username/password pairs
verify = AuthVerify({
"admin": "admin123",
"guest": "guest123",
}, expire_time=7 * 86400)
# 2) Mount AuthService
# /login -> login page + auth API
# /private/** -> protected routes
auth = AuthService("/login", verify, "/private", methods=["GET", "HEAD", "POST"], route_type="prefix", title="My Protected Server")
# 3) Protected content under /private
files = FileService(r"/path/to/private-files", "/private", allowUpload=False)
server = Server(services=[auth, files])
server.start()Behavior:
- Unauthenticated
GET /private/...requests are redirected to/login?next=<original_path>. - After successful login, the login page returns to
nextautomatically. - For non-GET unauthenticated requests, the service returns
401with a JSON body includingauth_url.
If you want a lightweight JSON API layer, use SimpleAPIRouter. It handles JSON request parsing, JSON responses, and path parameters such as /users/{user_id}/posts/{post_id}.
from cryskura import Server
from cryskura.Services import SimpleAPIRouter
router = SimpleAPIRouter()
@router.get("/users/{user_id}/posts/{post_id}")
def get_post(params, body):
return 200, {
"user_id": params["user_id"],
"post_id": params["post_id"],
"body": body,
}
@router.post("/users/{user_id}/posts")
def create_post(params, body):
return 201, {"user_id": params["user_id"], "created": body}
server = Server(services=router.build("/api"))
server.start()Notes:
- The template must match exactly, so
/api/users/1/posts/2is valid, but/api/users/1/posts/2/extrais not. HEADrequests are supported for@router.get(...)routes and return headers without a response body.
To create a custom service, extend the BaseService class and implement the required methods:
from cryskura.Services import BaseService, Route
class MyService(BaseService):
def __init__(self):
routes = [Route("/myservice", ["GET"], "exact")]
super().__init__(routes)
def handle_GET(self, request, path, args):
request.send_response(200)
request.send_header("Content-Type", "text/plain")
request.end_headers()
request.wfile.write(b"Hello from MyService!")When CryskuraHTTP runs behind a reverse proxy (nginx, HAProxy, etc.), configure trusted proxy IPs so that X-Forwarded-* headers are used for client IP, scheme, and host:
from cryskura import Server
from cryskura.Services import FileService
server = Server(
services=[FileService(".", "/")],
trusted_proxy_ips=["127.0.0.1", "10.0.0.0/8"],
)Or via CLI:
cryskura -tp 127.0.0.1 -tp 10.0.0.0/8When a request comes from a trusted IP, the server uses:
X-Forwarded-For(leftmost IP) foraddress_string()X-Forwarded-Protofor the request schemeX-Forwarded-HostandX-Forwarded-Portfor virtual host routing
Configure CORS headers globally or per-service:
from cryskura import Server, CORSConfig, CORSManager
from cryskura.Services import FileService, AuthService
# Simple: one CORSConfig for all services
cors = CORSConfig(
allow_origins=["https://example.com"],
allow_credentials=True,
)
server = Server(services=[...], cors=cors)
# Advanced: per-service overrides
cors_mgr = CORSManager(CORSConfig(allow_origins=["*"]))
cors_mgr.set_service_override(
AuthService, CORSConfig(allow_origins=["https://auth.example.com"])
)
server = Server(services=[...], cors=cors_mgr)CLI options:
cryskura --cors-origin https://example.com --cors-credentials --cors-max-age 3600Enable file-based logging by providing a log_dir:
server = Server(services=[...], log_dir="/var/log/cryskura")Logs are written to <log_dir>/latest/access.log and <log_dir>/latest/server.log. On server start and daily at midnight, the latest directory is rotated to a timestamped name (e.g., 2026-05-27T15-30-00/).
cryskura --log-dir /var/log/cryskuraCryskuraHTTP includes a built-in uPnP client to facilitate automatic port forwarding. This can be particularly useful when running the server behind a router or firewall.
To enable uPnP port forwarding, you can use the --uPnP flag when starting the server from the command line:
cryskura --interface 0.0.0.0 --port 8080 --path /path/to/serve --uPnPYou can also enable uPnP port forwarding when starting the server using the Python API:
from cryskura import Server
server = Server(interface="0.0.0.0", port=8080, uPnP=True)
server.start()The built-in uPnP client can be used independently for custom port forwarding needs. Here’s how you can use the uPnPClient class directly in your Python code:
First, you need to initialize the uPnPClient with the desired network interface:
from cryskura import uPnP
# Initialize uPnP client for a specific interface
upnp_client = uPnP(interface="0.0.0.0")
# Use 0.0.0.0 for all IPv4 interfaces
if upnp_client.available:
print("uPnP client initialized successfully.")
else:
print("uPnP client is not available.")To add a port mapping, use the add_port_mapping method:
if upnp_client.available:
success, mappings = upnp_client.add_port_mapping(
remote_port=8080,
local_port=8080,
protocol="TCP",
description="CryskuraHTTP Server"
)
if success:
print("Port mapping added successfully.")
for mapping in mappings:
print(f"Service is available at {mapping[0]}:{mapping[1]}")
else:
print("Failed to add port mapping.")This will add a port mapping for port 8080 on the remote device to port 8080 on the local device using the TCP protocol. The description is just a label for the mapping, which can be used to identify it later.
To remove port mappings, use the remove_port_mapping method:
if upnp_client.available:
upnp_client.remove_port_mapping()
print("Port mapping removed.")This will remove all port mappings that were added by the client. It's a good practice to remove port mappings when they are no longer needed. You can place this code in a cleanup section of your script or in an exception handler to ensure that the mappings are removed even if an error occurs. For example:
try:
Your code here...
except Exception as exception:
upnp_client.remove_port_mapping()
raise exceptionThis will ensure that the port mappings are removed even if an exception occurs during the execution of your code.
If you encounter issues with uPnP, ensure that:
-
Your router supports uPnP and has it enabled.
-
The
upnpclientlibrary is installed. You can install it using:pip install upnpclient
or install the
cryskurapackage with theupnpextra:pip install cryskura[upnp]
-
The network interface specified is correct and accessible.
For more detailed information on the uPnPClient class and its methods, refer to the source code in the uPnP.py file.
This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please open an issue or submit a pull request.
For any questions or suggestions, please open an issue here on GitHub.
Enjoy using CryskuraHTTP!