Add custom hostname option (#929)

<!--
Thanks for opening a PR! Your contribution is much appreciated.
In order to make sure your PR is handled as smoothly as possible we
request that you follow the checklist sections below.
Choose the right checklist for the change that you're making:
-->

## Description

Add `--host` / `-H` CLI argument to allow users to specify the host
address the UI should bind to. This allows for more flexibility so
people can bind only to `127.0.0.1` for example instead of the default
of `0.0.0.0` which exposes all interfaces.

Fixes # N/A

## Type of change

- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [ ] (N/A) I have commented my code, particularly in hard-to-understand
areas
- [ ] (N/A) I have added or updated the docstring for new or existing
methods
- [x] I have modified this PR to merge to the develop branch

---------

Co-authored-by: bobokun <12660469+bobokun@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Parsa Yazdani 2025-08-30 22:40:27 +10:00 committed by GitHub
parent 385d0c633d
commit 3bb4591437
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 8 deletions

View file

@ -3,6 +3,7 @@
| **Shell Command** | **Docker Environment Variable** | **Config Command** | **Description** | **Default Value** |
|:---------------------------------------:|:-------------------------------:|:---------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------:|
| `-ws` or `--web-server` | QBT_WEB_SERVER | N/A | Start the webUI server to handle command requests via HTTP API. | False |
| `-H` or `--host` | QBT_HOST | N/A | Hostname for the web server (default: 0.0.0.0). | 8080 |
| `-p` or `--port` | QBT_PORT | N/A | Port number for the web server (default: 8080). | 8080 |
| `-b` or `--base-url` | QBT_BASE_URL | N/A | Base URL path for the web UI (e.g., '/qbit-manage'). Default is empty (root). | "" |
| `-r` or`--run` | QBT_RUN | N/A | Run without the scheduler. Script will exit after completion. | False |

View file

@ -2,14 +2,14 @@
## Overview
qBit Manage provides a REST API that allows you to trigger commands via HTTP requests. The API server runs on port 8080 by default and can be configured using the `--port` option or `QBT_PORT` environment variable.
qBit Manage provides a REST API that allows you to trigger commands via HTTP requests. The API server runs at 8080, listening to all hostnames, by default and can be configured using the `--host` and `--port` options or `QBT_HOST` and `QBT_PORT` environment variables.
## Running the Web Server
### Command Line
```bash
python qbit_manage.py --web-server --port 8080
python qbit_manage.py --web-server --host 0.0.0.0 --port 8080
```
### Docker
@ -22,6 +22,7 @@ services:
container_name: qbit_manage
environment:
- QBT_WEB_SERVER=true # Enable web server
- QBT_HOST=0.0.0.0 # Set web server host
- QBT_PORT=8080 # Set web server port
ports:
- "8080:8080" # Map container port to host

View file

@ -56,6 +56,14 @@ parser.add_argument(
help="Start the webUI server to handle command requests via HTTP API. "
"Default: enabled on desktop (non-Docker) runs; disabled in Docker.",
)
parser.add_argument(
"-H",
"--host",
dest="host",
type=str,
default="0.0.0.0",
help="Hostname for the web server (default: 0.0.0.0).",
)
parser.add_argument(
"-p",
"--port",
@ -268,6 +276,7 @@ web_server = get_arg("QBT_WEB_SERVER", args.web_server, arg_bool=True)
# Auto-enable web server by default on non-Docker if not explicitly set via env/flag
if web_server is None and not is_docker:
web_server = True
host = get_arg("QBT_HOST", args.host, arg_int=True)
port = get_arg("QBT_PORT", args.port, arg_int=True)
base_url = get_arg("QBT_BASE_URL", args.base_url)
run = get_arg("QBT_RUN", args.run, arg_bool=True)
@ -338,6 +347,7 @@ for v in [
"debug",
"trace",
"web_server",
"host",
"port",
"base_url",
]:
@ -611,6 +621,7 @@ def end():
# Define the web server target at module level (required for Windows spawn/frozen PyInstaller)
def run_web_server(
host,
port,
process_args,
is_running,
@ -642,7 +653,7 @@ def run_web_server(
# Configure and run uvicorn
import uvicorn as _uvicorn
config = _uvicorn.Config(app, host="0.0.0.0", port=port, log_level="info", access_log=False)
config = _uvicorn.Config(app, host=host, port=port, log_level="info", access_log=False)
server = _uvicorn.Server(config)
server.run()
except KeyboardInterrupt:
@ -751,12 +762,12 @@ def main():
logger.debug(f"Unknown CLI arguments ignored: {_unknown_cli}")
logger.separator("Starting Web Server")
logger.info(f"Web API server running on http://0.0.0.0:{port}")
logger.info(f"Web API server running on http://{host}:{port}")
if base_url:
logger.info(f"Access the WebUI at http://localhost:{port}/{base_url.lstrip('/')}")
logger.info(f"Root path http://localhost:{port}/ will redirect to the WebUI")
logger.info(f"Access the WebUI at http://{host}:{port}/{base_url.lstrip('/')}")
logger.info(f"Root path http://{host}:{port}/ will redirect to the WebUI")
else:
logger.info(f"Access the WebUI at http://localhost:{port}")
logger.info(f"Access the WebUI at http://{host}:{port}")
# Create a copy of args to pass to the web server process
process_args = args.copy()
@ -765,6 +776,7 @@ def main():
web_process = multiprocessing.Process(
target=run_web_server,
args=(
host,
port,
process_args,
is_running,
@ -781,7 +793,7 @@ def main():
is_desktop_app = os.getenv("QBT_DESKTOP_APP", "").lower() == "true"
if not is_docker and not is_desktop_app:
try:
ui_url = f"http://127.0.0.1:{port}"
ui_url = f"http://{'127.0.0.1' if host == '0.0.0.0' else host}:{port}"
if base_url:
ui_url = f"{ui_url}/{base_url.lstrip('/')}"
threading.Thread(target=_open_browser_when_ready, args=(ui_url, logger), daemon=True).start()