ngn container: configuration and authentication¶
The runtime image in dockerfiles/Runtime.Dockerfile starts ngn serve --host
0.0.0.0 as root inside the container, in /home/agent/workspace. It serves the web UI with
no configuration file or API key. Starting and passing /api/bootstrap
does not verify provider access: live chat still needs an account, a supported
model and credentials. With no credential source, the UI shows setup guidance
and a chat attempt returns a specific, safe error instead of claiming success.
Use an authenticated, trusted network boundary around the container; it is a
single-user workspace, not a multi-user service.
Root access inside the container¶
Approved shell tools run with the same container identity as ngn. The runtime
image and web Kubernetes examples use UID/GID 0 and a writable container root
filesystem, so commands such as apt-get update and apt-get install can install
system dependencies. Tool approval still applies: becoming root does not grant
automatic approval to run a tool.
The Kubernetes examples drop all capabilities, then add CHOWN, DAC_OVERRIDE,
FOWNER, SETUID, and SETGID for package ownership and the package manager's
unprivileged download user. They retain the runtime's default seccomp profile,
disable privilege escalation and service-account-token mounting, and do not
mount a Docker socket or host system directories. No privileged: true,
SYS_ADMIN, host networking, or host process namespace is needed.
For the same configuration with Docker, use a published image digest:
docker run --rm --user 0:0 --cap-drop ALL \
--cap-add CHOWN --cap-add DAC_OVERRIDE --cap-add FOWNER \
--cap-add SETUID --cap-add SETGID --security-opt no-new-privileges \
-p 127.0.0.1:8765:8765 \
ghcr.io/abi-jey/nagents/agent-server@sha256:<reviewed-digest>
Package installations change the container's writable layer. They disappear
when the container is replaced; put permanent system dependencies in a derived
image. Keep sessions, credentials, and workspace files on the configured data
volume. The retained agent account also supports an explicitly non-root
deployment with Docker --user 1000:1000 --env HOME=/home/agent, or equivalent
Kubernetes settings and writable volumes owned by that user.
When changing an existing deployment from UID 1000 to UID 0, first stop ngn at
an idle maintenance window and back up its persistent state. Preserve its
HOME, XDG_DATA_HOME, XDG_CONFIG_HOME, and workspace/data paths, and migrate
ownership of only its dedicated private state to the new UID/GID. Update any
initializer that sets ownership too. Keep authentication directories at 0700
and credential files at 0600: the credential store checks ownership against
the running UID and will reject a store still owned by the previous user.
Changing only the image's USER does not override a pod's runAsNonRoot,
runAsUser, or read-only root filesystem settings.
Two ways to configure an API-key connection¶
For a mounted file, use secret-free JSON. A complete Kubernetes
ConfigMap + Deployment + ClusterIP Service is in
examples/k8s/ngn-container-config.yaml.
The deployment selects the projected file explicitly:
The ConfigMap's providers.json selects an OpenAI API-key connection and
config.json chooses gpt-6-luna. The Secret reference sets that environment
variable in the ngn container; a browser's environment cannot supply it.
Replace the example image tag with a digest of an image built from the updated
Dockerfile. Change the model to one your account can use; setting a model name
does not grant model access.
For UI-first setup, omit --config and the config volume/mount. The web
client starts without a selected provider; add and activate a named connection
in Provider connections before chatting. Supply its key variable to the container:
env:
- name: NGN_MODEL
value: gpt-6-luna
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ngn-provider-example
key: OPENAI_API_KEY
optional: true
Keep the example's XDG_DATA_HOME, XDG_CONFIG_HOME and writable /data and
/workspace volumes. A zero-config container shows setup guidance until a
named connection is selected. Enter the variable name OPENAI_API_KEY in
that connection; never enter its value in configuration. An explicit
--config must point to an existing readable file. Environment defaults have
lower precedence than JSON; explicit CLI options have higher precedence. ngn
does not interpret NGN_CONFIG or automatically read .env files.
Provision and verify¶
- Build/publish the updated image and use its digest in your private render of
the sample. Provision a Secret from a private file, for example
kubectl -n <namespace> create secret generic ngn-provider-example --from-file=OPENAI_API_KEY=/private/path/openai-api-key(key only, with no trailing newline). Do not place the key in a ConfigMap, JSON, image, command argument or logs. The Secret is optional only to allow UI-first startup; a missing key cannot run inference. - Deploy the ConfigMap example, or the env-only variant, in your namespace.
Provide a persistent writable data volume when you want settings, sessions
and credentials to survive replacement; the example's
emptyDirvolumes are deliberately ephemeral. Use a single replica withRecreatefor a persistent SQLite database. Grant access to the Service only through your approved ingress/proxy. Kubernetes ConfigMap projected files use symlinks under/etc/ngn/..20.../; a diagnostic naming that resolved path means the file was read, not that the path is invalid. - Open the UI, confirm the selected connection and model in Settings, then
make one live request.
/api/bootstrapand a ready pod prove only local UI startup. Rotate a Secret with a controlled container restart so its env value is refreshed. A saved named provider connection can override flat defaults; select the intended connection in Settings if one already exists on the persistent data volume.
ChatGPT/Codex subscription route¶
auth: chatgpt uses the ngn-owned renewable login at
$XDG_DATA_HOME/ngn/auth/openai.json, not OPENAI_API_KEY. If you use this
route, run ngn login chatgpt with the same persistent XDG_DATA_HOME as
the serving container (with only one process refreshing the login), or transfer
an existing ngn OpenAIAuth store as a regular private file owned by the
container user, with private directory/file permissions (0700/0600). It is not
a generic Codex ~/.codex/auth.json file. auth: codex is a separate local
Codex discovery mode and needs explicit CODEX_HOME/~/.codex files inside
the container. A host's login is never implicitly available in a pod.
auth: auto may choose a saved ngn/Codex login before an OpenAI API key;
choose auth: api-key explicitly when the Secret should power chat. GPT-Live
uses separate model/voice settings and credentials.
An on-disk login status of “saved” only confirms that a file can be parsed; tokens can be expired/revoked, renewal can fail, and the selected model can be unavailable. The web error now distinguishes known authentication, permission, quota and connection failures using bounded internal error codes. Unknown upstream error bodies and credential contents are not returned or logged by the web error mapping. A model-catalog failure is also not proof of a specific token/entitlement issue. Check the server's safe error category and the configured auth route before changing credentials or models.