diff --git a/surfsense_backend/.env.example b/surfsense_backend/.env.example index 9a66a43a9..2fd950ecd 100644 --- a/surfsense_backend/.env.example +++ b/surfsense_backend/.env.example @@ -3,45 +3,78 @@ DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/surfsense SECRET_KEY=SECRET NEXT_FRONTEND_URL=http://localhost:3000 -#Auth +# Auth AUTH_TYPE=GOOGLE or LOCAL # For Google Auth Only GOOGLE_OAUTH_CLIENT_ID=924507538m GOOGLE_OAUTH_CLIENT_SECRET=GOCSV -#Embedding Model +# Embedding Model EMBEDDING_MODEL=mixedbread-ai/mxbai-embed-large-v1 RERANKERS_MODEL_NAME=ms-marco-MiniLM-L-12-v2 RERANKERS_MODEL_TYPE=flashrank -#LiteLLM TTS Provider: https://docs.litellm.ai/docs/text_to_speech#supported-providers +# LiteLLM TTS Provider: https://docs.litellm.ai/docs/text_to_speech#supported-providers TTS_SERVICE=openai/tts-1 -#Respective TTS Service API +# Respective TTS Service API TTS_SERVICE_API_KEY= -#OPTIONAL: TTS Provider API Base +# OPTIONAL: TTS Provider API Base TTS_SERVICE_API_BASE= -#LiteLLM STT Provider: https://docs.litellm.ai/docs/audio_transcription#supported-providers +# LiteLLM STT Provider: https://docs.litellm.ai/docs/audio_transcription#supported-providers STT_SERVICE=openai/whisper-1 -#Respective STT Service API +# Respective STT Service API STT_SERVICE_API_KEY="" -#OPTIONAL: STT Provider API Base +# OPTIONAL: STT Provider API Base STT_SERVICE_API_BASE= FIRECRAWL_API_KEY=fcr-01J0000000000000000000000 -#File Parser Service +# File Parser Service ETL_SERVICE=UNSTRUCTURED or LLAMACLOUD UNSTRUCTURED_API_KEY=Tpu3P0U8iy LLAMA_CLOUD_API_KEY=llx-nnn -#OPTIONAL: Add these for LangSmith Observability +# OPTIONAL: Add these for LangSmith Observability LANGSMITH_TRACING=true LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY=lsv2_pt_..... LANGSMITH_PROJECT=surfsense +# Uvicorn Server Configuration +# Full documentation for Uvicorn options can be found at: https://www.uvicorn.org/#command-line-options +UVICORN_HOST="0.0.0.0" +UVICORN_PORT=8000 +UVICORN_LOG_LEVEL=info +# OPTIONAL: Advanced Uvicorn Options (uncomment to use) +# UVICORN_PROXY_HEADERS=false +# UVICORN_FORWARDED_ALLOW_IPS="127.0.0.1" +# UVICORN_WORKERS=1 +# UVICORN_ACCESS_LOG=true +# UVICORN_LOOP="auto" +# UVICORN_HTTP="auto" +# UVICORN_WS="auto" +# UVICORN_LIFESPAN="auto" +# UVICORN_LOG_CONFIG="" +# UVICORN_SERVER_HEADER=true +# UVICORN_DATE_HEADER=true +# UVICORN_LIMIT_CONCURRENCY= +# UVICORN_LIMIT_MAX_REQUESTS= +# UVICORN_TIMEOUT_KEEP_ALIVE=5 +# UVICORN_TIMEOUT_NOTIFY=30 +# UVICORN_SSL_KEYFILE="" +# UVICORN_SSL_CERTFILE="" +# UVICORN_SSL_KEYFILE_PASSWORD="" +# UVICORN_SSL_VERSION="" +# UVICORN_SSL_CERT_REQS="" +# UVICORN_SSL_CA_CERTS="" +# UVICORN_SSL_CIPHERS="" +# UVICORN_HEADERS="" +# UVICORN_USE_COLORS=true +# UVICORN_UDS="" +# UVICORN_FD="" +# UVICORN_ROOT_PATH="" diff --git a/surfsense_backend/app/config/uvicorn.py b/surfsense_backend/app/config/uvicorn.py new file mode 100644 index 000000000..f7086e122 --- /dev/null +++ b/surfsense_backend/app/config/uvicorn.py @@ -0,0 +1,82 @@ +import os + +def _parse_bool(value): + """Parse boolean value from string.""" + return value.lower() == "true" if value else False + +def _parse_int(value, var_name): + """Parse integer value with error handling.""" + try: + return int(value) + except ValueError: + raise ValueError(f"Invalid integer value for {var_name}: {value}") + +def _parse_headers(value): + """Parse headers from comma-separated string.""" + try: + return [ + tuple(h.split(":", 1)) + for h in value.split(",") + if ":" in h + ] + except Exception: + raise ValueError(f"Invalid headers format: {value}") + + +def load_uvicorn_config(args=None): + """ + Load Uvicorn configuration from environment variables and CLI args. + Returns a dict suitable for passing to uvicorn.Config. + """ + config_kwargs = dict( + app="app.app:app", + host=os.getenv("UVICORN_HOST", "0.0.0.0"), + port=int(os.getenv("UVICORN_PORT", 8000)), + log_level=os.getenv("UVICORN_LOG_LEVEL", "info"), + reload=args.reload if args else False, + reload_dirs=["app"] if (args and args.reload) else None, + ) + + # Configuration mapping for advanced options + config_mapping = { + "UVICORN_PROXY_HEADERS": ("proxy_headers", _parse_bool), + "UVICORN_FORWARDED_ALLOW_IPS": ("forwarded_allow_ips", str), + "UVICORN_WORKERS": ("workers", lambda x: _parse_int(x, "UVICORN_WORKERS")), + "UVICORN_ACCESS_LOG": ("access_log", _parse_bool), + "UVICORN_LOOP": ("loop", str), + "UVICORN_HTTP": ("http", str), + "UVICORN_WS": ("ws", str), + "UVICORN_LIFESPAN": ("lifespan", str), + "UVICORN_ENV_FILE": ("env_file", str), + "UVICORN_LOG_CONFIG": ("log_config", str), + "UVICORN_SERVER_HEADER": ("server_header", _parse_bool), + "UVICORN_DATE_HEADER": ("date_header", _parse_bool), + "UVICORN_LIMIT_CONCURRENCY": ("limit_concurrency", lambda x: _parse_int(x, "UVICORN_LIMIT_CONCURRENCY")), + "UVICORN_LIMIT_MAX_REQUESTS": ("limit_max_requests", lambda x: _parse_int(x, "UVICORN_LIMIT_MAX_REQUESTS")), + "UVICORN_TIMEOUT_KEEP_ALIVE": ("timeout_keep_alive", lambda x: _parse_int(x, "UVICORN_TIMEOUT_KEEP_ALIVE")), + "UVICORN_TIMEOUT_NOTIFY": ("timeout_notify", lambda x: _parse_int(x, "UVICORN_TIMEOUT_NOTIFY")), + "UVICORN_SSL_KEYFILE": ("ssl_keyfile", str), + "UVICORN_SSL_CERTFILE": ("ssl_certfile", str), + "UVICORN_SSL_KEYFILE_PASSWORD": ("ssl_keyfile_password", str), + "UVICORN_SSL_VERSION": ("ssl_version", lambda x: _parse_int(x, "UVICORN_SSL_VERSION")), + "UVICORN_SSL_CERT_REQS": ("ssl_cert_reqs", lambda x: _parse_int(x, "UVICORN_SSL_CERT_REQS")), + "UVICORN_SSL_CA_CERTS": ("ssl_ca_certs", str), + "UVICORN_SSL_CIPHERS": ("ssl_ciphers", str), + "UVICORN_HEADERS": ("headers", _parse_headers), + "UVICORN_USE_COLORS": ("use_colors", _parse_bool), + "UVICORN_UDS": ("uds", str), + "UVICORN_FD": ("fd", lambda x: _parse_int(x, "UVICORN_FD")), + "UVICORN_ROOT_PATH": ("root_path", str), + } + + # Process advanced configuration options + for env_var, (config_key, parser) in config_mapping.items(): + value = os.getenv(env_var) + if value: + try: + config_kwargs[config_key] = parser(value) + except ValueError as e: + raise ValueError(f"Configuration error for {env_var}: {e}") + + + return config_kwargs diff --git a/surfsense_backend/main.py b/surfsense_backend/main.py index 81ef52049..f44b7d697 100644 --- a/surfsense_backend/main.py +++ b/surfsense_backend/main.py @@ -1,22 +1,24 @@ import uvicorn import argparse import logging +from dotenv import load_dotenv +from app.config.uvicorn import load_uvicorn_config logging.basicConfig( level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%Y-%m-%d %H:%M:%S' + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", ) +load_dotenv() + if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Run the SurfSense application') - parser.add_argument('--reload', action='store_true', help='Enable hot reloading') + parser = argparse.ArgumentParser(description="Run the SurfSense application") + parser.add_argument("--reload", action="store_true", help="Enable hot reloading") args = parser.parse_args() - uvicorn.run( - "app.app:app", - host="0.0.0.0", - log_level="info", - reload=args.reload, - reload_dirs=["app"] - ) + config_kwargs = load_uvicorn_config(args) + config = uvicorn.Config(**config_kwargs) + server = uvicorn.Server(config) + + server.run() diff --git a/surfsense_web/content/docs/docker-installation.mdx b/surfsense_web/content/docs/docker-installation.mdx index ca91d218f..0a5ba8a3a 100644 --- a/surfsense_web/content/docs/docker-installation.mdx +++ b/surfsense_web/content/docs/docker-installation.mdx @@ -110,6 +110,42 @@ Before you begin, ensure you have: | LANGSMITH_API_KEY | Your LangSmith API key | | LANGSMITH_PROJECT | LangSmith project name (e.g., `surfsense`) | +**Backend Uvicorn Server Configuration:** +| ENV VARIABLE | DESCRIPTION | DEFAULT VALUE | +|------------------------------|---------------------------------------------|---------------| +| UVICORN_HOST | Host address to bind the server | 0.0.0.0 | +| UVICORN_PORT | Port to run the backend API | 8000 | +| UVICORN_LOG_LEVEL | Logging level (e.g., info, debug, warning) | info | +| UVICORN_PROXY_HEADERS | Enable/disable proxy headers | false | +| UVICORN_FORWARDED_ALLOW_IPS | Comma-separated list of allowed IPs | 127.0.0.1 | +| UVICORN_WORKERS | Number of worker processes | 1 | +| UVICORN_ACCESS_LOG | Enable/disable access log (true/false) | true | +| UVICORN_LOOP | Event loop implementation | auto | +| UVICORN_HTTP | HTTP protocol implementation | auto | +| UVICORN_WS | WebSocket protocol implementation | auto | +| UVICORN_LIFESPAN | Lifespan implementation | auto | +| UVICORN_LOG_CONFIG | Path to logging config file or empty string | | +| UVICORN_SERVER_HEADER | Enable/disable Server header | true | +| UVICORN_DATE_HEADER | Enable/disable Date header | true | +| UVICORN_LIMIT_CONCURRENCY | Max concurrent connections | | +| UVICORN_LIMIT_MAX_REQUESTS | Max requests before worker restart | | +| UVICORN_TIMEOUT_KEEP_ALIVE | Keep-alive timeout (seconds) | 5 | +| UVICORN_TIMEOUT_NOTIFY | Worker shutdown notification timeout (sec) | 30 | +| UVICORN_SSL_KEYFILE | Path to SSL key file | | +| UVICORN_SSL_CERTFILE | Path to SSL certificate file | | +| UVICORN_SSL_KEYFILE_PASSWORD | Password for SSL key file | | +| UVICORN_SSL_VERSION | SSL version | | +| UVICORN_SSL_CERT_REQS | SSL certificate requirements | | +| UVICORN_SSL_CA_CERTS | Path to CA certificates file | | +| UVICORN_SSL_CIPHERS | SSL ciphers | | +| UVICORN_HEADERS | Comma-separated list of headers | | +| UVICORN_USE_COLORS | Enable/disable colored logs | true | +| UVICORN_UDS | Unix domain socket path | | +| UVICORN_FD | File descriptor to bind to | | +| UVICORN_ROOT_PATH | Root path for the application | | + +For more details, see the [Uvicorn documentation](https://www.uvicorn.org/#command-line-options). + ### Frontend Environment Variables | ENV VARIABLE | DESCRIPTION | diff --git a/surfsense_web/content/docs/manual-installation.mdx b/surfsense_web/content/docs/manual-installation.mdx index a6a104a0b..1f58783dc 100644 --- a/surfsense_web/content/docs/manual-installation.mdx +++ b/surfsense_web/content/docs/manual-installation.mdx @@ -80,6 +80,44 @@ Edit the `.env` file and set the following variables: | LANGSMITH_API_KEY | Your LangSmith API key | | LANGSMITH_PROJECT | LangSmith project name (e.g., `surfsense`) | +**Uvicorn Server Configuration** +| ENV VARIABLE | DESCRIPTION | DEFAULT VALUE | +|------------------------------|---------------------------------------------|---------------| +| UVICORN_HOST | Host address to bind the server | 0.0.0.0 | +| UVICORN_PORT | Port to run the backend API | 8000 | +| UVICORN_LOG_LEVEL | Logging level (e.g., info, debug, warning) | info | +| UVICORN_PROXY_HEADERS | Enable/disable proxy headers | false | +| UVICORN_FORWARDED_ALLOW_IPS | Comma-separated list of allowed IPs | 127.0.0.1 | +| UVICORN_WORKERS | Number of worker processes | 1 | +| UVICORN_ACCESS_LOG | Enable/disable access log (true/false) | true | +| UVICORN_LOOP | Event loop implementation | auto | +| UVICORN_HTTP | HTTP protocol implementation | auto | +| UVICORN_WS | WebSocket protocol implementation | auto | +| UVICORN_LIFESPAN | Lifespan implementation | auto | +| UVICORN_LOG_CONFIG | Path to logging config file or empty string | | +| UVICORN_SERVER_HEADER | Enable/disable Server header | true | +| UVICORN_DATE_HEADER | Enable/disable Date header | true | +| UVICORN_LIMIT_CONCURRENCY | Max concurrent connections | | +| UVICORN_LIMIT_MAX_REQUESTS | Max requests before worker restart | | +| UVICORN_TIMEOUT_KEEP_ALIVE | Keep-alive timeout (seconds) | 5 | +| UVICORN_TIMEOUT_NOTIFY | Worker shutdown notification timeout (sec) | 30 | +| UVICORN_SSL_KEYFILE | Path to SSL key file | | +| UVICORN_SSL_CERTFILE | Path to SSL certificate file | | +| UVICORN_SSL_KEYFILE_PASSWORD | Password for SSL key file | | +| UVICORN_SSL_VERSION | SSL version | | +| UVICORN_SSL_CERT_REQS | SSL certificate requirements | | +| UVICORN_SSL_CA_CERTS | Path to CA certificates file | | +| UVICORN_SSL_CIPHERS | SSL ciphers | | +| UVICORN_HEADERS | Comma-separated list of headers | | +| UVICORN_USE_COLORS | Enable/disable colored logs | true | +| UVICORN_UDS | Unix domain socket path | | +| UVICORN_FD | File descriptor to bind to | | +| UVICORN_ROOT_PATH | Root path for the application | | + +Refer to the `.env.example` file for all available Uvicorn options and their usage. Uncomment and set in your `.env` file as needed. + +For more details, see the [Uvicorn documentation](https://www.uvicorn.org/#command-line-options). + ### 2. Install Dependencies Install the backend dependencies using `uv`: