Deployment Guide
This guide covers different deployment options for protoLabs.
Deployment Options
| Option | Best For | Isolation | Setup Complexity |
|---|---|---|---|
| Local Development | Development | None | Low |
| Docker (Isolated) | Testing, demos | Full | Low |
| Docker (Projects Mounted) | Personal use | Partial | Medium |
| systemd + Docker | Production server | Configurable | Medium |
| Cloudflare Pages | Landing page hosting | Full | Low |
Landing Page (Cloudflare Pages)
The protoLabs.studio landing page (site/index.html) is deployed as a static site on Cloudflare Pages.
Architecture
site/index.html → Cloudflare Pages → protolabs.studio
(300+ edge nodes, serverless)No build step. Cloudflare serves the static HTML directly from the site/ directory on the main branch.
Cloudflare Pages Configuration
| Setting | Value |
|---|---|
| Project name | protolabs-studio |
| Repository | protoLabsAI/automaker |
| Production branch | main |
| Root directory | site |
| Build command | (none) |
| Build output | / |
| Watch paths | site/** |
Custom Domains
| Domain | Type | Behavior |
|---|---|---|
protolabs.studio | Apex | Primary (serves content) |
www.protolabs.studio | CNAME | 301 redirect to apex |
Security & Performance
All configured in the protolabs.studio Cloudflare zone:
| Setting | Value |
|---|---|
| SSL mode | Full (strict) |
| HSTS | ON, max-age=31536000, include subdomains |
| Min TLS Version | 1.2 |
| Bot Fight Mode | Super Bot Fight Mode (Pro) |
| Auto Minify | HTML, CSS, JS |
| Brotli | ON |
| HTTP/3 | ON |
| Always Online | ON |
| Browser Cache TTL | 4 hours |
| Edge Cache TTL | 1 day |
Newsletter Integration
The signup form posts directly to Buttondown (username: protoLabsAI). No server-side code or API keys required. Submissions are tagged launch-list for segmentation.
Deployment Trigger
Merging to main with changes in site/** triggers an automatic Cloudflare Pages deploy. No CI configuration needed — Cloudflare watches the repo directly.
Verification
curl -I https://protolabs.studio # 200 + CF-Ray header
curl -I https://www.protolabs.studio # 301 → apex
curl -I http://protolabs.studio # redirect → HTTPSLocal Development
For development, run protoLabs directly on your machine:
# Install dependencies
npm install
# Interactive launcher
npm run dev
# Or directly:
npm run dev:full # Web mode — starts UI (:3007) AND server (:3008) together
npm run dev:web # UI only at localhost:3007 (requires server separately)Requirements
- Node.js 22+
- Git
- npm
Environment Variables
Create a .env file:
ANTHROPIC_API_KEY=sk-ant-xxx
AUTOMAKER_API_KEY=your-local-keyDocker (Isolated)
Run protoLabs in complete isolation from your filesystem:
docker compose up -dAccess at http://localhost:3007 (UI), http://localhost:3008 (API), http://localhost:3009 (Docs)
Characteristics
- No access to host files - Only Docker volumes
- Named volumes persist data - Survives container restarts
- Projects created inside container - Use web UI to create projects
When to Use
- Testing protoLabs safely
- Demo environments
- CI/CD testing
Docker (Projects Mounted)
Mount your projects directory for development use:
1. Create Override File
Create docker-compose.override.yml:
services:
server:
volumes:
# Mount your projects directory
# IMPORTANT: Container path MUST match host path
- /home/youruser/dev:/home/youruser/dev:rw
environment:
- ALLOWED_ROOT_DIRECTORY=/home/youruser/dev
- GH_TOKEN=${GH_TOKEN}2. Build with Your UID/GID
UID=$(id -u) GID=$(id -g) docker compose build3. Start
docker compose up -dPath Mapping Rules
Critical: Container paths MUST match host paths for the MCP plugin to work:
# CORRECT - paths match
- /home/youruser/dev:/home/youruser/dev:rw
# WRONG - paths don't match (MCP plugin will fail)
- /projects:/home/youruser/devsystemd
Two systemd units ship in the repo. Pick exactly one per host:
| Unit | Runs | When to use |
|---|---|---|
automaker-docker.service | docker compose up -d | Containerized prod, full filesystem isolation, no host CLI access from agents |
automaker-host.service | npm start (= start-automaker.mjs --production) | Bare-metal prod. Agents can shell out to host CLIs (gh, codex, opencode, infisical, claude). |
The host-process variant exists because agents spawn external tools via child_process; in containers those tools either aren't installed or can't see the host's auth files. If your operator workflow depends on gh auth login or codex login happening on the host, use automaker-host.service.
Install the host-process variant
# Copy the service file
sudo cp automaker-host.service /etc/systemd/system/
# Edit for your environment if defaults don't match
sudo nano /etc/systemd/system/automaker-host.service
# WorkingDirectory = clone path (default: /opt/protomaker)
# User / Group = deploy user (default: automaker)
# Environment=HOME = $HOME for that user (default: /home/automaker)
sudo systemctl daemon-reload
sudo systemctl enable --now automaker-host.service
journalctl -u automaker-host -fInstall the Docker variant
# Copy the service file
sudo cp automaker-docker.service /etc/systemd/system/
# Edit for your environment
sudo nano /etc/systemd/system/automaker-docker.service
# WorkingDirectory = path containing the compose file
# User / Group = deploy userThe shipped file uses the default docker-compose.yml. For a prod deploy, set WorkingDirectory to the directory containing docker-compose.prod.yml and add Environment=COMPOSE_FILE=docker-compose.prod.yml to the [Service] block.
Enable and start
sudo systemctl daemon-reload
# Pick exactly one:
sudo systemctl enable --now automaker-host.service
# OR
sudo systemctl enable --now automaker-docker.service
# Check status (substitute the unit you enabled):
sudo systemctl status automaker-host4. Management Commands
# View logs
sudo journalctl -u automaker -f
# Restart
sudo systemctl restart automaker
# Stop
sudo systemctl stop automaker
# Disable on boot
sudo systemctl disable automakerEnvironment Variables Reference
Authentication
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY | Yes* | Anthropic API key |
CLAUDE_OAUTH_CREDENTIALS | Yes* | Claude CLI OAuth JSON |
AUTOMAKER_API_KEY | No | protoLabs API key (default: protoLabs_studio_key) |
CURSOR_AUTH_TOKEN | No | Cursor CLI OAuth token |
GH_TOKEN | No | GitHub CLI token |
*At least one of ANTHROPIC_API_KEY or CLAUDE_OAUTH_CREDENTIALS is required.
Server Configuration
| Variable | Default | Description |
|---|---|---|
PORT | 3008 | Server port |
HOST | 0.0.0.0 | Host to bind to |
HOSTNAME | localhost | Hostname for user-facing URLs |
DATA_DIR | ./data or /data | Data storage directory |
ALLOWED_ROOT_DIRECTORY | /projects | Restrict file operations |
CORS_ORIGIN | http://localhost:3007 | Allowed CORS origin |
Feature Flags
| Variable | Default | Description |
|---|---|---|
IS_CONTAINERIZED | false | Skip sandbox confirmation dialogs |
AUTOMAKER_MOCK_AGENT | false | Use mock agent (for testing) |
AUTOMAKER_AUTO_LOGIN | false | Skip login prompt (dev only) |
Integrations
| Variable | Required | Description |
|---|---|---|
DISCORD_TOKEN | No | Discord bot token for event routing and notifications |
DISCORD_GUILD_ID | No | Discord server (guild) ID |
DISCORD_CHANNEL_SUGGESTIONS | No | Channel ID for #suggestions — community feature ideas |
DISCORD_CHANNEL_PROJECT_PLANNING | No | Channel ID for #project-planning — epic and milestone discussions |
DISCORD_CHANNEL_AGENT_LOGS | No | Channel ID for #agent-logs — agent start/stop/complete events |
DISCORD_CHANNEL_CODE_REVIEW | No | Channel ID for #code-review — PR reviews and architecture discussions |
DISCORD_CHANNEL_INFRA | No | Channel ID for #infra — infrastructure alerts, health checks, Ava Gateway heartbeat monitoring |
Monitoring (Grafana)
| Variable | Default | Description |
|---|---|---|
GF_ADMIN_USER | admin | Grafana admin username (override in staging/prod) |
GF_ADMIN_PASSWORD | admin | Grafana admin password (override in staging/prod) |
Set these in your .env file to override the defaults for staging/production deployments:
GF_ADMIN_USER=your-admin-username
GF_ADMIN_PASSWORD=a-strong-passwordNote: Production deployments use Docker secrets for credential management. See
docker-compose.prod.ymlfor the production pattern.
Frontend Configuration
| Variable | Default | Description |
|---|---|---|
VITE_SERVER_URL | '' | API server URL (empty = relative) |
VITE_HOSTNAME | localhost | Hostname for API URLs |
Extracting OAuth Credentials
Claude CLI (macOS)
# Extract from Keychain
./scripts/get-claude-token.sh
# Use in Docker
export CLAUDE_OAUTH_CREDENTIALS=$(./scripts/get-claude-token.sh)
docker compose up -dClaude CLI (Linux)
# On Linux, mount the directory directly
services:
server:
volumes:
- ~/.claude:/home/automaker/.claude:roCursor CLI (macOS)
# Extract from Keychain
./scripts/get-cursor-token.sh
# Use in Docker
export CURSOR_AUTH_TOKEN=$(./scripts/get-cursor-token.sh)Cursor CLI (Linux)
# Extract from config file
export CURSOR_AUTH_TOKEN=$(jq -r '.accessToken' ~/.config/cursor/auth.json)GitHub CLI
# Extract existing token
export GH_TOKEN=$(gh auth token)SSL/TLS Configuration
For production deployments with HTTPS, use a reverse proxy:
nginx Example
server {
listen 443 ssl;
server_name protolabs.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3007;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}
location /api {
proxy_pass http://localhost:3008;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}Update CORS
When using a custom domain:
services:
server:
environment:
- CORS_ORIGIN=https://protolabs.example.comUpdating
Docker
# Pull latest code
git pull
# Rebuild and restart
docker compose build --no-cache
docker compose up -dsystemd
# Pull latest code
cd /path/to/protomaker
git pull
# Rebuild and restart
sudo systemctl restart automakerBackup Before Updating
# Backup Docker volumes
docker run --rm \
-v automaker-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/automaker-backup-$(date +%Y%m%d).tar.gz /dataSee backup-recovery.md for detailed backup procedures.
Proxmox VM Specifications
Recommended Specs by Use Case
| Use Case | Disk | RAM | vCPU | Notes |
|---|---|---|---|---|
| Minimum | 25 GB | 4 GB | 2 | Evaluation only, expect slowness |
| Baseline | 40 GB | 8 GB | 4 | Most users, comfortable operation |
| Heavy Use | 80-120 GB | 16 GB | 6-8 | Multiple concurrent agents, large repos |
Proxmox-Specific Settings
Storage: Use thin provisioning, virtio-scsi with discard enabled, enable TRIM in guest OS.
Memory: Do NOT overcommit RAM. Disable ballooning (Node.js + Docker perform poorly with it).
CPU: Set CPU type to host. Enable NUMA only if >= 16 GB RAM.
Recommended Distro: Ubuntu 22.04 LTS or Debian 12.