Deploy OpenClaw on a DigitalOcean Droplet
A production-ready deployment guide covering server provisioning, security hardening, process management, and monitoring. By the end of this guide, you will have OpenClaw running as a persistent systemd service on an Ubuntu droplet with automatic restarts, firewall protection, and log rotation.
Estimated time: 45 minutes | Cost: $6-24/month | Difficulty: Intermediate
Prerequisites
Before you begin, make sure you have:
- A DigitalOcean account with a valid payment method (sign up here)
- An SSH key pair on your local machine (generate one with
ssh-keygen -t ed25519if you do not have one) - Your SSH public key added to your DigitalOcean account under Settings > Security > SSH Keys
- An API key for your chosen LLM provider (e.g., Anthropic, OpenAI) -- OpenClaw needs this to run agents
- (Optional) A domain name if you want to expose OpenClaw behind a custom URL with SSL
Step 1: Create the Droplet
Log in to the DigitalOcean control panel and click Create > Droplets.
Recommended configuration:
| Setting | Value |
|---|---|
| Region | Choose the region closest to you or your users (e.g., nyc1, sfo3, fra1) |
| Image | Ubuntu 24.04 LTS (or 22.04 LTS) |
| Droplet Type | Basic (Shared CPU) |
| Plan | $6/mo (1 vCPU, 1 GB RAM) for light use; $12/mo (1 vCPU, 2 GB RAM) recommended for production |
| Authentication | SSH Key (select the key you added) |
| Hostname | openclaw-prod or similar |
Click Create Droplet and wait roughly 60 seconds for provisioning to finish. Copy the droplet's public IP address from the dashboard.
Tip: The $6/mo plan works fine for a single agent with light traffic. If you are running multiple concurrent agents or handling webhook-heavy workloads, start with the $12/mo plan so you have 2 GB of RAM and room to breathe.
Step 2: Initial Server Setup
SSH into your new droplet as root:
ssh root@YOUR_DROPLET_IP
Create a non-root user
Running everything as root is a security risk. Create a dedicated user:
# Create user and grant sudo privileges
adduser openclaw
usermod -aG sudo openclaw
# Copy your SSH key to the new user
rsync --archive --chown=openclaw:openclaw ~/.ssh /home/openclaw
Switch to the new user for the rest of the setup:
su - openclaw
Configure the firewall
Ubuntu ships with ufw (Uncomplicated Firewall). Enable it with sensible defaults:
# Allow SSH connections so you don't lock yourself out
sudo ufw allow OpenSSH
# Allow HTTP and HTTPS for the OpenClaw dashboard (port 18789) behind a reverse proxy
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable the firewall
sudo ufw enable
# Verify the rules
sudo ufw status verbose
You should see OpenSSH, 80/tcp, and 443/tcp listed as ALLOW.
Step 3: Install Dependencies
Install Node.js 20 LTS via nvm
nvm (Node Version Manager) lets you install and switch between Node.js versions without conflicting with system packages:
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# Load nvm into the current shell
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# Install Node.js 20 LTS
nvm install 20
# Verify the installation
node --version # Should print v20.x.x
npm --version # Should print 10.x.x
Install Docker and Docker Compose
Docker is optional but useful if you want to run OpenClaw in a container or add services like Redis or PostgreSQL alongside it:
# Remove any old Docker packages
sudo apt-get remove docker docker-engine docker.io containerd runc 2>/dev/null
# Install prerequisites
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the Docker repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine and Docker Compose plugin
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Add your user to the docker group (avoids needing sudo for docker commands)
sudo usermod -aG docker $USER
# Apply group changes (or log out and back in)
newgrp docker
# Verify Docker is running
docker --version
docker compose version
Step 4: Install OpenClaw
Install the CLI globally
npm install -g openclaw
Verify the installation:
openclaw --version
Configure environment variables
Create a dedicated directory for your OpenClaw configuration:
mkdir -p ~/.openclaw
Create the environment file with your API keys and settings:
cat > ~/.openclaw/.env << 'EOF'
# LLM Provider API Keys
# Uncomment and fill in the provider(s) you use
ANTHROPIC_API_KEY=your-anthropic-api-key-here
# OPENAI_API_KEY=your-openai-api-key-here
# OpenClaw Configuration
OPENCLAW_PORT=3111
OPENCLAW_HOST=0.0.0.0
OPENCLAW_LOG_LEVEL=info
# Optional: Webhook URL for notifications
# OPENCLAW_WEBHOOK_URL=https://your-webhook-endpoint.com/hook
EOF
Lock down permissions on the env file so only your user can read it:
chmod 600 ~/.openclaw/.env
Verify OpenClaw starts correctly
Run a quick test to make sure everything is wired up:
cd ~/.openclaw
openclaw start --dry-run
If the dry run succeeds, OpenClaw can read your configuration and connect to your LLM provider.
Step 5: Run as a Service
Running OpenClaw in a terminal session means it dies when you disconnect. A systemd service keeps it running permanently, starts it on boot, and restarts it automatically if it crashes.
Create the service file:
sudo tee /etc/systemd/system/openclaw.service > /dev/null << 'EOF'
[Unit]
Description=OpenClaw AI Agent Framework
Documentation=https://docs.openclaw.dev
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=openclaw
Group=openclaw
WorkingDirectory=/home/openclaw/.openclaw
# Load nvm and use the correct Node.js version
Environment=HOME=/home/openclaw
Environment=NVM_DIR=/home/openclaw/.nvm
ExecStart=/bin/bash -c 'source $NVM_DIR/nvm.sh && exec openclaw start'
# Load environment variables from the .env file
EnvironmentFile=/home/openclaw/.openclaw/.env
# Restart policy: always restart, wait 5 seconds between attempts
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=5
# Security: restrict what the service can do
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/home/openclaw/.openclaw
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw
[Install]
WantedBy=multi-user.target
EOF
Enable and start the service:
# Reload systemd to pick up the new service file
sudo systemctl daemon-reload
# Enable the service to start on boot
sudo systemctl enable openclaw
# Start the service now
sudo systemctl start openclaw
# Check the status
sudo systemctl status openclaw
You should see active (running) in green. To view live logs:
journalctl -u openclaw -f
Useful service management commands:
sudo systemctl restart openclaw # Restart after config changes
sudo systemctl stop openclaw # Stop the service
sudo systemctl status openclaw # Check health
journalctl -u openclaw --since "1 hour ago" # Recent logs
Step 6: Security Hardening
Your droplet is exposed to the public internet. These steps significantly reduce your attack surface.
Disable root SSH login
sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Warning: Before doing this, verify you can SSH in as the
openclawuser from another terminal window. If you lock yourself out, you will need to use the DigitalOcean console to regain access.
Install and configure fail2ban
fail2ban watches log files and bans IPs that show malicious behavior (like brute-force SSH attempts):
sudo apt-get install -y fail2ban
# Create a local configuration override
sudo tee /etc/fail2ban/jail.local > /dev/null << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check banned IPs at any time:
sudo fail2ban-client status sshd
Enable unattended security upgrades
Keep your server patched automatically:
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Select Yes when prompted. Ubuntu will now automatically install security patches overnight without requiring manual intervention.
Review firewall rules
Double-check that only the ports you need are open:
sudo ufw status numbered
If you do not need HTTP/HTTPS (e.g., OpenClaw only communicates outbound to APIs), remove those rules:
sudo ufw delete allow 80/tcp
sudo ufw delete allow 443/tcp
Step 7: Monitoring
Basic health check with a cron job
Create a script that checks whether OpenClaw is responding and restarts it if not:
sudo tee /usr/local/bin/openclaw-healthcheck.sh > /dev/null << 'SCRIPT'
#!/bin/bash
# Simple health check: verify the openclaw service is active
if ! systemctl is-active --quiet openclaw; then
echo "$(date): OpenClaw is down, restarting..." >> /var/log/openclaw-healthcheck.log
systemctl restart openclaw
fi
SCRIPT
sudo chmod +x /usr/local/bin/openclaw-healthcheck.sh
Schedule it to run every 5 minutes:
echo "*/5 * * * * root /usr/local/bin/openclaw-healthcheck.sh" | sudo tee /etc/cron.d/openclaw-healthcheck
Configure log rotation
Prevent log files from consuming all your disk space:
sudo tee /etc/logrotate.d/openclaw > /dev/null << 'EOF'
/home/openclaw/.openclaw/logs/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 640 openclaw openclaw
postrotate
systemctl restart openclaw > /dev/null 2>&1 || true
endscript
}
EOF
Journald (which captures systemd service logs) has its own rotation. Cap it at 500 MB:
sudo sed -i 's/#SystemMaxUse=/SystemMaxUse=500M/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald
Optional: External monitoring
For production deployments, consider adding an external monitoring agent:
Datadog (full observability):
DD_API_KEY=your-datadog-api-key bash -c \
"$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)"
Grafana Cloud (free tier available): Install the Grafana Agent to push metrics and logs to Grafana Cloud. This gives you dashboards, alerting, and log search without running your own Grafana instance.
Uptime Kuma (self-hosted, free): If you want a lightweight status page, run Uptime Kuma as a Docker container on the same droplet:
docker run -d --restart=always -p 3001:3001 \
-v uptime-kuma:/app/data \
--name uptime-kuma \
louislam/uptime-kuma:1
Cost Breakdown
| Plan | vCPUs | RAM | Disk | Transfer | Monthly Cost | Best For |
|---|---|---|---|---|---|---|
| Basic | 1 | 1 GB | 25 GB SSD | 1 TB | $6 | Single agent, light usage, testing |
| Basic | 1 | 2 GB | 50 GB SSD | 2 TB | $12 | Production single agent, moderate traffic |
| Basic | 2 | 2 GB | 60 GB SSD | 3 TB | $18 | Multiple agents, webhook-heavy workloads |
| Basic | 2 | 4 GB | 80 GB SSD | 4 TB | $24 | High-traffic production, concurrent agents |
Additional costs to consider:
- LLM API usage: This is typically your largest cost. Budget $10-100+/month depending on agent activity and model choice.
- Domain name: ~$10-15/year if you want a custom domain.
- Backups: DigitalOcean automated backups add 20% to the droplet cost ($1.20-$4.80/mo).
- Monitoring: Datadog starts at ~$15/host/month. Grafana Cloud has a generous free tier. Uptime Kuma is free.
Recommendation: Start with the $6/mo plan. DigitalOcean lets you resize droplets with a few clicks and minimal downtime. Scale up only when you actually need it.
Troubleshooting
OpenClaw fails to start
Check the service logs:
journalctl -u openclaw -n 50 --no-pager
Common causes:
- Missing or invalid API key in
~/.openclaw/.env. Verify the key works by runningopenclaw start --dry-run. - Node.js not found. The systemd service needs nvm loaded. Make sure the
NVM_DIRenvironment variable in the service file points to the correct path. - Port already in use. Check with
sudo ss -tlnp | grep 3111and kill the conflicting process.
Cannot SSH into the server
- Verify your SSH key is added to
~/.ssh/authorized_keysfor theopenclawuser. - If you disabled root login and cannot get in, use the DigitalOcean Console from the droplet dashboard (Access > Launch Droplet Console).
- Check that UFW has not blocked SSH: use the DigitalOcean console to run
sudo ufw allow OpenSSH.
High memory usage
- The $6 droplet only has 1 GB of RAM. Add swap space as a safety net:
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
- If memory is still a problem, resize to the $12/mo plan from the DigitalOcean dashboard.
Service keeps restarting
Check for crash loops:
journalctl -u openclaw --since "10 minutes ago" | grep -i error
If the service hits the restart limit (5 restarts in 60 seconds), systemd will stop trying. Reset the counter and investigate:
sudo systemctl reset-failed openclaw
sudo systemctl start openclaw
Docker permission denied
If you see permission denied when running Docker commands, your user is not in the docker group:
sudo usermod -aG docker $USER
newgrp docker
Firewall blocking connections
If external services cannot reach OpenClaw, verify the port is open:
sudo ufw allow 3111/tcp
sudo ufw reload
Next Steps
Once OpenClaw is running on your droplet, consider these improvements:
- Set up a reverse proxy: Use Nginx or Caddy to serve OpenClaw behind a domain with automatic SSL via Let's Encrypt.
- Enable backups: Turn on DigitalOcean automated backups from the droplet settings.
- Add a domain: Point an A record to your droplet IP and configure SSL.
- Set up CI/CD: Automate deployments with GitHub Actions that SSH into your droplet and update OpenClaw on push.
- Join the community: Share your deployment setup and custom skills at openclaw.dev/community.