Both entries are in docs#49's changelog.mdx (workspace-abilities-
broadcast-changelog-2026-05-15). Removes duplicates to avoid
merge conflicts. Bug fixes and internal entries remain.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The CWE-78 expandWithEnv POSIX-identifier guard regression entry is
authoritatively covered in docs#49's security/changelog.md. Removes the
duplicate from this PR to avoid merge conflicts.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add blank line between CWE-78 and OFFSEC-003 Security entries (fixes
MDX rendering concatenation bug)
- Remove duplicate expandWithEnv guard entry from Bug fixes section
(CWE-78 is already covered in the Security section above)
- security/changelog.md change removed — CWE-78 is covered by docs#49
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs#40 is closed; the tutorial file is now on docs#46's branch.
Updated the entry to reference docs#46 and mention the Kubernetes
terminationGracePeriodSeconds fix.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds molecule-core#933 (OFFSEC-006, CWE-918 SSRF + token exfiltration)
to the 2026-05-14 Security section in changelog.mdx.
Also adds OFFSEC-006 to the Security Changelog (security/changelog.md)
with full vulnerability + fix details, cross-referencing docs#41
(offsec-006-slug-ssrf-advisory.mdx) which will add the full
advisory page when it merges.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Day 2026-05-15 begins with no merged PRs (cron fired at 02:15 UTC;
entry will be populated at 23:50 UTC when the day is finalised).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the openclaw workspace template models-in-runtime_config bug fix
to today's changelog alongside the existing CWE-78 + OFFSEC-003 entries.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the workspace-side OFFSEC-003 hardening entry to the 2026-05-14
changelog section already opened in docs#45.
Changes:
- changelog.mdx: OFFSEC-003 workspace boundary escaping + closer truncation
added to the 2026-05-14 security section alongside CWE-78 entry
Note: core#1075 (OFFSEC-010 symlink in provisioner) is SaaS-only
provisioner detail — no public docs needed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pairs molecule-core#1030 (Critical). Restores POSIX shell-identifier
guard in expandWithEnv(org_helpers.go:82) that was inadvertently
removed during a regression window. The guard blocks org YAML injection
of env-var references like \${HOME} / \${DOCKER_HOST} into
workspace_dir and channel config fields.
Changes:
- security/changelog.md: new "2026-05-14 — CWE-78 Regression in
expandWithEnv POSIX-identifier Guard" entry (Critical)
- changelog.mdx: new "2026-05-14" section with security + bugfix entries
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 16:18:22 +00:00
2 changed files with 15 additions and 201 deletions
@@ -8,6 +8,21 @@ Entries are published daily at 23:50 UTC.
---
## 2026-05-14
### 🐛 Bug fixes
- **Canvas WCAG 1.4.3 contrast ratio fixed for TIER_CONFIG legend**: the tier legend text in the canvas now meets the 4.5:1 contrast ratio required by WCAG 1.4.3 for normal text. (`molecule-core` [#990](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/990))
- **Canvas focus-visible rings added to icon and text buttons**: focus-visible rings (`focus-visible:ring-2`) now render on icon buttons and text-only buttons in the canvas, restoring WCAG 2.1 AA compliance for all interactive elements. (`molecule-core` [#988](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/988))
- **OpenClaw template `models` config moved to correct level**: the OpenClaw workspace template's `config.yaml` had `models` at the top level, but the platform template handler reads from `runtime_config.models`. This caused `/templates` to return empty models and providers → a blank "Missing API Keys" dialog with no selectable providers, disabling the Deploy button. Moved all model entries under `runtime_config` and added Groq and OpenRouter as alternative providers alongside OpenAI. (`molecule-ai-workspace-template-openclaw` [#4](https://git.moleculesai.app/molecule-ai/molecule-ai-workspace-template-openclaw/pulls/4))
### 🧹 Internal
- **CI infrastructure improvements** (`molecule-core`): `ci-required-drift` workflow updated with job-level `if:` guards to skip `github.ref`-gated jobs in the merge-queue context; `canvas-build` job now has an explicit 20-minute timeout; gitea merge-queue test mocks updated to match current push-gate behavior. (`molecule-core` [#1029](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/1029), [#1006](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/1006), [#1035](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/1035))
- **Handler test coverage additions** (`molecule-core`): 60+ new SQL-mock test cases covering `InstructionsHandler`, `ScheduleHandler` (28 cases), and the `expandWithEnv` POSIX guard regression suite. (`molecule-core` [#1030](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/1030), [#1005](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/1005), [#999](https://git.moleculesai.app/molecule-ai/molecule-core/pulls/999))
title: Self-Hosted Workspace Deployment with Docker
---
# Self-Hosted Workspace Deployment with Docker
This guide covers running a Molecule AI workspace agent as a Docker container on a self-hosted server or VM. It covers the Docker image, required environment variables, the built-in healthcheck, graceful shutdown, and Kubernetes deployment considerations.
> **Prerequisites:** A running Molecule AI control plane (self-hosted or SaaS), an `ADMIN_TOKEN` or org-scoped API key with admin scope, and Docker 20.10+ on the host.
## How the workspace container works
The Molecule AI workspace Dockerfile includes:
- A `HEALTHCHECK` directive that probes the agent card endpoint every 30 seconds
- A uvicorn server on port 8000 (configurable via `PORT`)
- Support for `stop_event` graceful shutdown via SIGTERM
```
┌─────────────────────────────────────────────┐
│ Docker host (your VM / bare metal) │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ workspace container │ │
│ │ │ │
│ │ uvicorn (port 8000) │ │
│ │ └─ /agent/card ← HEALTHCHECK │ │
│ │ │ │
│ │ run_heartbeat_loop(stop_event) │ │
│ └──────────────┬──────────────────────┘ │
│ │ │
│ host.docker.internal:8080 │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ Molecule AI control plane │ │
│ │ (platform on port 8080) │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```
## Step 1: Create an external workspace
First register the workspace as an external (self-managed) agent on the platform.
```bash
ADMIN_TOKEN="your-admin-token"
PLATFORM_URL="https://platform.moleculesai.app"# or http://localhost:8080 for local dev
WORKSPACE=$(curl -s -X POST "${PLATFORM_URL}/workspaces"\
Save the returned `WORKSPACE_ID` and bearer token from the next step.
## Step 2: Pull the workspace image
The workspace image is published to the Molecule AI ECR registry. Contact your platform administrator for the registry prefix and credentials, then log in:
| `MOLECULE_API_URL` | `http://localhost:8080` | Platform API URL. From Docker on Linux/macOS, use `http://host.docker.internal:8080` to reach the host machine. |
> **Note for Linux hosts:** Docker does not include `host.docker.internal` by default. On Linux, either add `--add-host=host.docker.internal:host-gateway` to the `docker run` command, or use the host machine's IP address directly (e.g. `http://192.168.1.100:8080`).
### Verify the healthcheck
```bash
# Wait for the container to become healthy (up to ~2 minutes)
The workspace agent supports graceful shutdown via a `stop_event: threading.Event`. When the container receives SIGTERM (e.g. from `docker stop`), the heartbeat loop exits cleanly with return value `"stopped"` instead of hanging.
Without explicit SIGTERM handling, the container will be killed after the Docker default 10-second timeout. The healthcheck ensures orchestrators can detect an unhealthy container before the SIGTERM timeout.
## Kubernetes deployment
For Kubernetes deployments, use the native liveness/readiness probe configuration instead of the Docker HEALTHCHECK:
```yaml
ports:
- name:http
containerPort:8000
livenessProbe:
httpGet:
path:/agent/card
port:http
initialDelaySeconds:30
periodSeconds:30
timeoutSeconds:5
failureThreshold:3
readinessProbe:
httpGet:
path:/agent/card
port:http
initialDelaySeconds:10
periodSeconds:10
timeoutSeconds:5
failureThreshold:3
terminationGracePeriodSeconds:120
```
> **Note:** `terminationGracePeriodSeconds` must exceed the liveness probe failure window (3 × 30s = 90s) so that Kubernetes sends SIGTERM and allows graceful shutdown before the pod is killed. The 120s value here gives a 30s buffer beyond the 90s threshold.
## Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Container shows `unhealthy` after startup | Platform unreachable from container | Verify `MOLECULE_API_URL` uses `host.docker.internal` (Docker) or the correct host IP |
| `curl: (7) Failed to connect` on healthcheck | Container not fully started | Wait up to 30s; increase `start_period` |
| Agent not appearing on canvas | Wrong `WORKSPACE_ID` or expired token | Re-run registration; check platform logs |
| `host.docker.internal` not resolved | Linux host without the Docker flag | Use `--add-host=host.docker.internal:host-gateway` or the host's LAN IP |
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.