Codex CLI on Linux: install, sandbox, and servers

Linux is the platform where Codex needs something from you before the sandbox works. It is one package, and if you skip it the agent still runs while quietly warning that its boundary is not what you think.

By the Continuum team. We build a workbench that runs Claude Code, Codex, and their peers, so the model rates quoted here are the ones our own cost analytics ship with.

The short version

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.

What you need to know
  • Install with curl -fsSL https://chatgpt.com/codex/install.sh | sh, or npm. Never sudo npm i -g.
  • Homebrew is not a Linux route. The codex package is a macOS-only cask.
  • The Linux sandbox is bubblewrap as of Codex 0.115. Install bwrap first.
  • On Ubuntu 24.04, load the bwrap-userns-restrict AppArmor 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-access is defensible there.

Installing

The route OpenAI documents first.
curl -fsSL https://chatgpt.com/codex/install.sh | sh

# it lands in ~/.local/bin by default
export PATH="$HOME/.local/bin:$PATH"
codex --version
Or npm, with a user-writable prefix. Never sudo.
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.

ItemRequirement
DistributionUbuntu 20.04 or newer, Debian 10 or newer, and equivalents
RAM4 GB minimum, 8 GB recommended
Git2.23 or newer for the built-in pull-request helpers
SandboxThe bubblewrap package, providing bwrap
Architecturex86_64 and aarch64, statically linked against musl
The rest of the toolchain Codex expects to find.
# 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.

Install it, then confirm which binary Codex will find.
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.

Ubuntu 24.04: load the extra profile.
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.

SettingValuesControls
sandbox_moderead-only, workspace-write, danger-full-accessWhat a spawned command is capable of
approval_policyuntrusted, on-request, neverWhen Codex stops to ask you
~/.codex/config.toml
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.

01

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.

02

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.

03

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.

04

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

codex exec defaults to a read-only sandbox. Keep it that way where you can.
# 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"
In a container, the container is the sandbox.
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.

A systemd unit that actually finds Codex and its credential.
[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.

JobFlags
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.

  1. OpenAI Codex documentation
  2. Codex sandboxing
  3. Codex authentication
  4. openai/codex on GitHub
Try it

Linux hosts,
driven anywhere.

Continuum installs and supervises agents on Linux boxes over Tailscale, visible from your Mac, the web, or your phone.

free app · your subscriptions · local-first