[GH-ISSUE #57] issue: Docker backend publishes every terminal's port 8000 on all host interfaces even when TERMINALS_NETWORK is set #30

Open
opened 2026-10-18 21:13:34 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @silentoplayz on GitHub (Sep 10, 2026).
Original GitHub issue: https://github.com/open-webui/terminals/issues/57

Summary

With TERMINALS_NETWORK set, every terminal container the Docker backend starts still has its port 8000 published on the Docker host, on every interface, at a random high port. The orchestrator does not use that port in this mode, because it reaches the container by name on the named network. Every user's terminal is therefore reachable from any network the Docker host sits on. The terminal's own API key still gates commands and files. The health and config endpoints and the OpenAPI document answer without a key.

Expected Behavior

When TERMINALS_NETWORK names a network, terminal containers are reachable only on that network, by name. The README and the docs describe the setting that way. Containers communicate by name when it is set, and TERMINALS_DOCKER_HOST is described as relevant only without it. No host port is published in that mode. Without a network, the published port is bound to the address the orchestrator uses to reach it, which defaults to 127.0.0.1, rather than to every interface.

Actual Behavior

Running docker port on a terminal container shows port 8000 bound to 0.0.0.0 and to [::] on the host at a random port. The container sits on the named network, and the orchestrator talks to it by name. From a container on a different Docker network, and through the host's LAN address, /health, /api/config, and the OpenAPI document endpoint return 200 without any key. /files/cwd and /execute return 401. The published port has no consumer, since the orchestrator's routing uses the container name whenever a network is configured.

Steps to Reproduce

  1. Run the orchestrator with TERMINALS_BACKEND=docker and TERMINALS_NETWORK set to a user-defined network. The Compose file in the docs does this with open-webui-network.
  2. Connect it to Open WebUI and open a terminal as any user, so one terminal container is provisioned.
  3. On the Docker host, run docker port on that container.
  4. From a container on a different Docker network, or from another machine on the host's LAN, request /health at the host's address and the published port.

Observed: step 3 shows port 8000 bound to 0.0.0.0 and [::], and step 4 returns a status of ok. /api/config and the OpenAPI document endpoint answer the same way, and /files/cwd and /execute return 401.

Logs, Screenshots, and Config

  • Terminals 0.2.3 (ghcr.io/open-webui/terminals:latest, digest 5d2fd44366a4, built 2026-08-31), Docker backend, TERMINALS_NETWORK=owui-t8-net
  • Docker Engine 29.8.0 on Linux
  • Open WebUI 0.11.3

The orchestrator container itself was published on 127.0.0.1 only. The code on main at e15903af is the same as in the image.

$ docker port terminals-21f7d802ec1b-analysts-4360f4a92e62
8000/tcp -> 0.0.0.0:32825
8000/tcp -> [::]:32825
$ docker inspect terminals-21f7d802ec1b-analysts-4360f4a92e62 --format 'PublishAllPorts={{.HostConfig.PublishAllPorts}} NetworkMode={{.HostConfig.NetworkMode}}'
PublishAllPorts=true NetworkMode=owui-t8-net

From a container on the default bridge, which is not the terminals' network, through the Docker host's gateway address (the host's LAN address gave the same results):

$ for p in /health /api/config /openapi.json /files/cwd /execute; do docker run --rm --network bridge curlimages/curl -s -o /dev/null -w "$p %{http_code}\n" http://172.17.0.1:32825$p; done
/health 200
/api/config 200
/openapi.json 200
/files/cwd 401
/execute 401
$ docker run --rm --network bridge curlimages/curl -s http://172.17.0.1:32825/health
{"status":"ok"}

Additional Information

Anchor commit e15903af532d61b8264f354128edbca3e3ebd418 on main. The Docker backend sets PublishAllPorts for every container regardless of the network setting (docker.py#L102) and sets NetworkMode only when a network is named (#L139). The routing code reads the published port only when no network is configured (#L253-L268), so with a network configured the publication is never used. Terminal API keys come from secrets.token_urlsafe(24), so the protected endpoints are not open to guessing. The unauthenticated ones reveal a status line and three feature flags, plus the OpenAPI document.

A minimal fix publishes only when no network is named:

         host_config: dict = {
             "Binds": [f"{host_data_dir}:/home/user"],
-            "PublishAllPorts": True,
         }
+        if not network_name:
+            host_config["PublishAllPorts"] = True

When no network is named, the binding could also be narrowed to the address the orchestrator uses. An explicit PortBindings entry with HostIp set to TERMINALS_DOCKER_HOST (default 127.0.0.1) would do that. I left it out of the diff because that setting may hold a hostname rather than an address.

Originally created by @silentoplayz on GitHub (Sep 10, 2026). Original GitHub issue: https://github.com/open-webui/terminals/issues/57 ### Summary With TERMINALS_NETWORK set, every terminal container the Docker backend starts still has its port 8000 published on the Docker host, on every interface, at a random high port. The orchestrator does not use that port in this mode, because it reaches the container by name on the named network. Every user's terminal is therefore reachable from any network the Docker host sits on. The terminal's own API key still gates commands and files. The health and config endpoints and the OpenAPI document answer without a key. ### Expected Behavior When TERMINALS_NETWORK names a network, terminal containers are reachable only on that network, by name. The README and the docs describe the setting that way. Containers communicate by name when it is set, and TERMINALS_DOCKER_HOST is described as relevant only without it. No host port is published in that mode. Without a network, the published port is bound to the address the orchestrator uses to reach it, which defaults to 127.0.0.1, rather than to every interface. ### Actual Behavior Running docker port on a terminal container shows port 8000 bound to 0.0.0.0 and to [::] on the host at a random port. The container sits on the named network, and the orchestrator talks to it by name. From a container on a different Docker network, and through the host's LAN address, /health, /api/config, and the OpenAPI document endpoint return 200 without any key. /files/cwd and /execute return 401. The published port has no consumer, since the orchestrator's routing uses the container name whenever a network is configured. ### Steps to Reproduce 1. Run the orchestrator with TERMINALS_BACKEND=docker and TERMINALS_NETWORK set to a user-defined network. The Compose file in the docs does this with open-webui-network. 2. Connect it to Open WebUI and open a terminal as any user, so one terminal container is provisioned. 3. On the Docker host, run docker port on that container. 4. From a container on a different Docker network, or from another machine on the host's LAN, request /health at the host's address and the published port. Observed: step 3 shows port 8000 bound to 0.0.0.0 and [::], and step 4 returns a status of ok. /api/config and the OpenAPI document endpoint answer the same way, and /files/cwd and /execute return 401. ### Logs, Screenshots, and Config - Terminals 0.2.3 (`ghcr.io/open-webui/terminals:latest`, digest `5d2fd44366a4`, built 2026-08-31), Docker backend, `TERMINALS_NETWORK=owui-t8-net` - Docker Engine 29.8.0 on Linux - Open WebUI 0.11.3 The orchestrator container itself was published on 127.0.0.1 only. The code on `main` at `e15903af` is the same as in the image. ``` $ docker port terminals-21f7d802ec1b-analysts-4360f4a92e62 8000/tcp -> 0.0.0.0:32825 8000/tcp -> [::]:32825 $ docker inspect terminals-21f7d802ec1b-analysts-4360f4a92e62 --format 'PublishAllPorts={{.HostConfig.PublishAllPorts}} NetworkMode={{.HostConfig.NetworkMode}}' PublishAllPorts=true NetworkMode=owui-t8-net ``` From a container on the default bridge, which is not the terminals' network, through the Docker host's gateway address (the host's LAN address gave the same results): ``` $ for p in /health /api/config /openapi.json /files/cwd /execute; do docker run --rm --network bridge curlimages/curl -s -o /dev/null -w "$p %{http_code}\n" http://172.17.0.1:32825$p; done /health 200 /api/config 200 /openapi.json 200 /files/cwd 401 /execute 401 $ docker run --rm --network bridge curlimages/curl -s http://172.17.0.1:32825/health {"status":"ok"} ``` ### Additional Information Anchor commit `e15903af532d61b8264f354128edbca3e3ebd418` on `main`. The Docker backend sets `PublishAllPorts` for every container regardless of the network setting ([docker.py#L102](https://github.com/open-webui/terminals/blob/e15903af532d61b8264f354128edbca3e3ebd418/terminals/backends/docker.py#L102)) and sets `NetworkMode` only when a network is named ([#L139](https://github.com/open-webui/terminals/blob/e15903af532d61b8264f354128edbca3e3ebd418/terminals/backends/docker.py#L139)). The routing code reads the published port only when no network is configured ([#L253-L268](https://github.com/open-webui/terminals/blob/e15903af532d61b8264f354128edbca3e3ebd418/terminals/backends/docker.py#L253-L268)), so with a network configured the publication is never used. Terminal API keys come from `secrets.token_urlsafe(24)`, so the protected endpoints are not open to guessing. The unauthenticated ones reveal a status line and three feature flags, plus the OpenAPI document. A minimal fix publishes only when no network is named: ```diff host_config: dict = { "Binds": [f"{host_data_dir}:/home/user"], - "PublishAllPorts": True, } + if not network_name: + host_config["PublishAllPorts"] = True ``` When no network is named, the binding could also be narrowed to the address the orchestrator uses. An explicit `PortBindings` entry with `HostIp` set to `TERMINALS_DOCKER_HOST` (default 127.0.0.1) would do that. I left it out of the diff because that setting may hold a hostname rather than an address.
Author
Owner

@owui-terminator[bot] commented on GitHub (Sep 10, 2026):

🔍 Related Issues Found

I found some existing issues that might be related. Please check if any of these are duplicates or contain helpful solutions:

  1. 🟣 #25 How to specify custom network?
    This issue is about configuring a custom Docker network for terminals containers. The new issue is the same feature area and specifically depends on TERMINALS_NETWORK behavior, making it the closest related report.
    by arp-mbender

💡 If your issue is a duplicate, please close it and add any additional details to the existing issue instead.

This comment was generated automatically. React with 👍 if helpful, 👎 if not.

<!-- gh-comment-id:5623495051 --> @owui-terminator[bot] commented on GitHub (Sep 10, 2026): <!-- terminator-bot:related-issues-reply --> 🔍 **Related Issues Found** I found some existing issues that might be related. Please check if any of these are duplicates or contain helpful solutions: 1. 🟣 [#25](https://github.com/open-webui/terminals/issues/25) **How to specify custom network?** *This issue is about configuring a custom Docker network for terminals containers. The new issue is the same feature area and specifically depends on `TERMINALS_NETWORK` behavior, making it the closest related report.* *by arp-mbender* --- 💡 If your issue is a duplicate, please close it and add any additional details to the existing issue instead. *This comment was generated automatically.* React with 👍 if helpful, 👎 if not.
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
open-webui/terminals#30
No description provided.