Run OpenAI Codex CLI in a Docker container. Codex is OpenAI's lightweight coding agent that runs in your terminal.
- Quick Start
- Prerequisites
- Authentication
- Usage Examples
- Configuration
- Volume Mounts
- Working with External Files and Screenshots
- Environment Variables
- Ports
- Sandbox Mode
- MCP (Model Context Protocol) Support
- Troubleshooting
- Shell Alias (Convenience)
- Building Locally
- License
- Links
# Pull and run (replace with your API key)
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=your-key \
ungb/codex- Docker installed
- One of the following:
- OpenAI API key with API credits
- ChatGPT account for OAuth login
Choose your authentication method:
| Plan Type | Authentication Method | Section |
|---|---|---|
| API Credits (Pay-as-you-go) | API Key (recommended) | API Key Setup |
| ChatGPT Subscription | OAuth Login | OAuth Setup |
Get an API key from OpenAI Platform:
# Set your API key as an environment variable
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=sk-... \
ungb/codexOr use an environment variable from your shell:
# Export once in your shell
export OPENAI_API_KEY=sk-...
# Then use in docker commands
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexNote: This method doesn't require mounting
~/.codexfor authentication (though you may still want to mount it for custom instructions and history).
OAuth login is a two-step process:
# Login with browser OAuth - expose port 1455 for callback
docker run -it --rm \
-p 1455:1455 \
-v ~/.codex:/home/coder/.codex \
ungb/codex \
codex loginOr use host network:
docker run -it --rm \
--network host \
-v ~/.codex:/home/coder/.codex \
ungb/codex \
codex loginThis opens your browser, authenticates with your ChatGPT account, and saves tokens to ~/.codex/ on your host machine.
After the one-time login, simply run:
# No API key needed!
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
ungb/codexImportant: Always mount
-v ~/.codex:/home/coder/.codexto persist your login. Without this mount, you'll need to login every time.
How it works: OAuth tokens are stored in ~/.codex/ on your host. By mounting this directory, your credentials persist between container runs. You only need to run codex login once (or when tokens expire).
# Start an interactive Codex session
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexUse codex exec (or codex e) for non-interactive mode:
# Ask a question about your codebase
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec "explain the architecture of this project"
# Generate code
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec "add input validation to the user form"
# Fix bugs (with auto-approval)
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec --ask-for-approval never "fix the type errors in src/utils"
# JSON output (for scripts/automation)
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec --json "list all TODO comments"# Pipe prompt from stdin
echo "explain this code" | docker run -i --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec -
# Analyze git diff
git diff | docker run -i --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec "review these changes"# Full setup with persistent config, git, SSH, and screenshots
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/codex-screenshots:/screenshots \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex- Copy
docker-compose.ymlto your project:
curl -O https://raw.githubusercontent.com/ungb/codex-docker/main/docker-compose.yml- Create a
.envfile:
echo "OPENAI_API_KEY=your-key-here" > .env- Run:
# Interactive session
docker compose run --rm codex
# One-shot command (non-interactive)
docker compose run --rm codex codex exec "explain this code"# Auto-approve all changes (use with caution)
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex --full-auto "implement the TODO items in this file"
# YOLO mode - no approvals, no sandbox (dangerous!)
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex exec --yolo "fix the failing tests"# Less verbose output
docker run -it --rm \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex \
codex --quietThe ~/.codex directory contains your Codex configuration, custom instructions, and session history.
~/.codex/
├── config.json # Settings and preferences
├── instructions.md # Custom instructions for Codex
└── history/ # Session history
# Share your Codex config folder
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexCreate ~/.codex/instructions.md with custom instructions that Codex will follow:
# My Codex Instructions
- Always use TypeScript strict mode
- Prefer functional programming patterns
- Add JSDoc comments to public functionsThen mount it:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex| Mount | Purpose |
|---|---|
/workspace |
Your project directory (required) |
/home/coder/.codex |
Codex config, instructions, history, OAuth tokens |
/home/coder/.ssh |
SSH keys for git operations (read-only) |
/home/coder/.gitconfig |
Git configuration (read-only) |
/screenshots |
Optional: Dedicated folder for screenshots and images (recommended) |
Important: Drag-and-drop doesn't work when Codex runs in a Docker container because it's isolated from your host filesystem. You need to explicitly mount directories to make files accessible.
Create a dedicated folder on your host machine for screenshots and images you want to share with Codex:
# Create a dedicated screenshots folder
mkdir -p ~/codex-screenshotsUsing docker run:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/codex-screenshots:/screenshots \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexUsing docker-compose:
Update your docker-compose.yml to include the screenshots mount:
volumes:
- ./:/workspace
- ~/.codex:/home/coder/.codex
- ~/codex-screenshots:/screenshots # Add this line# Copy screenshots or images to the folder
cp ~/Downloads/screenshot.png ~/codex-screenshots/
cp ~/Desktop/diagram.jpg ~/codex-screenshots/
# Or save screenshots directly to this folder using your screenshot toolInside Codex, reference files using the mounted path:
Can you analyze /screenshots/screenshot.png?
Please review the UI in /screenshots/mockup.png and suggest improvements
Read the diagram at /screenshots/architecture.jpg and explain the flow
You can also mount your Downloads folder directly:
# Mount Downloads folder (read-only recommended for safety)
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/Downloads:/downloads:ro \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexThen reference files:
Analyze /downloads/screenshot.png
If you're working on a specific project, copy files directly into your project directory:
# Copy to your project directory (which is already mounted as /workspace)
cp ~/Downloads/screenshot.png /path/to/your/project/
# Then in Codex:
# Analyze /workspace/screenshot.pngYou can mount multiple directories for different purposes:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/codex-screenshots:/screenshots \
-v ~/Downloads:/downloads:ro \
-v ~/Documents:/docs:ro \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexThis gives you access to:
/workspace- Your current project/screenshots- Dedicated screenshots folder (read-write)/downloads- Downloads folder (read-only)/docs- Documents folder (read-only)
- Use descriptive paths: Instead of
screenshot.png, uselogin-page-error.png - Organize by purpose: Create subfolders in
~/codex-screenshots/likebugs/,designs/,diagrams/ - Read-only mounts: Use
:roflag for folders you only need to read from (safety measure) - Absolute paths: Always use absolute paths when referencing files (e.g.,
/screenshots/image.png)
# 1. Take a screenshot (macOS example)
# Press Cmd+Shift+4 and save to ~/codex-screenshots/
# 2. Start Codex with screenshots mounted
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/codex-screenshots:/screenshots \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex
# 3. In Codex, reference the screenshot
> Can you analyze the error message in /screenshots/error-screenshot.png and help me fix it?| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY |
Conditional* | Your OpenAI API key |
OPENAI_ORG_ID |
No | OpenAI organization ID |
OPENAI_API_BASE |
No | Custom API endpoint (for proxies) |
*Required unless using OAuth login.
| Port | Purpose |
|---|---|
| 1455 | OAuth callback for codex login |
Codex recommends Docker for sandboxing. When you run Codex inside this container, it's already isolated from your host system.
For nested Docker (Docker-in-Docker), mount the Docker socket:
docker run -it --rm \
-v $(pwd):/workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexWarning: MCP support in Docker containers is limited and may require additional configuration.
MCP servers may not work out of the box in Docker because:
- Stdio-based MCP servers need the server binary installed inside the container
- Network-based MCP servers need proper network configuration
- MCP servers that access local resources need those resources mounted
- Authentication for MCP servers may not transfer into the container
| MCP Type | Status | Notes |
|---|---|---|
| HTTP/SSE servers (remote) | May work | Requires --network host or port mapping |
| Stdio servers (local) | Unlikely | Server must be installed in container |
| Servers needing local files | Partial | Files must be mounted |
| Servers with OAuth | Unlikely | Auth flow may not complete |
# Mount MCP config and use host network
docker run -it --rm \
--network host \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexFROM ungb/codex:latest
USER root
RUN npm install -g @modelcontextprotocol/some-server
USER coderFull MCP support requires further investigation. If you have solutions, please open an issue or PR!
The container runs as user coder (UID 1000). If you have permission issues:
# Run with your user ID
docker run -it --rm \
--user $(id -u):$(id -g) \
-v $(pwd):/workspace \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexEnsure SSH keys are mounted and git is configured:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codexEnsure port 1455 is exposed:
docker run -it --rm \
-p 1455:1455 \
-v ~/.codex:/home/coder/.codex \
ungb/codex \
codex loginYou must mount ~/.codex to persist OAuth tokens between container runs:
# Always include this mount for OAuth persistence
-v ~/.codex:/home/coder/.codexIf you're still being prompted to login:
- Verify the mount exists:
ls -la ~/.codex/ - Check for credential files:
ls ~/.codex/*.json 2>/dev/null - Ensure you ran
codex loginwith the same mount path
# Check version
docker run --rm ungb/codex codex --version
# Show help
docker run --rm ungb/codex codex --help
# View configuration
docker run --rm \
-v ~/.codex:/home/coder/.codex \
ungb/codex \
cat /home/coder/.codex/config.jsonAdd to your ~/.bashrc or ~/.zshrc:
alias codex-docker='docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/codex-screenshots:/screenshots \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
ungb/codex codex'
# Usage (interactive): codex-docker
# Usage (one-shot): codex-docker exec "explain this code"
# Usage (with screenshot): codex-docker exec "analyze /screenshots/bug.png"alias codex-docker='docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.codex:/home/coder/.codex \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/codex-screenshots:/screenshots \
ungb/codex codex'
# Usage (interactive): codex-docker
# Usage (one-shot): codex-docker exec "explain this code"
# Usage (with screenshot): codex-docker exec "analyze /screenshots/bug.png"git clone https://github.com/ungb/codex-docker.git
cd codex-docker
docker build -t codex .MIT License - see LICENSE