docker-compose.yml publishes the supervisor as "${SUPERVISOR_PORT:-4500}:4300". With no interface in front of it Docker binds every address the host has, so the port answers anything that can route to the machine.
That is the service holding /var/run/docker.sock. Reaching it is root on the host by way of the four verbs it exposes, and SUPERVISOR_TOKEN is a shared secret in an environment variable rather than a network boundary.
The rest of the file already does the opposite. agent-computer, agent-bot and agent-langgraph are each published on 127.0.0.1, and the comment beside the computer's port gives the reasoning: the token is the request control, and loopback keeps the surface off routed networks. The supervisor is the one service where that argument is strongest and the prefix is missing.
docs/architecture.md already states the intended behaviour:
The supervisor exposes only ensure, stop, reset, and list operations. It holds the Docker socket, so do not expose it outside the deployment network.
So this is the compose file disagreeing with the documentation rather than an open design question.
Verified
Against Docker 29.1.3, with a stand-in service on 4300:
| published as |
from 127.0.0.1 |
from the host's routable address |
-p 4599:4300 (current) |
200 |
200 |
-p 127.0.0.1:4599:4300 |
200 |
connection refused |
The fix, and what it must not be
Only the published mapping should change. The process has to keep listening on every interface inside its own container: that is what the published mapping forwards to, and what a deployment running the server inside the compose network connects to as supervisor:4300 with no published port involved.
Binding the listener itself to loopback looks like the same change and is not. Same Docker version, same setup, published on loopback with the process bound to 127.0.0.1 inside the container: connection refused from the host as well, because the forward targets the container's interface address rather than its loopback.
Nothing changes for a default deployment. scripts/start.sh already reaches it on localhost.
Also worth a look, separately
postgres is published the same way, as "${POSTGRES_PORT:-5432}:5432". That is the database holding every stored credential and the whole audit trail. Happy to open that as its own issue if you want it treated the same way.
docker-compose.ymlpublishes the supervisor as"${SUPERVISOR_PORT:-4500}:4300". With no interface in front of it Docker binds every address the host has, so the port answers anything that can route to the machine.That is the service holding
/var/run/docker.sock. Reaching it is root on the host by way of the four verbs it exposes, andSUPERVISOR_TOKENis a shared secret in an environment variable rather than a network boundary.The rest of the file already does the opposite.
agent-computer,agent-botandagent-langgraphare each published on127.0.0.1, and the comment beside the computer's port gives the reasoning: the token is the request control, and loopback keeps the surface off routed networks. The supervisor is the one service where that argument is strongest and the prefix is missing.docs/architecture.mdalready states the intended behaviour:So this is the compose file disagreeing with the documentation rather than an open design question.
Verified
Against Docker 29.1.3, with a stand-in service on 4300:
127.0.0.1-p 4599:4300(current)-p 127.0.0.1:4599:4300The fix, and what it must not be
Only the published mapping should change. The process has to keep listening on every interface inside its own container: that is what the published mapping forwards to, and what a deployment running the server inside the compose network connects to as
supervisor:4300with no published port involved.Binding the listener itself to loopback looks like the same change and is not. Same Docker version, same setup, published on loopback with the process bound to
127.0.0.1inside the container: connection refused from the host as well, because the forward targets the container's interface address rather than its loopback.Nothing changes for a default deployment.
scripts/start.shalready reaches it onlocalhost.Also worth a look, separately
postgresis published the same way, as"${POSTGRES_PORT:-5432}:5432". That is the database holding every stored credential and the whole audit trail. Happy to open that as its own issue if you want it treated the same way.