Added deployment options

This commit is contained in:
SAGE 2026-01-29 18:25:02 +08:00
parent 8299614992
commit 8077b23bd4
5 changed files with 493 additions and 100 deletions

View File

@ -1,20 +1,25 @@
# ============================================================================
# VSCode Cloud IDE - Claude Code & Node.js Ready
# Browser-based VSCode with persistent extensions and Node.js
# https://github.com/sphinxcode/code-server
# Claude Code Server - Browser-based VS Code with AI Coding Assistants
# https://github.com/sphinxcode/claude-code-server
# ============================================================================
FROM codercom/code-server:latest
FROM codercom/code-server:4.108.0
USER root
# Install gosu for proper user switching, Node.js, and essential tools
# Cache bust: 2026-01-29-v3
# ============================================================================
# SYSTEM DEPENDENCIES
# Install gosu, Node.js 20, Python/uv, and essential tools
# Cache bust: 2026-01-29-v4
# ============================================================================
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
gosu \
nodejs \
python3 \
python3-pip \
git \
curl \
wget \
@ -25,6 +30,7 @@ RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
nano \
ripgrep \
&& npm install -g npm@latest \
&& pip3 install --break-system-packages uv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@ -32,36 +38,46 @@ RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
# PERSISTENCE CONFIGURATION
# ============================================================================
ENV HOME=/home/coder
ENV USER=coder
ENV HOME=/home/clauder
ENV USER=clauder
# XDG Base Directory Specification
ENV XDG_DATA_HOME=/home/coder/.local/share
ENV XDG_CONFIG_HOME=/home/coder/.config
ENV XDG_CACHE_HOME=/home/coder/.cache
ENV XDG_STATE_HOME=/home/coder/.local/state
ENV XDG_DATA_HOME=/home/clauder/.local/share
ENV XDG_CONFIG_HOME=/home/clauder/.config
ENV XDG_CACHE_HOME=/home/clauder/.cache
ENV XDG_STATE_HOME=/home/clauder/.local/state
# PATH: Volume paths FIRST (user installs), image paths LAST (fallbacks)
ENV PATH="/home/coder/.local/bin:/home/coder/.local/node/bin:/home/coder/.claude/local:/home/coder/node_modules/.bin:/usr/local/bin:/usr/bin:/usr/lib/code-server/lib/vscode/bin/remote-cli:${PATH}"
ENV PATH="/home/clauder/.local/bin:/home/clauder/.local/node/bin:/home/clauder/.claude/local:/home/clauder/node_modules/.bin:/usr/local/bin:/usr/bin:/usr/lib/code-server/lib/vscode/bin/remote-cli:${PATH}"
# Custom startup scripts directory
ENV ENTRYPOINTD=/home/coder/entrypoint.d
ENV ENTRYPOINTD=/home/clauder/entrypoint.d
# ============================================================================
# USER SETUP
# Create clauder user with same UID as coder for compatibility
# ============================================================================
RUN groupadd -g 1000 clauder 2>/dev/null || true \
&& useradd -m -s /bin/bash -u 1000 -g 1000 clauder 2>/dev/null || true \
&& usermod -l clauder coder 2>/dev/null || true \
&& groupmod -n clauder coder 2>/dev/null || true
# ============================================================================
# DIRECTORY SETUP
# ============================================================================
RUN mkdir -p \
/home/coder/.local/share \
/home/coder/.config \
/home/coder/.cache \
/home/coder/.local/state \
/home/coder/.local/bin \
/home/coder/.local/node \
/home/coder/.claude \
/home/coder/entrypoint.d \
/home/coder/workspace \
&& chown -R 1000:1000 /home/coder
/home/clauder/.local/share \
/home/clauder/.config \
/home/clauder/.cache \
/home/clauder/.local/state \
/home/clauder/.local/bin \
/home/clauder/.local/node \
/home/clauder/.claude \
/home/clauder/entrypoint.d \
/home/clauder/workspace \
&& chown -R 1000:1000 /home/clauder
# Copy our custom entrypoint (replaces base image's entrypoint)
COPY railway-entrypoint.sh /usr/bin/railway-entrypoint.sh
@ -70,6 +86,7 @@ RUN chmod +x /usr/bin/railway-entrypoint.sh
# ============================================================================
# FALLBACK CLAUDE CODE CLI INSTALLATION
# Installed to /usr/local/bin as fallback - volume version takes priority
# Claude Code is ALWAYS installed (cannot be disabled)
# ============================================================================
RUN curl -fsSL https://claude.ai/install.sh | bash \
@ -84,7 +101,7 @@ RUN curl -fsSL https://claude.ai/install.sh | bash \
# Stay as root - entrypoint handles user switching based on RUN_AS_USER
# ============================================================================
WORKDIR /home/coder/workspace
WORKDIR /home/clauder/workspace
EXPOSE 8080
# Use our entrypoint which calls code-server directly

