Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
bagelhole avatar

Openclaw Local Mac Mini

  • 78 installs
  • 44 repo stars
  • Updated May 22, 2026
  • bagelhole/devops-security-agent-skills

OpenClaw Local + Mac mini Setup is a Claude Code skill for cloning, running, and hosting OpenClaw locally as an always-on AI agent, including Mac mini production setup.

About

OpenClaw Local + Mac mini Setup covers running OpenClaw on a developer laptop or a dedicated Mac mini as an always-on local AI agent host. A developer uses it to clone and bootstrap the app, configure Docker Compose with optional Redis and Ollama services, and harden macOS for headless server operation. It also covers networking, monitoring, and launchd services for production-grade uptime.

  • Clone, bootstrap, and run OpenClaw locally with Docker Compose
  • Mac mini production setup with macOS hardening and launchd services
  • Includes Redis and Ollama services plus health checks and monitoring

Openclaw Local Mac Mini by the numbers

  • 78 all-time installs (skills.sh)
  • Ranked #596 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

openclaw-local-mac-mini capabilities & compatibility

Requires an LLM provider API key (OpenAI or Anthropic) or a local Ollama model; hardware is a Mac mini.

Capabilities
container hardening · kubernetes hardening · devops
Works with
docker · redis
Use cases
devops · orchestration
Platforms
macOS
Runs
Runs locally
Pricing
Bring your own API key
From the docs

What openclaw-local-mac-mini says it does

Running OpenClaw as a private, always-on local AI agent
SKILL.md
macOS 13 (Ventura) or later on Apple Silicon (M1/M2/M4 Mac mini recommended)
SKILL.md
At least 16 GB RAM (32 GB recommended for local model serving)
SKILL.md
npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill openclaw-local-mac-mini

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs78
repo stars44
Last updatedMay 22, 2026
Repositorybagelhole/devops-security-agent-skills

What it does

Set up and reliably run OpenClaw as a private, always-on local AI agent on a Mac mini host.

Who is it for?

Developers running OpenClaw as a private always-on local AI agent on Apple Silicon Mac mini hardware.

When should I use this skill?

When running OpenClaw as a private, always-on local AI agent or setting up a dedicated Mac mini AI server.

What you get

A reproducible OpenClaw deployment that stays up on a headless Mac mini with monitoring and launchd services.

  • Local OpenClaw install
  • Docker Compose stack
  • Hardened Mac mini host with launchd services

By the numbers

  • macOS 13+ on Apple Silicon required
  • 16 GB RAM minimum, 32 GB recommended

Files

SKILL.mdMarkdownGitHub ↗

OpenClaw Local + Mac mini Setup

Use this skill when you want to run OpenClaw on a developer laptop or promote it to a stable Mac mini host. Covers cloning and bootstrapping, Docker Compose configuration, Mac mini hardware optimization, networking, monitoring, and production-grade launchd services.

When to Use

  • Running OpenClaw as a private, always-on local AI agent
  • Setting up a dedicated Mac mini as a home-lab AI server
  • Deploying OpenClaw with Docker Compose for reproducible environments
  • Optimizing macOS for headless server operation
  • Monitoring a local AI service for uptime and performance

Prerequisites

  • macOS 13 (Ventura) or later on Apple Silicon (M1/M2/M4 Mac mini recommended)
  • Docker Desktop for Mac or OrbStack installed
  • Git, Node.js (v18+), and a package manager (npm or pnpm)
  • API keys for your chosen LLM provider (OpenAI, Anthropic, or local Ollama)
  • At least 16 GB RAM (32 GB recommended for local model serving)

Local Setup (Any Dev Machine)

Clone and Bootstrap

# Clone the repository
git clone https://github.com/openclaw/openclaw.git
cd openclaw

# Review the upstream README for current prerequisites
cat README.md

# Copy the example environment file
cp .env.example .env

# Edit .env with your provider keys and configuration
# At minimum, set the model provider and API key
cat > .env << 'ENV'
# LLM Provider Configuration
OPENAI_API_KEY=sk-your-openai-key-here
# Or for Anthropic:
# ANTHROPIC_API_KEY=sk-ant-your-key-here
# Or for local Ollama:
# OLLAMA_BASE_URL=http://localhost:11434

# Application settings
NODE_ENV=development
PORT=3000
HOST=0.0.0.0
LOG_LEVEL=info

# Database (if applicable)
DATABASE_URL=sqlite:./data/openclaw.db
ENV

Install Dependencies and Run

# Install dependencies
npm install
# Or with pnpm:
# pnpm install

# Run database migrations if needed
npm run db:migrate

# Start the development server
npm run dev

# Verify startup
curl -s http://localhost:3000/api/health | jq .
# Expected: {"status":"ok","version":"..."}

Validate the Setup

# Check the API health endpoint
curl -f http://localhost:3000/api/health

# Check the UI loads
curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/
# Expected: 200

# Run built-in tests if available
npm test

Docker Compose Setup

docker-compose.yml

version: "3.8"

services:
  openclaw:
    build:
      context: .
      dockerfile: Dockerfile
    image: openclaw:latest
    container_name: openclaw
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file:
      - .env
    environment:
      - NODE_ENV=production
      - HOST=0.0.0.0
      - PORT=3000
    volumes:
      - openclaw-data:/app/data
      - ./config:/app/config:ro
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 15s
    deploy:
      resources:
        limits:
          memory: 4G
        reservations:
          memory: 1G
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "5"

  # Optional: Redis for caching/queues
  redis:
    image: redis:7-alpine
    container_name: openclaw-redis
    restart: unless-stopped
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

  # Optional: Ollama for local model serving
  ollama:
    image: ollama/ollama:latest
    container_name: openclaw-ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama-models:/root/.ollama
    deploy:
      resources:
        limits:
          memory: 16G
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  openclaw-data:
  redis-data:
  ollama-models:

Running with Docker Compose

# Build and start all services
docker compose up -d --build

# Check service status
docker compose ps

# View logs
docker compose logs -f openclaw
docker compose logs -f --tail=100 ollama

# Pull a model into Ollama (if using local models)
docker exec openclaw-ollama ollama pull llama3:8b
docker exec openclaw-ollama ollama list

# Restart a single service
docker compose restart openclaw

# Stop everything
docker compose down

# Stop and remove volumes (full reset)
docker compose down -v

Mac mini Production Setup

macOS Hardening and Baseline

# Enable automatic security updates
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticDownload -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstall -bool true

# Enable FileVault disk encryption
sudo fdesetup enable

# Disable sleep (headless server should never sleep)
sudo pmset -a sleep 0
sudo pmset -a disksleep 0
sudo pmset -a displaysleep 0

# Enable auto-restart after power failure
sudo pmset -a autorestart 1

# Disable screen saver
defaults -currentHost write com.apple.screensaver idleTime 0

# Set hostname
sudo scutil --set ComputerName "openclaw-mini"
sudo scutil --set HostName "openclaw-mini"
sudo scutil --set LocalHostName "openclaw-mini"

# Verify power settings
pmset -g

Dedicated User Account

# Create a dedicated service user
sudo sysadminctl -addUser openclaw -fullName "OpenClaw Service" -password "temp-change-me" -admin

# Switch to the service user for setup
su - openclaw

# Clone and configure OpenClaw in the user's home
cd ~
git clone https://github.com/openclaw/openclaw.git
cd openclaw
cp .env.example .env
# Edit .env with production values

Secrets Management

# Store API keys in macOS Keychain instead of plaintext .env
security add-generic-password -a openclaw -s "OPENAI_API_KEY" -w "sk-your-key-here"
security add-generic-password -a openclaw -s "ANTHROPIC_API_KEY" -w "sk-ant-your-key-here"

# Retrieve a secret from Keychain in scripts
OPENAI_API_KEY=$(security find-generic-password -a openclaw -s "OPENAI_API_KEY" -w)
export OPENAI_API_KEY

# Helper script to load secrets from Keychain
cat > /Users/openclaw/openclaw/load-secrets.sh << 'SCRIPT'
#!/usr/bin/env bash
export OPENAI_API_KEY=$(security find-generic-password -a openclaw -s "OPENAI_API_KEY" -w 2>/dev/null)
export ANTHROPIC_API_KEY=$(security find-generic-password -a openclaw -s "ANTHROPIC_API_KEY" -w 2>/dev/null)
SCRIPT
chmod 700 /Users/openclaw/openclaw/load-secrets.sh

launchd Service Configuration

<!-- /Library/LaunchDaemons/com.openclaw.service.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.openclaw.service</string>

    <key>UserName</key>
    <string>openclaw</string>

    <key>WorkingDirectory</key>
    <string>/Users/openclaw/openclaw</string>

    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>source ./load-secrets.sh && /usr/local/bin/node ./dist/server.js</string>
    </array>

    <key>EnvironmentVariables</key>
    <dict>
        <key>NODE_ENV</key>
        <string>production</string>
        <key>PORT</key>
        <string>3000</string>
        <key>HOST</key>
        <string>0.0.0.0</string>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin</string>
    </dict>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
    </dict>

    <key>ThrottleInterval</key>
    <integer>10</integer>

    <key>StandardOutPath</key>
    <string>/var/log/openclaw/stdout.log</string>

    <key>StandardErrorPath</key>
    <string>/var/log/openclaw/stderr.log</string>

    <key>SoftResourceLimits</key>
    <dict>
        <key>NumberOfFiles</key>
        <integer>65536</integer>
    </dict>
</dict>
</plist>
# Create log directory
sudo mkdir -p /var/log/openclaw
sudo chown openclaw:staff /var/log/openclaw

# Load the service
sudo launchctl load -w /Library/LaunchDaemons/com.openclaw.service.plist

# Verify it is running
sudo launchctl list | grep openclaw
curl -f http://localhost:3000/api/health

# Stop/start/restart the service
sudo launchctl stop com.openclaw.service
sudo launchctl start com.openclaw.service

# Unload the service (disable)
sudo launchctl unload /Library/LaunchDaemons/com.openclaw.service.plist

# View logs
tail -f /var/log/openclaw/stdout.log
tail -f /var/log/openclaw/stderr.log

Docker Compose via launchd

<!-- /Library/LaunchDaemons/com.openclaw.docker.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.openclaw.docker</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/docker</string>
        <string>compose</string>
        <string>-f</string>
        <string>/Users/openclaw/openclaw/docker-compose.yml</string>
        <string>up</string>
    </array>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/var/log/openclaw/docker-stdout.log</string>

    <key>StandardErrorPath</key>
    <string>/var/log/openclaw/docker-stderr.log</string>
</dict>
</plist>

Networking

Tailscale for Secure Remote Access

# Install Tailscale on the Mac mini
brew install --cask tailscale

# Authenticate and connect
open /Applications/Tailscale.app
# Or via CLI:
tailscale up --authkey tskey-auth-your-key-here

# Verify Tailscale IP
tailscale ip -4
# e.g., 100.64.x.x

# Access OpenClaw from any Tailscale device
curl http://100.64.x.x:3000/api/health

# Enable MagicDNS for friendly names
# Access via: http://openclaw-mini:3000

Nginx Reverse Proxy (Optional)

# Install nginx via Homebrew
brew install nginx

# Configure reverse proxy
cat > /opt/homebrew/etc/nginx/servers/openclaw.conf << 'NGINX'
server {
    listen 80;
    server_name openclaw-mini openclaw-mini.local;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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 300s;
        proxy_send_timeout 300s;
    }

    # Rate limiting for API endpoints
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
NGINX

# Test and reload nginx
nginx -t
brew services restart nginx

macOS Firewall

# Enable the application firewall
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on

# Allow specific apps
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add /usr/local/bin/node
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add /opt/homebrew/bin/nginx

# Block all incoming except allowed
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setblockall on

# Verify
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate

Monitoring

Health Check Script

#!/usr/bin/env bash
# /Users/openclaw/openclaw/healthcheck.sh
set -euo pipefail

ENDPOINT="http://localhost:3000/api/health"
LOGFILE="/var/log/openclaw/healthcheck.log"
ALERT_EMAIL="admin@example.com"
MAX_FAILURES=3
FAILURE_COUNT_FILE="/tmp/openclaw-failures"

timestamp() { date '+%Y-%m-%d %H:%M:%S'; }

# Initialize failure counter
if [ ! -f "$FAILURE_COUNT_FILE" ]; then
  echo 0 > "$FAILURE_COUNT_FILE"
fi

if curl -sf --max-time 10 "$ENDPOINT" > /dev/null 2>&1; then
  echo "$(timestamp) OK" >> "$LOGFILE"
  echo 0 > "$FAILURE_COUNT_FILE"
else
  FAILURES=$(cat "$FAILURE_COUNT_FILE")
  FAILURES=$((FAILURES + 1))
  echo "$FAILURES" > "$FAILURE_COUNT_FILE"
  echo "$(timestamp) FAIL (count: $FAILURES)" >> "$LOGFILE"

  if [ "$FAILURES" -ge "$MAX_FAILURES" ]; then
    echo "$(timestamp) ALERT: OpenClaw down for $FAILURES checks" >> "$LOGFILE"
    # Attempt restart
    sudo launchctl stop com.openclaw.service
    sleep 2
    sudo launchctl start com.openclaw.service
    echo "$(timestamp) Service restarted" >> "$LOGFILE"
    echo 0 > "$FAILURE_COUNT_FILE"
  fi
fi
# Schedule health checks every 5 minutes via cron
crontab -e
# Add:
# */5 * * * * /Users/openclaw/openclaw/healthcheck.sh

Resource Monitoring

# Monitor CPU and memory usage of OpenClaw
ps aux | grep -E 'node|docker' | grep -v grep

# Continuous monitoring with top (non-interactive)
top -l 1 -s 0 | grep -E 'node|docker'

# Disk usage check
df -h /Users/openclaw
du -sh /Users/openclaw/openclaw/data/

# Docker resource usage
docker stats --no-stream openclaw openclaw-redis openclaw-ollama

# macOS Activity Monitor from CLI
sudo powermetrics --samplers cpu_power,gpu_power -n 1

Log Rotation

# /etc/newsyslog.d/openclaw.conf
# logfilename                        [owner:group]  mode  count  size  when  flags  [/pid_file]  [sig_num]
/var/log/openclaw/stdout.log         openclaw:staff  644   10     5120  *     JN
/var/log/openclaw/stderr.log         openclaw:staff  644   10     5120  *     JN
/var/log/openclaw/healthcheck.log    openclaw:staff  644   10     1024  *     JN
# Force log rotation
sudo newsyslog -F

# Or use a simple cron-based rotation
cat > /Users/openclaw/rotate-logs.sh << 'ROTATE'
#!/usr/bin/env bash
LOGDIR="/var/log/openclaw"
for log in "$LOGDIR"/*.log; do
  if [ -f "$log" ] && [ "$(stat -f%z "$log")" -gt 52428800 ]; then
    mv "$log" "${log}.$(date +%Y%m%d%H%M%S)"
    gzip "${log}."*
    touch "$log"
  fi
done
# Keep only last 10 rotated logs
ls -t "$LOGDIR"/*.gz 2>/dev/null | tail -n +11 | xargs rm -f
ROTATE
chmod +x /Users/openclaw/rotate-logs.sh

Validation Checklist

  • App starts after reboot without manual intervention (launchctl list | grep openclaw)
  • Health check succeeds from local network (curl -f http://<ip>:3000/api/health)
  • Health check succeeds via Tailscale (curl -f http://100.64.x.x:3000/api/health)
  • Secrets are not committed and not world-readable (ls -la .env, check .gitignore)
  • Access to admin interfaces is restricted to trusted users/devices
  • Docker volumes persist across container restarts (docker compose down && docker compose up -d)
  • Log rotation is active and disk usage stays bounded
  • Automatic restart works after crash (kill the process and verify relaunch)

Troubleshooting

SymptomDiagnosticFix
Slow responsestop -l 1, check model backendVerify RAM/CPU pressure; use a smaller model or remote API
Boot failuressudo launchctl list, check logsInspect /var/log/openclaw/stderr.log, fix working directory
Auth errorsCheck .env or Keychain secretsRe-check provider keys, scopes, and endpoint URLs
Random crasheslog show --predicate 'process == "node"'Pin dependency versions, check for OOM in dmesg
Port 3000 in uselsof -i :3000Kill conflicting process or change PORT in .env
Docker won't startdocker info, docker compose logsEnsure Docker Desktop/OrbStack is running
Ollama model slowdocker stats openclaw-ollamaAllocate more RAM to Docker, use quantized model
Tailscale unreachabletailscale status, ping 100.64.x.xRe-authenticate with tailscale up, check firewall
Disk fulldf -h, du -sh ~/openclaw/data/Prune Docker images (docker system prune), rotate logs

Related Skills

  • ollama-stack - Local model serving patterns
  • mac-mini-llm-lab - Mac mini reliability and security baseline
  • startup-it-troubleshooting - Small-team operational triage

Related skills

DevOps & CI/CDinfradeploymonitoring

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.