Add RUN_AS_USER variable - default root, set to coder for non-root

This commit is contained in:
SAGE 2026-01-29 17:19:43 +08:00
parent 5dd4e6a446
commit d384d20fa5
2 changed files with 77 additions and 68 deletions

View File

@ -4,16 +4,16 @@
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/template/TEMPLATE_ID)
Cloud IDE with persistent extensions, settings, and tools. Runs as non-root user.
Cloud IDE with persistent extensions, settings, and tools.
---
## Features
- **Claude Code** & **Node.js 20** pre-installed
- **Non-root execution** - runs as `coder` user (UID 1000)
- Extensions persist across redeployments
- Volume permissions auto-fixed on startup
- Configurable user (root or coder)
- Shell profile auto-configured with PATH
---
@ -23,12 +23,11 @@ Cloud IDE with persistent extensions, settings, and tools. Runs as non-root user
# Claude Code with auto-accept (for automation)
claude --dangerously-skip-permissions
# Or use the alias
claude-auto
# Interactive mode
claude
# Node.js ready
node --version
npm --version
```
---
@ -38,32 +37,35 @@ npm --version
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PASSWORD` | Yes | - | Login password |
| `RUN_AS_USER` | No | `root` | Set to `coder` for non-root |
| `CODER_HOME` | No | `/home/coder` | Volume mount path |
| `CODER_UID` | No | `1000` | User ID for coder |
| `CODER_GID` | No | `1000` | Group ID for coder |
| `CODER_UID` | No | `1000` | User ID (when RUN_AS_USER=coder) |
| `CODER_GID` | No | `1000` | Group ID (when RUN_AS_USER=coder) |
---
## How It Works
## Running as Non-Root (Recommended for Claude)
1. **Starts as root** - fixes volume permissions
2. **Switches to coder** - uses `gosu` for clean handoff
3. **Runs code-server** - as non-root user
Set in Railway variables:
```
RUN_AS_USER=coder
```
This means:
- ✅ No root permission warnings in code-server
- ✅ Existing volumes with root-owned files work fine
- ✅ Claude `--dangerously-skip-permissions` works
This enables:
- ✅ No root permission warnings
- ✅ `claude --dangerously-skip-permissions` works properly
- ✅ Better security
---
## Claude Code Authentication
## Update Behavior
After running `claude` for the first time:
1. Follow the authentication prompts
2. Your credentials are stored in `~/.claude/`
3. They persist across redeployments (on volume)
| Component | Behavior |
|-----------|----------|
| **Volume tools** | You control - install to `~/.local/bin/` |
| **Image tools** | Auto-update on redeploy (fallback) |
| **Extensions** | Persist on volume |
| **Claude auth** | Persists in `~/.claude/` |
---
@ -80,29 +82,6 @@ Make executable: `chmod +x script.sh`
---
## Update Behavior
| Component | Behavior |
|-----------|----------|
| **Volume tools** | You control - install to `~/.local/node/` or `~/.claude/local/` |
| **Image tools** | Auto-update on redeploy (fallback) |
| **Extensions** | Persist on volume |
| **Claude auth** | Persists on volume |
Logs show `[volume]` or `[image]` next to each tool.
---
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Permission denied | Check `CODER_UID` matches your volume owner |
| Claude not found | Run `which claude` to check PATH |
| Extensions missing | Verify volume mounted at `CODER_HOME` |
---
## Credits
- [code-server](https://github.com/coder/code-server) by Coder

View File

@ -3,7 +3,7 @@ set -e
# ============================================================================
# VSCode Cloud IDE - Railway Entrypoint
# Handles permission fix and user switching for non-root execution
# Handles permission fix and optional user switching
# ============================================================================
echo "╔══════════════════════════════════════════════════════════════════════╗"
@ -12,13 +12,16 @@ echo "╚═══════════════════════
echo ""
# ============================================================================
# CONFIGURABLE PATHS
# CONFIGURABLE PATHS AND USER
# ============================================================================
CODER_HOME="${CODER_HOME:-/home/coder}"
CODER_UID="${CODER_UID:-1000}"
CODER_GID="${CODER_GID:-1000}"
# RUN_AS_USER: Set to "coder" to run as non-root, or "root" (default) to stay as root
RUN_AS_USER="${RUN_AS_USER:-root}"
export HOME="$CODER_HOME"
export XDG_DATA_HOME="$CODER_HOME/.local/share"
export XDG_CONFIG_HOME="$CODER_HOME/.config"
@ -28,12 +31,17 @@ export XDG_STATE_HOME="$CODER_HOME/.local/state"
# PATH: Include ~/.local/bin where Claude installs by default
export PATH="$CODER_HOME/.local/bin:$CODER_HOME/.local/node/bin:$CODER_HOME/.claude/local:$CODER_HOME/node_modules/.bin:/usr/local/bin:/usr/bin:/usr/lib/code-server/lib/vscode/bin/remote-cli:$PATH"
echo "→ Initial user: $(whoami) (UID: $(id -u))"
echo "→ RUN_AS_USER: $RUN_AS_USER"
echo "→ HOME: $HOME"
# ============================================================================
# PERMISSION FIX (runs as root, then switches to coder)
# DIRECTORY CREATION AND PERMISSION FIX
# ============================================================================
if [ "$(id -u)" = "0" ]; then
echo "→ Running initial setup as root..."
echo ""
echo "→ Running setup as root..."
# Create directories if they don't exist
mkdir -p "$XDG_DATA_HOME" \
@ -50,11 +58,9 @@ if [ "$(id -u)" = "0" ]; then
# ========================================================================
# SHELL PROFILE SETUP
# Ensure PATH includes ~/.local/bin for Claude and other user tools
# ========================================================================
PROFILE_FILE="$HOME/.bashrc"
PATH_EXPORT='export PATH="$HOME/.local/bin:$HOME/.local/node/bin:$PATH"'
if [ ! -f "$PROFILE_FILE" ] || ! grep -q '.local/bin' "$PROFILE_FILE" 2>/dev/null; then
echo "→ Setting up shell profile..."
@ -82,24 +88,46 @@ fi
PROFILE
fi
# Fix ownership on the entire home directory
echo "→ Fixing permissions for coder user (UID: $CODER_UID)..."
chown -R "$CODER_UID:$CODER_GID" "$CODER_HOME" 2>/dev/null || true
# ========================================================================
# USER SWITCHING (if RUN_AS_USER=coder)
# ========================================================================
echo " ✓ Permissions fixed"
echo ""
# Re-exec this script as coder user using gosu
echo "→ Switching to coder user..."
exec gosu "$CODER_UID:$CODER_GID" "$0" "$@"
if [ "$RUN_AS_USER" = "coder" ]; then
echo "→ Fixing permissions for coder user (UID: $CODER_UID)..."
chown -R "$CODER_UID:$CODER_GID" "$CODER_HOME" 2>/dev/null || true
echo " ✓ Permissions fixed"
# Check if gosu is available
if command -v gosu &>/dev/null; then
echo "→ Switching to coder user via gosu..."
exec gosu "$CODER_UID:$CODER_GID" "$0" "$@"
else
echo " ⚠ gosu not found, staying as root"
fi
else
echo "→ Staying as root (set RUN_AS_USER=coder to switch)"
# Create symlinks from /root to volume for persistence
mkdir -p /root/.local 2>/dev/null || true
for dir in ".local/share" ".local/bin" ".local/node" ".config" ".cache" ".claude"; do
target="$CODER_HOME/$dir"
link="/root/$dir"
if [ -d "$target" ] && [ ! -L "$link" ]; then
rm -rf "$link" 2>/dev/null || true
mkdir -p "$(dirname "$link")" 2>/dev/null || true
ln -sf "$target" "$link" 2>/dev/null || true
fi
done
echo " ✓ Root directories symlinked to $CODER_HOME"
fi
fi
# ============================================================================
# RUNNING AS CODER USER FROM HERE
# RUNNING AS FINAL USER
# ============================================================================
echo "→ User: $(whoami) (UID: $(id -u))"
echo "→ HOME: $HOME"
echo ""
echo "Running as: $(whoami) (UID: $(id -u))"
# ============================================================================
# FIRST RUN SETUP
@ -138,10 +166,12 @@ claude
You'll need to authenticate with your Anthropic API key on first use.
## Persist Claude Authentication
## Configuration
Your Claude config at `~/.claude/` persists across redeployments.
After authenticating once, you won't need to re-authenticate.
Set these environment variables in Railway:
- `RUN_AS_USER=coder` - Run as non-root user (recommended for Claude)
- `RUN_AS_USER=root` - Stay as root (default)
Happy coding! 🚀
WELCOME
@ -171,7 +201,7 @@ echo " → npm: $(npm --version 2>/dev/null || echo 'not found')"
# git
echo " → git: $(git --version 2>/dev/null | cut -d' ' -f3 || echo 'not found')"
# Claude Code - show source (check ~/.local/bin first, then ~/.claude/local, then /usr/local/bin)
# Claude Code - show source
if [ -x "$CODER_HOME/.local/bin/claude" ]; then
echo " → claude: $(claude --version 2>/dev/null || echo 'installed') [volume ~/.local/bin]"
elif [ -x "$CODER_HOME/.claude/local/claude" ]; then