@@ -498,6 +498,65 @@ def parse_section(section):
498498 WEBSOCKET_EVENT_CALLER_TIMEOUT = 300
499499
500500
501+ import ssl as _ssl
502+
503+
504+ # Dedicated env var for a custom CA bundle file path. When set, this is
505+ # used as the default CA bundle for all outbound HTTPS connections that
506+ # have SSL verification enabled (i.e. when their per-connection SSL env
507+ # var is ``"True"``). Per-connection overrides (setting the SSL env var
508+ # to a path directly) take precedence over this global fallback.
509+ #
510+ # This follows the industry convention of ``SSL_CERT_FILE`` / ``REQUESTS_CA_BUNDLE``
511+ # but is scoped to Open WebUI to avoid interfering with system-level settings.
512+ AIOHTTP_CLIENT_SSL_CERT_FILE = os .getenv ('AIOHTTP_CLIENT_SSL_CERT_FILE' , '' ).strip ()
513+
514+
515+ def _build_ssl_context_from_file (path : str ) -> '_ssl.SSLContext | None' :
516+ """Create an SSLContext from a CA bundle file, or None if invalid."""
517+ if not path :
518+ return None
519+ if not os .path .isfile (path ):
520+ log .warning (
521+ 'SSL CA bundle path does not exist: %r, ignoring' ,
522+ path ,
523+ )
524+ return None
525+ ctx = _ssl .create_default_context (cafile = path )
526+ log .info ('Using custom SSL CA bundle: %s' , path )
527+ return ctx
528+
529+
530+ # Pre-built SSLContext from the dedicated env var (cached once at startup).
531+ _GLOBAL_SSL_CONTEXT = _build_ssl_context_from_file (AIOHTTP_CLIENT_SSL_CERT_FILE )
532+
533+
534+ def _parse_ssl_env (value : str ) -> 'bool | _ssl.SSLContext' :
535+ """Parse an SSL env var into a bool or SSLContext.
536+
537+ - ``"true"`` → uses ``AIOHTTP_CLIENT_SSL_CERT_FILE`` context if set,
538+ otherwise ``True`` (default SSL verification via certifi)
539+ - ``"false"`` → ``False`` (no verification)
540+ - ``"/path/to/ca-bundle.crt"`` → ``SSLContext`` loading that CA file
541+ (takes precedence over ``AIOHTTP_CLIENT_SSL_CERT_FILE``)
542+
543+ This allows users with corporate or internal CAs to point Open WebUI
544+ at a custom CA bundle without disabling verification entirely.
545+ """
546+ lower = value .strip ().lower ()
547+ if lower == 'true' :
548+ # Use the global dedicated CA bundle if configured, otherwise default
549+ return _GLOBAL_SSL_CONTEXT if _GLOBAL_SSL_CONTEXT is not None else True
550+ if lower == 'false' :
551+ return False
552+ # Treat as a file path to a CA bundle (per-connection override)
553+ ctx = _build_ssl_context_from_file (value .strip ())
554+ if ctx is not None :
555+ return ctx
556+ # Path was invalid — fall back to default
557+ return _GLOBAL_SSL_CONTEXT if _GLOBAL_SSL_CONTEXT is not None else True
558+
559+
501560REQUESTS_VERIFY = os .getenv ('REQUESTS_VERIFY' , 'True' ).lower () == 'true'
502561
503562_aiohttp_timeout_raw = os .getenv ('AIOHTTP_CLIENT_TIMEOUT' , '' )
@@ -507,7 +566,10 @@ def parse_section(section):
507566 AIOHTTP_CLIENT_TIMEOUT = 300
508567
509568
510- AIOHTTP_CLIENT_SESSION_SSL = os .getenv ('AIOHTTP_CLIENT_SESSION_SSL' , 'True' ).lower () == 'true'
569+ # SSL verification for general outbound requests (OpenAI, OAuth, etc.).
570+ # Accepts "True", "False", or a path to a CA bundle file.
571+ # When "True", falls back to AIOHTTP_CLIENT_SSL_CERT_FILE if set.
572+ AIOHTTP_CLIENT_SESSION_SSL = _parse_ssl_env (os .getenv ('AIOHTTP_CLIENT_SESSION_SSL' , 'True' ))
511573
512574# When False (default), outbound HTTP requests do not follow 3xx redirects.
513575AIOHTTP_CLIENT_ALLOW_REDIRECTS = os .getenv ('AIOHTTP_CLIENT_ALLOW_REDIRECTS' , 'False' ).lower () == 'true'
@@ -533,7 +595,12 @@ def parse_section(section):
533595 AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
534596
535597
536- AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = os .getenv ('AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL' , 'True' ).lower () == 'true'
598+ # SSL verification for tool server connections specifically.
599+ # Accepts "True", "False", or a path to a CA bundle file.
600+ # When "True", falls back to AIOHTTP_CLIENT_SSL_CERT_FILE if set.
601+ AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = _parse_ssl_env (
602+ os .getenv ('AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL' , 'True' )
603+ )
537604
538605AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER = os .getenv ('AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER' , '' )
539606
0 commit comments