1. Uvicorn y SSL
Para mas información ver la página oficial de Uvicorn.
Parece ser que Uvicorn es el servidor http/https
Si vamos a la definción del la funcion serve de fastHtml que está en el fichero core.py tenemos este código:
# %% ../nbs/api/00_core.ipynb def serve( appname=None, # Name of the module app='app', # App instance to be served host='0.0.0.0', # If host is 0.0.0.0 will convert to localhost port=None, # If port is None it will default to 5001 or the PORT environment variable reload=True, # Default is to reload the app upon code changes reload_includes:list[str]|str|None=None, # Additional files to watch for changes reload_excludes:list[str]|str|None=None # Files to ignore for changes ): "Run the app in an async server, with live reload set as the default." bk = inspect.currentframe().f_back glb = bk.f_globals code = bk.f_code if not appname: if glb.get('__name__')=='__main__': appname = Path(glb.get('__file__', '')).stem elif code.co_name=='main' and bk.f_back.f_globals.get('__name__')=='__main__': appname = inspect.getmodule(bk).__name__ if appname: if not port: port=int(os.getenv("PORT", default=5001)) print(f'Link: http://{"localhost" if host=="0.0.0.0" else host}:{port}') uvicorn.run(f'{appname}:{app}', host=host, port=port, reload=reload, reload_includes=reload_includes, reload_excludes=reload_excludes)
Y al final tenemos una llamada a "uvicorn.run" cuyo código está en main.py y és:
def run( app: ASGIApplication | Callable[..., Any] | str, *, host: str = "127.0.0.1", port: int = 8000, uds: str | None = None, fd: int | None = None, loop: LoopSetupType = "auto", http: type[asyncio.Protocol] | HTTPProtocolType = "auto", ws: type[asyncio.Protocol] | WSProtocolType = "auto", ws_max_size: int = 16777216, ws_max_queue: int = 32, ws_ping_interval: float | None = 20.0, ws_ping_timeout: float | None = 20.0, ws_per_message_deflate: bool = True, lifespan: LifespanType = "auto", interface: InterfaceType = "auto", reload: bool = False, reload_dirs: list[str] | str | None = None, reload_includes: list[str] | str | None = None, reload_excludes: list[str] | str | None = None, reload_delay: float = 0.25, workers: int | None = None, env_file: str | os.PathLike[str] | None = None, log_config: dict[str, Any] | str | RawConfigParser | IO[Any] | None = LOGGING_CONFIG, log_level: str | int | None = None, access_log: bool = True, proxy_headers: bool = True, server_header: bool = True, date_header: bool = True, forwarded_allow_ips: list[str] | str | None = None, root_path: str = "", limit_concurrency: int | None = None, backlog: int = 2048, limit_max_requests: int | None = None, timeout_keep_alive: int = 5, timeout_graceful_shutdown: int | None = None, ssl_keyfile: str | os.PathLike[str] | None = None, ssl_certfile: str | os.PathLike[str] | None = None, ssl_keyfile_password: str | None = None, ssl_version: int = SSL_PROTOCOL_VERSION, ssl_cert_reqs: int = ssl.CERT_NONE, ssl_ca_certs: str | None = None, ssl_ciphers: str = "TLSv1", headers: list[tuple[str, str]] | None = None, use_colors: bool | None = None, app_dir: str | None = None, factory: bool = False, h11_max_incomplete_event_size: int | None = None, ) -> None: if app_dir is not None: sys.path.insert(0, app_dir) config = Config( app, host=host, port=port, uds=uds, fd=fd, loop=loop, http=http, ws=ws, ws_max_size=ws_max_size, ws_max_queue=ws_max_queue, ws_ping_interval=ws_ping_interval, ws_ping_timeout=ws_ping_timeout, ws_per_message_deflate=ws_per_message_deflate, lifespan=lifespan, interface=interface, reload=reload, reload_dirs=reload_dirs, reload_includes=reload_includes, reload_excludes=reload_excludes, reload_delay=reload_delay, workers=workers, env_file=env_file, log_config=log_config, log_level=log_level, access_log=access_log, proxy_headers=proxy_headers, server_header=server_header, date_header=date_header, forwarded_allow_ips=forwarded_allow_ips, root_path=root_path, limit_concurrency=limit_concurrency, backlog=backlog, limit_max_requests=limit_max_requests, timeout_keep_alive=timeout_keep_alive, timeout_graceful_shutdown=timeout_graceful_shutdown, ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, ssl_keyfile_password=ssl_keyfile_password, ssl_version=ssl_version, ssl_cert_reqs=ssl_cert_reqs, ssl_ca_certs=ssl_ca_certs, ssl_ciphers=ssl_ciphers, headers=headers, use_colors=use_colors, factory=factory, h11_max_incomplete_event_size=h11_max_incomplete_event_size, ) server = Server(config=config) if (config.reload or config.workers > 1) and not isinstance(app, str): logger = logging.getLogger("uvicorn.error") logger.warning("You must pass the application as an import string to enable 'reload' or " "'workers'.") sys.exit(1) try: if config.should_reload: sock = config.bind_socket() ChangeReload(config, target=server.run, sockets=[sock]).run() elif config.workers > 1: sock = config.bind_socket() Multiprocess(config, target=server.run, sockets=[sock]).run() else: server.run() except KeyboardInterrupt: pass # pragma: full coverage finally: if config.uds and os.path.exists(config.uds): os.remove(config.uds) # pragma: py-win32 if not server.started and not config.should_reload and config.workers == 1: sys.exit(STARTUP_FAILURE)
Y hay que destacar que podemos trabajar con https si le damos la información del certificado de servidor que marcamos en amarillo (también hay que adecuar otros parámetros como los puertos, versión del ssl , etc)
2. Fasthtml y SSL
Para ejecutar SSL en FastHML podemos hacerlo de varias maneras
2.1 Copiando la función serve de fastHTML y modificándola para que admita también como parámetros de entrada los parámetros de certificado:
- ssl_keyfile
- ssl_certfile
- ssl_keyfile_password
- ssl_version
- ssl_cert_reqs
- ssl_ca_certs
- ssl_ciphers
Podemos tener nuestra función serve a la que podemos añadir las opciones del certificado, copiando la función serve de fastHTML y añadiéndole los parámetros de configuración del SSL que hemos detectado.
def serve( appname=None, # Name of the module app='app', # App instance to be served host='0.0.0.0', # If host is 0.0.0.0 will convert to localhost port=None, # If port is None it will default to 5001 or the PORT environment variable reload=True, # Default is to reload the app upon code changes reload_includes:list[str]|str|None=None, # Additional files to watch for changes reload_excludes:list[str]|str|None=None # Files to ignore for changes ssl_keyfile: str | os.PathLike[str] | None = None, ssl_certfile: str | os.PathLike[str] | None = None, ssl_keyfile_password: str | None = None, ssl_version: int = SSL_PROTOCOL_VERSION, ssl_cert_reqs: int = ssl.CERT_NONE, ssl_ca_certs: str | None = None, ssl_ciphers: str = "TLSv1", ): "Run the app in an async server, with live reload set as the default." bk = inspect.currentframe().f_back glb = bk.f_globals code = bk.f_code if not appname: if glb.get('__name__')=='__main__': appname = Path(glb.get('__file__', '')).stem elif code.co_name=='main' and bk.f_back.f_globals.get('__name__')=='__main__': appname = inspect.getmodule(bk).__name__ if appname: if not port: port=int(os.getenv("PORT", default=5001)) print(f'Link: http://{"localhost" if host=="0.0.0.0" else host}:{port}') uvicorn.run(f'{appname}:{app}', host=host, port=port, reload=reload, reload_includes=reload_includes, reload_excludes=reload_excludes, ssl_keyfile=ssl_keyfile, ssl_certfile= ssl_certfile, ssl_keyfile_password=ssl_keyfile_password, ssl_version=ssl_version, ssl_cert_reqs=ssl_cert_reqs, ssl_ca_certs= ssl_ca_certs, ssl_ciphers=ssl_ciphers)
2.2 Ejecutando uvicorn directamente y pasándole los parametros de certificado
Este ejemplo se ha copiado de uvicorn.
import uvicorn class App: ... app = App() if __name__ == "__main__": uvicorn.run("main:app", host="127.0.0.1", port=443, log_level="info",
ssl_keyfile='ruta1', ssl_certfile='ruta2, ssl_keyfile_password='mipaswword')
3. Uvicorn y nginx
http { server { listen 80; client_max_body_size 4G; server_name example.com; location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_redirect off; proxy_buffering off; proxy_pass http://uvicorn; } location /static { # path for static files root /path/to/app/static; } } map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream uvicorn { server unix:/tmp/uvicorn.sock; } }
No hay comentarios :
Publicar un comentario