Browse code

loadDaemonCliConfig: explicitly set default host

Setting the default host was implicitly handled in `normalizeHosts`; if
no hosts were provided, an empty entry was added to the list of hosts,
then passed through to `opts.ParseHost`, which handled an empty value
to set the default location (depending on TLS being enabled or XDG paths
to be used (when running with RootlessKit).

This patch makes the logic less magical:

- If no hosts are configured by the user (through CLI-flags or daemon.json),
then we append the default location.
- The handling for TLS listeners is open-coded for now; we need to decide
if we want to preserve this behavior (magically using TCP instead of a
unix-socket or named pipe if TLS is enabled).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2026/01/23 02:22:12
Showing 1 changed files
... ...
@@ -639,6 +639,30 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
639 639
 		}
640 640
 	}
641 641
 
642
+	// TODO(thaJeztah): consider making empty strings an error. Existing behavior allowed for empty strings to be used as default, even if explicitly set (`dockerd -H ""`).
643
+	conf.Hosts = slices.DeleteFunc(conf.Hosts, func(h string) bool {
644
+		return strings.TrimSpace(h) == ""
645
+	})
646
+	if len(conf.Hosts) == 0 {
647
+		// Set the default host if no hosts are configured.
648
+		// TODO(thaJeztah) can set defaults in config.New() instead?
649
+		if conf.TLS != nil && *conf.TLS {
650
+			// If no host is configured, but the "--tls" flag is set, we
651
+			// default to using a TCP connection instead of a unix-socket
652
+			// or named pipe.
653
+			//
654
+			// See https://github.com/moby/moby/commit/0906195fbbd6f379c163b80f23e4c5a60bcfc5f0
655
+			conf.Hosts = append(conf.Hosts, dopts.DefaultTLSHost)
656
+		} else {
657
+			// Otherwise use the default unix-socket (Linux) or named pipe (Windows).
658
+			h, err := defaultAPISocketPath(honorXDG)
659
+			if err != nil {
660
+				return nil, err
661
+			}
662
+			conf.Hosts = append(conf.Hosts, h)
663
+		}
664
+	}
665
+
642 666
 	if err := normalizeHosts(conf); err != nil {
643 667
 		return nil, err
644 668
 	}
... ...
@@ -718,27 +742,37 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
718 718
 	return conf, nil
719 719
 }
720 720
 
721
+// defaultAPISocketPath returns the default path for the Unix socket (Linux)
722
+// or named pipe (Windows).
723
+//
724
+// When running with rootlessKit, XDG dirs should be preferred, and the
725
+// default is to listen on an unprivileged socket in [XDG_RUNTIME_DIR].
726
+//
727
+// [XDG_RUNTIME_DIR]: https://specifications.freedesktop.org/basedir/0.8/#variables
728
+func defaultAPISocketPath(honorXDG bool) (string, error) {
729
+	if honorXDG {
730
+		runtimeDir, err := homedir.GetRuntimeDir()
731
+		if err != nil {
732
+			return "", err
733
+		}
734
+		return "unix://" + filepath.Join(runtimeDir, "docker.sock"), nil
735
+	}
736
+
737
+	// default unix-socket (Linux) or named pipe (Windows).
738
+	return dopts.DefaultHost, nil
739
+}
740
+
721 741
 // normalizeHosts normalizes the configured config.Hosts and removes duplicates.
722 742
 // It returns an error if it fails to parse a host.
723 743
 func normalizeHosts(cfg *config.Config) error {
724
-	hosts := slices.Clone(cfg.Hosts)
725
-	if len(hosts) == 0 {
726
-		// if no hosts are configured, create a single entry slice, so that the
727
-		// default is used.
728
-		//
729
-		// TODO(thaJeztah) implement a cleaner way for this; this depends on a
730
-		//                 side-effect of how we parse empty/partial hosts.
731
-		hosts = make([]string, 1)
732
-	}
733
-
734
-	useTLS := DefaultTLSValue
735
-	if cfg.TLS != nil {
736
-		useTLS = *cfg.TLS
744
+	if len(cfg.Hosts) == 0 {
745
+		return errors.New("no hosts specified")
737 746
 	}
738 747
 
748
+	hosts := slices.Clone(cfg.Hosts)
739 749
 	for i, h := range hosts {
740 750
 		var err error
741
-		hosts[i], err = dopts.ParseHost(useTLS, honorXDG, h)
751
+		hosts[i], err = dopts.ParseDaemonHost(h)
742 752
 		if err != nil {
743 753
 			return err
744 754
 		}