Migration
Drop-in migration paths from Tecnativa, LinuxServer, wollomatic, 11notes, and CetusGuard socket proxies — current env compatibility, same intent, stronger inspection underneath.
From Tecnativa/docker-socket-proxy
Sockguard accepts the current Tecnativa environment-variable surface, including section vars, ALLOW_RESTARTS, SOCKET_PATH, and LOG_LEVEL. Replace the image:
services:
socket-proxy:
- image: tecnativa/docker-socket-proxy
+ image: codeswhat/sockguard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CONTAINERS=1
- POST=0That gets you current Tecnativa env-surface compatibility. If you intentionally want section-wide raw archive/export or log/attach streaming parity from CONTAINERS=1 or IMAGES=1, also set SOCKGUARD_INSECURE_ALLOW_READ_EXFILTRATION=true; otherwise move to YAML and allow only the list/inspect endpoints you actually need.
When ready, migrate to YAML config for more control:
rules:
- match: { method: GET, path: "/containers/json" }
action: allow
- match: { method: GET, path: "/containers/*/json" }
action: allow
- match: { method: GET, path: "/_ping" }
action: allow
- match: { method: GET, path: "/version" }
action: allow
- match: { method: GET, path: "/events" }
action: allow
- match: { method: "*", path: "/**" }
action: denyFrom LinuxServer/socket-proxy
Same process as Tecnativa. Additionally, granular operation env vars are supported:
ALLOW_START=1
ALLOW_STOP=1
ALLOW_RESTARTS=1 # or the legacy singular ALLOW_RESTART=1; both map to the same rulesFrom wollomatic/socket-proxy
wollomatic already does more than a basic path gate: regex allowlists per method, IP or hostname admission, per-container label allowlists, optional bind-mount restrictions, JSON logging, active upstream watchdog checks, and a filtered unix-socket endpoint. Sockguard's migration story is mostly direct: body policy, named profiles, mTLS selectors, owner isolation, Prometheus metrics, trace/log correlation, and read-side visibility are the main upgrades; hostname admission maps best to mTLS DNS/URI selectors, CIDRs, unix peers, or container labels.
| wollomatic | sockguard |
|---|---|
-allowGET "^/(v[0-9.]+/)?containers/json$" | { method: GET, path: "/containers/json" } |
-allowGET "^/(v[0-9.]+/)?events$" | { method: GET, path: "/events" } |
-allowPOST "^/(v[0-9.]+/)?containers/[a-z0-9]+/start$" | { method: POST, path: "/containers/*/start" } |
-allowfrom=172.18.0.0/16 | clients.allowed_cidrs: ["172.18.0.0/16"] |
-allowfrom=traefik (hostname admission) | clients.allowed_cidrs with the caller's IP, or clients.container_labels for name-based resolution. For cryptographic caller identity, clients.client_certificate_profiles (mTLS) or clients.unix_peer_profiles are a stronger upgrade. |
socket-proxy.allow.get=.* | clients.container_labels.label_prefix: socket-proxy.allow. |
-allowbindmountfrom=/srv/data,/var/log | request_body.container_create.allowed_bind_mounts: ["/srv/data", "/var/log"] |
-proxysocketendpoint=/tmp/filtered.sock | listen.socket: /tmp/filtered.sock |
Key differences:
- Sockguard auto-strips API version prefixes — no need for
(v[0-9.]+/)?in patterns - Glob patterns (
*,**) instead of regex - YAML config instead of CLI flags
- Auto-anchoring built in (no need for
^and$) - Wollomatic already supports hostname allowlists and a filtered unix-socket endpoint today; Sockguard is stronger on exec/pull/build inspection, named profiles, ownership isolation, and visibility-controlled reads
From 11notes/docker-socket-proxy
11notes/docker-socket-proxy is a fixed read-only proxy — it allows every Docker API GET except seven exfiltration-prone endpoints and blocks every write. There is no rule syntax to translate; the equivalent in Sockguard is a default-deny config that allows reads broadly while denying those same endpoints first (first-match-wins):
rules:
# Deny the seven exfiltration-prone reads 11notes blocks
- match: { method: GET, path: "/containers/*/attach/ws" }
action: deny
- match: { method: GET, path: "/containers/*/export" }
action: deny
- match: { method: GET, path: "/containers/*/archive" }
action: deny
- match: { method: GET, path: "/secrets" }
action: deny
- match: { method: GET, path: "/configs" }
action: deny
- match: { method: GET, path: "/swarm/unlockkey" }
action: deny
- match: { method: GET, path: "/images/*/get" }
action: deny
# Allow everything else read-only — writes fall through to default-deny
- match: { method: GET, path: "/**" }
action: allowThe 11notes environment variables configure the process, not the policy, so they map to Sockguard's listener and upstream settings rather than to rules:
| 11notes env var | Sockguard equivalent |
|---|---|
SOCKET_PROXY_DOCKER_SOCKET | upstream.socket (env: SOCKGUARD_UPSTREAM_SOCKET) |
SOCKET_PROXY_VOLUME | listen.socket (env: SOCKGUARD_LISTEN_SOCKET) |
SOCKET_PROXY_HTTP_LISTEN_IP | listen.address — mTLS is required for any non-loopback bind |
SOCKET_PROXY_UID / SOCKET_PROXY_GID | Sockguard's image already runs as UID 65532; set container runtime user: / group_add only when you need to match the host Docker socket's numeric UID/GID |
DEBUG | log.level: debug (env: SOCKGUARD_LOG_LEVEL) |
Once migrated, tighten the broad GET /** allow into the specific list/inspect endpoints your client actually needs, then re-enable individual writes with body inspection instead of leaving the whole API read-only.
From hectorm/cetusguard
CetusGuard is the closest in spirit to Sockguard — a zero-dependency, default-deny proxy with method + path rules. Its rules use a METHOD[,METHOD] PATTERN grammar with regex patterns and %VARIABLE% placeholders; Sockguard expresses the same intent as YAML glob rules:
| CetusGuard rule | Sockguard rule |
|---|---|
GET %API_PREFIX_CONTAINERS%/json | { method: GET, path: "/containers/json" } |
GET %API_PREFIX_CONTAINERS%/%CONTAINER_ID_OR_NAME%/json | { method: GET, path: "/containers/*/json" } |
POST %API_PREFIX_CONTAINERS%/%CONTAINER_ID_OR_NAME%/start | { method: POST, path: "/containers/*/start" } |
%API_PREFIX_*% placeholders become literal path segments (/containers, /images, …), id placeholders such as %CONTAINER_ID_OR_NAME% become a * glob, and a GET,POST method list becomes two rules. CetusGuard's flags and env vars map to Sockguard's listener and upstream config:
| CetusGuard | Sockguard |
|---|---|
-frontend-addr / CETUSGUARD_FRONTEND_ADDR | listen.address (TCP) or listen.socket (unix) |
-backend-addr / CETUSGUARD_BACKEND_ADDR | upstream.socket |
-frontend-tls-cert / -frontend-tls-key | listen.tls.cert_file / listen.tls.key_file |
-frontend-tls-cacert | listen.tls.client_ca_file (enables mTLS) |
-rules / -rules-file / CETUSGUARD_RULES* | The YAML rules: block |
-log-level / CETUSGUARD_LOG_LEVEL | log.level |
builtin /_ping, /info, /version rules | Allow them explicitly — Sockguard has no implicit allows |
Key differences:
- Sockguard auto-strips Docker API version prefixes (
/v1.45/…) before matching, so patterns never account for them - Glob patterns (
*,**) with auto-anchoring instead of regex - CetusGuard filters on method + path only; Sockguard adds request-body inspection, named per-client profiles, owner isolation, read-side visibility/redaction, rate limits, and metrics on top
- CetusGuard can dial a remote daemon over backend TLS today; Sockguard's upstream is the local socket, with remote TCP upstreams on the v1.1 roadmap
Admin API
Sockguard's optional admin endpoints — config dry-run validation and policy version introspection. Deploy on a dedicated listener to keep admin traffic off the Docker-API data plane.
Security Model
Sockguard's defense-in-depth model — transport admission, client admission, method/path filtering, request-body inspection, ownership isolation, visibility-controlled reads, and structured access plus audit logging.