4141DEFAULT_WORKERS = 1
4242TIMEOUT_KEEP_ALIVE_SECONDS = 120
4343DEFAULT_LIMIT_MAX_REQUESTS = 0
44+ ALL_INTERFACES_HOST = "0.0.0.0"
4445
4546
4647def _runtime_profile_selection_message (workers : int , limit_max_requests : int ) -> str :
@@ -115,6 +116,10 @@ def _sanitize_pythonpath_for_serve() -> None:
115116 os .environ ["PYTHONPATH" ] = src_path
116117
117118
119+ def _resolve_bind_host (args : argparse .Namespace ) -> str :
120+ return ALL_INTERFACES_HOST if bool (getattr (args , "host_all" , False )) else str (args .host )
121+
122+
118123def _build_parser () -> argparse .ArgumentParser :
119124 parser = argparse .ArgumentParser (
120125 description = "PyPNM CLI for service startup and system configuration." ,
@@ -140,7 +145,13 @@ def _build_parser() -> argparse.ArgumentParser:
140145 subparsers = parser .add_subparsers (dest = "command" )
141146
142147 serve_parser = subparsers .add_parser ("serve" , help = "Start the FastAPI service (Uvicorn)." )
143- serve_parser .add_argument ("--host" , default = HOST_DEFAULT , help = f"Host to bind (default: { HOST_DEFAULT } )" )
148+ host_group = serve_parser .add_mutually_exclusive_group ()
149+ host_group .add_argument ("--host" , default = HOST_DEFAULT , help = f"Host to bind (default: { HOST_DEFAULT } )" )
150+ host_group .add_argument (
151+ "--host-all" ,
152+ action = "store_true" ,
153+ help = f"Bind on all IPv4 interfaces ({ ALL_INTERFACES_HOST } )." ,
154+ )
144155 serve_parser .add_argument ("--port" , default = PORT_DEFAULT , type = int , help = f"Port to bind (default: { PORT_DEFAULT } )" )
145156 serve_parser .add_argument ("--ssl" , action = "store_true" , help = "Enable HTTPS (requires cert and key)." )
146157 serve_parser .add_argument ("--cert" , default = "./certs/cert.pem" , help = "Path to SSL certificate (PEM)." )
@@ -230,6 +241,7 @@ def _build_parser() -> argparse.ArgumentParser:
230241
231242
232243def _run_serve (args : argparse .Namespace ) -> int :
244+ bind_host = _resolve_bind_host (args )
233245 run_background = bool (getattr (args , "run_background" , False ))
234246 background_log_file = str (getattr (args , "background_log_file" , "" )).strip ()
235247 background_pidfile = str (getattr (args , "background_pidfile" , "" )).strip ()
@@ -239,9 +251,9 @@ def _run_serve(args: argparse.Namespace) -> int:
239251 return EXIT_CODE_USAGE
240252
241253 if args .ssl :
242- print (f"🔒 Launching FastAPI with HTTPS on https://{ args . host } :{ args .port } " )
254+ print (f"🔒 Launching FastAPI with HTTPS on https://{ bind_host } :{ args .port } " )
243255 else :
244- print (f"🌐 Launching FastAPI with HTTP on http://{ args . host } :{ args .port } " )
256+ print (f"🌐 Launching FastAPI with HTTP on http://{ bind_host } :{ args .port } " )
245257
246258 _sanitize_pythonpath_for_serve ()
247259
@@ -269,7 +281,7 @@ def _run_serve(args: argparse.Namespace) -> int:
269281
270282 uvicorn_args = {
271283 "app" : "pypnm.api.main:app" ,
272- "host" : args . host ,
284+ "host" : bind_host ,
273285 "port" : args .port ,
274286 "timeout_keep_alive" : TIMEOUT_KEEP_ALIVE_SECONDS ,
275287 "log_level" : args .log_level ,
0 commit comments