222
PROJECT_BRIEF.md Normal file
View File

@ -0,0 +1,222 @@
# Project Brief: Code-Server Railway Template
**Project:** VSCode Cloud IDE with Claude Code Integration
**Repository:** `sphinxcode/code-server`
**Railway Service:** `code-ajna` (claude.sphinx.codes)
**Status:** In Progress
---
## Executive Summary
Create a production-ready, marketable Railway template that provides browser-based VS Code (code-server) with pre-installed Claude Code CLI, persistent extensions, and configurable user permissions.
---
## Original Problems
### 1. Root User Permission Issues
- **Symptom:** code-server displayed security warnings about running as root
- **Cause:** `RAILWAY_RUN_UID=0` was set, forcing container to run as root
- **Impact:** Couldn't bypass certain settings, security warnings in UI
### 2. Non-Persistent Tools
- **Symptom:** npm, npx, extensions disappeared after redeployment
- **Cause:** Container running as root with `HOME=/root` (ephemeral), while volume mounted at `/home/coder`
- **Impact:** Users lost installed tools and configurations on each deploy
### 3. Claude Code Not Pre-installed
- **Request:** Template users should have Claude Code CLI available out-of-the-box
- **Requirement:** Support for `claude --dangerously-skip-permissions` flag
---
## Solution Architecture
### Infrastructure
| Component | Value |
|-----------|-------|
| Base Image | `codercom/code-server:latest` |
| Volume Mount | `/home/coder` (Railway volume) |
| Service URL | `claude.sphinx.codes` |
| Project ID | `59ae99d7-dc99-4642-ae06-642cd8d8c83a` |
| Service ID | `34522d52-ba69-4fcf-83b7-210a765a0a76` |
| Environment ID | `a921a831-e480-451b-b9c7-04ce2f647c68` |
### Key Files Modified
#### [Dockerfile](file:///E:/AI-Terminal/sphinxcode/code-server/Dockerfile)
- Installs `gosu` for proper user switching
- Installs Node.js 20 LTS as fallback
- Installs Claude Code CLI to `/usr/local/bin/claude`
- Installs essential tools: ripgrep, jq, htop, vim, nano
- Sets up XDG directories for persistence
- PATH prioritizes volume paths over image paths
#### [railway-entrypoint.sh](file:///E:/AI-Terminal/sphinxcode/code-server/railway-entrypoint.sh)
- Configurable user via `RUN_AS_USER` variable
- Shell profile setup (`.bashrc`, `.profile`) with PATH
- Permission fixing via `chown` when switching users
- User switching via `gosu` when `RUN_AS_USER=coder`
- Root symlinks for persistence when staying as root
- First-run initialization with welcome README
- Environment verification logging
#### [README.md](file:///E:/AI-Terminal/sphinxcode/code-server/README.md)
- Documentation for all configuration variables
- Quick start guide for Claude Code
- Update behavior explanation
- Troubleshooting guide
---
## Configuration Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PASSWORD` | Yes | - | code-server login password |
| `RUN_AS_USER` | No | `root` | Set to `coder` for non-root execution |
| `CODER_HOME` | No | `/home/coder` | Volume mount path |
| `CODER_UID` | No | `1000` | User ID when switching to coder |
| `CODER_GID` | No | `1000` | Group ID when switching to coder |
| `GIT_REPO` | No | - | Repository to auto-clone on startup |
---
## Persistence Strategy
### Volume-First PATH Priority
```
$HOME/.local/bin ← User-installed tools (Claude, etc.)
$HOME/.local/node/bin ← User-installed Node.js
$HOME/.claude/local ← Claude Code from volume
/usr/local/bin ← Image fallback (Claude)
/usr/bin ← Image fallback (Node.js)
```
### What Persists (on volume)
- Extensions: `~/.local/share/code-server/extensions/`
- Claude Code: `~/.local/bin/claude` or `~/.claude/`
- Claude auth: `~/.claude/` (API keys, settings)
- Node.js: `~/.local/node/` (if user installs)
- Shell config: `~/.bashrc`, `~/.profile`
- Workspace: `~/workspace/`
### What Auto-Updates (from image)
- Node.js fallback in `/usr/bin/node`
- Claude Code fallback in `/usr/local/bin/claude`
- System packages (git, curl, etc.)
---
## User Modes
### Root Mode (Default)
```
RUN_AS_USER=root (or not set)
```
- Stays as root user
- Creates symlinks from `/root/``/home/coder/` for persistence
- Compatible with existing volumes owned by root
### Coder Mode (Recommended for Claude)
```
RUN_AS_USER=coder
```
- Switches to coder user (UID 1000) via gosu
- Fixes volume permissions before switching
- No root warnings in code-server UI
- Required for `claude --dangerously-skip-permissions`
---
## Issues Encountered & Resolved
### 1. Railway Start Command Override
- **Problem:** Railway had a custom start command that bypassed our ENTRYPOINT
- **Solution:** Cleared the start command via `mcp_railway_service_update`
### 2. Docker Layer Caching
- **Problem:** Railway used cached layers, ignoring our changes
- **Solution:** Added cache-bust comments to force rebuild
### 3. Claude Installs to ~/.local/bin
- **Problem:** Assumed Claude installed to `~/.claude/local/`
- **Solution:** Updated PATH to include `$HOME/.local/bin` first
### 4. Shell Profile Not Configured
- **Problem:** New terminals didn't have PATH set
- **Solution:** Entrypoint now writes to `.bashrc` and `.profile`
---
## Current Status
### Completed ✅
- Dockerfile with gosu, Node.js, Claude Code
- Entrypoint with RUN_AS_USER variable
- Shell profile auto-configuration
- PATH priority for volume-installed tools
- README documentation
- Removed conflicting `railway.json`
- Cleared Railway start command override
- Set `RUN_AS_USER=coder` on Railway
### Pending Verification 🔄
- Confirm entrypoint output appears in Railway logs
- Verify user switches to `coder` (not `root@xxx`)
- Test `claude --dangerously-skip-permissions` works
- Confirm Claude authentication persists
---
## Expected Startup Logs
```
╔══════════════════════════════════════════════════════════════════════════╗
║ VSCode Cloud IDE - Claude Code & Node.js Ready ║
╚══════════════════════════════════════════════════════════════════════════╝
→ Initial user: root (UID: 0)
→ RUN_AS_USER: coder
→ HOME: /home/coder
→ Running setup as root...
→ Setting up shell profile...
✓ Shell profile configured
→ Fixing permissions for coder user (UID: 1000)...
✓ Permissions fixed
→ Switching to coder user via gosu...
→ Running as: coder (UID: 1000)
Environment:
→ Node.js: v20.x.x [volume/image]
→ npm: x.x.x
→ git: x.x.x
→ claude: x.x.x [volume/image]
════════════════════════════════════════════════════════════════════════
Starting code-server as coder...
════════════════════════════════════════════════════════════════════════
```
---
## Files Summary
| File | Location | Purpose |
|------|----------|---------|
| `Dockerfile` | sphinxcode/code-server | Image build configuration |
| `railway-entrypoint.sh` | sphinxcode/code-server | Container startup script |
| `README.md` | sphinxcode/code-server | User documentation |
| `railway.toml` | sphinxcode/code-server | Railway deployment config |
---
## Next Steps
1. **Verify Deployment** - Check if entrypoint runs and user switches properly
2. **Test Claude** - Authenticate and run `claude --dangerously-skip-permissions`
3. **Create Railway Template** - Make template public for others to deploy
4. **Update Template Docs** - Include volume attachment instructions

133
README.md
View File

@ -1,26 +1,17 @@
# VSCode Cloud IDE
# Claude Code Server
**Browser-based VSCode with Claude Code & Node.js**
**Browser-based VS Code with Claude Code & AI Coding Assistants**
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/template/TEMPLATE_ID)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/template/claude-code-server)
Cloud IDE with persistent extensions, settings, and tools.
---
## Features
- **Claude Code** & **Node.js 20** pre-installed
- Extensions persist across redeployments
- Configurable user (root or coder)
- Shell profile auto-configured with PATH
Cloud IDE with persistent extensions, settings, and tools. Pre-installed Claude Code CLI.
---
## Quick Start
```bash
# Claude Code with auto-accept (for automation)
# Claude Code with auto-accept
claude --dangerously-skip-permissions
# Or use the alias
@ -32,46 +23,80 @@ claude
---
## Environment Variables
## ⚠️ Claude Code Authentication
| 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 (when RUN_AS_USER=coder) |
| `CODER_GID` | No | `1000` | Group ID (when RUN_AS_USER=coder) |
When running `claude` for the first time:
1. The CLI will display an authentication URL
2. **Copy the URL to a different browser** (not this code-server browser)
3. Complete the login in that browser
4. Copy the code displayed after login
5. Paste the code back into the CLI
Your credentials persist in `~/.claude/` across redeployments.
---
## Running as Non-Root (Recommended for Claude)
## 📍 Railway Deployment
Set in Railway variables:
```
RUN_AS_USER=coder
```
> **Region**: Set your Railway region to **US West** for the fastest performance.
This enables:
### Required Variables
| Variable | Description |
|----------|-------------|
| `PASSWORD` | Login password for code-server |
### User Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `CLAUDER_HOME` | `/home/clauder` | Volume mount path |
| `CLAUDER_UID` | `1000` | User ID for clauder |
| `CLAUDER_GID` | `1000` | Group ID for clauder |
| `RUN_AS_USER` | `root` | Set to `clauder` for non-root execution |
### Pre-Install AI CLIs
Set to `1` to install on startup (default: `0`):
| Variable | CLI | Description |
|----------|-----|-------------|
| `INSTALL_OPENCODE` | OpenCode | Google's agentic AI IDE |
| `INSTALL_GEMINI` | Gemini CLI | Google Gemini assistant |
| `INSTALL_KILOCODE` | KiloCode | VS Code AI coding |
| `INSTALL_CONTINUE` | Continue | Open-source AI code assistant |
| `INSTALL_CODEX` | Codex | OpenAI Codex CLI |
> **Note**: Claude Code is **always installed** and cannot be disabled.
### Pre-Install Development Frameworks
| Variable | Framework | Description |
|----------|-----------|-------------|
| `INSTALL_BMAD` | BMAD Method | Spec-driven development workflow |
| `INSTALL_OPENSPEC` | OpenSpec | AI-powered spec generation |
| `INSTALL_SPECKIT` | Spec-Kit | GitHub's specification toolkit |
---
## How It Works
1. **Starts as root** fixes volume permissions
2. **Installs optional CLIs** based on environment variables
3. **Switches to clauder** uses `gosu` for clean handoff
4. **Runs code-server** as non-root user
This means:
- ✅ No root permission warnings
- ✅ `claude --dangerously-skip-permissions` works properly
- ✅ Better security
---
## Update Behavior
| 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/` |
- ✅ Existing volumes work fine
- ✅ Claude `--dangerously-skip-permissions` works
---
## Custom Startup Scripts
Add to `$CODER_HOME/entrypoint.d/`:
Add scripts to `$CLAUDER_HOME/entrypoint.d/`:
```bash
#!/bin/bash
@ -82,6 +107,30 @@ Make executable: `chmod +x script.sh`
---
## Update Behavior
| Component | Behavior |
|-----------|----------|
| **Volume tools** | You control install to `~/.local/bin/` |
| **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 `CLAUDER_UID` matches your volume owner |
| Claude not found | Run `which claude` to check PATH |
| Extensions missing | Verify volume mounted at `CLAUDER_HOME` |
| Auth URL won't open | Copy URL to a different browser |
---
## Credits
- [code-server](https://github.com/coder/code-server) by Coder

View File

@ -2,12 +2,13 @@
set -e
# ============================================================================
# VSCode Cloud IDE - Railway Entrypoint
# Handles permission fix and optional user switching
# Claude Code Server - Railway Entrypoint
# Handles permission fix, optional user switching, and CLI installations
# https://github.com/sphinxcode/claude-code-server
# ============================================================================
echo "╔══════════════════════════════════════════════════════════════════════╗"
echo "║ VSCode Cloud IDE - Claude Code & Node.js Ready ║"
echo "║ Claude Code Server - AI Coding Assistants Ready ║"
echo "╚══════════════════════════════════════════════════════════════════════╝"
echo ""
@ -15,21 +16,21 @@ echo ""
# CONFIGURABLE PATHS AND USER
# ============================================================================
CODER_HOME="${CODER_HOME:-/home/coder}"
CODER_UID="${CODER_UID:-1000}"
CODER_GID="${CODER_GID:-1000}"
CLAUDER_HOME="${CLAUDER_HOME:-/home/clauder}"
CLAUDER_UID="${CLAUDER_UID:-1000}"
CLAUDER_GID="${CLAUDER_GID:-1000}"
# RUN_AS_USER: Set to "coder" to run as non-root, or "root" (default) to stay as root
# RUN_AS_USER: Set to "clauder" 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"
export XDG_CACHE_HOME="$CODER_HOME/.cache"
export XDG_STATE_HOME="$CODER_HOME/.local/state"
export HOME="$CLAUDER_HOME"
export XDG_DATA_HOME="$CLAUDER_HOME/.local/share"
export XDG_CONFIG_HOME="$CLAUDER_HOME/.config"
export XDG_CACHE_HOME="$CLAUDER_HOME/.cache"
export XDG_STATE_HOME="$CLAUDER_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"
export PATH="$CLAUDER_HOME/.local/bin:$CLAUDER_HOME/.local/node/bin:$CLAUDER_HOME/.claude/local:$CLAUDER_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"
@ -56,6 +57,94 @@ if [ "$(id -u)" = "0" ]; then
"$XDG_DATA_HOME/code-server/extensions" \
"$XDG_CONFIG_HOME/code-server" 2>/dev/null || true
# ========================================================================
# OPTIONAL CLI INSTALLATIONS
# Install CLIs based on environment variables (only if not already present)
# ========================================================================
echo ""
echo "→ Checking optional CLI installations..."
# OpenCode
if [ "${INSTALL_OPENCODE:-0}" = "1" ]; then
if ! command -v opencode &>/dev/null; then
echo " → Installing OpenCode..."
curl -fsSL https://raw.githubusercontent.com/opencode-ai/opencode/refs/heads/main/install | bash || echo " ⚠ OpenCode install failed"
else
echo " ✓ OpenCode already installed"
fi
fi
# Gemini CLI
if [ "${INSTALL_GEMINI:-0}" = "1" ]; then
if ! command -v gemini &>/dev/null; then
echo " → Installing Gemini CLI..."
npm install -g @google/gemini-cli || echo " ⚠ Gemini CLI install failed"
else
echo " ✓ Gemini CLI already installed"
fi
fi
# KiloCode CLI
if [ "${INSTALL_KILOCODE:-0}" = "1" ]; then
if ! command -v kilocode &>/dev/null; then
echo " → Installing KiloCode CLI..."
npm install -g @kilocode/cli || echo " ⚠ KiloCode CLI install failed"
else
echo " ✓ KiloCode CLI already installed"
fi
fi
# Continue CLI
if [ "${INSTALL_CONTINUE:-0}" = "1" ]; then
if ! command -v continue &>/dev/null; then
echo " → Installing Continue CLI..."
npm install -g @continuedev/cli || echo " ⚠ Continue CLI install failed"
else
echo " ✓ Continue CLI already installed"
fi
fi
# Codex CLI
if [ "${INSTALL_CODEX:-0}" = "1" ]; then
if ! command -v codex &>/dev/null; then
echo " → Installing Codex CLI..."
npm install -g @openai/codex || echo " ⚠ Codex CLI install failed"
else
echo " ✓ Codex CLI already installed"
fi
fi
# ========================================================================
# OPTIONAL DEVELOPMENT FRAMEWORK INSTALLATIONS
# ========================================================================
# BMAD Method
if [ "${INSTALL_BMAD:-0}" = "1" ]; then
echo " → Installing BMAD Method..."
npx bmad-method install || echo " ⚠ BMAD install failed"
fi
# OpenSpec
if [ "${INSTALL_OPENSPEC:-0}" = "1" ]; then
if ! command -v openspec &>/dev/null; then
echo " → Installing OpenSpec..."
npm install -g @fission-ai/openspec@latest || echo " ⚠ OpenSpec install failed"
else
echo " ✓ OpenSpec already installed"
fi
fi
# Spec-Kit
if [ "${INSTALL_SPECKIT:-0}" = "1" ]; then
if ! command -v specify &>/dev/null; then
echo " → Installing Spec-Kit..."
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git || echo " ⚠ Spec-Kit install failed"
else
echo " ✓ Spec-Kit already installed"
fi
fi
# ========================================================================
# SHELL PROFILE SETUP
# ========================================================================
@ -67,7 +156,7 @@ if [ "$(id -u)" = "0" ]; then
cat >> "$PROFILE_FILE" << 'PROFILE'
# ============================================================================
# VSCode Cloud IDE - PATH Configuration
# Claude Code Server - PATH Configuration
# ============================================================================
export PATH="$HOME/.local/bin:$HOME/.local/node/bin:$HOME/.claude/local:$PATH"
@ -89,28 +178,28 @@ PROFILE
fi
# ========================================================================
# USER SWITCHING (if RUN_AS_USER=coder)
# USER SWITCHING (if RUN_AS_USER=clauder)
# ========================================================================
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
if [ "$RUN_AS_USER" = "clauder" ]; then
echo "→ Fixing permissions for clauder user (UID: $CLAUDER_UID)..."
chown -R "$CLAUDER_UID:$CLAUDER_GID" "$CLAUDER_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" "$@"
echo "→ Switching to clauder user via gosu..."
exec gosu "$CLAUDER_UID:$CLAUDER_GID" "$0" "$@"
else
echo " ⚠ gosu not found, staying as root"
fi
else
echo "→ Staying as root (set RUN_AS_USER=coder to switch)"
echo "→ Staying as root (set RUN_AS_USER=clauder 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"
target="$CLAUDER_HOME/$dir"
link="/root/$dir"
if [ -d "$target" ] && [ ! -L "$link" ]; then
rm -rf "$link" 2>/dev/null || true
@ -118,7 +207,7 @@ PROFILE
ln -sf "$target" "$link" 2>/dev/null || true
fi
done
echo " ✓ Root directories symlinked to $CODER_HOME"
echo " ✓ Root directories symlinked to $CLAUDER_HOME"
fi
fi
@ -133,14 +222,14 @@ echo "→ Running as: $(whoami) (UID: $(id -u))"
# FIRST RUN SETUP
# ============================================================================
FIRST_RUN_MARKER="$XDG_DATA_HOME/.vscode-cloud-initialized"
FIRST_RUN_MARKER="$XDG_DATA_HOME/.claude-code-server-initialized"
if [ ! -f "$FIRST_RUN_MARKER" ]; then
echo "→ First run detected - initializing..."
if [ ! -f "$HOME/workspace/README.md" ]; then
cat > "$HOME/workspace/README.md" << 'WELCOME'
# Welcome to VSCode Cloud IDE
# Welcome to Claude Code Server
Your cloud development environment is ready!
@ -164,13 +253,21 @@ claude-auto
claude
```
You'll need to authenticate with your Anthropic API key on first use.
## Claude Code Authentication
⚠️ **Important**: When authenticating Claude Code:
1. Copy the authentication URL
2. Open it in a **different browser** (not this code-server browser)
3. Complete the login there
4. Copy the code and paste it back into the CLI
Your credentials persist across redeployments.
## Configuration
Set these environment variables in Railway:
- `RUN_AS_USER=coder` - Run as non-root user (recommended for Claude)
- `RUN_AS_USER=clauder` - Run as non-root user (recommended)
- `RUN_AS_USER=root` - Stay as root (default)
Happy coding! 🚀
@ -189,7 +286,7 @@ echo ""
echo "Environment:"
# Node.js - show source
if [ -x "$CODER_HOME/.local/node/bin/node" ]; then
if [ -x "$CLAUDER_HOME/.local/node/bin/node" ]; then
echo " → Node.js: $(node --version 2>/dev/null) [volume]"
else
echo " → Node.js: $(node --version 2>/dev/null || echo 'not found') [image]"
@ -201,10 +298,10 @@ 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
if [ -x "$CODER_HOME/.local/bin/claude" ]; then
# Claude Code - show source (always installed)
if [ -x "$CLAUDER_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
elif [ -x "$CLAUDER_HOME/.claude/local/claude" ]; then
echo " → claude: $(claude --version 2>/dev/null || echo 'installed') [volume ~/.claude/local]"
elif command -v claude &>/dev/null; then
echo " → claude: $(claude --version 2>/dev/null || echo 'installed') [image]"
@ -212,6 +309,13 @@ else
echo " → claude: not installed"
fi
# Show optional CLIs if installed
command -v opencode &>/dev/null && echo " → opencode: installed"
command -v gemini &>/dev/null && echo " → gemini: installed"
command -v kilocode &>/dev/null && echo " → kilocode: installed"
command -v continue &>/dev/null && echo " → continue: installed"
command -v codex &>/dev/null && echo " → codex: installed"
# Extensions count
if [ -d "$XDG_DATA_HOME/code-server/extensions" ]; then
EXT_COUNT=$(find "$XDG_DATA_HOME/code-server/extensions" -maxdepth 1 -type d 2>/dev/null | wc -l)
@ -245,4 +349,4 @@ echo "Starting code-server as $(whoami)..."
echo "════════════════════════════════════════════════════════════════════════"
echo ""
exec dumb-init /usr/bin/code-server --bind-addr 0.0.0.0:8080 /home/coder/workspace
exec dumb-init /usr/bin/code-server --bind-addr 0.0.0.0:8080 "$HOME/workspace"

View File

@ -1,5 +1,6 @@
# ============================================================================
# VSCode Cloud IDE - Railway Configuration
# Claude Code Server - Railway Configuration
# https://github.com/sphinxcode/claude-code-server
# ============================================================================
[build]