# Backend.AI Web Server
[](https://badge.fury.io/gh/lablup%2Fbackend.ai-webserver) [](https://badge.fury.io/py/backend.ai-webserver)
A webapp hosting daemon which serves our `webui` as a SPA and proxies API requests
## Installation
Prepare a Python virtualenv (Python 3.9 or higher) and a Redis server (6.2 or higher).
```console
$ git clone https://github.com/lablup/backend.ai-webserver webserver
$ cd webserver
$ pip install -U -e .
$ cp webserver.sample.conf webserver.conf
```
## Mode
If `service.mode` is set "webui" (the default), the webserver handles
PWA-style fallbacks (e.g., serving `index.html` when there are no matching
files for the requested URL path).
The PWA must exclude `/server` and `/func` URL prefixes from its own routing
to work with the webserver's web sessions and the API proxy.
If it is set "static", the webserver serves the static files as-is,
without any fallbacks or hooking, while preserving the `/server` and `/func`
prefixed URLs and their functionalities.
If you want to serve web UI in webserver with "webui" mode, prepare static web UI source by choosing one of the followings.
### Option 1: Build web UI from source
Build **[backend.ai-webui](https://github.com/lablup/backend.ai-webui)** and copy all files under `build/bundle`
into the `src/ai/backend/web/static` directory.
### Option 2: Use pre-built web UI
To download and deploy web UI from pre-built source, do the following:
```console
cd src/ai/backend/web
curl --fail -sL https://github.com/lablup/backend.ai-webui/releases/download/v$TARGET_VERSION/backend.ai-webui-bundle-$TARGET_VERSION.zip > /tmp/bai-webui.zip
rm -rf static
mkdir static
cd static
unzip /tmp/bai-webui.zip
```
### Setup configuration for webserver
You don't have to write `config.toml` for the web UI as this webserver auto-generates it on-the-fly.
Edit `webserver.conf` to match with your environment.
## Usage
To execute web server, run command below. (for debugging, append a `--debug` flag)
```console
$ python -m ai.backend.web.server
```
Raw data
{
"_id": null,
"home_page": "https://github.com/lablup/backend.ai",
"name": "backend.ai-webserver",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.14,>=3.13",
"maintainer_email": null,
"keywords": null,
"author": "Lablup Inc. and contributors",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/8e/3b/bdebdbc27db935c85e34e195f92bc8ce52294ea64f99fd96af8dd771d095/backend_ai_webserver-25.11.0.tar.gz",
"platform": null,
"description": "# Backend.AI Web Server\n\n[](https://badge.fury.io/gh/lablup%2Fbackend.ai-webserver) [](https://badge.fury.io/py/backend.ai-webserver)\n\nA webapp hosting daemon which serves our `webui` as a SPA and proxies API requests\n\n\n## Installation\n\nPrepare a Python virtualenv (Python 3.9 or higher) and a Redis server (6.2 or higher).\n\n```console\n$ git clone https://github.com/lablup/backend.ai-webserver webserver\n$ cd webserver\n$ pip install -U -e .\n$ cp webserver.sample.conf webserver.conf\n```\n\n## Mode\n\nIf `service.mode` is set \"webui\" (the default), the webserver handles\nPWA-style fallbacks (e.g., serving `index.html` when there are no matching\nfiles for the requested URL path).\nThe PWA must exclude `/server` and `/func` URL prefixes from its own routing\nto work with the webserver's web sessions and the API proxy.\n\nIf it is set \"static\", the webserver serves the static files as-is,\nwithout any fallbacks or hooking, while preserving the `/server` and `/func`\nprefixed URLs and their functionalities.\n\nIf you want to serve web UI in webserver with \"webui\" mode, prepare static web UI source by choosing one of the followings.\n\n### Option 1: Build web UI from source\n\nBuild **[backend.ai-webui](https://github.com/lablup/backend.ai-webui)** and copy all files under `build/bundle`\ninto the `src/ai/backend/web/static` directory.\n\n### Option 2: Use pre-built web UI\n\nTo download and deploy web UI from pre-built source, do the following:\n\n```console\ncd src/ai/backend/web\ncurl --fail -sL https://github.com/lablup/backend.ai-webui/releases/download/v$TARGET_VERSION/backend.ai-webui-bundle-$TARGET_VERSION.zip > /tmp/bai-webui.zip\nrm -rf static\nmkdir static\ncd static\nunzip /tmp/bai-webui.zip\n```\n### Setup configuration for webserver\n\nYou don't have to write `config.toml` for the web UI as this webserver auto-generates it on-the-fly.\n\nEdit `webserver.conf` to match with your environment.\n\n\n## Usage\n\nTo execute web server, run command below. (for debugging, append a `--debug` flag)\n\n\n```console\n$ python -m ai.backend.web.server\n```\n",
"bugtrack_url": null,
"license": "LGPLv3",
"summary": "Backend.AI WebUI Host",
"version": "25.11.0",
"project_urls": {
"Documentation": "https://docs.backend.ai/",
"Homepage": "https://github.com/lablup/backend.ai",
"Source": "https://github.com/lablup/backend.ai"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7f6dcccd7f4dfd10c3c4783b3cdda499f6d23db331b4d1f6d26150c3cf80b296",
"md5": "8bd4d2ea226d2eb0d7b665963b26452d",
"sha256": "7b514ce33994180b61d174e6d59e2ec17583366e880f00292a7f343185d8cfc5"
},
"downloads": -1,
"filename": "backend_ai_webserver-25.11.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8bd4d2ea226d2eb0d7b665963b26452d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.14,>=3.13",
"size": 26511421,
"upload_time": "2025-07-09T04:55:36",
"upload_time_iso_8601": "2025-07-09T04:55:36.417321Z",
"url": "https://files.pythonhosted.org/packages/7f/6d/cccd7f4dfd10c3c4783b3cdda499f6d23db331b4d1f6d26150c3cf80b296/backend_ai_webserver-25.11.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "8e3bbdebdbc27db935c85e34e195f92bc8ce52294ea64f99fd96af8dd771d095",
"md5": "c27cd183052a8316c3513368fbbc18fa",
"sha256": "c36953996a8a400aa655306bab324c431ddb3983919ab78528d151f1ae9e322c"
},
"downloads": -1,
"filename": "backend_ai_webserver-25.11.0.tar.gz",
"has_sig": false,
"md5_digest": "c27cd183052a8316c3513368fbbc18fa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.14,>=3.13",
"size": 25800387,
"upload_time": "2025-07-09T04:55:54",
"upload_time_iso_8601": "2025-07-09T04:55:54.488638Z",
"url": "https://files.pythonhosted.org/packages/8e/3b/bdebdbc27db935c85e34e195f92bc8ce52294ea64f99fd96af8dd771d095/backend_ai_webserver-25.11.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-09 04:55:54",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "lablup",
"github_project": "backend.ai",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "aiodataloader",
"specs": [
[
"~=",
"0.4.2"
]
]
},
{
"name": "aiodocker",
"specs": [
[
"==",
"0.24.0"
]
]
},
{
"name": "aiofiles",
"specs": [
[
"~=",
"24.1.0"
]
]
},
{
"name": "aiohttp",
"specs": [
[
"~=",
"3.11.16"
]
]
},
{
"name": "aiohttp_cors",
"specs": [
[
"~=",
"0.8.1"
]
]
},
{
"name": "aiohttp_jinja2",
"specs": [
[
"~=",
"1.6"
]
]
},
{
"name": "aiohttp_sse",
"specs": [
[
">=",
"2.2"
]
]
},
{
"name": "aiodns",
"specs": [
[
"==",
"3.2"
]
]
},
{
"name": "aiomonitor",
"specs": [
[
"~=",
"0.7.0"
]
]
},
{
"name": "aioresponses",
"specs": [
[
">=",
"0.7.3"
]
]
},
{
"name": "aiosqlite",
"specs": [
[
"~=",
"0.21.0"
]
]
},
{
"name": "aiosignal",
"specs": [
[
"==",
"1.3.2"
]
]
},
{
"name": "aiotools",
"specs": [
[
"~=",
"1.9.0"
]
]
},
{
"name": "aiotusclient",
"specs": [
[
"~=",
"0.1.4"
]
]
},
{
"name": "alembic",
"specs": [
[
"~=",
"1.13.2"
]
]
},
{
"name": "appdirs",
"specs": [
[
"~=",
"1.4.4"
]
]
},
{
"name": "async_timeout",
"specs": [
[
"~=",
"4.0"
]
]
},
{
"name": "asyncpg",
"specs": [
[
">=",
"0.29.0"
]
]
},
{
"name": "asynctest",
"specs": [
[
">=",
"0.13.0"
]
]
},
{
"name": "asyncudp",
"specs": [
[
">=",
"0.11"
]
]
},
{
"name": "attrs",
"specs": [
[
">=",
"25.3"
]
]
},
{
"name": "bcrypt",
"specs": [
[
"~=",
"4.2.0"
]
]
},
{
"name": "boto3",
"specs": [
[
"~=",
"1.35"
]
]
},
{
"name": "cachetools",
"specs": [
[
"~=",
"5.5.0"
]
]
},
{
"name": "callosum",
"specs": [
[
"~=",
"1.0.3"
]
]
},
{
"name": "cattrs",
"specs": [
[
"~=",
"24.1.1"
]
]
},
{
"name": "click",
"specs": [
[
"~=",
"8.1.7"
]
]
},
{
"name": "coloredlogs",
"specs": [
[
"~=",
"15.0"
]
]
},
{
"name": "colorama",
"specs": [
[
">=",
"0.4.6"
]
]
},
{
"name": "cryptography",
"specs": [
[
">=",
"44.0.2"
]
]
},
{
"name": "dataclasses-json",
"specs": [
[
"~=",
"0.5.7"
]
]
},
{
"name": "faker",
"specs": [
[
"~=",
"24.7.1"
]
]
},
{
"name": "graphene",
"specs": [
[
"~=",
"3.3.0"
]
]
},
{
"name": "graypy",
"specs": [
[
"==",
"2.1.0"
]
]
},
{
"name": "humanize",
"specs": [
[
">=",
"3.1.0"
]
]
},
{
"name": "ifaddr",
"specs": [
[
"~=",
"0.2"
]
]
},
{
"name": "inquirer",
"specs": [
[
"~=",
"3.3.0"
]
]
},
{
"name": "janus",
"specs": [
[
"~=",
"2.0"
]
]
},
{
"name": "Jinja2",
"specs": [
[
"~=",
"3.1.6"
]
]
},
{
"name": "jupyter-client",
"specs": [
[
">=",
"8.6"
]
]
},
{
"name": "kubernetes",
"specs": [
[
"~=",
"10.0.0"
]
]
},
{
"name": "kubernetes-asyncio",
"specs": [
[
"~=",
"9.1.0"
]
]
},
{
"name": "lark",
"specs": [
[
"~=",
"1.1.5"
]
]
},
{
"name": "more-itertools",
"specs": [
[
"~=",
"10.5.0"
]
]
},
{
"name": "msgpack",
"specs": [
[
"~=",
"1.1.0"
]
]
},
{
"name": "multidict",
"specs": [
[
"~=",
"6.2.0"
]
]
},
{
"name": "namedlist",
"specs": [
[
"~=",
"1.8"
]
]
},
{
"name": "networkx",
"specs": [
[
"~=",
"3.3.0"
]
]
},
{
"name": "orjson",
"specs": [
[
"~=",
"3.10.16"
]
]
},
{
"name": "opentelemetry-api",
"specs": [
[
"~=",
"1.33.1"
]
]
},
{
"name": "opentelemetry-sdk",
"specs": [
[
"~=",
"1.33.1"
]
]
},
{
"name": "opentelemetry-exporter-otlp-proto-grpc",
"specs": [
[
"~=",
"1.33.1"
]
]
},
{
"name": "opentelemetry-instrumentation-aiohttp-client",
"specs": [
[
"~=",
"0.54b1"
]
]
},
{
"name": "opentelemetry-instrumentation-aiohttp-server",
"specs": [
[
"~=",
"0.54b1"
]
]
},
{
"name": "opentelemetry-instrumentation-logging",
"specs": [
[
"~=",
"0.54b1"
]
]
},
{
"name": "pexpect",
"specs": [
[
"~=",
"4.8"
]
]
},
{
"name": "prometheus-client",
"specs": [
[
"~=",
"0.21.1"
]
]
},
{
"name": "psutil",
"specs": [
[
"~=",
"7.0"
]
]
},
{
"name": "pycryptodome",
"specs": [
[
">=",
"3.20.0"
]
]
},
{
"name": "pyhumps",
"specs": [
[
"~=",
"3.8.0"
]
]
},
{
"name": "pyroscope-io",
"specs": [
[
"~=",
"0.8.8"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
">=",
"2.9"
]
]
},
{
"name": "python-dotenv",
"specs": [
[
"~=",
"0.20.0"
]
]
},
{
"name": "python-json-logger",
"specs": [
[
"~=",
"3.2.0"
]
]
},
{
"name": "pyzmq",
"specs": [
[
"~=",
"26.4"
]
]
},
{
"name": "PyJWT",
"specs": [
[
"~=",
"2.10.1"
]
]
},
{
"name": "PyYAML",
"specs": [
[
"~=",
"6.0"
]
]
},
{
"name": "pydantic",
"specs": [
[
"~=",
"2.11.3"
]
]
},
{
"name": "packaging",
"specs": [
[
">=",
"24.1"
]
]
},
{
"name": "hiredis",
"specs": [
[
">=",
"3.0.0"
]
]
},
{
"name": "redis",
"specs": [
[
"==",
"4.5.5"
]
]
},
{
"name": "rich",
"specs": [
[
"~=",
"13.6"
]
]
},
{
"name": "ruamel.yaml",
"specs": [
[
"~=",
"0.18.10"
]
]
},
{
"name": "SQLAlchemy",
"specs": [
[
"~=",
"1.4.54"
]
]
},
{
"name": "setproctitle",
"specs": [
[
"~=",
"1.3.5"
]
]
},
{
"name": "setuptools",
"specs": [
[
"~=",
"80.0.0"
]
]
},
{
"name": "tabulate",
"specs": [
[
"~=",
"0.8.9"
]
]
},
{
"name": "temporenc",
"specs": [
[
"~=",
"0.1.0"
]
]
},
{
"name": "tenacity",
"specs": [
[
">=",
"9.0"
]
]
},
{
"name": "toml",
"specs": [
[
"~=",
"0.10.2"
]
]
},
{
"name": "tomli",
"specs": [
[
"~=",
"2.0.1"
]
]
},
{
"name": "tomlkit",
"specs": [
[
"~=",
"0.13.2"
]
]
},
{
"name": "tqdm",
"specs": [
[
"~=",
"4.67.1"
]
]
},
{
"name": "trafaret",
"specs": [
[
"~=",
"2.1"
]
]
},
{
"name": "treelib",
"specs": [
[
"~=",
"1.7.0"
]
]
},
{
"name": "typeguard",
"specs": [
[
"~=",
"4.3"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"~=",
"4.11"
]
]
},
{
"name": "textual",
"specs": [
[
"~=",
"0.79.1"
]
]
},
{
"name": "uvloop",
"specs": [
[
"~=",
"0.21"
]
]
},
{
"name": "valkey-glide",
"specs": [
[
"~=",
"2.0.1"
]
]
},
{
"name": "yarl",
"specs": [
[
"~=",
"1.19.0"
]
]
},
{
"name": "zipstream-new",
"specs": [
[
"~=",
"1.1.8"
]
]
},
{
"name": "pytest",
"specs": [
[
">=",
"8.3.3"
]
]
},
{
"name": "pytest-aiohttp",
"specs": [
[
"~=",
"1.0.5"
]
]
},
{
"name": "pytest-dependency",
"specs": [
[
">=",
"0.6.0"
]
]
},
{
"name": "types-six",
"specs": []
},
{
"name": "types-setuptools",
"specs": []
},
{
"name": "types-python-dateutil",
"specs": []
},
{
"name": "types-aiofiles",
"specs": []
},
{
"name": "types-cachetools",
"specs": []
},
{
"name": "types-Jinja2",
"specs": []
},
{
"name": "types-PyYAML",
"specs": []
},
{
"name": "types-redis",
"specs": []
},
{
"name": "types-tabulate",
"specs": []
},
{
"name": "types-toml",
"specs": []
},
{
"name": "backend.ai-krunner-alpine",
"specs": [
[
"==",
"5.4.0"
]
]
},
{
"name": "backend.ai-krunner-static-gnu",
"specs": [
[
"==",
"4.4.0"
]
]
},
{
"name": "etcd-client-py",
"specs": [
[
"~=",
"0.4.0"
]
]
}
],
"lcname": "backend.ai-webserver"
}