diff --git a/.gitignore b/.gitignore index 9dc547c9c..f155dc3ca 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ apps/ios/*.mobileprovision # Local untracked files .local/ .vscode/ +data/ IDENTITY.md USER.md .tgz diff --git a/Dockerfile.azure b/Dockerfile.azure new file mode 100644 index 000000000..c1b84151b --- /dev/null +++ b/Dockerfile.azure @@ -0,0 +1,47 @@ +FROM node:22-bookworm + +# Install Bun (required for build scripts) +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:${PATH}" + +RUN corepack enable + +WORKDIR /app + +ARG CLAWDBOT_DOCKER_APT_PACKAGES="" +RUN if [ -n "$CLAWDBOT_DOCKER_APT_PACKAGES" ]; then \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $CLAWDBOT_DOCKER_APT_PACKAGES && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ + fi + +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ +COPY ui/package.json ./ui/package.json +COPY patches ./patches +COPY scripts ./scripts + +RUN pnpm install --frozen-lockfile + +COPY . . +RUN CLAWDBOT_A2UI_SKIP_MISSING=1 pnpm build +# Force pnpm for UI build (Bun may fail on ARM/Synology architectures) +ENV CLAWDBOT_PREFER_PNPM=1 +RUN pnpm ui:install +RUN pnpm ui:build + +ENV NODE_ENV=production + +# Security hardening: Run as non-root user +# The node:22-bookworm image includes a 'node' user (uid 1000) +# This reduces the attack surface by preventing container escape via root privileges + +# Create default config for Azure deployment (Control UI token-only + trust Azure proxy) +RUN mkdir -p /home/node/.moltbot && \ + echo '{"gateway":{"controlUi":{"allowInsecureAuth":true},"trustedProxies":["169.254.0.0/16"]},"agents":{"defaults":{"model":{"primary":"azure-openai/gpt-4o-mini"}}}}' > /home/node/.moltbot/moltbot.json && \ + chown -R node:node /home/node/.moltbot + +USER node + +# Azure Web App startup command +CMD ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789", "--allow-unconfigured"] diff --git a/docs/platforms/azure/deploy-guide.md b/docs/platforms/azure/deploy-guide.md new file mode 100644 index 000000000..dfd78fd01 --- /dev/null +++ b/docs/platforms/azure/deploy-guide.md @@ -0,0 +1,390 @@ +# Deploying Moltbot to Azure Web App for Containers + +This guide covers deploying Moltbot gateway to Azure Web App for Containers with Azure OpenAI as the LLM provider. + +## Prerequisites + +- Azure CLI installed and authenticated (`az login`) +- Docker (for local testing, optional) +- An Azure subscription with permissions to create resources + +## Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Azure Web App │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ Container (Node.js) │ │ +│ │ ┌─────────────────────────────────────────────┐ │ │ +│ │ │ Moltbot Gateway │ │ │ +│ │ │ - Control UI (WebSocket) │ │ │ +│ │ │ - Agent runtime │ │ │ +│ │ └─────────────────────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Azure OpenAI │ +│ - GPT-5.2, GPT-5.2-codex, etc. │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Step 1: Create Azure Resources + +### 1.1 Create Resource Group + +```bash +RESOURCE_GROUP="moltbot-rg" +LOCATION="eastus2" + +az group create --name $RESOURCE_GROUP --location $LOCATION +``` + +### 1.2 Create Azure Container Registry (ACR) + +```bash +ACR_NAME="moltbotreg" # Must be globally unique + +az acr create \ + --resource-group $RESOURCE_GROUP \ + --name $ACR_NAME \ + --sku Basic \ + --admin-enabled true +``` + +### 1.3 Create Azure OpenAI Resource + +```bash +OPENAI_NAME="moltbot-openai" + +az cognitiveservices account create \ + --name $OPENAI_NAME \ + --resource-group $RESOURCE_GROUP \ + --location $LOCATION \ + --kind OpenAI \ + --sku S0 +``` + +Deploy a model (e.g., gpt-4o-mini): + +```bash +az cognitiveservices account deployment create \ + --name $OPENAI_NAME \ + --resource-group $RESOURCE_GROUP \ + --deployment-name "gpt-4o-mini" \ + --model-name "gpt-4o-mini" \ + --model-version "2024-07-18" \ + --model-format OpenAI \ + --sku-capacity 10 \ + --sku-name Standard +``` + +Get the endpoint and key: + +```bash +# Endpoint +az cognitiveservices account show \ + --name $OPENAI_NAME \ + --resource-group $RESOURCE_GROUP \ + --query properties.endpoint -o tsv + +# Key +az cognitiveservices account keys list \ + --name $OPENAI_NAME \ + --resource-group $RESOURCE_GROUP \ + --query key1 -o tsv +``` + +### 1.4 Create App Service Plan + +```bash +APP_SERVICE_PLAN="moltbot-plan" + +az appservice plan create \ + --name $APP_SERVICE_PLAN \ + --resource-group $RESOURCE_GROUP \ + --location $LOCATION \ + --is-linux \ + --sku B1 +``` + +### 1.5 Create Web App + +```bash +WEB_APP_NAME="moltbot-app" # Must be globally unique + +az webapp create \ + --resource-group $RESOURCE_GROUP \ + --plan $APP_SERVICE_PLAN \ + --name $WEB_APP_NAME \ + --deployment-container-image-name "${ACR_NAME}.azurecr.io/moltbot-azure:latest" +``` + +## Step 2: Configure the Dockerfile + +Create `Dockerfile.azure` in the repository root: + +```dockerfile +FROM node:22-bookworm + +# Install bun for faster builds +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:${PATH}" +RUN corepack enable + +WORKDIR /app + +# Copy package files +COPY package.json pnpm-lock.yaml ./ +COPY patches ./patches + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Copy source and build +COPY . . +RUN pnpm build + +# Prune dev dependencies +RUN pnpm prune --prod + +ENV NODE_ENV=production + +# Create config directory and bake in Azure-specific config +# IMPORTANT: trustedProxies is required for Azure's internal proxy +RUN mkdir -p /home/node/.moltbot && \ + echo '{"gateway":{"controlUi":{"allowInsecureAuth":true},"trustedProxies":["169.254.0.0/16"]},"agents":{"defaults":{"model":{"primary":"azure-openai/gpt-4o-mini"}}}}' > /home/node/.moltbot/moltbot.json && \ + chown -R node:node /home/node/.moltbot + +USER node + +EXPOSE 18789 + +CMD ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789", "--allow-unconfigured"] +``` + +### Key Configuration Notes + +| Setting | Purpose | +|---------|---------| +| `allowInsecureAuth: true` | Control UI uses token-only auth (skips device pairing). Security downgrade; prefer HTTPS + pairing when possible. | +| `trustedProxies: ["169.254.0.0/16"]` | Trust Azure's internal proxy for `X-Forwarded-*` headers | +| `--bind lan` | Bind to all interfaces (required for container networking) | +| `--allow-unconfigured` | Start without requiring pre-configured channels | + +## Step 3: Build and Push Container Image + +### 3.1 Build with ACR Tasks (Recommended) + +```bash +az acr build \ + --registry $ACR_NAME \ + --image moltbot-azure:latest \ + --file Dockerfile.azure \ + . +``` + +### 3.2 Alternative: Build Locally and Push + +```bash +# Login to ACR +az acr login --name $ACR_NAME + +# Build +docker build -t ${ACR_NAME}.azurecr.io/moltbot-azure:latest -f Dockerfile.azure . + +# Push +docker push ${ACR_NAME}.azurecr.io/moltbot-azure:latest +``` + +## Step 4: Configure Web App + +### 4.1 Connect ACR to Web App + +```bash +# Get ACR credentials +ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) +ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) + +# Configure container settings +az webapp config container set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --docker-custom-image-name "${ACR_NAME}.azurecr.io/moltbot-azure:latest" \ + --docker-registry-server-url "https://${ACR_NAME}.azurecr.io" \ + --docker-registry-server-user $ACR_USERNAME \ + --docker-registry-server-password $ACR_PASSWORD +``` + +### 4.2 Configure Environment Variables + +```bash +# Generate a secure gateway token +GATEWAY_TOKEN=$(openssl rand -hex 16) + +az webapp config appsettings set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --settings \ + WEBSITES_PORT=18789 \ + MOLTBOT_STATE_DIR=/home/node/.moltbot \ + MOLTBOT_CONFIG_PATH=/home/node/.moltbot/moltbot.json \ + CLAWDBOT_GATEWAY_TOKEN=$GATEWAY_TOKEN \ + AZURE_OPENAI_API_KEY="" \ + AZURE_OPENAI_ENDPOINT="https://.openai.azure.com/" \ + AZURE_OPENAI_API_VERSION="2024-08-01-preview" + +echo "Gateway Token: $GATEWAY_TOKEN" +``` + +### 4.3 Enable WebSockets and Always On + +```bash +az webapp config set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --web-sockets-enabled true \ + --always-on true +``` + +### 4.4 Set Startup Command + +```bash +az webapp config set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --startup-file 'node dist/index.js gateway --bind lan --port 18789 --allow-unconfigured' +``` + +## Step 5: Deploy and Verify + +### 5.1 Restart the Web App + +```bash +az webapp restart --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME +``` + +### 5.2 Check Logs + +```bash +# Stream logs +az webapp log tail --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME + +# Or download logs +az webapp log download \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --log-file /tmp/webapp-logs.zip +``` + +### 5.3 Verify Deployment + +Look for these indicators in the logs: + +``` +[gateway] agent model: azure-openai/gpt-4o-mini +[gateway] listening on 0.0.0.0:18789 +``` + +If you see warnings about untrusted proxy headers, the `trustedProxies` config is not applied correctly. + +### 5.4 Access Control UI + +Open in browser: + +``` +https://.azurewebsites.net/?token= +``` + +## Troubleshooting + +### Problem: "pairing required" Error + +**Cause**: The gateway doesn't recognize the connection as authorized. + +**Solutions**: +1. Ensure `dangerouslyDisableDeviceAuth: true` is in the config +2. Ensure `trustedProxies` includes `169.254.0.0/16` +3. Access with the token: `?token=` + +### Problem: "Proxy headers detected from untrusted address" + +**Cause**: Azure's internal proxy IP is not trusted. + +**Solution**: Add `"trustedProxies": ["169.254.0.0/16"]` to gateway config. + +### Problem: Container Crash Loop + +**Check logs for**: +- `Cannot find module` - Startup command is malformed +- `SyntaxError` - Config JSON is invalid +- Port binding errors - Ensure `WEBSITES_PORT=18789` + +**Common fix**: Verify `appCommandLine` is set correctly: + +```bash +az webapp config show -g $RESOURCE_GROUP -n $WEB_APP_NAME --query appCommandLine +``` + +If it shows `""` (empty quotes), the image CMD won't be used. Set it explicitly: + +```bash +az webapp config set -g $RESOURCE_GROUP -n $WEB_APP_NAME \ + --startup-file 'node dist/index.js gateway --bind lan --port 18789 --allow-unconfigured' +``` + +### Problem: Azure OpenAI Not Working + +**Verify**: +1. Model deployment name matches config (e.g., `gpt-4o-mini`) +2. API key is correct +3. Endpoint URL format: `https://.openai.azure.com/` +4. API version is supported (e.g., `2024-08-01-preview`) + +### Problem: 503 Service Unavailable + +**Causes**: +- Container still starting (wait 1-2 minutes) +- Container crashing (check logs) +- Port mismatch (verify `WEBSITES_PORT`) + +## Environment Variables Reference + +| Variable | Required | Description | +|----------|----------|-------------| +| `WEBSITES_PORT` | Yes | Port the container listens on (18789) | +| `MOLTBOT_STATE_DIR` | Yes | Directory for runtime state | +| `MOLTBOT_CONFIG_PATH` | Yes | Path to config JSON file | +| `CLAWDBOT_GATEWAY_TOKEN` | Yes | Token for Control UI authentication | +| `AZURE_OPENAI_API_KEY` | Yes | Azure OpenAI API key | +| `AZURE_OPENAI_ENDPOINT` | Yes | Azure OpenAI endpoint URL | +| `AZURE_OPENAI_API_VERSION` | Yes | API version (e.g., 2024-08-01-preview) | + +## Security Recommendations + +1. **Use Managed Identity** instead of API keys where possible +2. **Restrict network access** with Azure Private Endpoints +3. **Enable HTTPS Only** in Web App settings +4. **Rotate gateway tokens** periodically +5. **Use Azure Key Vault** for secrets in production + +## Updating the Deployment + +To deploy a new version: + +```bash +# Rebuild image +az acr build --registry $ACR_NAME --image moltbot-azure:latest --file Dockerfile.azure . + +# Restart to pull new image +az webapp restart --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME +``` + +## Cleanup + +To remove all resources: + +```bash +az group delete --name $RESOURCE_GROUP --yes --no-wait +```