Fix Docker daemon socket permission denied safely
Separate a stopped daemon, wrong Docker context, rootless socket, stale environment override, and real Unix-socket authorization before changing group membership.
Restore access to the intended Docker daemon without making the socket world-writable or exposing an unauthenticated TCP API.
- Docker Engine 27.x, 28.x
- systemd 255+
- Host access Use a normal account with sudo for read-only service and socket inspection.
- Daemon ownership Know whether the intended engine is rootful, rootless, remote over SSH/TLS, or Docker Desktop.
- Security approval Treat Docker daemon access as host-level privileged access, not ordinary application group membership.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A repeatable Docker Engine incident record that starts with the literal `permission denied while trying to connect to the Docker daemon socket` symptom and preserves the first useful failure instead of hiding it with an early restart or broad permission change.
- A layer-by-layer decision path from client context through configuration and runtime evidence to one narrowly scoped remediation, followed by positive and negative verification.
- A reusable evidence bundle containing commands, concrete example output, timestamps, identities, effective configuration, and stop conditions that another operator can review without access to the original terminal.
- You can identify which boundary failed, explain why competing hypotheses were rejected, and state what changed before declaring the incident resolved.
- The repaired path succeeds under the intended identity while an unauthorized or incorrect path still fails, proving that the fix did not simply remove a security control.
- The final evidence distinguishes a transient recovery from a durable repair by checking logs, counters, configuration provenance, and the original user-visible operation.
Architecture
How the parts fit together
Docker Engine troubleshooting is treated as an evidence pipeline rather than a list of guesses. The operator captures the symptom, resolves client and target context, inspects the first authoritative server-side failure, tests the smallest cause boundary, applies one reviewed change, and repeats the same observation path. This keeps a secondary error from replacing the primary cause and makes rollback possible.
- Copy the literal error and the command that produced it before retrying, restarting, pruning, resetting, or editing anything.
- Resolve the selected identity, configuration, target, and current runtime state so later commands inspect the same path the user exercised.
- Read the nearest authoritative log or effective configuration and align timestamps across the client and server evidence.
- Test one hypothesis with a read-only command; if evidence disagrees, return to the previous layer instead of stacking speculative changes.
- Back up the affected configuration or reference, apply the narrow repair, validate syntax, and reload only the component that owns the decision.
- Repeat the original action plus a negative control, record the outcome, and keep rollback material until the observation window is complete.
Assumptions
- The command is intended for a locally managed Linux Docker Engine.
- The operator will not chmod the socket or expose port 2375.
- Rootless and rootful engines are kept distinct during diagnosis.
- Clocks are close enough that client and server timestamps can be correlated. If they are not, record the offset before comparing logs.
- The operator has a recovery path that does not depend on the component being changed, such as console access, a second session, or a preserved remote reference.
- Commands are first run in the affected environment with placeholders reviewed. OneLiners never executes them and does not know local policy, tenancy, or maintenance constraints.
Key concepts
- Docker context
- A named client target that can select a local Unix socket, SSH endpoint, or TLS endpoint independently of the current shell directory.
- DOCKER_HOST
- An environment override that can redirect the client away from the context-selected endpoint.
- docker.sock
- The default rootful Unix socket; write access effectively grants control over a root-privileged daemon.
- Rootless socket
- A per-user daemon endpoint commonly exposed below `$XDG_RUNTIME_DIR`, with lifecycle and permissions owned by that user.
- Supplementary group
- A group added to a login session at session creation; editing `/etc/group` does not alter every existing process immediately.
Fill these once. Every matching command and configuration block updates immediately; values stay in this page only.
Security and production boundaries
- Rootful Docker API access normally permits host filesystem mounts and privileged containers, so it is equivalent to powerful host administration.
- Never solve the error with chmod 666/777 on docker.sock or an unauthenticated tcp://0.0.0.0:2375 listener.
- Do not paste private keys, tokens, complete environment dumps, authorization headers, or unredacted customer data into tickets or external analysis tools.
- A successful operation after disabling authentication, trust, host verification, sandboxing, or least privilege is a security regression, not a valid repair.
- Prefer effective configuration and narrow identity tests over recursive ownership changes, mode 777, global trust bypasses, or force options copied from unrelated incidents.
Stop before continuing if
- Stop if the selected daemon contains production workloads and ownership is unclear.
- Stop if access would be granted to a shared or externally controlled account.
- Stop if the target, account, environment, repository, or service instance cannot be identified unambiguously.
- Stop before a destructive cleanup, force update, broad permission change, or production reload when backup and recovery evidence is missing.
- Stop if the proposed action would conceal the first error or remove logs, failed objects, repository references, or configuration needed for diagnosis.
instruction
Freeze the symptom and define the incident boundary
Before changing Docker Engine, preserve the literal `permission denied while trying to connect to the Docker daemon socket` message, the exact action that produced it, the affected identity, target, UTC time, and expected result. Decide which production boundary is in scope and name the independent recovery path you will keep available.
Why this step matters
A retry, restart, cleanup, permission change, or configuration edit can replace the primary failure with a secondary one. A fixed starting record lets every later check answer a specific hypothesis.
What to understand
Record whether the problem affects one user or workload, one target, one host, or every comparable path; this determines whether to begin at the client, transport, or service boundary.
Write down the expected successful behavior in observable terms such as an exit status, HTTP response, remote object ID, authenticated principal, or stable service state.
Keep console access, a second session, an earlier configuration, or a recoverable reference independent of the component being diagnosed.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Incident scope Tool: Docker Engine Observed: `permission denied while trying to connect to the Docker daemon socket` Affected target: production-app-01 Observed at: 2026-08-17T14:02:11Z Expected: the reviewed operation completes without weakening an access or safety control Recovery path: console session and last known-good configuration retained
Security notes
- Redact secrets and customer data, but retain error text, timestamps, object IDs, modes, owners, and target names needed to reproduce the decision.
Alternatives
- When direct production inspection is restricted, reproduce the same version and configuration boundary in an isolated environment and mark which evidence is illustrative.
Stop conditions
- Stop before any mutation if the target, identity, affected environment, expected result, or recovery path is still ambiguous.
command
Capture the selected Docker endpoint
Record the current context, endpoint, and Docker environment overrides before using sudo, because sudo can silently select a different client configuration.
Why this step matters
A permission error is meaningful only after the exact endpoint is known; local, rootless, SSH, TLS, and Desktop endpoints have different owners and repairs.
What to understand
An explicit DOCKER_HOST overrides the context endpoint and may be inherited from shell startup or automation.
Comparing `sudo docker` with `docker` is not a clean permission test because root may use a different context and credentials.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
context inspect --format- Prints only the selected daemon endpoint from the context definition.
env | grep '^DOCKER_'- Shows client endpoint and TLS overrides that take precedence in the current shell.
docker context show && docker context inspect --format '{{json .Endpoints.docker.Host}}' && env | grep '^DOCKER_' || truedefault "unix:///var/run/docker.sock" DOCKER_HOST=unix:///var/run/docker.sock
Checkpoint: Checkpoint: Capture the selected Docker endpoint
docker context show && docker context inspect --format '{{json .Endpoints.docker.Host}}' && env | grep '^DOCKER_' || trueContinue whenThe endpoint is the intended local rootful or rootless socket and all overrides are explained.
Stop whenThe endpoint is remote, uses an unknown context, or points to an unexpected user's runtime directory.
If this step fails
The context does not exist.
Likely causeA deleted or user-specific Docker configuration is still named by automation.
docker context lsprintf '%s ' "${DOCKER_CONTEXT:-unset}"
ResolutionSelect an existing reviewed context or recreate it from documented endpoint details.
Security notes
- Do not print TLS private-key contents from a context; endpoint metadata is sufficient.
Alternatives
- Use `docker -H unix:///var/run/docker.sock info` only as an explicit diagnostic override, not a permanent shell alias.
Stop conditions
- The endpoint is remote, uses an unknown context, or points to an unexpected user's runtime directory.
command
Separate daemon availability from authorization
Check the Docker service, socket unit, process, and recent logs before interpreting the client message as a file-mode problem.
Why this step matters
A stopped or crash-looping daemon, missing socket unit, and inaccessible socket can produce similar client summaries but require completely different action.
What to understand
Use the service log to identify daemon.json conflicts, storage failures, or startup errors before restarting.
Socket activation may own `/run/docker.sock`; changing the file directly is temporary and will be replaced.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
systemctl show- Returns stable machine-readable service state and result fields.
journalctl -u- Bounds authoritative daemon startup evidence to one unit and time window.
systemctl is-active docker.service docker.socket; systemctl show docker.service -p ActiveState -p SubState -p Result; sudo journalctl -u docker.service --since '-15 minutes' --no-pager | tail -n 60active active ActiveState=active SubState=running Result=success Aug 17 12:05:41 host dockerd[2184]: API listen on /run/docker.sock
Checkpoint: Checkpoint: Separate daemon availability from authorization
systemctl is-active docker.service docker.socket; systemctl show docker.service -p ActiveState -p SubState -p Result; sudo journalctl -u docker.service --since '-15 minutes' --no-pager | tail -n 60Continue whenThe intended daemon is active and reports the expected Unix socket, or its startup failure is captured explicitly.
Stop whenThe daemon has a configuration, storage, or security failure; repair that cause before changing user authorization.
If this step fails
Docker is active but the log names another socket.
Likely causeA systemd override or daemon.json hosts setting changed the endpoint.
systemctl cat docker.servicesudo dockerd --validate --config-file=/etc/docker/daemon.json
ResolutionReconcile one authoritative host configuration and validate it; do not create an extra unauthenticated listener.
Security notes
- Daemon logs can contain registry names and image references; redact private tenant identifiers externally.
Alternatives
- For a documented rootless engine, inspect `systemctl --user status docker` as the owning user instead.
Stop conditions
- The daemon has a configuration, storage, or security failure; repair that cause before changing user authorization.
command
Inspect the socket and current login identity
Compare the socket type, owner, group, mode, path traversal, current UID, supplementary groups, and the Docker group definition.
Why this step matters
Authorization depends on the current process groups and the actual socket metadata, not only on whether the username appears in `/etc/group`.
What to understand
A login created before group membership changed may lack the group even when getent lists the user.
A socket owned by another group or user can indicate rootless Docker, a packaging override, or tampering; do not normalize it blindly.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
stat -L- Follows the conventional `/var/run` link and reports the live socket metadata.
id- Shows groups available to the current process, which is what the kernel checks.
getent group- Reads the configured group database, including directory-backed identities.
stat -Lc 'type=%F owner=%U group=%G mode=%a path=%n' /var/run/docker.sock && namei -l /var/run/docker.sock && id && getent group dockertype=socket owner=root group=docker mode=660 path=/var/run/docker.sock f: /var/run/docker.sock uid=1001(alice) gid=1001(alice) groups=1001(alice),998(docker) docker:x:998:alice
Checkpoint: Checkpoint: Inspect the socket and current login identity
stat -Lc 'type=%F owner=%U group=%G mode=%a path=%n' /var/run/docker.sock && namei -l /var/run/docker.sock && id && getent group dockerContinue whenThe rootful socket is root:docker 660 and the current login either clearly has or clearly lacks the approved docker group.
Stop whenThe path is not a socket, metadata differs without explanation, or Docker access is not approved for this account.
If this step fails
The user appears in getent but not in id.
Likely causeThe current login session predates the group change or an identity provider cache is stale.
idgetent group docker
ResolutionCreate a fresh authenticated session after confirming policy; do not chmod the socket.
Security notes
- Membership in the docker group is effectively root-equivalent on a rootful daemon and must follow privileged-access policy.
Alternatives
- Use rootless Docker when the workload does not require a rootful host daemon.
Stop conditions
- The path is not a socket, metadata differs without explanation, or Docker access is not approved for this account.
command
Check whether rootless Docker is the intended engine
Inspect the per-user service, runtime socket, and rootless context before adding access to the rootful daemon.
Why this step matters
Adding a user to the rootful Docker group is the wrong repair when their intended engine is an already running rootless daemon selected by the wrong context.
What to understand
Rootless lifecycle belongs to the user's systemd manager and should not be diagnosed through the system docker.service alone.
The context marker and endpoint must agree with XDG_RUNTIME_DIR for the authenticated user.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
systemctl --user- Queries the service manager and environment owned by the current user.
docker context ls- Lists endpoints and marks the client-selected context.
systemctl --user is-active docker.service 2>/dev/null || true; printf 'runtime=%s
' "${XDG_RUNTIME_DIR:-unset}"; docker context lsactive runtime=/run/user/1001 NAME DESCRIPTION DOCKER ENDPOINT rootless * Rootless Docker unix:///run/user/1001/docker.sock default Current DOCKER_HOST based config unix:///var/run/docker.sock
Checkpoint: Checkpoint: Check whether rootless Docker is the intended engine
systemctl --user is-active docker.service 2>/dev/null || true; printf 'runtime=%s
' "${XDG_RUNTIME_DIR:-unset}"; docker context lsContinue whenThe intended rootless or rootful architecture is explicit and the client selects its matching socket.
Stop whenBoth daemons hold production workloads or the ownership model is undocumented.
If this step fails
The user service is active but XDG_RUNTIME_DIR is unset in automation.
Likely causeThe job is not running in a real login/user-manager session.
loginctl show-user "$USER" -p Linger -p Statesystemctl --user status docker
ResolutionUse a documented lingering user service and explicitly selected rootless context rather than borrowing the rootful socket.
Security notes
- Rootless reduces daemon privilege but does not make untrusted containers or exposed APIs harmless.
Alternatives
- Use a remote Docker context over SSH to a dedicated build host when local daemon access is inappropriate.
Stop conditions
- Both daemons hold production workloads or the ownership model is undocumented.
decision
Grant only approved group access and refresh the session
When policy explicitly approves rootful Docker access and the socket is correctly owned, add only the named user to the docker group and create a fresh login session.
Why this step matters
A controlled group change preserves the socket's restrictive mode and produces an auditable privileged-access grant tied to a named account.
What to understand
`-aG` appends the group; omitting `-a` can remove unrelated supplementary groups.
A new authenticated session is preferable to `newgrp` for long-running desktops, agents, and services because every relevant process must receive the new group set.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- Adds one named account to the rootful Docker privileged group. Existing sessions are unchanged until reauthentication.
Syntax explained
usermod -aG docker- Appends the user to the Docker group without replacing other supplementary groups.
getent group docker- Verifies the directory/group database update before session refresh.
Values stay on this page and are never sent or saved.
sudo usermod -aG docker {{user}} && getent group docker && printf 'Log out every session for %s, log in again, then run: id && docker info --format '{{json .ServerVersion}}'
' {{user}}docker:x:998:alice
Log out every session for alice, log in again, then run: id && docker info --format '{{json .ServerVersion}}'Checkpoint: Checkpoint: Grant only approved group access and refresh the session
sudo usermod -aG docker {{user}} && getent group docker && printf 'Log out every session for %s, log in again, then run: id && docker info --format '{{json .ServerVersion}}'
' {{user}}Continue whenThe approved account appears in the Docker group; no socket mode, owner, daemon host, or TCP listener changed.
Stop whenApproval is missing, the account is shared, the socket metadata is abnormal, or the intended architecture is rootless/remote.
If this step fails
Access still fails in a new session.
Likely causeThe job runs as another user, connects to another context, or the identity provider did not deliver the group.
iddocker context inspectstat -Lc '%U %G %a %n' /var/run/docker.sock
ResolutionReconcile the actual process identity and endpoint; do not broaden socket mode.
Security notes
- Record the grant as privileged access and remove it when no longer required.
Alternatives
- Install and use rootless Docker or a remote SSH context instead of granting local rootful daemon control.
Stop conditions
- Approval is missing, the account is shared, the socket metadata is abnormal, or the intended architecture is rootless/remote.
command
Verify daemon access and absence of an unsafe listener
From the fresh session, prove identity, context, server version, socket metadata, and listening endpoints; then confirm an unapproved account remains denied.
Why this step matters
The repair is complete only when the intended user reaches the intended daemon and no world-writable socket or unexpected plaintext API was introduced.
What to understand
Record DockerRootDir to prevent later storage checks from inspecting the wrong engine.
An empty listener check is expected for a local-socket-only engine; port 2376 is acceptable only when the documented TLS configuration owns it.
Record the command, UTC timestamp, exit status, and the exact output before moving to the next layer. A later successful command must not erase evidence of the original failure.
Interpret this result together with the previous checkpoint. One matching line is evidence for a hypothesis, not permission to apply every commonly suggested fix.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Syntax explained
docker info --format- Proves server connectivity and records stable server identity fields.
ss -lntp- Detects unexpected Docker TCP listeners on conventional ports.
id && docker context show && docker info --format 'server={{.ServerVersion}} root={{.DockerRootDir}}' && stat -Lc '%U:%G %a %n' /var/run/docker.sock && sudo ss -lntp | grep -E ':(2375|2376)\b' || trueuid=1001(alice) gid=1001(alice) groups=1001(alice),998(docker) default server=28.3.3 root=/var/lib/docker root:docker 660 /var/run/docker.sock
Checkpoint: Checkpoint: Verify daemon access and absence of an unsafe listener
id && docker context show && docker info --format 'server={{.ServerVersion}} root={{.DockerRootDir}}' && stat -Lc '%U:%G %a %n' /var/run/docker.sock && sudo ss -lntp | grep -E ':(2375|2376)\b' || trueContinue whenThe approved user reaches the correct daemon, the socket remains root:docker 660, and no undocumented listener exists.
Stop whenDockerRootDir, context, server identity, socket mode, or listener differs from the approved architecture.
If this step fails
Docker works only with sudo.
Likely causeThe non-root process still lacks the socket group or selects a different endpoint.
iddocker context inspectenv | grep '^DOCKER_' || true
ResolutionRepair session identity or context; sudo success alone is not proof that the intended client path works.
Security notes
- Test negative access with a controlled unapproved account, not by weakening the socket temporarily.
Alternatives
- Use `docker context create --docker host=ssh://...` for a separately governed remote daemon.
Stop conditions
- DockerRootDir, context, server identity, socket mode, or listener differs from the approved architecture.
verification
Observe for recurrence and close with evidence
After the original Docker Engine operation succeeds, repeat the same read-only observation path used at the start. Watch the relevant logs, counters, identities, and target state for a bounded period, then record the proven cause, exact change, verification result, rollback point, and remaining uncertainty.
Why this step matters
A single successful retry may be a transient recovery. Repeating the original checks and retaining the rollback point distinguishes a durable repair from a restart-only improvement.
What to understand
Use the same client identity, target, path, and configuration selection as the original failure so the positive result is comparable.
Include one negative or unauthorized control where safe; this proves the repair did not work by removing authentication, trust, isolation, or branch protection.
Keep the evidence concise enough for another operator to reproduce, but include software versions and exact object or configuration references.
System changes
- No persistent change. This step reads current configuration, identity, runtime state, or logs and records evidence for the incident timeline.
Observation window: 15 minutes Original operation: PASS Original signature recurrences: 0 Negative control: PASS Rollback point retained: yes Cause and repair recorded: yes Remaining uncertainty: none observed within the stated boundary
Checkpoint: Checkpoint: the repair remains valid
id && docker context show && docker info --format 'server={{.ServerVersion}} root={{.DockerRootDir}}' && stat -Lc '%U:%G %a %n' /var/run/docker.sock && sudo ss -lntp | grep -E ':(2375|2376)\b' || trueContinue whenThe intended operation stays healthy, the original signature does not recur, and the negative control still enforces the expected boundary.
Stop whenThe result depends on an unexplained retry, disabled control, different target, or unrecorded manual state.
If this step fails
The error returns during the observation window.
Likely causeThe change treated a symptom, another instance still has the old state, or an automated process reverted or recreated the failing condition.
docker context show && docker context inspect --format '{{json .Endpoints.docker.Host}}' && env | grep '^DOCKER_' || trueid && docker context show && docker info --format 'server={{.ServerVersion}} root={{.DockerRootDir}}' && stat -Lc '%U:%G %a %n' /var/run/docker.sock && sudo ss -lntp | grep -E ':(2375|2376)\b' || true
ResolutionPreserve the recurrence, compare it with the first evidence set, restore the known-good state if necessary, and reopen the unresolved layer instead of stacking another repair.
Security notes
- Store only redacted operational evidence and remove temporary debug output according to local retention policy after review.
Alternatives
- Use the service's approved monitoring or audit trail when an interactive observation window is not practical.
Stop conditions
- Do not close the incident while the result is intermittent, the rollback point is missing, or a safety control remains weakened.
Finish line
Verification checklist
id && docker context show && docker info --format 'server={{.ServerVersion}} root={{.DockerRootDir}}' && stat -Lc '%U:%G %a %n' /var/run/docker.sock && sudo ss -lntp | grep -E ':(2375|2376)\b' || trueThe operation completes with exit status 0 and without the original error. The output identifies the intended host, service, repository, or endpoint.docker context show && docker context inspect --format '{{json .Endpoints.docker.Host}}' && env | grep '^DOCKER_' || trueA fresh diagnostic capture shows the healthy path and no recurrence of the original signature. Logs and counters remain stable during the observation window.Recovery guidance
Common problems and safe checks
Cannot connect to the Docker daemon instead of permission denied.
Likely causeThe daemon is stopped, the endpoint is wrong, or the rootless user manager is unavailable.
docker context inspectsystemctl is-active dockersystemctl --user is-active docker
ResolutionRepair daemon lifecycle or select the intended context before changing authorization.
The socket returns to different ownership after restart.
Likely causesystemd socket configuration or packaging owns creation and replaces manual metadata edits.
systemctl cat docker.socketsystemctl show docker.socket -p SocketMode -p SocketGroup
ResolutionFix the declarative socket unit or package configuration; never rely on post-start chmod.
A CI runner intermittently loses access.
Likely causeJobs use different service accounts, ephemeral group sets, or contexts.
iddocker context showprintf '%s ' "${DOCKER_HOST:-unset}"
ResolutionGive the dedicated runner identity one documented endpoint and provision its privilege before job startup.
Reference
Frequently asked questions
Why not chmod 666 /var/run/docker.sock?
It grants every local user control over a root-privileged daemon and is replaced on socket recreation. Correct the approved identity or architecture instead.
Why does sudo docker work?
Root can usually access the rootful socket, but sudo may also use a different context and credential store. It proves neither that the daemon is correct nor that the intended user is authorized.
Is the docker group safe for normal users?
No. Docker documents that group membership grants root-level privileges on a rootful daemon. Treat it as privileged access.
Should I expose port 2375?
No. An unauthenticated plaintext Docker API can hand remote users control of the host. Use SSH or properly configured mutual TLS when remote access is required.
Recovery
Rollback
Remove the added group membership and restore the previously selected context without changing socket modes.
- Run `sudo gpasswd -d {{user}} docker` after confirming another administration path.
- Terminate the user's old sessions, create a fresh login, and verify Docker access is removed.
- Restore the documented context or rootless endpoint and confirm no TCP listener was introduced.
Evidence