Skip to content

Instantly share code, notes, and snippets.

@Melvynx
Last active February 2, 2026 14:23
Show Gist options
  • Select an option

  • Save Melvynx/85801f5d4cfb70851cc70312dab5bd54 to your computer and use it in GitHub Desktop.

Select an option

Save Melvynx/85801f5d4cfb70851cc70312dab5bd54 to your computer and use it in GitHub Desktop.
OpenClaw VPS Setup - Fresh v2
#!/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