Docker host
Record docker exec, docker attach and docker compose exec on a Linux server that runs Docker, without changing your images.
On a Linux server that runs Docker, the standard install also records every interactive session into a container: docker exec, docker attach, docker run -it and docker compose exec. Your images and containers don't change.
Install
Install shellz on the server exactly as described in Linux server:
curl -fsSL https://get.shellz.dev | sudo sh -s -- szt_<join token>shellz finds Docker automatically. Docker isn't restarted and running containers keep running. If you install Docker after shellz, it's picked up within 15 seconds.
Check it:
sudo /usr/local/bin/shellz status ...
Containers recording Docker sessions on /run/docker.sockRight after install, the line may end with (recording; dockerd moves to /run/shellz/dockerd.sock at its next restart). That's normal: sessions are already recorded, and Docker switches sockets the next time it restarts. A line starting with NOT RECORDED explains what's wrong; see What isn't covered.
How it works
Every Docker command talks to the Docker daemon through the API socket, /run/docker.sock. shellz moves the daemon to a private socket, /run/shellz/dockerd.sock, readable only by root, and serves the original socket path itself with the same owner and permissions. Members of the docker group keep working as before.
shellz forwards every Docker API call to the daemon unchanged. When a call opens a session into a container (exec or attach), shellz records the stream in both directions before passing it on.
The change is made with systemd drop-in files (zz-shellz.conf) for docker.socket and docker.service, which are removed when shellz is removed. If someone deletes or replaces the socket, shellz puts it back within a second and raises a tamper-repaired alert.
What gets recorded
| Command | Recorded |
|---|---|
docker exec -it <container> bash | Yes, as a full session |
docker exec <container> <command> (no terminal) | Yes, as a command session |
docker attach <container> | Yes |
docker run -it <image> | Yes, as an attach session |
docker compose exec <service> sh | Yes |
| Docker API calls from tools and SDKs using the socket | Exec and attach calls, yes |
docker logs, docker ps, image builds and pulls | No, these aren't sessions |
Each container session shows:
- the container's ID, name and image, and whether it was exec or attach;
- the user inside the container;
- the server account that called Docker, read from the kernel, not from anything the client says;
- a link to the parent session when the
dockercommand was run from a recorded SSH session.
As with SSH sessions, input typed at hidden prompts isn't recorded.
When recording isn't possible
If shellz can't record a new container session, for example because the spool is full while the network is down, the recording policy decides what happens:
- Fail closed and buffer: the Docker API returns an error, the client shows
shellz: recording unavailable, container session refused, and asession-refusedalert is raised. - Fail open: the session runs.
What isn't covered
shellz raises an alert when it finds Docker set up in a way it can't record:
| Alert | Cause | Fix |
|---|---|---|
docker-tcp-listener (critical) | The Docker daemon also accepts API calls on a TCP port. Calls over TCP bypass recording. | Remove the -H tcp://... flag or the TCP hosts entry. |
unsupported-container-runtime (warning) | hosts is set in /etc/docker/daemon.json, so shellz can't move the socket. | Move the socket settings into the systemd unit and remove hosts from daemon.json. |
unsupported-container-runtime (warning) | Docker runs without a docker.service unit, for example from a snap. | Use Docker's packages for your distribution. |
unsupported-container-runtime (warning) | Rootless Docker, Podman, or containerd tools (ctr, nerdctl, crictl) are in use. | Add shellz inside the image for those containers. |
Root on the server can reach containers without Docker, for example with nsenter into a container's namespaces. That's still a login on the server, so the outer SSH session records it, but the container session itself isn't recorded separately.
Removing shellz from a Docker host
When shellz is removed, it deletes its drop-ins and gives the original socket back to Docker. If containers are running, shellz doesn't restart Docker. Instead it prints a note asking you to run this when convenient, so systemd manages the socket again:
sudo systemctl restart docker.socket docker.service