# 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/66/44/f219743aa89af29850810a23c0ca38570529814673ff7a30530eaa9c32c0/backend_ai_webserver-25.11.2.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.2",
"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": "1063c396a655afede2d914ce1fea11fd44df9dd397af1d2bf6157c4bfb281d27",
"md5": "5d887502da6f158f526c09b609a5b8e4",
"sha256": "2045a4f257a17cac10da7462ec3c7821e7faff37badfcc3c6baa84e787100e1f"
},
"downloads": -1,
"filename": "backend_ai_webserver-25.11.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5d887502da6f158f526c09b609a5b8e4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.14,>=3.13",
"size": 26511420,
"upload_time": "2025-07-15T16:26:38",
"upload_time_iso_8601": "2025-07-15T16:26:38.474718Z",
"url": "https://files.pythonhosted.org/packages/10/63/c396a655afede2d914ce1fea11fd44df9dd397af1d2bf6157c4bfb281d27/backend_ai_webserver-25.11.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "6644f219743aa89af29850810a23c0ca38570529814673ff7a30530eaa9c32c0",
"md5": "75544e46b9e9d1ddb0a5103da72e87b6",
"sha256": "9c09ae1b19d9cdd0b6a16fa7e219d8d2fdc0bfa639efe71c74bbea008ce5a064"
},
"downloads": -1,
"filename": "backend_ai_webserver-25.11.2.tar.gz",
"has_sig": false,
"md5_digest": "75544e46b9e9d1ddb0a5103da72e87b6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.14,>=3.13",
"size": 25800613,
"upload_time": "2025-07-15T16:26:55",
"upload_time_iso_8601": "2025-07-15T16:26:55.615866Z",
"url": "https://files.pythonhosted.org/packages/66/44/f219743aa89af29850810a23c0ca38570529814673ff7a30530eaa9c32c0/backend_ai_webserver-25.11.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-15 16:26:55",
"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"
}