Skip to content

fix(server): add explicit HostIp to Traefik port bindings#4106

Open
knowsuchagency wants to merge 1 commit intoDokploy:canaryfrom
knowsuchagency:fix/traefik-explicit-host-ip
Open

fix(server): add explicit HostIp to Traefik port bindings#4106
knowsuchagency wants to merge 1 commit intoDokploy:canaryfrom
knowsuchagency:fix/traefik-explicit-host-ip

Conversation

@knowsuchagency
Copy link
Copy Markdown

@knowsuchagency knowsuchagency commented Mar 30, 2026

Description

Traefik port bindings in initializeStandaloneTraefik currently omit the HostIp field:

portBindings[`80/tcp`] = [{ HostPort: "80" }]; // no HostIp

This causes Docker to inherit the daemon's default bind IP. If a user sets "ip": "127.0.0.1" in /etc/docker/daemon.json — a common hardening step to prevent containers from accidentally binding to public interfaces — Traefik's ports 80/443 also become localhost-only, breaking all public access.

Changes

  • Add TRAEFIK_BIND_IP environment variable (defaults to 0.0.0.0 for backward compatibility)
  • Set HostIp explicitly on all port bindings in initializeStandaloneTraefik:
    • Main HTTP/HTTPS/HTTP3 ports
    • Dashboard port (8080)
    • Additional ports loop

This makes Dokploy compatible with Docker daemon-level IP hardening while preserving existing behavior by default.

Checklist

  • My branch was forked from canary
  • I have read the CONTRIBUTING.md
  • I tested locally

Related Issues

Refs #2915 — this is a partial fix covering Traefik port bindings. The broader per-service IP binding requested in #2915 would be a separate change.

🤖 Generated with Claude Code

Greptile Summary

This PR fixes Traefik port bindings in initializeStandaloneTraefik to be compatible with Docker daemons that have a restricted default bind IP (e.g. "ip": "127.0.0.1" in daemon.json). It introduces a TRAEFIK_BIND_IP environment variable (defaulting to 0.0.0.0) and sets it as HostIp on every port binding, overriding the daemon default and restoring public accessibility without requiring daemon reconfiguration.

  • All five port-binding sites are consistently updated: HTTP (80), HTTPS (443), HTTP3 (443/udp), dashboard (8080), and the additional-ports loop.
  • Default value 0.0.0.0 preserves existing behavior for users who have not configured Docker IP hardening.
  • initializeTraefikService (Swarm mode) is intentionally left unchanged and the PR description correctly scopes this as a partial fix.
  • No input validation is performed on TRAEFIK_BIND_IP; an invalid IP will produce a cryptic Docker error at container creation time rather than a clear startup warning (see inline comment).

Confidence Score: 5/5

Safe to merge — the change is minimal, backward-compatible, and correctly addresses the stated problem with no logic regressions.

All findings are P2 (no input validation on the new env var). The core logic is correct, the default value preserves backward compatibility, and the fix is applied consistently to every affected port binding site.

No files require special attention.

Important Files Changed

Filename Overview
packages/server/src/setup/traefik-setup.ts Adds explicit HostIp to all port bindings in initializeStandaloneTraefik using a new TRAEFIK_BIND_IP env var (defaults to 0.0.0.0). The change is minimal, backward-compatible, and correctly applied to all five binding sites.

Reviews (1): Last reviewed commit: "fix(server): add explicit HostIp to Trae..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

(4/5) You can add custom instructions or style guidelines for the agent here!

Traefik port bindings in initializeStandaloneTraefik omit HostIp,
causing Docker to inherit the daemon default. If a user configures
"ip": "127.0.0.1" in daemon.json (a common hardening step to prevent
containers from binding to public interfaces), Traefik's ports 80/443
also become localhost-only, breaking all public access.

Add a TRAEFIK_BIND_IP environment variable (defaults to "0.0.0.0" for
backward compatibility) and set HostIp explicitly on all port bindings
including the dashboard and additional ports.

Refs Dokploy#2915

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Mar 30, 2026
export const TRAEFIK_HTTP3_PORT =
Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443;
export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.6.7";
export const TRAEFIK_BIND_IP = process.env.TRAEFIK_BIND_IP || "0.0.0.0";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 No validation of TRAEFIK_BIND_IP

TRAEFIK_BIND_IP is passed directly from the environment into Docker's port binding HostIp field with no format validation. An invalid value (e.g. a hostname, a CIDR range, or a typo like 0.0.0.) will cause docker.createContainer() to throw a cryptic error rather than a user-friendly message.

Consider adding a basic sanity check or at least logging the resolved value at startup so operators can confirm the setting is applied as expected:

Suggested change
export const TRAEFIK_BIND_IP = process.env.TRAEFIK_BIND_IP || "0.0.0.0";
export const TRAEFIK_BIND_IP = process.env.TRAEFIK_BIND_IP || "0.0.0.0";
// Basic guard so a misconfigured value surfaces early with a clear message.
if (!/^(\d{1,3}\.){3}\d{1,3}$|^::$|^::1$/.test(TRAEFIK_BIND_IP)) {
console.warn(
`TRAEFIK_BIND_IP "${TRAEFIK_BIND_IP}" does not look like a valid IP address – falling back to 0.0.0.0`,
);
}

This is consistent with how operators discover misconfigured TRAEFIK_PORT / TRAEFIK_SSL_PORT values today (the pattern is not validated there either), so this is purely a hardening suggestion.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant