feat: add Docker support and improve /health endpoint

- Add Dockerfile (node:20-alpine, EXPOSE 3456, ENV for session tokens)
- Add docker-compose.yml with restart: unless-stopped
- Add .dockerignore
- Improve /health: add version, uptime, uptimeHuman, per-pool ready/error status
- Listen on 0.0.0.0 for container compatibility
- Bump version to 1.4.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 11:11:13 +10:00
co-authored by Claude Sonnet 4.6
parent 857c703b0a
commit 6ff48f68c0
6 changed files with 71 additions and 6 deletions
+8
View File
@@ -0,0 +1,8 @@
.git
.gitignore
*.md
node_modules
.env
.env.*
scripts/
start.sh
+14
View File
@@ -0,0 +1,14 @@
FROM node:20-alpine
WORKDIR /app
COPY server.mjs ./
COPY setup.mjs ./
COPY package.json ./
ENV CLAUDE_SESSION_TOKEN="" \
CLAUDE_COOKIES=""
EXPOSE 3456
CMD ["node", "server.mjs"]
+19
View File
@@ -28,6 +28,25 @@ The proxy translates OpenAI-compatible `/v1/chat/completions` requests into `cla
## Quick Install
### Docker (recommended)
```bash
git clone https://github.com/dtzp555-max/openclaw-claude-proxy.git
cd openclaw-claude-proxy
cp .env.example .env # add your CLAUDE_SESSION_TOKEN / CLAUDE_COOKIES
docker compose up -d
```
Or as a single command if you already have a `.env` ready:
```bash
git clone https://github.com/dtzp555-max/openclaw-claude-proxy.git && cd openclaw-claude-proxy && docker compose up -d
```
Health check: `curl http://localhost:3456/health`
### Node.js (local)
```bash
# Clone
git clone https://github.com/dtzp555-max/openclaw-claude-proxy.git
+7
View File
@@ -0,0 +1,7 @@
services:
claude-proxy:
build: .
ports:
- "3456:3456"
env_file: .env
restart: unless-stopped
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "openclaw-claude-proxy",
"version": "1.3.1",
"version": "1.4.0",
"description": "OpenAI-compatible proxy that routes requests through Claude CLI — use your Claude Pro/Max subscription as an OpenClaw model provider",
"type": "module",
"bin": {
+22 -5
View File
@@ -26,6 +26,9 @@ const TIMEOUT = parseInt(process.env.CLAUDE_TIMEOUT || "300000", 10);
const POOL_SIZE = parseInt(process.env.CLAUDE_POOL_SIZE || "1", 10);
const POOL_MAX_IDLE = parseInt(process.env.CLAUDE_POOL_MAX_IDLE || "60000", 10); // max idle time before recycle
const VERSION = "1.4.0";
const START_TIME = Date.now();
// Model alias mapping: request model → claude CLI --model arg
const MODEL_MAP = {
"claude-opus-4-6": "opus",
@@ -292,13 +295,27 @@ const server = createServer(async (req, res) => {
return handleChatCompletions(req, res);
}
// GET /health — includes pool status
// GET /health — includes pool status, version, uptime
if (req.url === "/health") {
const poolStatus = {};
for (const [model, arr] of pool) {
poolStatus[model] = { total: arr.length, ready: arr.filter(e => e.ready).length };
const readyCount = arr.filter(e => e.ready).length;
const errorCount = arr.filter(e => !e.ready).length;
poolStatus[model] = {
total: arr.length,
ready: readyCount,
error: errorCount,
status: readyCount > 0 ? "ready" : "error",
};
}
return jsonResponse(res, 200, { status: "ok", pool: poolStatus });
const uptimeMs = Date.now() - START_TIME;
return jsonResponse(res, 200, {
status: "ok",
version: VERSION,
uptime: uptimeMs,
uptimeHuman: `${Math.floor(uptimeMs / 3600000)}h ${Math.floor((uptimeMs % 3600000) / 60000)}m ${Math.floor((uptimeMs % 60000) / 1000)}s`,
pool: poolStatus,
});
}
// Catch-all: try to handle any POST with messages
@@ -312,8 +329,8 @@ const server = createServer(async (req, res) => {
// ── Start ──────────────────────────────────────────────────────────────
initPool();
server.listen(PORT, "127.0.0.1", () => {
console.log(`openclaw-claude-proxy v1.3.1 listening on http://127.0.0.1:${PORT}`);
server.listen(PORT, "0.0.0.0", () => {
console.log(`openclaw-claude-proxy v${VERSION} listening on http://0.0.0.0:${PORT}`);
console.log(`Models: ${MODELS.map((m) => m.id).join(", ")}`);
console.log(`Claude binary: ${CLAUDE}`);
console.log(`Timeout: ${TIMEOUT}ms`);