packaging: run as invoking user by default, silence nginx console, richer install help

Three operational fixes for the distributable image:

run_oci.sh: default the container to the invoking user (uid:gid, SUDO_UID-aware)
instead of the image's root default, with a new --root opt-out. The image has no
USER directive and supervisord sets no user=, so a run without --user created
root-owned dirs (logs, coderai-tmp, hf cache) in the bind-mounted /cache; a later
--user run then couldn't write them ("cannot write /cache/logs ... logging to
stdout only"). Running as the user by default makes a fresh install safe
regardless of run order. --root restores the old behaviour (and throwaway config
copy) for shared root-managed data dirs.

nginx.conf: error_log crit (was info) + access_log off. nginx's [notice]
startup/worker lines and per-request access logs were piped to the container
console by supervisord and buried coderai's own output on attach / docker logs.
Real failures (crit/alert/emerg) still surface.

install.sh: print an extensive post-install guide (quick start, --local + --map,
where data lives, the run-as-you default, file logging, docker logs/stop, --help).
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent bb8ebcf0
......@@ -118,6 +118,42 @@ if [ "${#OTHERS[@]}" -gt 0 ]; then
fi
say ""
say "Done. Quick start:"
say " coderai-docker --nvidia # or --vulkan / --cpu"
say " coderai-docker --help # all options (local config, --map, --debug, file log)"
say "═══════════════════════════════════════════════════════════════════════════"
say " CoderAI installed."
say "═══════════════════════════════════════════════════════════════════════════"
[ -n "$LOADED_TAG" ] && say " Image: $LOADED_TAG"
say " Runner: $BIN_DIR/coderai-docker"
if [ "$(id -u)" -ne 0 ] && ! case ":${PATH:-}:" in *":$BIN_DIR:"*) true;; *) false;; esac; then
say " NOTE: $BIN_DIR is not on PATH yet — open a new terminal or 'source ~/.bashrc'."
fi
say ""
say " QUICK START"
say " coderai-docker --nvidia # GPU via NVIDIA; or --vulkan / --cpu"
say " coderai-docker --nvidia -d # run detached (background)"
say " then open: http://localhost:8776/admin # web UI (default port 8776)"
say ""
say " USE YOUR LOCAL CONFIG + DATA (recommended)"
say " coderai-docker --nvidia --local \\"
say " --map /AI/huggingface --map /AI/offloads"
say " --local reads config/models.json from ~/.coderai (edits persist there)."
say " --map H[:C] bind-mounts a host dir so absolute paths in models.json resolve;"
say " repeat it for each models/cache location you reference."
say ""
say " WHERE THINGS LIVE"
say " Runtime data (models/cache): ./coderai-runtime, or ~/.config/coderai-runtime"
say " with --local (override with --data-dir PATH)."
say " The container runs as YOU by default (uid:gid), so nothing it writes to"
say " those dirs is root-owned. Use --root only if you deliberately want root."
say ""
say " LOGS"
say " coderai-docker --nvidia --debug # tee a host-tailable file log"
say " Default log path: <cache>/logs/coderai.log (also visible via 'docker logs')."
say " tail -F ~/.config/coderai-runtime/cache/logs/coderai.log # with --local"
say ""
say " MANAGE"
say " docker logs -f coderai # follow output of a detached run"
say " docker stop coderai # stop it (the container is --rm, so it's removed)"
say ""
say " ALL OPTIONS"
say " coderai-docker --help # port/host, tools, --root, --user, --config-dir, …"
say "═══════════════════════════════════════════════════════════════════════════"
......@@ -8,7 +8,11 @@
worker_processes auto;
daemon off;
pid /tmp/nginx.pid;
error_log /dev/stderr info;
# crit only: nginx's startup/worker [notice] lines and per-request info would
# otherwise stream to the container console (supervisord pipes nginx stderr to
# /dev/fd/1), drowning out coderai's own output on attach / `docker logs`. Real
# failures (crit/alert/emerg) still surface.
error_log /dev/stderr crit;
events {
worker_connections 1024;
......@@ -19,7 +23,9 @@ http {
default_type application/octet-stream;
sendfile on;
server_tokens off;
access_log /dev/stdout;
# Off: per-request access lines would stream to the container console and
# bury coderai's output on attach. coderai logs its own requests already.
access_log off;
# Writable temp paths under /tmp so the listed user (root or --user UID) can
# always create them; the defaults under /var/lib/nginx are root-only.
......
......@@ -40,12 +40,18 @@ CODERAI_EXTRA_ARGS="${CODERAI_EXTRA_ARGS:-}"
DATA_ROOT="$PWD/coderai-runtime"
DATA_ROOT_EXPLICIT=0
IS_LOCAL=0
# Run the container as a specific user. Empty = container default (root). When set
# (e.g. via --user with no value -> your uid:gid) AND a config dir is used, the
# config is mounted IN PLACE so the app's edits persist to it (files stay owned by
# you). Without --user, an in-place mount as root would create root-owned files,
# so we fall back to the throwaway temp copy.
USER_SPEC=""
# Run the container as a specific user. DEFAULT: the invoking user (uid:gid) so
# nothing the container creates in the mounted /config|/models|/cache (logs,
# coderai-tmp, hf cache, …) is left root-owned — a single root run would
# otherwise poison those dirs so later --user runs can't write them (the
# "cannot write /cache/logs … logging to stdout only" symptom). Pass --root to
# opt back into the image's root default; pass --user UID[:GID] to pick another.
# When non-empty AND a config dir is used, the config is mounted IN PLACE so the
# app's edits persist to it (files stay owned by you); under --root we fall back
# to a throwaway temp copy so a root container can't leave root-owned config.
# Prefer the pre-sudo identity (SUDO_UID/GID) so `sudo coderai-docker` still runs
# the container as the real user, not root — same anti-footgun goal.
USER_SPEC="${SUDO_UID:-$(id -u)}:${SUDO_GID:-$(id -g)}"
DETACH=0
NAME="coderai"
EXTRA_ARGS=()
......@@ -116,10 +122,15 @@ Options:
--local Shortcut for --config-dir ~/.coderai. Also puts the runtime
dir under ~/.config/coderai-runtime (override with --data-dir).
Add --user to persist the app's config edits back to it.
--user[=UID[:GID]] Run the container as that user (no value = your uid:gid). With
a config dir, switches to an IN-PLACE mount so config edits
persist there, owned by you. Without it, --config-dir/--local
use a throwaway copy (no persistence).
--user[=UID[:GID]] Run the container as that user (no value = your uid:gid).
This is the DEFAULT (the invoking user) so the container
never leaves root-owned files in the mounts. With a config
dir, uses an IN-PLACE mount so config edits persist there,
owned by you.
--root Run the container as root (the image default). Opts out of
the default --user; anything written to the mounts will be
root-owned, and --config-dir/--local use a throwaway copy
(no persistence) to avoid root-owned config.
--inplace-config Mount --config-dir in place (config edits persist there).
--map HOST[:CONT] Bind-mount a host dir at the SAME path (or HOST:CONT) inside
the container, so absolute paths in models.json resolve
......@@ -186,6 +197,10 @@ while [[ $# -gt 0 ]]; do
if [[ $# -ge 2 && "$2" =~ ^[0-9] ]]; then USER_SPEC="$2"; shift 2
else USER_SPEC="$(id -u):$(id -g)"; shift; fi ;;
--user=*) USER_SPEC="${1#*=}"; shift ;;
# Opt back into the image's root default (the container runs as root). Anything
# it writes into the mounts will be root-owned — only use when you really want
# that (e.g. a shared root-managed data dir).
--root) USER_SPEC=""; shift ;;
--map)
[[ $# -ge 2 ]] || { echo "Error: --map requires HOST[:CONT]" >&2; exit 2; }
MAPS+=("$2"); shift 2 ;;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment