Install with the standalone script from chatgpt.com/codex/install.sh or with npm. Homebrew is not an option on Linux: the codex package is a macOS cask. The Linux sandbox uses bubblewrap, so install the bwrap package first, and on Ubuntu 24.04 load the bwrap AppArmor profile. On servers, authenticate with device code or an API key. Checked against OpenAI docs in August 2026.
- Install with
curl -fsSL https://chatgpt.com/codex/install.sh | sh, or npm. Neversudo npm i -g. - Homebrew is not a Linux route. The
codexpackage is a macOS-only cask. - The Linux sandbox is bubblewrap as of Codex 0.115. Install
bwrapfirst. - On Ubuntu 24.04, load the
bwrap-userns-restrictAppArmor profile or the sandbox warns. - Headless: prefer
codex login --device-auth. Servers and CI want an API key. - In a container the container is the boundary, so
danger-full-accessis defensible there.
Installing
curl -fsSL https://chatgpt.com/codex/install.sh | sh
# it lands in ~/.local/bin by default
export PATH="$HOME/.local/bin:$PATH"
codex --version
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
npm install -g @openai/codex
Baseline and prerequisites, checked August 2026.
| Item | Requirement |
|---|---|
| Distribution | Ubuntu 20.04 or newer, Debian 10 or newer, and equivalents |
| RAM | 4 GB minimum, 8 GB recommended |
| Git | 2.23 or newer for the built-in pull-request helpers |
| Sandbox | The bubblewrap package, providing bwrap |
| Architecture | x86_64 and aarch64, statically linked against musl |
# Ubuntu / Debian
sudo apt install -y git curl ripgrep bubblewrap
# Fedora / RHEL
sudo dnf install -y git curl ripgrep bubblewrap
# Arch
sudo pacman -S git curl ripgrep bubblewrap
The bubblewrap prerequisite
The Linux sandbox is built on bubblewrap, which isolates a spawned command using user namespaces. It changed: WSL1 was supported through Codex 0.114 and dropped at 0.115 precisely because the Linux sandbox moved to bubblewrap. Guides describing Landlock and seccomp are describing the older implementation.
sudo apt install bubblewrap # or: sudo dnf install bubblewrap
which bwrap
bwrap --version
The Ubuntu AppArmor case
Ubuntu restricts unprivileged user namespaces through AppArmor, so an installed bubblewrap is not always enough. On Ubuntu 25.04 the package ships the profile at /etc/apparmor.d/bwrap-userns-restrict and no extra work is needed. On Ubuntu 24.04, Codex can still warn that it cannot create the namespace.
sudo apt update
sudo apt install apparmor-profiles apparmor-utils
sudo install -m 0644 \
/usr/share/apparmor/extra-profiles/bwrap-userns-restrict \
/etc/apparmor.d/bwrap-userns-restrict
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
Codex prints a startup warning when bwrap is missing or the namespace cannot be created. Read that warning as "the sandbox is not what the config says it is", and fix it before running anything unattended.
Sandbox and approvals on a Linux box
Two orthogonal settings. Most Linux confusion is conflating them.
| Setting | Values | Controls |
|---|---|---|
sandbox_mode | read-only, workspace-write, danger-full-access | What a spawned command is capable of |
approval_policy | untrusted, on-request, never | When Codex stops to ask you |
sandbox_mode = "workspace-write"
approval_policy = "on-request"
[sandbox_workspace_write]
network_access = false # off by default; this makes it explicit
writable_roots = [] # add siblings the build genuinely writes
exclude_slash_tmp = false # /tmp is writable unless you exclude it
Headless: how to sign in without a browser
The browser login needs a browser and a reachable localhost callback. On a server you have neither, and there are four documented answers in descending order of preference.
Device code, if your account allows it
codex login --device-auth
Beta as of August 2026. Enable device-code login in ChatGPT security settings for a personal account, or in workspace permissions for a managed one, then open the printed link and enter the one-time code.
Forward the callback over SSH
ssh -L 1455:localhost:1455 user@remote
# then, inside that session
codex login
The browser flow works normally; the tunnel carries the callback back to the machine that has the browser.
Copy an existing credential
ssh user@remote 'install -d -m 700 ~/.codex && umask 077 && cat > ~/.codex/auth.json && chmod 600 ~/.codex/auth.json' < ~/.codex/auth.json
Treat auth.json exactly like a password. It carries access tokens. Never commit it, paste it into a ticket, or leave it world-readable.
Use an API key for anything unattended
printenv OPENAI_API_KEY | codex login --with-api-key
A ChatGPT subscription is licensed for interactive use by a person. Automation should hold its own key, with a spending limit set in the console before the first run.
Servers, CI, and containers
# read-only review, safe on a shared runner
codex exec "review the diff on this branch"
# machine-readable event stream
codex exec --json "summarise the last 20 commits" | jq
# a scripted refactor, after committing
codex exec --sandbox workspace-write "apply the rename described in RENAME.md"
# do not persist a rollout file on a shared box
codex exec --ephemeral "triage this repository"
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates ripgrep bubblewrap \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m -s /bin/bash agent
USER agent
ENV PATH="/home/agent/.local/bin:${PATH}"
RUN curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh
WORKDIR /workspace
ENTRYPOINT ["codex"]
Two Linux details bite in exactly this spot. A systemd unit or a cron job gets a minimal environment, so ~/.local/bin is usually not on its PATH and the run dies at "command not found" rather than at anything interesting. And CODEX_HOME follows the user the job runs as, so a service account has its own empty config root and its own missing credential until you put one there.
[Service]
User=agent
Environment=HOME=/home/agent
Environment=CODEX_HOME=/home/agent/.codex
Environment=PATH=/home/agent/.local/bin:/usr/local/bin:/usr/bin:/bin
WorkingDirectory=/srv/repo
ExecStart=/home/agent/.local/bin/codex exec --sandbox read-only "triage new issues"
Sensible pairings for an unattended Linux run.
| Job | Flags |
|---|---|
| Review a diff or triage an issue | --sandbox read-only --ask-for-approval never |
| Scripted refactor on a clean tree | --sandbox workspace-write --ask-for-approval never |
| Anything reading untrusted input | --sandbox read-only, always |
| Inside a disposable container | --sandbox danger-full-access is defensible |
| A build that needs a sibling checkout | --add-dir /path/to/sibling |
Questions people ask
Run curl -fsSL https://chatgpt.com/codex/install.sh | sh, or npm install -g @openai/codex with a user-writable prefix. Never use sudo with npm; it leaves root-owned files that break later installs.
No. Homebrew ships Codex as a macOS cask containing Darwin binaries only. On Linux use the standalone installer script or npm.
It uses bubblewrap to isolate spawned commands with user namespaces. Install your distribution bubblewrap package so the bwrap binary is on PATH; Codex uses the first one it finds and otherwise falls back to a bundled helper.
That is AppArmor on Ubuntu. On 24.04, install apparmor-profiles, copy bwrap-userns-restrict into /etc/apparmor.d/ and load it with apparmor_parser -r. Loading the profile is better than disabling the restriction globally.
Not as the primary mechanism. The Linux sandbox moved to bubblewrap in Codex 0.115, which is the same change that ended WSL1 support. Older guides describe the earlier implementation.
Prefer codex login --device-auth. Otherwise forward the callback with ssh -L 1455:localhost:1455, copy an existing ~/.codex/auth.json, or pipe an API key into codex login --with-api-key for unattended work.
It is defensible there, because the container supplies the boundary the sandbox would otherwise provide. On a shared host it is not, and --add-dir usually solves the real problem instead.
The Linux release binaries are statically linked against musl, which is the good case for Alpine. You still need bubblewrap available for the sandbox, and unprivileged user namespaces enabled in the kernel.
Sources
Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.