Skip to content

fix(deploy): bind MySQL/Redis to localhost and switch CubeProxy to host networking#269

Open
fslongjin wants to merge 1 commit into
TencentCloud:masterfrom
fslongjin:refactor-cubeproxy-network-mode-and-nginx-config
Open

fix(deploy): bind MySQL/Redis to localhost and switch CubeProxy to host networking#269
fslongjin wants to merge 1 commit into
TencentCloud:masterfrom
fslongjin:refactor-cubeproxy-network-mode-and-nginx-config

Conversation

@fslongjin
Copy link
Copy Markdown
Member

Summary

  • Bind MySQL (3306) and Redis (6379) ports to 127.0.0.1 only, preventing external network access to these services with default credentials
  • Switch CubeProxy from Docker bridge networking to network_mode: host so it can reach Redis via localhost (following CoreDNS's existing pattern)
  • Add parameterized nginx.conf.template so CubeProxy nginx listens on configurable ports (default 443/80), maintaining the same external-facing behavior

Security Impact

Before: MySQL and Redis were accessible on all network interfaces (0.0.0.0) with weak default credentials. Any client that could reach the host IP could connect.

After: Both services are only accessible from 127.0.0.1. External connections are refused.

Files Changed

File Change
deploy/one-click/support/docker-compose.yaml.template MySQL/Redis port binding → 127.0.0.1
deploy/one-click/cubeproxy/docker-compose.yaml.template network_mode: host, remove ports, add nginx.conf volume
deploy/one-click/cubeproxy/nginx.conf.template New: parameterized nginx config with __CUBE_PROXY_HTTPS_PORT__/__CUBE_PROXY_HTTP_PORT__
deploy/one-click/scripts/one-click/up-cube-proxy.sh Redis IP default → 127.0.0.1, nginx template processing, port variables
deploy/one-click/env.example Updated variables

Test plan

  • Run full one-click install flow, verify all services start normally
  • ss -tlnp | grep -E '3306|6379' confirms MySQL/Redis only on 127.0.0.1
  • Verify external IP connections to 3306/6379 are refused
  • Verify CubeMaster connects to MySQL/Redis normally
  • Verify CubeProxy connects to Redis and HTTPS proxy works
  • ss -tlnp | grep -E ':443|:80' confirms CubeProxy listens on 443/80

🤖 Generated with Claude Code

…st networking

MySQL and Redis were exposed on 0.0.0.0 via Docker port mapping, making
them accessible from any network interface with default credentials.
This change restricts both services to 127.0.0.1 only.

CubeProxy previously reached Redis via the host's external IP from a
Docker bridge container. Since Redis is now localhost-only, CubeProxy
switches to network_mode: host (matching CoreDNS's existing pattern).
The nginx listen ports are parameterized via a new nginx.conf.template
so the external ports (443/80) remain unchanged.

Signed-off-by: longjin <longjin@tencent.com>

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: longjin <longjin@dragonos.org>
@staryxchen
Copy link
Copy Markdown
Collaborator

/cubebot review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

Claude finished @staryxchen's task in 54s —— View job


Reviewing PR #269: fix(deploy): bind MySQL/Redis to localhost and switch CubeProxy to host networking

Todo List

  • Gather context and read changed files
  • Understand request
  • Read changed files and analyze code
  • Complete code review and post feedback

Code Review

Overview

This PR improves security by binding MySQL/Redis to 127.0.0.1 and switches CubeProxy to network_mode: host (matching CoreDNS's existing pattern) so it can reach Redis via localhost. The new parameterized nginx.conf.template is a nice improvement over a hardcoded config.

Security (Positive)

  • MySQL/Redis binding to 127.0.0.1 (support/docker-compose.yaml.template:12,38) — This is the right call. With default credentials (cube_pass/ceuhvu123), exposing these on 0.0.0.0 was a significant risk. External connections are now properly refused.

Issues Found

1. user root; in nginx — runs as root unnecessarily

File: deploy/one-click/cubeproxy/nginx.conf.template:1

The nginx worker processes run as root. This is a defense-in-depth concern — if there's ever a code execution vulnerability in OpenResty/Lua, an attacker gains root access. The official OpenResty image drops privileges to nobody or a dedicated openresty user. Consider removing the user root; directive or changing it to a non-privileged user.

2. worker_processes 12 is hardcoded

File: deploy/one-click/cubeproxy/nginx.conf.template:2

Hardcoding 12 workers means suboptimal CPU utilization on machines with fewer or more cores. Consider using auto to let nginx detect the available CPU count at runtime:

worker_processes auto;

3. SSL certificate paths are hardcoded

File: deploy/one-click/cubeproxy/nginx.conf.template:128-129

The cert paths reference cube.app+3.pem and cube.app+3-key.pem directly. If the mkcert-generated certificate has a different name (e.g., different domain), nginx will fail to start. Consider parameterizing these paths (e.g., __CUBE_PROXY_SSL_CERT__ / __CUBE_PROXY_SSL_KEY__) similar to how ports are handled.

4. Readiness check only monitors HTTPS port

File: deploy/one-click/scripts/one-click/up-cube-proxy.sh:119-125

The startup health check only verifies CUBE_PROXY_HTTPS_PORT. If the HTTP server block fails to start (e.g., port 80 conflict), the script won't detect it. Consider checking both ports, or at minimum logging a warning if the HTTP port isn't listening.

5. No HTTP→HTTPS redirect

File: deploy/one-click/cubeproxy/nginx.conf.template:90-122

The HTTP server block (port 80) proxies to the backend directly rather than redirecting to HTTPS. This means traffic on port 80 is unencrypted end-to-end. If this is intentional (e.g., some clients must use HTTP), consider adding a comment explaining why. Otherwise, a 301 redirect to the HTTPS counterpart would be more secure.

6. Port conflict risk with network_mode: host

File: deploy/one-click/cubeproxy/docker-compose.yaml.template:9

With network_mode: host, ports 443 and 80 are consumed directly on the host network namespace. If another service (or a previous Docker port mapping) is already using these ports, the container will fail to start with a cryptic "address in use" error. Previously with bridge networking, Docker handled port conflict gracefully. Consider documenting this requirement or adding a pre-flight check in the script.

Minor Suggestions

  • CUBE_PROXY_DNS_ANSWER_IP still uses CUBE_SANDBOX_NODE_IP (env.example:83) — This is unchanged from before, but worth noting that DNS responses may still leak the node IP. If this is intentional (DNS needs to return a reachable IP), a comment would help clarify.

Summary

Severity Issue File
Medium nginx runs as root nginx.conf.template:1
Low worker_processes hardcoded to 12 nginx.conf.template:2
Medium SSL cert paths hardcoded nginx.conf.template:128-129
Low Readiness only checks HTTPS port up-cube-proxy.sh:119
Low No HTTP→HTTPS redirect nginx.conf.template:90-122
Low Port conflict risk with host networking docker-compose.yaml.template:9

The core security improvement (binding MySQL/Redis to localhost) is solid. The network_mode: host change is consistent with the existing CoreDNS pattern. The main concerns are the nginx running as root and the hardcoded SSL cert paths, which could cause runtime failures in different deployment environments.

@@ -0,0 +1,181 @@
user root;
worker_processes 12;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a template, it's best not to hard-code it; use auto instead.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that this is for reference only and should not be used directly in a production environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants