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:
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
Reference in New Issue
Block a user