Claude Code v2.1.78+ Root Restriction — Non-Root User Workaround
Trigger
Claude Code desktop auto-updated to v2.1.78, introducing a permanent security policy: --dangerously-skip-permissions is blocked when running as root/sudo. This flag is automatically passed by Claude Code desktop when connecting to a remote server via SSH. Since the VPS was configured as root@72.61.173.164, the remote ccd-cli process crashed on every connection attempt with exit code 1.
This is a permanent Anthropic security policy, not a bug.
Three Issues Resolved
Issue 1 — Stale SSH Host Key
The VPS had been rebuilt previously, leaving a stale host key in ~/.ssh/known_hosts on the desktop machine. Fixed with ssh-keygen -R 72.61.173.164 and re-accepting the new key.
Issue 2 — Root + Skip-Permissions Block (Primary)
Fix: Created non-root user claude (uid=1002) with:
- Passwordless sudo:
ALL=(ALL) NOPASSWD:ALL - Group memberships:
claude,root,sudo - SSH alias
aj-vps-claude(User: claude) added to desktop~/.ssh/config - Desktop SSH Host changed from
aj-vpstoaj-vps-claude - Original
aj-vpsalias (User: root) preserved for direct terminal SSH
Issue 3 — Malformed Settings Hook
/root/.claude/settings.json had a malformed Stop hook (missing matcher field and hooks array wrapper). Fixed with proper {"matcher": "", "hooks": [...]} structure.
Post-Migration Fix — OpenClaw Config Continuity
After the user change, Claude Code’s runtime (running as claude with HOME=/home/claude) could not see the OpenClaw setup at /root/.claude/ — settings, hooks, skills, plugins, agent-instructions, CLAUDE.md, todos, sessions were all invisible.
Fix applied:
- Replaced
/home/claude/.claude/(empty runtime directories) with symlink:/home/claude/.claude→/root/.claude - Set group read/write permissions:
chmod -R g+rwX /root/.claude/ - Set setgid on all directories:
find /root/.claude -type d -exec chmod g+s {} \; - Works because
claudeuser is in therootgroup
Final Verified State
| Component | Status |
|---|---|
Claude Code CLI as user claude (uid=1002) | Operational |
SSH: aj-vps-claude (claude) for Claude Code, aj-vps (root) for terminal | Both working |
/home/claude/.claude → /root/.claude symlink | Full R/W verified |
| settings.json — hooks, plugins, alwaysThinkingEnabled, effortLevel | All wired |
31 skills at ~/.claude/skills/ | All discoverable |
3 Python hooks at ~/.claude/hooks/ | All firing |
| Agent instructions (SOUL.md + 12 agents) | Accessible |
MCP registrations (/root/.claude.json) | Readable |
| Project memories (17 files) | Full R/W |
OpenClaw — separate openclaw user (uid=1001), systemd, port 18789 | Completely unaffected |
Docker — claude user uses sudo docker | Working |
Workspaces — /root/aj-workspace, /root/aj-ea | Both accessible |
Architecture Invariants
- Single source of truth: All Claude Code config lives at
/root/.claude/. Symlink ensures bothrootandclaudeusers see the same state. - OpenClaw isolation: Runs as its own
openclawuser — zero coupling with Claude Code user change. - New files inherit group: setgid ensures files created by either user remain group-accessible.
- No functional change: Every capability (hooks, skills, plugins, MCP servers, agent instructions, memory) works identically.
Key Takeaway
Anthropic’s root restriction is permanent. The claude user with passwordless sudo provides identical authority without triggering the binary-level block. The symlink from /home/claude/.claude → /root/.claude ensures zero config divergence. This setup survives future Claude Code updates as long as non-root + sudo remains permitted.
Related
- claude-code-oauth-token-tiered-api-access
- mcp-server-registration-in-claude-code-ssh-remote-three
- mcp-server-registration-only-mechanism-2-works-in-ssh
- docker-non-root-user-volume-mount-match-host-uid-to
- vps-credential-leaks-in-tmp-from-previous-sessions-found
- playwright-interaction-testing-mandate
- claude-code-hook-architecture-expansion-precompact-postcompa
- gws-oauth-token-expiry-testing-vs-production-consent-screen
- workspace-memory-split-brain
- permanent-mcp-servers-must-be-verified-live-not-from-docs
- openclaw-skill-sync-path-and-verification-pattern
- openclaw-skill-sync-path
- orphaned-claude-sessions-ram-accumulation
- duplicate-crontab-double-execution-claude-vs-root
- universal-completion-gate-must-re-run-after-every-material-e
- operational-mcp-servers-were-duplicated-across-three-workspa
- subagent-stall-root-cause-missing-edit-write-wildcards
- brainstorm-server-env-isolation-for-concurrent-sessions
- hooks-registry-drifts-silently-as-hooks-are-added
- dual-claude-json-session-reads-home-not-root
- dual-claude-json-files-diverge-silently-session-reads-home-c
- dual-claude-json-config-parity-required-for-root-sessions
- tableau-mcp-gap-set-project-default-permissions