chore(docker-compose): tighten host port exposure (LAN-safe defaults)#644
Merged
chore(docker-compose): tighten host port exposure (LAN-safe defaults)#644
Conversation
The stack ships with several permissive defaults that are fine for localhost-only development but become a foot-gun on a shared LAN: - frontend_multi_user defaults to admin / admin - mcp_cloud defaults to PLANEXE_MCP_REQUIRE_AUTH=false with empty API key - database_postgres defaults to user/password planexe / planexe - worker_plan has no auth at all Previously every published port bound to 0.0.0.0 (Docker's default for the short-form ports: syntax), so anyone on the same network could hit them. Now: - database_postgres and worker_plan are pinned to 127.0.0.1; nothing outside the host should call them directly. - frontend_multi_user and mcp_cloud honor PLANEXE_BIND_HOST (default 127.0.0.1). Set PLANEXE_BIND_HOST=0.0.0.0 to expose them to the LAN after also setting strong credentials / API keys. Documented at the top of docker-compose.yml next to the existing port- conflict note. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…_HOST Mirror the docker-compose.yml change in docker-compose.md: - TL;DR notes the new default and links to the new section. - New "Bind host (LAN exposure)" section spells out which services ship with permissive defaults, what is now bound to 127.0.0.1, and how to opt back into LAN access via PLANEXE_BIND_HOST=0.0.0.0 (with the credentials checklist that should accompany it). - Per-service notes updated to reflect bind-host behavior. - Example "docker compose ps" output shows 127.0.0.1 mappings instead of 0.0.0.0 / [::]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
database_postgres and worker_plan are only ever called by other containers in the stack, so there is no reason to publish them to the host at all. Remove their `ports:` directives. Side benefits: - Eliminates the long-standing collision with a local Postgres on 5432 that previously required PLANEXE_POSTGRES_PORT=5433 to work around. The conflict cannot happen if the port is never published. - Reduces attack surface further: even on 127.0.0.1 the postgres default-password and unauthenticated worker_plan are no longer reachable from any host process. frontend_multi_user (5001) and mcp_cloud (8001) keep host mappings since the user's browser / external MCP clients need them; they remain bound to PLANEXE_BIND_HOST (default 127.0.0.1). Documentation in docker-compose.md updated to match, with a worked example showing how to add a docker-compose.override.yml for ad-hoc host access during debugging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The compose stack used Docker's short-form
ports:everywhere, which binds the host side to0.0.0.0. Combined with several permissive defaults (admin/admin on the frontend,PLANEXE_MCP_REQUIRE_AUTH=falsewith no API key on mcp_cloud, defaultplanexe/planexepostgres credentials, no auth at all on worker_plan), the whole stack was reachable from the LAN out of the box. This PR closes that and also drops host port mappings for the two services that nothing outside the docker network should ever call.Changes (
docker-compose.yml)database_postgres—ports:removed entirely. Reachable asdatabase_postgres:5432inside the docker network. Side benefit: no more host-side collision with a developer's local Postgres on 5432; the priorPLANEXE_POSTGRES_PORT=5433workaround is no longer needed.worker_plan—ports:removed entirely.frontend_multi_userreaches it asworker_plan:8000inside the docker network.frontend_multi_user(5001) andmcp_cloud(8001) — still published, now bound to${PLANEXE_BIND_HOST:-127.0.0.1}.Docs (
docker-compose.md)docker-compose.override.ymlexample for ad-hoc host access (DBeaver,psql,curlto worker_plan) during debugging.docker compose psoutput updated to match.Opting back into LAN access
For the two published services (testing on phone, Claude Desktop on another machine):
export PLANEXE_BIND_HOST=0.0.0.0 docker compose up…after also setting strong
PLANEXE_FRONTEND_MULTIUSER_ADMIN_PASSWORD,PLANEXE_MCP_API_KEY, andPLANEXE_MCP_REQUIRE_AUTH=true.To poke at the unpublished services from the host, either
docker compose execor drop adocker-compose.override.yml(template in the docs).Test plan
docker compose configshows onlyfrontend_multi_userandmcp_cloudpublished, both withhost_ip: 127.0.0.1database_postgres/worker_planno longer have apublished:entry indocker compose config./rebuild.sheven on a host with a local Postgres listening on 5432 (the conflict that motivated this change)PLANEXE_BIND_HOST=0.0.0.0 docker compose upmakes frontend reachable from another LAN device