# Grok2API (VM `sze@100.78.69.20`) Grok2API deployed as a Docker Compose stack on the primary VM. OpenAI-compatible API proxy for Grok models via [chenyme/grok2api](https://github.com/chenyme/grok2api). Cloudflare bypass via WARP + FlareSolverr. ## Current Configuration | Field | Value | |---|---| | VM | `sze@100.78.69.20` (Tailscale, Pop!_OS 24.04) | | Containers | `grok2api`, `warp`, `flaresolverr` (Docker Compose) | | LAN access | `http://192.168.0.178:8000` | | Tailscale access | `http://100.78.69.20:8000` | | HTTPS (Tailscale) | `https://pop-os.tail3fb075.ts.net:4443` | | Admin panel | `http://100.78.69.20:8000/admin` (password: `@D8312p$`) | | Compose file | `~/grok2api/docker-compose.yml` | | Data | `~/grok2api/data/` | | Logs | `~/grok2api/logs/` | | Config | `~/grok2api/data/config.toml` (root-owned, use `sudo` to edit) | | Nezha monitor | HTTP GET `http://127.0.0.1:8000` every 60s | ## API Endpoint OpenAI-compatible. Use from any client that supports the OpenAI format. | Field | Value | |---|---| | Base URL (local) | `http://127.0.0.1:8000/v1` | | Base URL (Tailscale) | `http://100.78.69.20:8000/v1` | | Base URL (HTTPS) | `https://pop-os.tail3fb075.ts.net:4443/v1` | | API key | `OmsgU7ngA6TuXd1u` | | Auth header | `Authorization: Bearer OmsgU7ngA6TuXd1u` | ### Available Models | Model ID | Type | |---|---| | `grok-4.1-mini` | Text (fast) | | `grok-4.1-fast` | Text (fast) | | `grok-4.1-expert` | Text (reasoning) | | `grok-4.1-thinking` | Text (reasoning, chain-of-thought) | | `grok-4.20-beta` | Text (latest beta) | | `grok-4` | Text | | `grok-4-thinking` | Text (reasoning) | | `grok-4-heavy` | Text (large) | | `grok-3` | Text | | `grok-3-mini` | Text (fast) | | `grok-3-thinking` | Text (reasoning) | | `grok-imagine-1.0` | Image generation | | `grok-imagine-1.0-fast` | Image generation (fast) | | `grok-imagine-1.0-edit` | Image editing | ### Example: curl ```bash curl http://127.0.0.1:8000/v1/chat/completions \ -H "Authorization: Bearer OmsgU7ngA6TuXd1u" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-4.1-mini", "messages": [{"role": "user", "content": "Hello"}], "stream": false }' ``` ### Example: List models ```bash curl http://127.0.0.1:8000/v1/models \ -H "Authorization: Bearer OmsgU7ngA6TuXd1u" ``` ## OpenClaw Integration Grok2API is configured as the primary model provider for OpenClaw on the same VM. Config in `~/.openclaw/openclaw.json`: | Field | Value | |---|---| | Provider name | `grok2api` | | Base URL | `http://127.0.0.1:8000/v1` | | API type | `openai-completions` | | Default model | `grok2api/grok-4.1-mini` | | Fallback | `minimax/MiniMax-M2.7` | When grok2api fails (token pool exhausted, CF challenge, etc.), OpenClaw auto-falls back to MiniMax. ## Architecture ``` ┌──────────────┐ │ grok.com │ │ (Cloudflare)│ └──────┬───────┘ │ ┌─────────────┴──────────────┐ │ │ ┌────────┴────────┐ ┌────────┴────────┐ │ WARP proxy │ │ FlareSolverr │ │ socks5://:1080 │ │ http://:8191 │ │ (clean IP) │ │ (CF challenge │ └────────┬────────┘ │ solver) │ │ └────────┬────────┘ │ │ ┌────────┴────────────────────────────┴┐ │ grok2api │ │ http://0.0.0.0:8000 │ │ Routes traffic via WARP │ │ Uses cf_clearance from FlareSolverr │ └───────────────┬──────────────────────┘ │ ┌───────────────┴──────────────────┐ │ │ ┌──────┴──────┐ ┌───────┴───────┐ │ OpenClaw │ │ Direct API │ │ (primary) │ │ consumers │ └─────────────┘ └───────────────┘ ``` ## Cloudflare Bypass (WARP + FlareSolverr) grok.com uses Cloudflare's managed JavaScript challenge. Plain HTTP requests from server IPs get 403. Two containers solve this: | Container | Image | Purpose | Port | Cost | |---|---|---|---|---| | `warp` | `caomingjun/warp:latest` | Cloudflare WARP VPN (clean exit IP) | 1080 (SOCKS5) | Free, no account | | `flaresolverr` | `ghcr.io/flaresolverr/flaresolverr:latest` | Headless browser CF challenge solver | 8191 | Free, no account | **How it works:** 1. FlareSolverr launches a headless Chrome, navigates to `grok.com`, solves the JS challenge, and extracts `cf_clearance` cookies 2. grok2api uses these cookies + WARP SOCKS5 proxy for all upstream requests 3. Cookies auto-refresh every 10 minutes (`CF_REFRESH_INTERVAL: 600`) **Proxy config** in `config.toml`: ```toml [proxy] base_proxy_url = "socks5://warp:1080" enabled = true flaresolverr_url = "http://flaresolverr:8191" ``` ## Quick Commands ```bash # SSH into VM ssh sze@100.78.69.20 # Status (all 3 containers) docker ps --filter name=grok2api --filter name=warp --filter name=flaresolverr # Restart all cd ~/grok2api && docker compose restart # Restart just grok2api (e.g. after config edit) cd ~/grok2api && docker compose restart grok2api # Logs (all) cd ~/grok2api && docker compose logs -f # Logs (grok2api only) cd ~/grok2api && docker compose logs -f grok2api # Update all images cd ~/grok2api && docker compose pull && docker compose up -d # Check WARP connectivity docker exec warp curl -s --socks5 127.0.0.1:1080 https://cloudflare.com/cdn-cgi/trace | grep warp # Edit config (root-owned file) sudo nano ~/grok2api/data/config.toml # Then: cd ~/grok2api && docker compose restart grok2api # Check token pool curl -s http://127.0.0.1:8000/admin/api/tokens -H "Authorization: Bearer @D8312p$" | python3 -m json.tool | head -30 ``` ## HTTPS via Caddy Caddy reverse proxies port 8000 to HTTPS on port 4443 over Tailscale: ``` https://pop-os.tail3fb075.ts.net:4443 { reverse_proxy localhost:8000 tls /etc/caddy/certs/tailscale-cert.pem /etc/caddy/certs/tailscale-key.pem } ``` ## Configuration Runtime config lives at `~/grok2api/data/config.toml` (root-owned, use `sudo` to edit). Key settings: | Setting | Config key | Current value | |---|---|---| | Admin password | `app.app_key` | `@D8312p$` | | API key | `app.api_key` | `OmsgU7ngA6TuXd1u` | | Streaming | `app.stream` | `true` | | Thinking chain | `app.thinking` | `true` | | Temporary mode | `app.temporary` | `true` | | Proxy enabled | `proxy.enabled` | `true` | | Proxy URL | `proxy.base_proxy_url` | `socks5://warp:1080` | | FlareSolverr | `proxy.flaresolverr_url` | `http://flaresolverr:8191` | | CF refresh | env `CF_REFRESH_INTERVAL` | `600` (seconds) | Edit via the admin panel at `/admin` or directly in the TOML file (restart after file edits). ## Token Pool SSO tokens are managed by [grok-register](../grok-register/grok-register-setup.md) and auto-pushed to grok2api. Current pool: ~83 active tokens. | Field | Value | |---|---| | Token type | `ssoBasic` (x.ai session JWT) | | Quota per token | 80 requests | | Auto-refresh | Every 8 hours (`token.auto_refresh`) | | Admin endpoint | `POST http://127.0.0.1:8000/admin/api/tokens/add` | | Admin auth | `Authorization: Bearer @D8312p$` | ## Troubleshooting | Issue | Fix | |---|---| | 403 from grok.com | Check FlareSolverr is running: `docker ps --filter name=flaresolverr`. Check cf_clearance refresh in logs: `docker compose logs grok2api \| grep cf_clearance` | | WARP not connected | `docker logs warp \| tail -20`. Restart: `docker compose restart warp` | | FlareSolverr fails to solve | Check logs: `docker logs flaresolverr`. May need image update: `docker compose pull flaresolverr && docker compose up -d` | | All tokens failing | Token pool may be exhausted. Refresh via grok-register Web UI (`http://100.78.69.20:5000`) or CLI | | Container won't start | `cd ~/grok2api && docker compose logs` | | Admin login fails | Verify `app.app_key` in config.toml | | 502 via Caddy | Verify grok2api container is running: `docker ps` | | Config edit permission denied | File is root-owned: `sudo nano ~/grok2api/data/config.toml` |