feat: Enable SSL flags for local development (#7060)
* ssl-support: Enable SSL for local development to simulate a production-like environment. This would allow testing features requiring SSL during development, third party integrations, and allowing easier SSL integration without WAFs and reverse proxies * rebase * rebase fixes --------- Co-authored-by: lpetkov <lpetkov@pros.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com> Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com>
This commit is contained in:
parent
3fccfd75ed
commit
58b9551758
4 changed files with 33 additions and 12 deletions
|
|
@ -122,6 +122,8 @@ python -m langflow run [OPTIONS]
|
|||
| <Link id="run-auto-saving-interval"/>`--auto-saving-interval` | `1000` | Integer | Set the interval for flow auto-saving in milliseconds.<br/>See [`LANGFLOW_AUTO_SAVING_INTERVAL` variable](./environment-variables.md#LANGFLOW_AUTO_SAVING_INTERVAL). |
|
||||
| <Link id="run-health-check-max-retries"/>`--health-check-max-retries` | `5` | Integer | Set the maximum number of retries for the health check. Use `--no-health-check-max-retries` to disable the maximum number of retries for the health check.<br/>See [`LANGFLOW_HEALTH_CHECK_MAX_RETRIES` variable](./environment-variables.md#LANGFLOW_HEALTH_CHECK_MAX_RETRIES). |
|
||||
| <Link id="run-max-file-size-upload"/>`--max-file-size-upload` | `100` | Integer | Set the maximum file size for the upload in megabytes.<br/>See [`LANGFLOW_MAX_FILE_SIZE_UPLOAD` variable](./environment-variables.md#LANGFLOW_MAX_FILE_SIZE_UPLOAD). |
|
||||
| <Link id="run-ssl-cert-file-path"/>`--ssl-cert-file-path` | Not set | String | Path to the SSL certificate file on the local system. |
|
||||
| <Link id="run-ssl-key-file-path"/>`--ssl-key-file-path` | Not set | String | Path to the SSL key file on the local system. |
|
||||
| <Link id="run-help"/>`--help` | *Not applicable* | *Not applicable* | Display information about the command usage and its options and arguments. |
|
||||
|
||||
### langflow superuser
|
||||
|
|
|
|||
|
|
@ -226,9 +226,11 @@ The following table lists the environment variables supported by Langflow.
|
|||
| <Link id="LANGFLOW_LOAD_FLOWS_PATH"/><span class="env-prefix">LANGFLOW_</span>LOAD_FLOWS_PATH | String | Not set | Path to a directory containing flow JSON files to be loaded on startup. Note that this feature only works if <span class="env-prefix">LANGFLOW_</span>AUTO_LOGIN is enabled. |
|
||||
| <Link id="LANGFLOW_WORKER_TIMEOUT"/><span class="env-prefix">LANGFLOW_</span>WORKER_TIMEOUT | Integer | `300` | Worker timeout in seconds.<br/>See [`--worker-timeout` option](./configuration-cli.md#run-worker-timeout). |
|
||||
| <Link id="LANGFLOW_WORKERS"/><span class="env-prefix">LANGFLOW_</span>WORKERS | Integer | `1` | Number of worker processes.<br/>See [`--workers` option](./configuration-cli.md#run-workers). |
|
||||
|
||||
| <Link id="LANGFLOW_SSL_CERT_FILE"/><span class="env-prefix">LANGFLOW_</span>SSL_CERT_FILE | String | Not set | Path to the SSL certificate file on the local system. |
|
||||
| <Link id="LANGFLOW_SSL_KEY_FILE"/><span class="env-prefix">LANGFLOW_</span>SSL_KEY_FILE | String | Not set | Path to the SSL key file on the local system. |
|
||||
</div>
|
||||
|
||||
|
||||
## Configure .env, override.conf, and tasks.json files
|
||||
|
||||
The following examples show how to configure Langflow using environment variables in different scenarios.
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@ def run(
|
|||
help="Defines the polling interval for the webhook.",
|
||||
show_default=False,
|
||||
),
|
||||
ssl_cert_file_path: str | None = typer.Option(
|
||||
None, help="Defines the SSL certificate file path.", show_default=False
|
||||
),
|
||||
ssl_key_file_path: str | None = typer.Option(None, help="Defines the SSL key file path.", show_default=False),
|
||||
) -> None:
|
||||
"""Run Langflow."""
|
||||
# Register SIGTERM handler
|
||||
|
|
@ -202,6 +206,8 @@ def run(
|
|||
log_level = settings_service.settings.log_level
|
||||
frontend_path = settings_service.settings.frontend_path
|
||||
backend_only = settings_service.settings.backend_only
|
||||
ssl_cert_file_path = settings_service.settings.ssl_cert_file if ssl_cert_file_path is None else ssl_cert_file_path
|
||||
ssl_key_file_path = settings_service.settings.ssl_key_file if ssl_key_file_path is None else ssl_key_file_path
|
||||
|
||||
# create path object if frontend_path is provided
|
||||
static_files_dir: Path | None = Path(frontend_path) if frontend_path else None
|
||||
|
|
@ -215,7 +221,10 @@ def run(
|
|||
"bind": f"{host}:{port}",
|
||||
"workers": get_number_of_workers(workers),
|
||||
"timeout": worker_timeout,
|
||||
"certfile": ssl_cert_file_path,
|
||||
"keyfile": ssl_key_file_path,
|
||||
}
|
||||
protocol = "https" if options["keyfile"] and options["certfile"] else "http"
|
||||
|
||||
# Define an env variable to know if we are just testing the server
|
||||
if "pytest" in sys.modules:
|
||||
|
|
@ -226,10 +235,10 @@ def run(
|
|||
# Run using uvicorn on MacOS and Windows
|
||||
# Windows doesn't support gunicorn
|
||||
# MacOS requires an env variable to be set to use gunicorn
|
||||
run_on_windows(host, port, log_level, options, app)
|
||||
run_on_windows(host, port, log_level, options, app, protocol)
|
||||
else:
|
||||
# Run using gunicorn on Linux
|
||||
process = run_on_mac_or_linux(host, port, log_level, options, app)
|
||||
process = run_on_mac_or_linux(host, port, log_level, options, app, protocol)
|
||||
if open_browser and not backend_only:
|
||||
click.launch(f"http://{host}:{port}")
|
||||
if process:
|
||||
|
|
@ -250,12 +259,14 @@ def run(
|
|||
raise typer.Exit(1) from e
|
||||
|
||||
|
||||
def wait_for_server_ready(host, port) -> None:
|
||||
def wait_for_server_ready(host, port, protocol) -> None:
|
||||
"""Wait for the server to become ready by polling the health endpoint."""
|
||||
status_code = 0
|
||||
while status_code != httpx.codes.OK:
|
||||
try:
|
||||
status_code = httpx.get(f"http://{host}:{port}/health").status_code
|
||||
status_code = httpx.get(
|
||||
f"{protocol}://{host}:{port}/health", verify=host not in ("127.0.0.1", "localhost")
|
||||
).status_code
|
||||
except HTTPError:
|
||||
time.sleep(1)
|
||||
except Exception: # noqa: BLE001
|
||||
|
|
@ -263,18 +274,18 @@ def wait_for_server_ready(host, port) -> None:
|
|||
time.sleep(1)
|
||||
|
||||
|
||||
def run_on_mac_or_linux(host, port, log_level, options, app):
|
||||
def run_on_mac_or_linux(host, port, log_level, options, app, protocol):
|
||||
webapp_process = Process(target=run_langflow, args=(host, port, log_level, options, app))
|
||||
webapp_process.start()
|
||||
wait_for_server_ready(host, port)
|
||||
wait_for_server_ready(host, port, protocol)
|
||||
|
||||
print_banner(host, port)
|
||||
print_banner(host, port, protocol)
|
||||
return webapp_process
|
||||
|
||||
|
||||
def run_on_windows(host, port, log_level, options, app) -> None:
|
||||
def run_on_windows(host, port, log_level, options, app, protocol) -> None:
|
||||
"""Run the Langflow server on Windows."""
|
||||
print_banner(host, port)
|
||||
print_banner(host, port, protocol)
|
||||
run_langflow(host, port, log_level, options, app)
|
||||
|
||||
|
||||
|
|
@ -358,7 +369,7 @@ def stylize_text(text: str, to_style: str, *, is_prerelease: bool) -> str:
|
|||
return text.replace(to_style, styled_text)
|
||||
|
||||
|
||||
def print_banner(host: str, port: int) -> None:
|
||||
def print_banner(host: str, port: int, protocol: str) -> None:
|
||||
notices = []
|
||||
package_names = [] # Track package names for pip install instructions
|
||||
is_pre_release = False # Track if any package is a pre-release
|
||||
|
|
@ -398,7 +409,7 @@ def print_banner(host: str, port: int) -> None:
|
|||
"We collect anonymous usage data to improve Langflow.\n"
|
||||
"You can opt-out by setting [bold]DO_NOT_TRACK=true[/bold] in your environment."
|
||||
)
|
||||
access_link = f"Access [link=http://{host}:{port}]http://{host}:{port}[/link]"
|
||||
access_link = f"Access [link={protocol}://{host}:{port}]{protocol}://{host}:{port}[/link]"
|
||||
|
||||
panel_content = "\n\n".join([title, *styled_notices, info_text, telemetry_text, access_link])
|
||||
panel = Panel(panel_content, box=box.ROUNDED, border_style="blue", expand=False)
|
||||
|
|
@ -416,6 +427,8 @@ def run_langflow(host, port, log_level, options, app) -> None:
|
|||
port=port,
|
||||
log_level=log_level.lower(),
|
||||
loop="asyncio",
|
||||
ssl_keyfile=options["keyfile"],
|
||||
ssl_certfile=options["certfile"],
|
||||
)
|
||||
else:
|
||||
from langflow.server import LangflowApplication
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ class Settings(BaseSettings):
|
|||
"""The polling interval for the webhook in ms."""
|
||||
fs_flows_polling_interval: int = 10000
|
||||
"""The polling interval in milliseconds for synchronizing flows from the file system."""
|
||||
ssl_cert_file: str | None = None
|
||||
"""Path to the SSL certificate file on the local system."""
|
||||
ssl_key_file: str | None = None
|
||||
"""Path to the SSL key file on the local system."""
|
||||
|
||||
# MCP Server
|
||||
mcp_server_enabled: bool = True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue