Last active
February 2, 2026 14:23
-
-
Save Melvynx/85801f5d4cfb70851cc70312dab5bd54 to your computer and use it in GitHub Desktop.
OpenClaw VPS Setup - Fresh v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ClawPro VPS Setup Script | |
| # Sets up OpenClaw + Docker + useful aliases | |
| set -e | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' | |
| echo -e "${BLUE}" | |
| echo "========================================" | |
| echo " ClawPro VPS Setup" | |
| echo "========================================" | |
| echo -e "${NC}" | |
| if [ "$EUID" -ne 0 ]; then | |
| echo -e "${RED}Please run as root${NC}" | |
| exit 1 | |
| fi | |
| GATEWAY_TOKEN=$(openssl rand -hex 32) | |
| KEYRING_PASSWORD=$(openssl rand -hex 32) | |
| echo -e "${GREEN}Generated Gateway Token (save this!):${NC}" | |
| echo " $GATEWAY_TOKEN" | |
| echo "" | |
| echo -e "${YELLOW}[1/7] Installing Docker...${NC}" | |
| if command -v docker &> /dev/null; then | |
| echo "Docker already installed" | |
| else | |
| apt-get update -qq | |
| apt-get install -y -qq git curl ca-certificates | |
| curl -fsSL https://get.docker.com | sh | |
| fi | |
| echo -e "${YELLOW}[2/7] Installing GitHub CLI...${NC}" | |
| if command -v gh &> /dev/null; then | |
| echo "GitHub CLI already installed" | |
| else | |
| curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null | |
| apt update -qq && apt install -y -qq gh | |
| fi | |
| echo -e "${YELLOW}[3/7] Installing Node.js 22+...${NC}" | |
| REQUIRED_NODE_VERSION=22 | |
| CURRENT_NODE_VERSION=$(node -v 2>/dev/null | sed 's/v//' | cut -d. -f1) | |
| if [ "$CURRENT_NODE_VERSION" -ge "$REQUIRED_NODE_VERSION" ] 2>/dev/null; then | |
| echo "Node.js $(node -v) already installed" | |
| else | |
| echo "Installing Node.js 22..." | |
| curl -fsSL https://deb.nodesource.com/setup_22.x | bash - > /dev/null 2>&1 | |
| apt install -y -qq nodejs | |
| fi | |
| echo -e "${YELLOW}[4/7] Installing Claude Code...${NC}" | |
| if command -v claude &> /dev/null; then | |
| echo "Claude Code already installed" | |
| else | |
| curl -fsSL https://claude.ai/install.sh | bash | |
| echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc | |
| export PATH="$HOME/.local/bin:$PATH" | |
| fi | |
| echo -e "${YELLOW}[5/7] Setting up OpenClaw...${NC}" | |
| if [ -d "/root/openclaw" ]; then | |
| echo "OpenClaw directory exists, pulling latest..." | |
| cd /root/openclaw && git pull --quiet || true | |
| else | |
| git clone --quiet https://github.com/openclaw/openclaw.git /root/openclaw | |
| fi | |
| mkdir -p /root/.openclaw /root/.openclaw/workspace /root/.openclaw/bin /root/.claude /root/.config/gh | |
| cat > /root/.openclaw/bin/openclaw << 'SCRIPT' | |
| #!/bin/bash | |
| cd /app && node dist/index.js "$@" | |
| SCRIPT | |
| chmod +x /root/.openclaw/bin/openclaw | |
| # Create config files if they don't exist | |
| touch /root/.openclaw/openclaw.json | |
| echo '{}' > /root/.openclaw/openclaw.json | |
| touch /root/.claude.json | |
| touch /root/.claude/settings.json | |
| echo '{}' > /root/.claude/settings.json | |
| # Set permissions for node user (uid 1000) | |
| chown -R 1000:1000 /root/.openclaw /root/.claude /root/.config/gh /root/.claude.json | |
| chmod 644 /root/.claude.json /root/.openclaw/openclaw.json | |
| cat > /root/openclaw/.env << EOF | |
| OPENCLAW_IMAGE=openclaw:local | |
| OPENCLAW_GATEWAY_TOKEN=${GATEWAY_TOKEN} | |
| OPENCLAW_GATEWAY_BIND=lan | |
| OPENCLAW_GATEWAY_PORT=18789 | |
| OPENCLAW_BRIDGE_PORT=18790 | |
| OPENCLAW_CONFIG_DIR=/root/.openclaw | |
| OPENCLAW_WORKSPACE_DIR=/root/.openclaw/workspace | |
| GOG_KEYRING_PASSWORD=${KEYRING_PASSWORD} | |
| XDG_CONFIG_HOME=/home/node/.openclaw | |
| # Optional - fill these manually if needed | |
| GOG_ACCOUNT= | |
| OPENAI_API_KEY= | |
| ELEVENLABS_API_KEY= | |
| GH_TOKEN= | |
| CLAUDE_AI_SESSION_KEY= | |
| CLAUDE_WEB_SESSION_KEY= | |
| CLAUDE_WEB_COOKIE= | |
| EOF | |
| cat > /root/openclaw/docker-compose.yml << 'EOF' | |
| services: | |
| openclaw-gateway: | |
| image: ${OPENCLAW_IMAGE} | |
| build: | |
| context: . | |
| dockerfile: Dockerfile.clawpro | |
| restart: unless-stopped | |
| command: ["node", "dist/index.js", "gateway", "--bind", "${OPENCLAW_GATEWAY_BIND:-lan}", "--port", "${OPENCLAW_GATEWAY_PORT}"] | |
| env_file: | |
| - .env | |
| environment: | |
| - HOME=/home/node | |
| - NODE_ENV=production | |
| - TERM=xterm-256color | |
| - IS_SANDBOX=1 | |
| - BROWSER=echo | |
| - OPENCLAW_GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND} | |
| - OPENCLAW_GATEWAY_PORT=${OPENCLAW_GATEWAY_PORT} | |
| - OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN} | |
| - GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD} | |
| - XDG_CONFIG_HOME=${XDG_CONFIG_HOME} | |
| - PATH=/home/node/.openclaw/bin:/home/node/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin | |
| volumes: | |
| - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw | |
| - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace | |
| - /root/.claude:/home/node/.claude | |
| - /root/.claude.json:/home/node/.claude.json | |
| - /root/.config/gh:/home/node/.config/gh | |
| - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock | |
| ports: | |
| - "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789" | |
| - "127.0.0.1:${OPENCLAW_BRIDGE_PORT:-18790}:18790" | |
| - "8788:8788" | |
| openclaw-cli: | |
| image: ${OPENCLAW_IMAGE} | |
| build: | |
| context: . | |
| dockerfile: Dockerfile.clawpro | |
| stdin_open: true | |
| tty: true | |
| entrypoint: ["node", "dist/index.js"] | |
| env_file: | |
| - .env | |
| environment: | |
| - HOME=/home/node | |
| - NODE_ENV=production | |
| - TERM=xterm-256color | |
| - IS_SANDBOX=1 | |
| - BROWSER=echo | |
| - GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD} | |
| - XDG_CONFIG_HOME=${XDG_CONFIG_HOME} | |
| - PATH=/home/node/.openclaw/bin:/home/node/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin | |
| volumes: | |
| - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw | |
| - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace | |
| - /root/.claude:/home/node/.claude | |
| - /root/.claude.json:/home/node/.claude.json | |
| - /root/.config/gh:/home/node/.config/gh | |
| - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock | |
| EOF | |
| echo -e "${YELLOW}[6/7] Building Docker image (takes a few minutes)...${NC}" | |
| cd /root/openclaw | |
| cat > Dockerfile.clawpro << 'DOCKERFILE' | |
| FROM node:22-bookworm | |
| # Install system dependencies | |
| RUN apt-get update && apt-get install -y \ | |
| socat \ | |
| curl \ | |
| git \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Install Bun globally | |
| RUN curl -fsSL https://bun.sh/install | bash \ | |
| && cp /root/.bun/bin/bun /usr/local/bin/bun \ | |
| && chmod +x /usr/local/bin/bun | |
| # Install GitHub CLI | |
| RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ | |
| && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ | |
| && apt update && apt install -y gh && rm -rf /var/lib/apt/lists/* | |
| # Install Claude Code (native only, no npm) | |
| RUN curl -fsSL https://claude.ai/install.sh | bash | |
| ENV PATH="/root/.local/bin:${PATH}" | |
| # Create claude-run wrapper (provides TTY via script for non-interactive use) | |
| RUN printf '#!/bin/bash\nexec script -q -c "claude $*" /dev/null\n' > /usr/local/bin/claude-run && chmod +x /usr/local/bin/claude-run | |
| # Install ccusage globally | |
| RUN npm install -g ccusage | |
| WORKDIR /app | |
| COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ | |
| COPY ui/package.json ./ui/package.json | |
| COPY scripts ./scripts | |
| RUN corepack enable | |
| RUN pnpm install --frozen-lockfile | |
| COPY . . | |
| RUN OPENCLAW_A2UI_SKIP_MISSING=1 pnpm build | |
| RUN pnpm ui:install | |
| RUN pnpm ui:build | |
| # Create node user home with proper directories and copy claude | |
| RUN mkdir -p /home/node/.local/bin /home/node/.local/share /home/node/.config /home/node/.claude && chown -R node:node /home/node | |
| RUN cp -r /root/.local/share/claude /home/node/.local/share/ && chown -R node:node /home/node/.local/share/claude | |
| RUN bash -c 'CLAUDE_BIN=$(ls /home/node/.local/share/claude/versions/ | head -1) && ln -sf /home/node/.local/share/claude/versions/$CLAUDE_BIN /home/node/.local/bin/claude' && chown -h node:node /home/node/.local/bin/claude | |
| # Add claude to PATH for node user | |
| ENV PATH="/home/node/.local/bin:${PATH}" | |
| RUN echo 'export PATH="/home/node/.local/bin:$PATH"' >> /home/node/.bashrc && chown node:node /home/node/.bashrc | |
| ENV NODE_ENV=production | |
| CMD ["node","dist/index.js"] | |
| DOCKERFILE | |
| docker compose down 2>/dev/null || true | |
| docker rmi openclaw:local 2>/dev/null || true | |
| docker build -t openclaw:local -f Dockerfile.clawpro . | |
| docker compose up -d openclaw-gateway | |
| echo -e "${YELLOW}[7/7] Creating aliases...${NC}" | |
| if ! grep -q "# ClawPro aliases" /root/.bashrc 2>/dev/null; then | |
| cat >> /root/.bashrc << 'ALIASES' | |
| # ClawPro aliases | |
| alias oc-docker='docker exec -it -u node openclaw-openclaw-gateway-1 bash' | |
| alias oc='docker exec -it -u node openclaw-openclaw-gateway-1' | |
| alias oc-logs='docker logs -f openclaw-openclaw-gateway-1' | |
| alias oc-restart='docker restart openclaw-openclaw-gateway-1' | |
| alias oc-stop='docker stop openclaw-openclaw-gateway-1' | |
| alias oc-start='docker start openclaw-openclaw-gateway-1' | |
| alias oc-claude='docker exec -it -u node openclaw-openclaw-gateway-1 claude' | |
| alias oc-cli='docker exec -it -u node openclaw-openclaw-cli-1' | |
| alias claude='IS_SANDBOX=1 /root/.local/bin/claude' | |
| ALIASES | |
| fi | |
| echo "" | |
| echo -e "${GREEN}========================================" | |
| echo " Setup Complete!" | |
| echo "========================================${NC}" | |
| echo "" | |
| echo -e "${BLUE}Gateway Token:${NC} $GATEWAY_TOKEN" | |
| echo "" | |
| echo -e "${YELLOW}Aliases (run: source ~/.bashrc):${NC}" | |
| echo " oc-docker - Enter gateway container" | |
| echo " oc-cli - Enter CLI container" | |
| echo " oc - Run command in gateway" | |
| echo " oc-logs - View container logs" | |
| echo " oc-restart - Restart container" | |
| echo " oc-claude - Run Claude in container" | |
| echo " claude - Run Claude on host (sandbox)" | |
| echo "" | |
| echo -e "${YELLOW}Next steps:${NC}" | |
| echo " 1. source ~/.bashrc" | |
| echo " 2. Run onboard + fix permissions + start gateway:" | |
| echo " cd ~/openclaw && docker compose run --rm -it openclaw-cli onboard --no-install-daemon && chown -R 1000:1000 /root/.openclaw /root/.claude /root/.config/gh /root/.claude.json && docker compose up -d openclaw-gateway" | |
| echo " 3. gh auth login" | |
| echo " 4. claude login" | |
| echo " 5. Fix permissions after login (IMPORTANT):" | |
| echo " chown -R 1000:1000 /root/.claude /root/.claude.json /root/.config/gh && docker restart openclaw-openclaw-gateway-1" | |
| echo "" | |
| echo -e "${YELLOW}Optional .env vars to fill:${NC}" | |
| echo " /root/openclaw/.env" | |
| echo " - GOG_ACCOUNT, OPENAI_API_KEY, ELEVENLABS_API_KEY" | |
| echo " - GH_TOKEN, CLAUDE_AI_SESSION_KEY, etc." | |
| echo "" | |
| echo -e "${YELLOW}Access from laptop:${NC}" | |
| echo " ssh -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP" | |
| echo " Open: http://localhost:18789" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment