Initial commit — OpenClaw VM infrastructure

- ansible/: VM provisioning playbooks and roles
  - provision-vm.yml: create KVM VM from Ubuntu cloud image
  - install.yml: install OpenClaw on guest (upstream)
  - customize.yml: swappiness, virtiofs fstab, linger
  - roles/vm/: libvirt domain XML, cloud-init templates
  - inventory.yml + host_vars/zap.yml: zap instance config
- backup-openclaw-vm.sh: daily rsync + MinIO upload
- restore-openclaw-vm.sh: full redeploy from scratch
- README.md: full operational documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
William Valentin
2026-03-12 12:18:31 -07:00
commit aceeb7b542
71 changed files with 7840 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
---
title: Architecture
description: Technical implementation details
---
# Architecture
## Component Overview
```
┌─────────────────────────────────────────┐
│ UFW Firewall (SSH only) │
└──────────────┬──────────────────────────┘
┌──────────────┴──────────────────────────┐
│ DOCKER-USER Chain (iptables) │
│ Blocks all external container access │
└──────────────┬──────────────────────────┘
┌──────────────┴──────────────────────────┐
│ Docker Daemon │
│ - Non-root containers │
│ - Localhost-only binding │
└──────────────┬──────────────────────────┘
┌──────────────┴──────────────────────────┐
│ OpenClaw Container │
│ User: openclaw │
│ Port: 127.0.0.1:3000 │
└──────────────────────────────────────────┘
```
## File Structure
```
/opt/openclaw/
├── Dockerfile
├── docker-compose.yml
/home/openclaw/.openclaw/
├── config.yml
├── sessions/
└── credentials/
/etc/systemd/system/
└── openclaw.service
/etc/docker/
└── daemon.json
/etc/ufw/
└── after.rules (DOCKER-USER chain)
```
## Service Management
OpenClaw runs as a systemd service that manages the Docker container:
```bash
# Systemd controls Docker Compose
systemd → docker compose → openclaw container
```
## Installation Flow
1. **Tailscale Setup** (`tailscale.yml`)
- Add Tailscale repository
- Install Tailscale package
- Display connection instructions
2. **User Creation** (`user.yml`)
- Create `openclaw` system user
3. **Docker Installation** (`docker.yml`)
- Install Docker CE + Compose V2
- Add user to docker group
- Create `/etc/docker` directory
4. **Firewall Setup** (`firewall.yml`)
- Install UFW
- Configure DOCKER-USER chain
- Configure Docker daemon (`/etc/docker/daemon.json`)
- Allow SSH (22/tcp) and Tailscale (41641/udp)
5. **Node.js Installation** (`nodejs.yml`)
- Add NodeSource repository
- Install Node.js 22.x
- Install pnpm globally
6. **OpenClaw Setup** (`openclaw.yml`)
- Create directories
- Generate configs from templates
- Build Docker image
- Start container via Compose
- Install systemd service
## Key Design Decisions
### Why UFW + DOCKER-USER?
Docker manipulates iptables directly, bypassing UFW. The DOCKER-USER chain is evaluated before Docker's FORWARD chain, allowing us to block traffic before Docker sees it.
### Why Localhost Binding?
Defense in depth. Even if DOCKER-USER fails, localhost binding prevents external access.
### Why Systemd Service?
- Auto-start on boot
- Clean lifecycle management
- Integration with system logs
- Dependency management (after Docker)
### Why Non-Root Container?
Principle of least privilege. If container is compromised, attacker has limited privileges.
## Ansible Task Order
```
main.yml
├── tailscale.yml (VPN setup)
├── user.yml (create openclaw user)
├── docker.yml (install Docker, create /etc/docker)
├── firewall.yml (configure UFW + Docker daemon)
├── nodejs.yml (Node.js + pnpm)
└── openclaw.yml (container setup)
```
Order matters: Docker must be installed before firewall configuration because:
1. `/etc/docker` directory must exist for `daemon.json`
2. Docker service must exist to be restarted after config changes
+408
View File
@@ -0,0 +1,408 @@
# Configuration Guide
This guide explains all available configuration options for the OpenClaw Ansible installer.
## Configuration File
All default variables are defined in:
**[`roles/openclaw/defaults/main.yml`](../roles/openclaw/defaults/main.yml)**
## How to Configure
### Method 1: Command Line Variables
Pass variables directly via `-e` flag:
```bash
ansible-playbook playbook.yml --ask-become-pass \
-e openclaw_install_mode=development \
-e "openclaw_ssh_keys=['ssh-ed25519 AAAAC3... user@host']"
```
### Method 2: Variables File
Create a `vars.yml` file:
```yaml
# vars.yml
openclaw_install_mode: development
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx user@host"
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB... admin@laptop"
openclaw_repo_url: "https://github.com/YOUR_USERNAME/openclaw.git"
openclaw_repo_branch: "main"
tailscale_authkey: "tskey-auth-xxxxxxxxxxxxx"
nodejs_version: "22.x"
```
Then use it:
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars.yml
```
### Method 3: Edit Defaults
Directly edit `roles/openclaw/defaults/main.yml` before running the playbook.
**Note**: This is not recommended for version control, use variables files instead.
## Available Variables
### User Configuration
#### `openclaw_user`
- **Type**: String
- **Default**: `openclaw`
- **Description**: System user name for running OpenClaw
- **Example**:
```bash
-e openclaw_user=myuser
```
#### `openclaw_home`
- **Type**: String
- **Default**: `/home/openclaw`
- **Description**: Home directory for the openclaw user
- **Example**:
```bash
-e openclaw_home=/home/myuser
```
#### `openclaw_ssh_keys`
- **Type**: List of strings
- **Default**: `[]` (empty)
- **Description**: SSH public keys for accessing the openclaw user account
- **Example**:
```yaml
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx user@host"
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB... admin@laptop"
```
```bash
-e "openclaw_ssh_keys=['ssh-ed25519 AAAAC3... user@host']"
```
### Installation Mode
#### `openclaw_install_mode`
- **Type**: String (`release` or `development`)
- **Default**: `release`
- **Description**: Installation mode
- `release`: Install via npm (`pnpm install -g openclaw@latest`)
- `development`: Clone repo, build from source, symlink binary
- **Example**:
```bash
-e openclaw_install_mode=development
```
### Development Mode Settings
These variables only apply when `openclaw_install_mode: development`
#### `openclaw_repo_url`
- **Type**: String (Git URL)
- **Default**: `https://github.com/openclaw/openclaw.git`
- **Description**: Git repository URL to clone
- **Example**:
```bash
-e openclaw_repo_url=https://github.com/YOUR_USERNAME/openclaw.git
```
#### `openclaw_repo_branch`
- **Type**: String
- **Default**: `main`
- **Description**: Git branch to checkout
- **Example**:
```bash
-e openclaw_repo_branch=feature-branch
```
#### `openclaw_code_dir`
- **Type**: String (Path)
- **Default**: `{{ openclaw_home }}/code`
- **Description**: Directory where code repositories are stored
- **Example**:
```bash
-e openclaw_code_dir=/home/openclaw/projects
```
#### `openclaw_repo_dir`
- **Type**: String (Path)
- **Default**: `{{ openclaw_code_dir }}/openclaw`
- **Description**: Full path to openclaw repository
- **Example**:
```bash
-e openclaw_repo_dir=/home/openclaw/projects/openclaw
```
### OpenClaw Settings
#### `openclaw_port`
- **Type**: Integer
- **Default**: `3000`
- **Description**: Port for OpenClaw gateway (currently informational)
- **Example**:
```bash
-e openclaw_port=8080
```
#### `openclaw_config_dir`
- **Type**: String (Path)
- **Default**: `{{ openclaw_home }}/.openclaw`
- **Description**: OpenClaw configuration directory
- **Example**:
```bash
-e openclaw_config_dir=/etc/openclaw
```
### Node.js Configuration
#### `nodejs_version`
- **Type**: String
- **Default**: `22.x`
- **Description**: Node.js major version to install
- **Example**:
```bash
-e nodejs_version=20.x
```
### Tailscale Configuration
#### `tailscale_authkey`
- **Type**: String
- **Default**: `""` (empty - manual setup required)
- **Description**: Tailscale authentication key for automatic connection
- **Example**:
```bash
-e tailscale_authkey=tskey-auth-k1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6
```
- **Get Key**: https://login.tailscale.com/admin/settings/keys
### OS-Specific Settings
These are automatically set based on the detected OS:
#### `homebrew_prefix`
- **Type**: String (Path)
- **Default**: `/opt/homebrew` (macOS) or `/home/linuxbrew/.linuxbrew` (Linux)
- **Description**: Homebrew installation prefix
- **Read-only**: Set automatically based on OS
#### `package_manager`
- **Type**: String
- **Default**: `brew` (macOS) or `apt` (Linux)
- **Description**: System package manager
- **Read-only**: Set automatically based on OS
## Configuration Examples
### Basic Setup with SSH Keys
```yaml
# vars.yml
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx user@desktop"
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHyyyyyyyy user@laptop"
```
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars.yml
```
### Development Setup
```yaml
# vars-dev.yml
openclaw_install_mode: development
openclaw_repo_url: "https://github.com/myorg/openclaw.git"
openclaw_repo_branch: "develop"
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx dev@workstation"
```
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars-dev.yml
```
### Production Setup with Tailscale
```yaml
# vars-prod.yml
openclaw_install_mode: release
tailscale_authkey: "tskey-auth-k1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6"
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx admin@mgmt-server"
nodejs_version: "22.x"
```
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars-prod.yml
```
### Custom User and Directories
```yaml
# vars-custom.yml
openclaw_user: mybot
openclaw_home: /opt/mybot
openclaw_config_dir: /etc/mybot
openclaw_code_dir: /opt/mybot/repositories
```
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars-custom.yml
```
### Testing Different Branches
```yaml
# vars-testing.yml
openclaw_install_mode: development
openclaw_repo_branch: "experimental-feature"
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxxxxxxxx tester@qa"
```
```bash
ansible-playbook playbook.yml --ask-become-pass -e @vars-testing.yml
```
## Environment-Specific Configurations
### Development Environment
```yaml
# environments/dev.yml
openclaw_install_mode: development
openclaw_repo_url: "https://github.com/openclaw/openclaw.git"
openclaw_repo_branch: "main"
openclaw_ssh_keys:
- "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
```
### Staging Environment
```yaml
# environments/staging.yml
openclaw_install_mode: release
tailscale_authkey: "{{ lookup('env', 'TAILSCALE_AUTHKEY_STAGING') }}"
openclaw_ssh_keys:
- "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
```
### Production Environment
```yaml
# environments/prod.yml
openclaw_install_mode: release
tailscale_authkey: "{{ lookup('env', 'TAILSCALE_AUTHKEY_PROD') }}"
openclaw_ssh_keys:
- "ssh-ed25519 AAAAC3... ops@prod-mgmt"
- "ssh-ed25519 AAAAC3... admin@backup-server"
nodejs_version: "22.x"
```
## Security Best Practices
### SSH Keys
1. **Use dedicated keys**: Create separate SSH keys for OpenClaw access
```bash
ssh-keygen -t ed25519 -f ~/.ssh/openclaw_ed25519 -C "openclaw-access"
```
2. **Limit key permissions**: Use SSH key options to restrict access
```
from="192.168.1.0/24" ssh-ed25519 AAAAC3... admin@trusted-network
```
3. **Rotate keys regularly**: Update SSH keys periodically
```bash
ansible-playbook playbook.yml --ask-become-pass \
-e "openclaw_ssh_keys=['$(cat ~/.ssh/new_key.pub)']"
```
### Tailscale Auth Keys
1. **Use ephemeral keys** for temporary access
2. **Set expiration times** for auth keys
3. **Use reusable keys** only for automation
4. **Store in secrets manager**: Don't commit to git
```bash
# Use environment variable
export TAILSCALE_AUTHKEY=$(vault read -field=key secret/tailscale)
ansible-playbook playbook.yml --ask-become-pass \
-e tailscale_authkey="$TAILSCALE_AUTHKEY"
```
### Sensitive Variables
Never commit sensitive data to git:
```yaml
# ❌ BAD - Don't do this
tailscale_authkey: "tskey-auth-actual-key-here"
# ✅ GOOD - Use environment variables or vault
tailscale_authkey: "{{ lookup('env', 'TAILSCALE_AUTHKEY') }}"
# ✅ GOOD - Use Ansible Vault
tailscale_authkey: "{{ vault_tailscale_authkey }}"
```
Create encrypted vault:
```bash
ansible-vault create secrets.yml
# Add: vault_tailscale_authkey: tskey-auth-xxxxx
ansible-playbook playbook.yml --ask-become-pass \
-e @secrets.yml --ask-vault-pass
```
## Validation
After configuration, verify settings:
```bash
# Check what variables will be used
ansible-playbook playbook.yml --ask-become-pass \
-e @vars.yml --check --diff
# View all variables
ansible-playbook playbook.yml --ask-become-pass \
-e @vars.yml -e "ansible_check_mode=true" \
--tags never -vv
```
## Troubleshooting
### SSH Keys Not Working
Check file ownership and permissions:
```bash
sudo ls -la /home/openclaw/.ssh/
sudo cat /home/openclaw/.ssh/authorized_keys
```
### Tailscale Not Connecting
Verify auth key is valid:
```bash
sudo tailscale up --authkey=YOUR_KEY --verbose
```
### Installation Mode Issues
Check which mode is active:
```bash
ansible-playbook playbook.yml --ask-become-pass \
-e @vars.yml --check | grep "install_mode"
```
## See Also
- [Main README](../README.md)
- [Development Mode Guide](development-mode.md)
- [Upgrade Notes](../UPGRADE_NOTES.md)
- [Defaults File](../roles/openclaw/defaults/main.yml)
+431
View File
@@ -0,0 +1,431 @@
# Development Mode Installation
This guide explains how to install OpenClaw in **development mode**, where the application is built from source instead of installed from npm.
## Overview
### Release Mode vs Development Mode
| Feature | Release Mode | Development Mode |
|---------|-------------|------------------|
| Source | npm registry | GitHub repository |
| Installation | `pnpm install -g openclaw@latest` | `git clone` + `pnpm build` |
| Location | `~/.local/share/pnpm/global/...` | `~/code/openclaw/` |
| Binary | Global pnpm package | Symlink to `bin/openclaw.js` |
| Updates | `pnpm install -g openclaw@latest` | `git pull` + `pnpm build` |
| Use Case | Production, stable deployments | Development, testing, debugging |
| Recommended For | End users | Developers, contributors |
## Installation
### Quick Install
```bash
# Clone the ansible installer
git clone https://github.com/openclaw/openclaw-ansible.git
cd openclaw-ansible
# Run in development mode
./run-playbook.sh -e openclaw_install_mode=development
```
### Manual Install
```bash
# Install ansible
sudo apt update && sudo apt install -y ansible git
# Clone repository
git clone https://github.com/openclaw/openclaw-ansible.git
cd openclaw-ansible
# Install collections
ansible-galaxy collection install -r requirements.yml
# Run playbook with development mode
ansible-playbook playbook.yml --ask-become-pass -e openclaw_install_mode=development
```
## What Gets Installed
### Directory Structure
```
/home/openclaw/
├── .openclaw/ # Configuration directory
│ ├── sessions/
│ ├── credentials/
│ ├── data/
│ └── logs/
├── .local/
│ ├── bin/
│ │ └── openclaw # Symlink -> ~/code/openclaw/bin/openclaw.js
│ └── share/pnpm/
└── code/
└── openclaw/ # Git repository
├── bin/
│ └── openclaw.js
├── dist/ # Built files
├── src/ # Source code
├── package.json
└── pnpm-lock.yaml
```
### Installation Steps
The Ansible playbook performs these steps:
1. **Create `~/code` directory**
```bash
mkdir -p ~/code
```
2. **Clone repository**
```bash
cd ~/code
git clone https://github.com/openclaw/openclaw.git
```
3. **Install dependencies**
```bash
cd openclaw
pnpm install
```
4. **Build from source**
```bash
pnpm build
```
5. **Create symlink**
```bash
ln -sf ~/code/openclaw/bin/openclaw.js ~/.local/bin/openclaw
chmod +x ~/code/openclaw/bin/openclaw.js
```
6. **Add development aliases** to `.bashrc`:
```bash
alias openclaw-rebuild='cd ~/code/openclaw && pnpm build'
alias openclaw-dev='cd ~/code/openclaw'
alias openclaw-pull='cd ~/code/openclaw && git pull && pnpm install && pnpm build'
```
## Development Workflow
### Making Changes
```bash
# 1. Navigate to repository
openclaw-dev
# or: cd ~/code/openclaw
# 2. Make your changes
vim src/some-file.ts
# 3. Rebuild
openclaw-rebuild
# or: pnpm build
# 4. Test immediately
openclaw --version
openclaw doctor
```
### Pulling Updates
```bash
# Pull latest changes and rebuild
openclaw-pull
# Or manually:
cd ~/code/openclaw
git pull
pnpm install
pnpm build
```
### Testing Changes
```bash
# After rebuilding, the openclaw command uses the new code immediately
openclaw status
openclaw gateway
# View daemon logs
openclaw logs
```
### Switching Branches
```bash
cd ~/code/openclaw
# Switch to feature branch
git checkout feature-branch
pnpm install
pnpm build
# Switch back to main
git checkout main
pnpm install
pnpm build
```
## Development Aliases
The following aliases are added to `.bashrc`:
| Alias | Command | Purpose |
|-------|---------|---------|
| `openclaw-dev` | `cd ~/code/openclaw` | Navigate to repo |
| `openclaw-rebuild` | `cd ~/code/openclaw && pnpm build` | Rebuild after changes |
| `openclaw-pull` | `cd ~/code/openclaw && git pull && pnpm install && pnpm build` | Update and rebuild |
Plus an environment variable:
```bash
export OPENCLAW_DEV_DIR="$HOME/code/openclaw"
```
## Configuration Variables
You can customize the development installation:
```yaml
# In playbook or command line
openclaw_install_mode: "development"
openclaw_repo_url: "https://github.com/openclaw/openclaw.git"
openclaw_repo_branch: "main"
openclaw_code_dir: "/home/openclaw/code"
openclaw_repo_dir: "/home/openclaw/code/openclaw"
```
### Using a Fork
```bash
ansible-playbook playbook.yml --ask-become-pass \
-e openclaw_install_mode=development \
-e openclaw_repo_url=https://github.com/YOUR_USERNAME/openclaw.git \
-e openclaw_repo_branch=your-feature-branch
```
### Custom Location
```bash
ansible-playbook playbook.yml --ask-become-pass \
-e openclaw_install_mode=development \
-e openclaw_code_dir=/home/openclaw/projects
```
## Switching Between Modes
### From Release to Development
```bash
# Uninstall global package
pnpm uninstall -g openclaw
# Run ansible in development mode
ansible-playbook playbook.yml --ask-become-pass -e openclaw_install_mode=development
```
### From Development to Release
```bash
# Remove symlink
rm ~/.local/bin/openclaw
# Remove repository (optional)
rm -rf ~/code/openclaw
# Install from npm
pnpm install -g openclaw@latest
```
## Troubleshooting
### Build Fails
```bash
cd ~/code/openclaw
# Check Node.js version (needs 22.x)
node --version
# Clean install
rm -rf node_modules
pnpm install
pnpm build
```
### Symlink Not Working
```bash
# Check symlink
ls -la ~/.local/bin/openclaw
# Recreate symlink
rm ~/.local/bin/openclaw
ln -sf ~/code/openclaw/bin/openclaw.js ~/.local/bin/openclaw
chmod +x ~/code/openclaw/bin/openclaw.js
```
### Command Not Found
```bash
# Ensure ~/.local/bin is in PATH
echo $PATH | grep -q ".local/bin" || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
```
### Git Issues
```bash
cd ~/code/openclaw
# Reset to clean state
git reset --hard origin/main
git clean -fdx
# Rebuild
pnpm install
pnpm build
```
## Performance Considerations
### Build Time
First build takes longer (~1-2 minutes depending on system):
```bash
pnpm install # Downloads dependencies
pnpm build # Compiles TypeScript
```
Subsequent rebuilds are faster (~10-30 seconds):
```bash
pnpm build # Only recompiles changed files
```
### Disk Usage
Development mode uses more disk space:
- **Release mode**: ~150 MB (global pnpm cache)
- **Development mode**: ~400 MB (repo + node_modules + dist)
### Memory Usage
No difference in runtime memory usage between modes.
## CI/CD Integration
### Testing Before Merge
```bash
# Test specific commit
cd ~/code/openclaw
git fetch origin pull/123/head:pr-123
git checkout pr-123
pnpm install
pnpm build
# Test it
openclaw doctor
```
### Automated Testing
```bash
#!/bin/bash
# test-openclaw.sh
cd ~/code/openclaw
git pull
pnpm install
pnpm build
# Run tests
pnpm test
# Integration test
openclaw doctor
```
## Best Practices
### Development Workflow
1. ✅ **Always rebuild after code changes**
```bash
openclaw-rebuild
```
2. ✅ **Test changes before committing**
```bash
pnpm build && openclaw doctor
```
3. ✅ **Keep dependencies updated**
```bash
pnpm update
pnpm build
```
4. ✅ **Use feature branches**
```bash
git checkout -b feature/my-feature
```
### Don't Do
- ❌ Editing code without rebuilding
- ❌ Running `pnpm link` manually (breaks setup)
- ❌ Installing global packages while in dev mode
- ❌ Modifying symlink manually
## Advanced Usage
### Multiple Repositories
You can have multiple clones:
```bash
# Main development
~/code/openclaw/ # main branch
# Experimental features
~/code/openclaw-test/ # testing branch
# Switch binary symlink
ln -sf ~/code/openclaw-test/bin/openclaw.js ~/.local/bin/openclaw
```
### Custom Build Options
```bash
cd ~/code/openclaw
# Development build (faster, includes source maps)
NODE_ENV=development pnpm build
# Production build (optimized)
NODE_ENV=production pnpm build
```
### Debugging
```bash
# Run with debug output
DEBUG=* openclaw gateway
# Or specific namespaces
DEBUG=openclaw:* openclaw gateway
```
## See Also
- [Main README](../README.md)
- [Security Architecture](security.md)
- [Troubleshooting Guide](troubleshooting.md)
- [OpenClaw Repository](https://github.com/openclaw/openclaw)
+268
View File
@@ -0,0 +1,268 @@
---
title: Installation Guide
description: Detailed installation and configuration instructions
---
# Installation Guide
## Quick Install
```bash
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw-ansible/main/install.sh | bash
```
## Manual Installation
### Prerequisites
```bash
sudo apt update
sudo apt install -y ansible git
```
### Clone and Run
```bash
git clone https://github.com/openclaw/openclaw-ansible.git
cd openclaw-ansible
# Install Ansible collections
ansible-galaxy collection install -r requirements.yml
# Run playbook
ansible-playbook playbook.yml --ask-become-pass
```
## Post-Installation
### 1. Connect to Tailscale
```bash
# Interactive login
sudo tailscale up
# Or with auth key for automation
sudo tailscale up --authkey tskey-auth-xxxxx
# Check status
sudo tailscale status
```
Get auth keys from: https://login.tailscale.com/admin/settings/keys
### 2. Configure OpenClaw
```bash
# Edit config
sudo nano /home/openclaw/.openclaw/config.yml
# Key settings to configure:
# - provider: whatsapp/telegram/signal
# - phone: your number
# - ai.provider: anthropic/openai
# - ai.model: claude-3-5-sonnet-20241022
```
### 3. Login to Provider
```bash
# Login (will prompt for QR code or phone verification)
sudo docker exec -it openclaw openclaw login
# Check connection
sudo docker logs -f openclaw
```
## Service Management
### Systemd Commands
```bash
# Start/stop/restart
sudo systemctl start openclaw
sudo systemctl stop openclaw
sudo systemctl restart openclaw
# View status
sudo systemctl status openclaw
# Enable/disable auto-start
sudo systemctl enable openclaw
sudo systemctl disable openclaw
```
### Docker Commands
```bash
# View logs
sudo docker logs openclaw
sudo docker logs -f openclaw # follow
# Shell access
sudo docker exec -it openclaw bash
# Restart container
sudo docker restart openclaw
# Check status
sudo docker compose -f /opt/openclaw/docker-compose.yml ps
```
### Firewall Management
```bash
# View UFW status
sudo ufw status verbose
# Add custom rule
sudo ufw allow 8080/tcp comment 'Custom service'
sudo ufw reload
# View Docker isolation
sudo iptables -L DOCKER-USER -n -v
```
## Accessing OpenClaw
OpenClaw's web interface runs on port 3000 (localhost only).
### Via Tailscale (Recommended)
```bash
# After connecting Tailscale, browse to:
http://TAILSCALE_IP:3000
```
Wait, port 3000 is bound to localhost, so this won't work directly. Need to update the compose file or use SSH tunnel.
### Via SSH Tunnel
```bash
ssh -L 3000:localhost:3000 user@server
# Then browse to: http://localhost:3000
```
## Verification
### Security Check
```bash
# Check open ports (should show only SSH + Tailscale)
sudo ss -tlnp
# External port scan (only port 22 should be open)
nmap -p- YOUR_SERVER_IP
# Test container isolation
sudo docker run -d -p 80:80 --name test-nginx nginx
curl http://YOUR_SERVER_IP:80 # Should fail
curl http://localhost:80 # Should work
sudo docker rm -f test-nginx
```
### UFW Status
```bash
sudo ufw status verbose
# Expected output:
# Status: active
# To Action From
# -- ------ ----
# 22/tcp ALLOW IN Anywhere
# 41641/udp ALLOW IN Anywhere
```
### Tailscale Status
```bash
sudo tailscale status
# Expected output:
# 100.x.x.x hostname user@ linux -
```
## Uninstall
```bash
# Stop services
sudo systemctl stop openclaw
sudo systemctl disable openclaw
sudo tailscale down
# Remove containers and data
sudo docker compose -f /opt/openclaw/docker-compose.yml down
sudo rm -rf /opt/openclaw
sudo rm -rf /home/openclaw/.openclaw
sudo rm /etc/systemd/system/openclaw.service
sudo systemctl daemon-reload
# Remove packages (optional)
sudo apt remove --purge tailscale docker-ce docker-ce-cli containerd.io docker-compose-plugin nodejs
# Remove user (optional)
sudo userdel -r openclaw
# Reset firewall (optional)
sudo ufw disable
sudo ufw --force reset
```
## Advanced Configuration
### Custom Port
Edit `/opt/openclaw/docker-compose.yml`:
```yaml
ports:
- "127.0.0.1:3001:3000" # Change 3001 to desired port
```
Then restart:
```bash
sudo systemctl restart openclaw
```
### Environment Variables
Add to `/opt/openclaw/docker-compose.yml`:
```yaml
environment:
- NODE_ENV=production
- ANTHROPIC_API_KEY=sk-ant-xxx
- DEBUG=openclaw:*
```
### Volume Mounts
Add additional volumes in docker-compose.yml:
```yaml
volumes:
- /home/openclaw/.openclaw:/home/openclaw/.openclaw
- /path/to/custom:/custom
```
## Automation
### Unattended Install
```bash
# Set Tailscale auth key in playbook vars
ansible-playbook playbook.yml \
--ask-become-pass \
-e "tailscale_authkey=tskey-auth-xxxxx"
```
### CI/CD Integration
```yaml
# Example GitHub Actions
- name: Deploy OpenClaw
run: |
ansible-playbook playbook.yml \
-e "tailscale_authkey=${{ secrets.TAILSCALE_KEY }}" \
--become
```
+196
View File
@@ -0,0 +1,196 @@
---
title: Security Architecture
description: Firewall configuration, Docker isolation, and security hardening details
---
# Security Architecture
## Overview
This playbook implements a multi-layer defense strategy to secure OpenClaw installations.
## Security Layers
### Layer 1: UFW Firewall
```bash
# Default policies
Incoming: DENY
Outgoing: ALLOW
Routed: DENY
# Allowed
SSH (22/tcp): ALLOW
Tailscale (41641/udp): ALLOW
```
### Layer 2: Fail2ban (SSH Protection)
Automatic protection against SSH brute-force attacks:
```bash
# Configuration
Max retries: 5 attempts
Ban time: 1 hour (3600 seconds)
Find time: 10 minutes (600 seconds)
# Check status
sudo fail2ban-client status sshd
# Unban an IP
sudo fail2ban-client set sshd unbanip IP_ADDRESS
```
### Layer 3: DOCKER-USER Chain
Custom iptables chain that prevents Docker from bypassing UFW:
```
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-USER -i lo -j ACCEPT
-A DOCKER-USER -i <default_interface> -j DROP
COMMIT
```
**Result**: Even `docker run -p 80:80 nginx` won't expose port 80 externally.
### Layer 4: Localhost-Only Binding
All container ports bind to 127.0.0.1:
```yaml
ports:
- "127.0.0.1:3000:3000"
```
### Layer 5: Non-Root Container
Container processes run as unprivileged `openclaw` user.
### Layer 6: Systemd Hardening
The openclaw service runs with security restrictions:
- `NoNewPrivileges=true` - Prevents privilege escalation
- `PrivateTmp=true` - Isolated /tmp directory
- `ProtectSystem=strict` - Read-only system directories
- `ProtectHome=read-only` - Limited home directory access
- `ReadWritePaths` - Only ~/.openclaw is writable
### Layer 7: Scoped Sudo Access
The openclaw user has limited sudo permissions (not full root):
```bash
# Allowed commands only:
- systemctl start/stop/restart/status openclaw
- systemctl daemon-reload
- tailscale commands
- journalctl for openclaw logs
```
### Layer 8: Automatic Security Updates
Unattended-upgrades is configured for automatic security patches:
```bash
# Check status
sudo unattended-upgrade --dry-run
# View logs
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log
```
**Note**: Automatic reboots are disabled. Monitor for pending reboots:
```bash
cat /var/run/reboot-required 2>/dev/null || echo "No reboot required"
```
## Verification
```bash
# Check firewall
sudo ufw status verbose
# Check fail2ban
sudo fail2ban-client status
# Check Tailscale status
sudo tailscale status
# Check Docker isolation
sudo iptables -L DOCKER-USER -n -v
# Port scan from external machine (only SSH + Tailscale should be open)
nmap -p- YOUR_SERVER_IP
# Test container isolation
sudo docker run -d -p 80:80 --name test-nginx nginx
curl http://YOUR_SERVER_IP:80 # Should fail/timeout
curl http://localhost:80 # Should work
sudo docker rm -f test-nginx
# Check unattended-upgrades
sudo systemctl status unattended-upgrades
```
## Tailscale Access
OpenClaw's web interface (port 3000) is bound to localhost. Access it via:
1. **SSH tunnel**:
```bash
ssh -L 3000:localhost:3000 user@server
# Then browse to http://localhost:3000
```
2. **Tailscale** (recommended):
```bash
# On server: already done by playbook
sudo tailscale up
# From your machine:
# Browse to http://TAILSCALE_IP:3000
```
## Network Flow
```
Internet → UFW (SSH only) → fail2ban → DOCKER-USER Chain → DROP
Container → NAT → Internet (outbound allowed)
```
## Known Limitations
### macOS Support
- macOS firewall configuration is basic (Application Firewall only)
- No fail2ban equivalent on macOS
- Consider using Little Snitch or similar for enhanced macOS security
### IPv6
- Docker IPv6 is disabled by default (`ip6tables: false` in daemon.json)
- If your network uses IPv6, review and test firewall rules accordingly
### Installation Script
- The `curl | bash` installation pattern has inherent risks
- For high-security environments, clone the repository and audit before running
- Consider using `--check` mode first: `ansible-playbook playbook.yml --check`
## Security Checklist
After installation, verify:
- [ ] `sudo ufw status` shows only SSH and Tailscale allowed
- [ ] `sudo fail2ban-client status sshd` shows jail active
- [ ] `sudo iptables -L DOCKER-USER -n` shows DROP rule
- [ ] `nmap -p- YOUR_IP` from external shows only port 22
- [ ] `docker run -p 80:80 nginx` + `curl YOUR_IP:80` times out
- [ ] Tailscale access works for web UI
## Reporting Security Issues
If you discover a security vulnerability, please report it privately:
- OpenClaw: https://github.com/openclaw/openclaw/security
- This installer: https://github.com/openclaw/openclaw-ansible/security
+160
View File
@@ -0,0 +1,160 @@
---
title: Troubleshooting
description: Common issues and solutions
---
# Troubleshooting
## Container Can't Reach Internet
**Symptom**: OpenClaw can't connect to WhatsApp/Telegram
**Check**:
```bash
# Test from container
sudo docker exec openclaw ping -c 3 8.8.8.8
# Check UFW allows outbound
sudo ufw status verbose | grep OUT
```
**Solution**:
```bash
# Verify DOCKER-USER allows established connections
sudo iptables -L DOCKER-USER -n -v
# Restart Docker + Firewall
sudo systemctl restart docker
sudo ufw reload
sudo systemctl restart openclaw
```
## Port Already in Use
**Symptom**: Port 3000 conflict
**Solution**:
```bash
# Find what's using port 3000
sudo ss -tlnp | grep 3000
# Change OpenClaw port
sudo nano /opt/openclaw/docker-compose.yml
# Change: "127.0.0.1:3001:3000"
sudo systemctl restart openclaw
```
## Firewall Lockout
**Symptom**: Can't SSH after installation
**Solution** (via console/rescue mode):
```bash
# Disable UFW temporarily
sudo ufw disable
# Check SSH rule exists
sudo ufw status numbered
# Re-add SSH rule
sudo ufw allow 22/tcp
# Re-enable
sudo ufw enable
```
## Container Won't Start
**Check logs**:
```bash
# Systemd logs
sudo journalctl -u openclaw -n 50
# Docker logs
sudo docker logs openclaw
# Compose status
sudo docker compose -f /opt/openclaw/docker-compose.yml ps
```
**Common fixes**:
```bash
# Rebuild image
cd /opt/openclaw
sudo docker compose build --no-cache
sudo systemctl restart openclaw
# Check permissions
sudo chown -R openclaw:openclaw /home/openclaw/.openclaw
```
## Verify Docker Isolation
**Test that external ports are blocked**:
```bash
# Start test container
sudo docker run -d -p 80:80 --name test-nginx nginx
# From EXTERNAL machine (should fail):
curl http://YOUR_SERVER_IP:80
# From SERVER (should work):
curl http://localhost:80
# Cleanup
sudo docker rm -f test-nginx
```
## UFW Status Shows Inactive
**Fix**:
```bash
# Enable UFW
sudo ufw enable
# Reload rules
sudo ufw reload
# Verify
sudo ufw status verbose
```
## Ansible Playbook Fails
### Failed to set permissions on temporary files (Become Issue)
**Symptom**: `fatal: [host]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user..."}`
**Cause**: This happens when connecting as an unprivileged user (e.g., `ansible`) and using `become_user` to switch to another unprivileged user (e.g., `openclaw`). Ansible struggles to share temporary module files between them if the filesystem doesn't support POSIX ACLs.
**Solution**:
Enable **Ansible Pipelining** in your `ansible.cfg`. This executes modules via stdin without creating temporary files.
```ini
[defaults]
pipelining = True
```
Alternatively, if you cannot use pipelining, you can allow world-readable temporary files (less secure):
```ini
[defaults]
allow_world_readable_tmpfiles = True
```
### Collection missing
...
```bash
ansible-galaxy collection install -r requirements.yml
```
**Permission denied**:
```bash
# Run with --ask-become-pass
ansible-playbook playbook.yml --ask-become-pass
```
**Docker daemon not running**:
```bash
sudo systemctl start docker
# Re-run playbook
```