{"id":1990,"date":"2026-01-28T05:08:35","date_gmt":"2026-01-28T05:08:35","guid":{"rendered":"https:\/\/veerhost.com\/?p=1990"},"modified":"2026-02-19T12:50:59","modified_gmt":"2026-02-19T12:50:59","slug":"how-to-set-up-openclaw","status":"publish","type":"post","link":"https:\/\/veerhost.com\/de\/how-to-set-up-openclaw\/","title":{"rendered":"How to Set Up OpenClaw (Step-by-Step Guide)"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Quick Requirements Checklist<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Recommended Hosting<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Veerhost VPS<\/strong> (Ubuntu 22.04 \/ 24.04 recommended)<\/li>\n\n\n\n<li>SSH access + sudo user<\/li>\n\n\n\n<li>A domain (optional but recommended for webhooks\/dashboards)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Software You\u2019ll Need<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Git<\/li>\n\n\n\n<li>Node.js 18+ <strong>or<\/strong> Python 3.10+<\/li>\n\n\n\n<li>A database (MySQL\/Postgres)<\/li>\n\n\n\n<li>(Optional) Redis for queues\/caching<\/li>\n\n\n\n<li>Nginx + SSL if using webhooks<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 1 \u2014 VPS Preparation (Veerhost)<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">1) SSH into your Veerhost server<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ssh root@YOUR_SERVER_IP\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you use a non-root user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ssh youruser@YOUR_SERVER_IP\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2) Update packages<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update &amp;&amp; sudo apt -y upgrade\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3) Install core dependencies<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install git curl unzip ufw\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4) Basic firewall (recommended)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Allow SSH and web traffic:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw allow OpenSSH\nsudo ufw allow 80\nsudo ufw allow 443\nsudo ufw enable\nsudo ufw status\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 2 \u2014 Get OpenClaw Files onto Veerhost<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Option A: Clone from Git (recommended)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\ngit clone https:\/\/github.com\/openclaw\/openclaw.git openclaw\ncd openclaw\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Option B: Upload a ZIP<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Upload via SFTP, then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\nunzip openclaw.zip -d openclaw\ncd openclaw\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 3 \u2014 Configure Environment Variables (.env)<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Most bots use a <code>.env<\/code> file so you don\u2019t hardcode secrets in source files.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create <code>.env<\/code><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>nano .env\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Example <code>.env<\/code> (generic, works for many bots)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Bot platform token\nBOT_TOKEN=YOUR_TOKEN_HERE\n\n# Optional: webhook mode\nWEBHOOK_ENABLED=false\nWEBHOOK_URL=https:\/\/bot.yourdomain.com\/webhook\nWEBHOOK_PORT=3000\n\n# Database\nDB_TYPE=postgres\nDB_HOST=127.0.0.1\nDB_PORT=5432\nDB_NAME=openclaw\nDB_USER=openclaw_user\nDB_PASSWORD=STRONG_PASSWORD_HERE\n\n# Optional Redis\nREDIS_URL=redis:\/\/127.0.0.1:6379\n\n# App settings\nNODE_ENV=production\nLOG_LEVEL=info\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save and exit (Ctrl+O, Enter, Ctrl+X).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Lock down permissions<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod 600 .env\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 4 \u2014 Database Setup (Choose MySQL or PostgreSQL)<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Option 1: PostgreSQL (excellent for production)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Install PostgreSQL<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install postgresql postgresql-contrib\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Create database + user<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres psql\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside <code>psql<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE DATABASE openclaw;\nCREATE USER openclaw_user WITH ENCRYPTED PASSWORD 'STRONG_PASSWORD_HERE';\nGRANT ALL PRIVILEGES ON DATABASE openclaw TO openclaw_user;\n\\q\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update <code>.env<\/code> accordingly (DB_HOST, DB_USER, DB_PASSWORD, etc.).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Option 2: MySQL (common on hosting stacks)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Install MySQL<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install mysql-server\nsudo mysql_secure_installation\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Create database + user<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mysql\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In MySQL:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE DATABASE openclaw CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER 'openclaw_user'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD_HERE';\nGRANT ALL PRIVILEGES ON openclaw.* TO 'openclaw_user'@'localhost';\nFLUSH PRIVILEGES;\nEXIT;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update <code>.env<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DB_TYPE=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_NAME=openclaw\nDB_USER=openclaw_user\nDB_PASSWORD=STRONG_PASSWORD_HERE\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 5A \u2014 Deploy OpenClaw (Node.js Version)<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">If your bot has <code>package.json<\/code>, use this section.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1) Install Node.js 18+ (LTS)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -fsSL https:\/\/deb.nodesource.com\/setup_18.x | sudo -E bash -\nsudo apt -y install nodejs\nnode -v\nnpm -v\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2) Install dependencies<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/openclaw\nnpm ci --omit=dev\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If your project uses build steps:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm run build\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3) Run a quick test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Common start commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm start\n# or\nnode index.js\n# or\nnode src\/main.js\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If it starts successfully, stop it (Ctrl+C) and continue to production process management.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4) Run in production with PM2 (auto-restart)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Install PM2<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo npm i -g pm2\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Start the bot<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use your actual entry file (examples below):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 start \"npm start\" --name openclaw\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 start dist\/index.js --name openclaw\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Save and enable startup on reboot<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 save\npm2 startup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">PM2 will print a command\u2014copy\/paste it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">View logs<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 logs openclaw\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Common PM2 commands<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 status\npm2 restart openclaw\npm2 stop openclaw\npm2 delete openclaw\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 5B \u2014 Deploy OpenClaw (Python Version)<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">If your bot has <code>requirements.txt<\/code> or <code>pyproject.toml<\/code>, use this section.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1) Install Python tooling<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install python3 python3-venv python3-pip\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2) Create virtual environment<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/openclaw\npython3 -m venv .venv\nsource .venv\/bin\/activate\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3) Install dependencies<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install --upgrade pip wheel\npip install -r requirements.txt\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4) Run a quick test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python main.py\n# or\npython -m bot\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stop it (Ctrl+C).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5) Run in production with systemd (recommended for Python)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Create a service file<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/systemd\/system\/openclaw.service\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Paste (adjust paths and entrypoint):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=OpenClaw Service\nAfter=network.target\n\n&#91;Service]\nType=simple\nUser=%i\nWorkingDirectory=\/home\/%i\/openclaw\nEnvironmentFile=\/home\/%i\/openclaw\/.env\nExecStart=\/home\/%i\/openclaw\/.venv\/bin\/python main.py\nRestart=always\nRestartSec=5\n\n&#91;Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enable it (replace <code>youruser<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now openclaw@youruser\nsudo systemctl status openclaw@youruser --no-pager\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>journalctl -u openclaw@youruser -f\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 6 \u2014 Webhook + Nginx + SSL (If Your Bot Uses Webhooks)<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Some bot platforms prefer <strong>webhooks<\/strong> instead of long polling. If OpenClaw supports webhooks (or includes a dashboard), set it up properly with HTTPS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1) Install Nginx<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install nginx\nsudo systemctl enable --now nginx\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2) Point your domain to the VPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In DNS:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>A<\/code> record: <code>bot.yourdomain.com<\/code> \u2192 <code>YOUR_SERVER_IP<\/code><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">3) Configure Nginx reverse proxy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Create a site config:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/nginx\/sites-available\/openclaw\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example (proxy to port <code>3000<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    server_name bot.yourdomain.com;\n\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:3000;\n        proxy_http_version 1.1;\n\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enable it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ln -s \/etc\/nginx\/sites-available\/openclaw \/etc\/nginx\/sites-enabled\/openclaw\nsudo nginx -t\nsudo systemctl reload nginx\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4) Add SSL with Let\u2019s Encrypt (Certbot)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install certbot python3-certbot-nginx\nsudo certbot --nginx -d bot.yourdomain.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now update <code>.env<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WEBHOOK_ENABLED=true\nWEBHOOK_URL=https:\/\/bot.yourdomain.com\/webhook\nWEBHOOK_PORT=3000\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Restart your bot process (PM2\/systemd).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 7 \u2014 Code Examples You Can Copy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Below are common patterns you might need while integrating OpenClaw with webhooks, health checks, and database connections.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A) Node.js \u2014 Minimal webhook server (Express)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.get(\"\/health\", (req, res) => res.status(200).send(\"OK\"));\n\napp.post(\"\/webhook\", async (req, res) => {\n  try {\n    const update = req.body;\n\n    \/\/ TODO: pass update to OpenClaw handler\n    \/\/ await bot.handleUpdate(update);\n\n    return res.status(200).json({ ok: true });\n  } catch (err) {\n    console.error(\"Webhook error:\", err);\n    return res.status(500).json({ ok: false });\n  }\n});\n\nconst port = process.env.WEBHOOK_PORT || 3000;\napp.listen(port, () => console.log(`Webhook listening on ${port}`));\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">B) Python \u2014 Minimal webhook server (FastAPI)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import os\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import PlainTextResponse\n\napp = FastAPI()\n\n@app.get(\"\/health\")\ndef health():\n    return PlainTextResponse(\"OK\")\n\n@app.post(\"\/webhook\")\nasync def webhook(request: Request):\n    update = await request.json()\n\n    # TODO: pass update to OpenClaw handler\n    # await bot.handle_update(update)\n\n    return {\"ok\": True}\n\nif __name__ == \"__main__\":\n    import uvicorn\n    port = int(os.getenv(\"WEBHOOK_PORT\", \"3000\"))\n    uvicorn.run(app, host=\"127.0.0.1\", port=port)\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">C) Node.js \u2014 Example Postgres connection (pg)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import pg from \"pg\";\nconst { Pool } = pg;\n\nexport const pool = new Pool({\n  host: process.env.DB_HOST,\n  port: Number(process.env.DB_PORT || 5432),\n  database: process.env.DB_NAME,\n  user: process.env.DB_USER,\n  password: process.env.DB_PASSWORD,\n  max: 10,\n  idleTimeoutMillis: 30000,\n});\n\nexport async function testDb() {\n  const res = await pool.query(\"SELECT NOW() AS now\");\n  console.log(\"DB OK:\", res.rows&#91;0].now);\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">D) Python \u2014 Example Postgres connection (psycopg)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import os\nimport psycopg\n\ndef get_conn():\n    return psycopg.connect(\n        host=os.getenv(\"DB_HOST\", \"127.0.0.1\"),\n        port=int(os.getenv(\"DB_PORT\", \"5432\")),\n        dbname=os.getenv(\"DB_NAME\", \"openclaw\"),\n        user=os.getenv(\"DB_USER\", \"openclaw_user\"),\n        password=os.getenv(\"DB_PASSWORD\", \"\"),\n    )\n\nwith get_conn() as conn:\n    with conn.cursor() as cur:\n        cur.execute(\"SELECT NOW()\")\n        print(\"DB OK:\", cur.fetchone()&#91;0])\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 8 \u2014 Troubleshooting (Most Common Issues)<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">1) \u201cBot token invalid\u201d \/ \u201c401 Unauthorized\u201d<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Double-check <code>BOT_TOKEN<\/code><\/li>\n\n\n\n<li>Ensure no extra spaces or quotes in <code>.env<\/code><\/li>\n\n\n\n<li>Restart the process after updating secrets<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2) Port already in use<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Find what is using port 3000:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo lsof -i :3000\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stop it or change <code>WEBHOOK_PORT<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3) Nginx returns 502 Bad Gateway<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Your bot process may be down<\/li>\n\n\n\n<li>Your bot is listening on the wrong interface\/port<\/li>\n\n\n\n<li>Confirm it\u2019s bound to <code>127.0.0.1:3000<\/code> (or your configured port)<\/li>\n\n\n\n<li>Check logs:\n<ul class=\"wp-block-list\">\n<li><code>pm2 logs openclaw<\/code><\/li>\n\n\n\n<li><code>journalctl -u openclaw@youruser -f<\/code><\/li>\n\n\n\n<li><code>sudo tail -n 200 \/var\/log\/nginx\/error.log<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">4) Database connection fails<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Confirm DB service is running:\n<ul class=\"wp-block-list\">\n<li><code>sudo systemctl status postgresql<\/code><\/li>\n\n\n\n<li><code>sudo systemctl status mysql<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Confirm credentials and ports match <code>.env<\/code><\/li>\n\n\n\n<li>Confirm user permissions were granted<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Part 9 \u2014 Updates, Backups, and Security<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Update the bot from Git<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/openclaw\ngit pull\nnpm ci --omit=dev   # Node\nnpm run build       # if needed\npm2 restart openclaw\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Or for Python:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/openclaw\ngit pull\nsource .venv\/bin\/activate\npip install -r requirements.txt\nsudo systemctl restart openclaw@youruser\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Back up your database (example: Postgres)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>pg_dump -U openclaw_user -d openclaw > openclaw_backup.sql\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Security Tips: Protect Your Veerhost VPS When Running OpenClaw<\/h1>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Security Disclaimer:<\/strong> OpenClaw should be deployed securely. Misconfigured servers (especially open ports, exposed dashboards, or unsecured databases) can be targeted by automated scanning and intrusion attempts. For your safety, follow the security steps in this guide\u2014close unused ports, protect admin panels, and keep your system updated.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Running a bot 24\/7 means your server is online 24\/7\u2014so security matters. Many attacks are not \u201cpersonal\u201d; they\u2019re automated bots scanning the internet for open ports, weak passwords, exposed databases, or public admin panels.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1) Close all unused ports (critical)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Only allow what you actually need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>22<\/strong> (SSH) \u2014 ideally restricted<\/li>\n\n\n\n<li><strong>80\/443<\/strong> (HTTP\/HTTPS) \u2014 only if you use webhooks\/dashboard<\/li>\n\n\n\n<li>Your bot\u2019s internal port (like 3000) should <strong>NOT<\/strong> be public if Nginx is proxying it.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">UFW: allow only SSH + web<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw default deny incoming\nsudo ufw default allow outgoing\n\nsudo ufw allow OpenSSH\nsudo ufw allow 80\nsudo ufw allow 443\n\nsudo ufw enable\nsudo ufw status\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Make sure your bot port is NOT exposed<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If your bot listens on port <code>3000<\/code>, do <strong>not<\/strong> allow it in UFW:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw delete allow 3000 2&gt;\/dev\/null || true\nsudo ufw status\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Also make the bot bind to <strong>localhost only<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Node\/FastAPI\/Uvicorn\/Express should listen on <code>127.0.0.1<\/code>, not <code>0.0.0.0<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Example (FastAPI \/ Uvicorn):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uvicorn app:app --host 127.0.0.1 --port 3000\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2) Secure SSH (reduce the biggest risk)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Use SSH keys (recommended)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Generate on your local machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ssh-keygen -t ed25519\nssh-copy-id youruser@YOUR_SERVER_IP\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Disable password login (after keys work)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Edit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/ssh\/sshd_config\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Set:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PasswordAuthentication no\nPermitRootLogin no\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Restart SSH:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl restart ssh\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3) Install Fail2ban (blocks brute-force logins)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install fail2ban\nsudo systemctl enable --now fail2ban\nsudo fail2ban-client status\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4) Never expose your database to the internet<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Databases should bind to localhost only unless you <em>really<\/em> need remote access.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Check listening ports<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ss -tulpn\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you see MySQL\/Postgres listening on <code>0.0.0.0<\/code>, fix it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Postgres<\/strong> config usually in:\n<ul class=\"wp-block-list\">\n<li><code>\/etc\/postgresql\/*\/main\/postgresql.conf<\/code> \u2192 <code>listen_addresses = 'localhost'<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>MySQL<\/strong> config usually in:\n<ul class=\"wp-block-list\">\n<li><code>\/etc\/mysql\/mysql.conf.d\/mysqld.cnf<\/code> \u2192 <code>bind-address = 127.0.0.1<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Restart DB service after changes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5) Protect any dashboard\/admin endpoints<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If OpenClaw has an admin page:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Put it behind <strong>auth<\/strong><\/li>\n\n\n\n<li>Restrict access by IP (best)<\/li>\n\n\n\n<li>Or use Basic Auth in Nginx<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Example: Nginx basic auth<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install apache2-utils\nsudo htpasswd -c \/etc\/nginx\/.htpasswd adminuser\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then in Nginx:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>location \/admin {\n    auth_basic \"Restricted\";\n    auth_basic_user_file \/etc\/nginx\/.htpasswd;\n    proxy_pass http:\/\/127.0.0.1:3000;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Reload:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nginx -t &amp;&amp; sudo systemctl reload nginx\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6) Keep the server updated (easy win)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update &amp;&amp; sudo apt -y upgrade\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Optional automatic security updates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt -y install unattended-upgrades\nsudo dpkg-reconfigure --priority=low unattended-upgrades\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7) Protect secrets (.env) and rotate tokens if leaked<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Keep <code>.env<\/code> permissions tight:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod 600 .env\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Never commit <code>.env<\/code> to Git<\/li>\n\n\n\n<li>If you suspect compromise: <strong>rotate BOT_TOKEN and DB passwords immediately<\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">8) Monitor logs regularly<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PM2:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>pm2 logs openclaw\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>systemd:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>journalctl -u openclaw@youruser -f\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Auth attempts:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tail -n 200 \/var\/log\/auth.log\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">9) Quick compromise checklist (if you suspect hacking)<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Change SSH passwords \/ rotate keys<\/li>\n\n\n\n<li>Rotate bot token + DB credentials<\/li>\n\n\n\n<li>Check unknown users: <code>cut -d: -f1 \/etc\/passwd<\/code><\/li>\n\n\n\n<li>Check suspicious processes: <code>ps aux --sort=-%cpu | head<\/code><\/li>\n\n\n\n<li>Check open ports: <code>sudo ss -tulpn<\/code><\/li>\n\n\n\n<li>Consider rebuilding the VPS if you see clear compromise indicators<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">FAQ: OpenClaw on Veerhost<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">Should I use long polling or webhooks?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Long polling<\/strong> is easier (no domain\/SSL needed).<\/li>\n\n\n\n<li><strong>Webhooks<\/strong> are more production-friendly and often faster, but require HTTPS and a stable endpoint.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Can I host this on shared hosting?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Usually bots need a <strong>persistent process<\/strong> (always running). Shared hosting often stops background processes. A <strong>Veerhost VPS<\/strong> is the safest choice.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What\u2019s the best \u201calways on\u201d method?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Node.js: <strong>PM2<\/strong><\/li>\n\n\n\n<li>Python: <strong>systemd<\/strong><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Quick Requirements Checklist Recommended Hosting Software You\u2019ll Need Part 1 \u2014 VPS Preparation (Veerhost) 1) SSH into your Veerhost server If you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1991,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19],"tags":[],"class_list":["post-1990","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"_links":{"self":[{"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/posts\/1990","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/comments?post=1990"}],"version-history":[{"count":4,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/posts\/1990\/revisions"}],"predecessor-version":[{"id":2058,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/posts\/1990\/revisions\/2058"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/media\/1991"}],"wp:attachment":[{"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/media?parent=1990"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/categories?post=1990"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/veerhost.com\/de\/wp-json\/wp\/v2\/tags?post=1990"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}