How to use Codex on Ubuntu to debug Docker Compose services
When an application runs as several Docker containers, debugging usually means inspecting Compose configuration, container state, logs, health checks, networks, ports, mounts, environment variables, and service dependencies. Codex CLI can automate much of that investigation from an Ubuntu terminal because it can run the same local tools a developer would run manually.
Codex does not need a special Docker plugin for this workflow. In a local CLI session, the practical path is:
Codex CLI
|
| runs docker commands
v
Docker CLI
|
| talks through a Unix socket
v
/var/run/docker.sock
|
v
Docker daemon
|
v
Containers and Docker Compose servicesFor example, when Codex runs:
docker compose psthe installed docker client contacts the Docker daemon through the normal Docker endpoint. Codex itself is not reimplementing the Docker API; it is executing the local command-line tool inside the permissions available to the Codex session.
Prerequisites
The Ubuntu workstation needs:
- Docker Engine;
- Docker Compose;
- Codex CLI;
- a project directory containing
compose.yamlordocker-compose.yml.
First verify that Docker is running:
sudo systemctl status dockerIf it is stopped, enable and start it:
sudo systemctl enable --now dockerThen verify the installed tooling:
docker version
docker compose version
docker psIf those commands work, the local Docker environment is ready for Codex-assisted debugging.
Docker daemon access for the current user
On many Ubuntu systems, Docker initially requires sudo:
sudo docker psCodex normally runs as the current Linux user. For repeated local debugging, it is convenient for that user to run Docker commands directly:
sudo usermod -aG docker "$USER"Log out and log back in so the new group membership is applied. For the current terminal only, this may also work:
newgrp dockerVerify the result:
docker psTreat Docker group membership as administrative access. A process that can control the Docker daemon can create privileged containers, mount host directories, modify networks, stop services, and potentially reach sensitive host resources. Do not grant Docker access to untrusted users or unattended agents.
Install and start Codex CLI
OpenAI documents a standalone installer for macOS and Linux:
curl -fsSL https://chatgpt.com/codex/install.sh | shThe first run prompts for authentication using a ChatGPT account or an API key. After installation, verify the CLI:
codex --versionStart Codex from the project root so it can see the Compose file, Dockerfiles, application code, and local configuration:
cd ~/projects/my-application
codexA typical Compose project might look like:
my-application/
|-- compose.yaml
|-- backend/
| |-- Dockerfile
| `-- src/
|-- frontend/
| |-- Dockerfile
| `-- src/
|-- nginx/
| `-- nginx.conf
`-- .envSandbox and approval model
Codex uses sandbox and approval controls for local commands. A practical starting point for Docker debugging is the lower-risk local preset:
codex \
--sandbox workspace-write \
--ask-for-approval on-requestIn this mode, Codex can read files, edit files in the workspace, and run routine local commands inside the sandbox. When a command needs to cross a boundary, such as contacting a blocked local socket, Codex asks for approval.
Inside an interactive Codex session, inspect or change the active mode with:
/permissionsFor occasional Docker work, approve Docker commands one by one. This keeps privileged operations visible. It is especially appropriate when the host has important containers, persistent databases, or unrelated workloads.
For frequent Docker debugging, use a narrowly scoped permission profile instead of full access. OpenAI documents permission profiles as the newer way to describe filesystem and network access together; they should not be mixed with older sandbox_mode settings in the same session.
Example ~/.codex/config.toml profile:
default_permissions = "docker-debug"
[permissions.docker-debug]
description = "Edit the current project and access the local Docker daemon."
extends = ":workspace"
[permissions.docker-debug.network]
enabled = true
mode = "limited"
[permissions.docker-debug.network.unix_sockets]
"/var/run/docker.sock" = "allow"The important entry is the explicit Unix-socket allow rule:
[permissions.docker-debug.network.unix_sockets]
"/var/run/docker.sock" = "allow"This profile keeps normal workspace protections, grants access to the Docker socket, and avoids danger-full-access. If endpoint tests must reach a local web service from inside the sandbox, allow only the necessary local targets:
[permissions.docker-debug.network.domains]
"localhost" = "allow"
"127.0.0.1" = "allow"Avoid these combinations unless the environment is isolated and disposable:
--dangerously-bypass-approvals-and-sandbox--sandbox danger-full-accessapproval_policy = "never"with broad local access- broad Docker cleanup commands without an explicit confirmation step
Rootless Docker
Rootless Docker may not use /var/run/docker.sock. Its socket is often under the current user’s runtime directory, for example:
/run/user/1000/docker.sockFind the active endpoint:
docker context inspect \
--format ' (index .Endpoints "docker").Host 'Example output:
unix:///run/user/1000/docker.sockRemove the unix:// prefix and allow that absolute path instead:
[permissions.docker-debug.network.unix_sockets]
"/run/user/1000/docker.sock" = "allow"Also check whether DOCKER_HOST overrides the default endpoint:
echo "$DOCKER_HOST"A structured debugging prompt
Once Docker access works, give Codex a constrained investigation prompt:
Inspect this Docker Compose project.
1. Read the Compose file and identify all services.
2. Run docker compose config to validate the effective configuration.
3. Run docker compose ps.
4. Identify stopped, unhealthy, or restarting services.
5. Read recent logs for affected services.
6. Inspect exit codes, health checks, ports, mounts,
environment variables, dependencies, and networks.
7. Explain the likely root cause before changing anything.
8. Make only the minimum necessary changes.
9. Rebuild and restart only the affected services.
10. Verify the fix using service status, logs, health checks,
and an endpoint request.
Do not delete volumes, prune Docker resources, remove databases,
or recreate unrelated services without asking me first.The final restriction matters. These commands can delete persistent data or disrupt unrelated workloads:
docker compose down -v
docker system prune -a
docker volume prune
docker rm -fThey should require explicit approval in an ordinary debugging session.
Useful Docker commands for Codex
Validate the effective Compose configuration:
docker compose configThis catches invalid YAML, missing environment variables, bad service references, invalid volume definitions, port conflicts, and dependency mistakes.
Check service state:
docker compose ps
docker compose ps --allLook for services in states such as:
Exited
Restarting
Unhealthy
CreatedRead logs:
docker compose logs --tail=200
docker compose logs --tail=200 backendUse long-running log follows only when needed:
docker compose logs -f backendInspect selected container state instead of dumping full JSON:
docker inspect \
--format '.State.Status}} {{.State.ExitCode}} {{.State.Error' \
CONTAINER_NAME
docker inspect \
--format 'json .State.Health' \
CONTAINER_NAMERun non-interactive checks inside a container:
docker exec CONTAINER_NAME env
docker exec CONTAINER_NAME ps aux
docker exec CONTAINER_NAME cat /etc/resolv.confInspect networks:
docker network ls
docker network inspect NETWORK_NAMEUse this to check whether services are attached to the expected network, whether container DNS names resolve, whether a service is isolated from a dependency, and whether an external network is wrong.
Check resource usage:
docker stats --no-streamRebuild only the affected service:
docker compose build backend
docker compose up -d backendOr rebuild and start one affected service in one step:
docker compose up -d --build backendAvoid rebuilding the whole application unless the problem affects shared images or shared configuration.
Host-side endpoint verification
A running container is not proof that the application works. After startup, test the exposed endpoint from the host:
curl -v http://localhost:8080/healthFor HTTPS with a development certificate:
curl -vk https://localhost:8443/healthA complete verification loop should include:
docker compose ps
docker compose logs --tail=100 SERVICE_NAME
curl -v http://localhost:PORT/healthThe process may be alive while its HTTP endpoint, database connection, dependency integration, or health check is failing.
Example: backend restart loop
Suppose the backend service repeatedly restarts. Ask Codex:
Investigate why the backend service is restarting.
Do not modify files until you explain the root cause.Codex should gather evidence first:
docker compose ps
docker compose logs --tail=200 backend
docker inspect backend
docker compose configIf the logs show:
connection refused: database:5432then inspect the dependency:
docker compose ps database
docker compose logs --tail=200 database
docker network inspect PROJECT_DEFAULT_NETWORKIf the backend starts before PostgreSQL is ready, a minimal fix may be a health check plus a health-gated dependency:
services:
database:
image: postgres:17
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
backend:
build: ./backend
depends_on:
database:
condition: service_healthyThen validate and restart only the affected services:
docker compose config
docker compose up -d --build database backend
docker compose ps
docker compose logs --tail=100 backendThe pattern is evidence first, narrow fix second, targeted restart third, and explicit verification last.
Project-specific Docker rules for Codex
For repeated use, put Docker safety rules in AGENTS.md at the project root:
# Docker Debugging Rules
- Inspect logs and status before modifying files.
- Explain the root cause before applying a fix.
- Prefer changes limited to the affected service.
- Do not run `docker compose down -v`.
- Do not run Docker prune commands.
- Do not delete named volumes.
- Do not reset or initialize databases.
- Do not expose additional ports without explaining why.
- Ask before stopping unrelated containers.
- After changes, validate with `docker compose config`.
- Verify fixes with service status, logs, health checks,
and endpoint tests.Codex reads AGENTS.md as durable project guidance at session start. Keep the file concise and place stricter rules closer to specialized subdirectories when only part of the repository needs them.
Troubleshooting Docker access
Permission denied on the Docker socket:
permission denied while trying to connect to the Docker daemon socketCheck socket permissions and group membership:
ls -l /var/run/docker.sock
id
getent group dockerIf the user was recently added to the docker group, log out and log back in.
Docker daemon unavailable:
Cannot connect to the Docker daemonCheck the service and recent daemon logs:
sudo systemctl status docker
sudo journalctl -u docker --no-pager -n 100
sudo systemctl start dockerDocker works manually but not from Codex:
docker psIf that works in the terminal but fails inside Codex, the likely issue is the Codex sandbox or permission profile rather than Docker itself. Check:
- whether Codex requested approval for the Docker command;
- the active mode with
/permissions; - whether the configured Unix socket matches the active Docker context;
- whether older
sandbox_modesettings are being mixed with permission profiles.
Wrong Docker context:
docker context show
docker context ls
docker context use defaultIf the active context points to a remote daemon, Codex may be debugging a different Docker host than expected.
Recommended security posture
For a development workstation:
- run Codex as a normal Linux user;
- keep project files under a dedicated workspace directory;
- start with
workspace-writeandon-requestapprovals; - approve Docker commands after reviewing them;
- use a Docker-specific permission profile only for frequent debugging;
- allow only the Docker Unix socket and any required localhost endpoints;
- avoid
danger-full-accessunless the host is isolated; - never allow unattended volume deletion or Docker pruning;
- keep secrets in protected environment files;
- review code and configuration changes before rebuilding services;
- maintain backups for databases and persistent volumes.
Codex is most useful here as an evidence-gathering and change-minimizing debugging agent. It should inspect status, logs, health checks, networks, configuration, and endpoint behavior before it edits files or restarts services.
Reference List
- https://developers.openai.com/codex/environment-variables
- https://developers.openai.com/codex/concepts/sandboxing
- https://developers.openai.com/codex/permissions
- https://developers.openai.com/codex/guides/agents-md
- https://docs.docker.com/engine/install/ubuntu/
- https://docs.docker.com/compose/
- https://docs.docker.com/engine/security/rootless/