Find the config file
-
On Linux, the Docker daemon configuration file is usually located at
/etc/docker/daemon.json. -
On Windows, the file is located at
C:\ProgramData\docker\config\daemon.json. -
If the file doesn’t exist, create it.
Edit config
Add the following configuration to the file:
{ "hosts": ["tcp://192.168.1.10:2375", "unix:///var/run/docker.sock"]}This tells Docker to listen on TCP port 2375 on IP (192.168.1.10) and on the Unix domain socket at /var/run/docker.sock. Replace 192.168.1.10 with your LAN or VPN IP.
The last line in that file must NOT have a comma after it, if there are more lines in there than the hosts’ line then add a comma to the end of all of them except the last one e.g.
{ "live-restore": true, "max-concurrent-downloads": 5, "max-concurrent-uploads": 5, "hosts": ["tcp://192.168.1.10:2375", "unix:///var/run/docker.sock"]}DON’T MAKE THIS ACCESSIBLE TO ALL INTERNET BY USING 0.0.0.0 for the IP.
-
Restart the Docker daemon
-
On Linux, you can restart the Docker daemon using the command
sudo systemctl restart docker. -
On Windows, you can restart the Docker daemon using the Docker Desktop application.
Test the configuration
Run the following command to test if the Docker socket is accessible via TCP:
docker -H tcp://192.168.1.10:2375 versionThis will give a sample output like this :
❯ docker -H tcp://192.168.192.10:2375 versionClient: Docker Engine - Community Version: 23.0.1 API version: 1.42 Go version: go1.19.5 Git commit: a5ee5b1 Built: Thu Feb 9 19:46:32 2023 OS/Arch: linux/arm64 Context: default
Server: Docker Engine - Community Engine: Version: 23.0.1 API version: 1.42 (minimum version 1.12) Go version: go1.19.5 Git commit: bc3805a Built: Thu Feb 9 19:46:32 2023 OS/Arch: linux/arm64 Experimental: false containerd: Version: 1.6.18 GitCommit: 2456e983eb9e37e47538f59ea18f2043c9a73640 runc: Version: 1.1.4 GitCommit: v1.1.4-0-g5fd4c4d docker-init: Version: 0.19.0 GitCommit: de40ad0That’s it! You have now set up the Docker socket to be accessible via TCP. Keep in mind that exposing the Docker daemon on a network socket can be a security risk, so make sure to properly secure the socket and limit access to it, such as over VPN only or on lan only.
When it doesn’t work
The most common reason docker -H tcp://... fails right after you restart the daemon: systemd is overriding your config. By default, the Docker service unit passes -H fd:// to dockerd, and that flag wins over daemon.json. Result — Docker starts, but it’s only listening on the fd socket, not TCP. You’ll see something like:
$ docker -H tcp://192.168.1.10:2375 pserror during connect: Get "http://192.168.1.10:2375/v1.24/containers/json": dial tcp 192.168.1.10:2375: connect: connection refusedFix it by creating a systemd override that removes the conflicting flag:
sudo mkdir -p /etc/systemd/system/docker.service.dsudo tee /etc/systemd/system/docker.service.d/override.conf > /dev/null <<’EOF’[Service]ExecStart=ExecStart=/usr/bin/dockerdEOF
sudo systemctl daemon-reloadsudo systemctl restart dockerThe empty ExecStart= line clears whatever the stock unit defined. Now dockerd starts clean and picks up your daemon.json hosts list. Run docker -H tcp://192.168.1.10:2375 version again — it should work.
Persistent access with DOCKER_HOST
Typing -H tcp://192.168.1.10:2375 every single command gets old fast. Export DOCKER_HOST in your shell config and it becomes the default:
# in ~/.bashrc or ~/.zshrc on your local machineexport DOCKER_HOST=tcp://192.168.1.10:2375After that, plain docker ps hits the remote daemon. Just remember to unset it when you need local Docker again — nothing quite like running docker rm -f and nuking containers on the wrong machine at 2 AM.
Firewall — don’t skip this
If you’re on a Linux host with ufw or firewalld, port 2375 won’t be open by default. Punch a hole, but scope it to your LAN range only:
# ufw example — allow only your LAN subnetsudo ufw allow from 192.168.1.0/24 to any port 2375 proto tcpIf you’re on WireGuard or Tailscale, allow the VPN interface subnet instead. The goal is: your machines can reach it, random internet scanners cannot. Port 2375 is unauthenticated — if it’s reachable from the open internet you’ve basically handed out root to whoever finds it first.
Actually using it — Portainer, Dozzle, Yacht
The whole point of TCP access is usually to hook up a dashboard or remote compose client. Here are the typical connection strings:
| Tool | Connection string |
|---|---|
| Portainer | tcp://192.168.1.10:2375 in the “Docker API” environment setup |
| Dozzle | DOZZLE_REMOTE_HOST=tcp://192.168.1.10:2375|hostname env var |
| Yacht | Docker host: tcp://192.168.1.10:2375 |
| Compose on remote | DOCKER_HOST=tcp://192.168.1.10:2375 docker compose up -d |
Portainer’s the most common use case here — you want the single Portainer instance on your “main” box to manage containers on three or four other hosts. This is exactly how to wire that up without installing an agent on each one. Though honestly, Portainer’s agent approach is cleaner for that scenario. TCP socket is fine for quick connections and dashboards like Dozzle that just tail logs.