OpenClaw RAG Hosting on VPS with pgvector and Docker

Why OpenClaw RAG hosting belongs on a VPS
OpenClaw RAG hosting fits a VPS when you want control over data, latency, and cost. That matters for support bots, sales assistants, and internal workflow agents that rely on private documents, predictable spend, and clean rollback options. If you are comparing managed app platforms with self-managed hosting, start with Hostperl VPS and keep the deployment close to your users in APAC.
This tutorial walks through a full Docker-based deployment for a private RAG stack: OpenClaw, PostgreSQL with pgvector, Redis for caching and jobs, and Nginx as the HTTPS front end. It assumes a fresh server and a setup your support team can maintain without guesswork.
If you want a broader buying view before you deploy, Hostperl also has a practical AI app hosting buyers guide for VPS and private deployments and a separate OpenClaw pgvector setup you can compare against this workflow.
What you will build
- OpenClaw running in Docker Compose
- PostgreSQL 16 with pgvector for embeddings
- Redis for caching and background jobs
- Nginx with TLS for
https://DOMAIN_NAME - Secure environment variables and a non-root runtime user
Use these placeholders throughout the tutorial: SERVER_IP is your VPS IP, for example 203.0.113.10; DOMAIN_NAME is your app domain, for example bot.example.com; ADMIN_USER is your sudo user, for example aiadmin; APP_DIR is /opt/openclaw; and APP_PORT is 3000.
First login and operating system check
On your local computer, connect as root if your VPS provider gave you root SSH access.
ssh root@SERVER_IPIf Hostperl or your image uses a default non-root login, use that account instead.
ssh ADMIN_USER@SERVER_IPOnce you are on the server, identify the OS before you install anything.
cat /etc/os-releaseYou should see either Ubuntu/Debian or AlmaLinux/Rocky Linux. Keep the original root session open until the new admin login is verified.
Create a non-root admin user safely
On the VPS as root, create the admin user, give it sudo or wheel access, and prepare SSH keys. Do not disable root login yet.
Ubuntu and Debian
adduser ADMIN_USER
usermod -aG sudo ADMIN_USERReplace ADMIN_USER with your chosen username. The first command creates the account and prompts for a password; the second grants sudo access.
AlmaLinux and Rocky Linux
useradd -m ADMIN_USER
passwd ADMIN_USER
usermod -aG wheel ADMIN_USERSet a strong password if you need temporary password logins. The wheel group grants sudo privileges on these systems.
Now set up SSH keys for the new account.
mkdir -p /home/ADMIN_USER/.ssh
chmod 700 /home/ADMIN_USER/.ssh
cp /root/.ssh/authorized_keys /home/ADMIN_USER/.ssh/authorized_keys
chown -R ADMIN_USER:ADMIN_USER /home/ADMIN_USER/.ssh
chmod 600 /home/ADMIN_USER/.ssh/authorized_keysIf you do not already have authorized_keys on root, paste your public key from your local computer into /home/ADMIN_USER/.ssh/authorized_keys with nano or vi. The permissions above should end with one key file owned by the new user.
Open a second terminal on your local computer and test the new login before you change SSH settings.
ssh ADMIN_USER@SERVER_IP
sudo -v
whoamiSuccessful output should show ADMIN_USER and no sudo errors. Keep the root session open until this works.
Install Docker, Nginx, and basic tools
On the VPS as the non-root sudo user, update packages and install Docker, Compose, Nginx, and utilities. The package names differ by distribution.
Ubuntu and Debian
sudo apt update
sudo apt install -y ca-certificates curl gnupg nginx docker.io docker-compose-plugin ufw jqCheck the installed versions so you know Docker and Nginx are available.
docker --version
docker compose version
nginx -vAlmaLinux and Rocky Linux
sudo dnf install -y dnf-plugins-core curl nginx jq firewalld
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-pluginVerify the versions after installation.
docker --version
docker compose version
nginx -vEnable the services now.
sudo systemctl enable --now docker
sudo systemctl enable --now nginxOn AlmaLinux and Rocky Linux, also enable the firewall service if it is not active.
sudo systemctl enable --now firewalldPrepare the OpenClaw app directory and secrets
On the VPS as the non-root sudo user, create a working directory and a private environment file. This is where you keep API keys, database credentials, and any provider-specific settings for embeddings or model calls.
sudo mkdir -p /opt/openclaw
sudo chown -R ADMIN_USER:ADMIN_USER /opt/openclaw
cd /opt/openclaw
pwdCreate the environment file.
nano /opt/openclaw/.envPaste this example content, then replace the values with your own secrets.
DOMAIN_NAME=bot.example.com
APP_PORT=3000
POSTGRES_DB=openclaw
POSTGRES_USER=openclaw
POSTGRES_PASSWORD=change-this-db-password
REDIS_URL=redis://redis:6379/0
OPENCLAW_SECRET_KEY=change-this-long-random-string
OPENAI_API_KEY=replace-with-your-key
EMBEDDING_MODEL=text-embedding-3-large
Save and exit, then lock down the file.
chmod 600 /opt/openclaw/.env
ls -l /opt/openclaw/.envYou want to see restrictive permissions such as -rw-------. That reduces the chance of accidental secret exposure during a support handoff or migration.
Deploy OpenClaw with PostgreSQL pgvector and Redis
Create the Docker Compose file next. This layout keeps the app, database, and cache in one predictable folder, which is easier to back up and move later.
nano /opt/openclaw/docker-compose.ymlPaste the following file. If your OpenClaw image name differs, replace ghcr.io/openclaw/openclaw:latest with the published image you use.
services:
postgres:
image: pgvector/pgvector:pg16
container_name: openclaw-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7.4-alpine
container_name: openclaw-redis
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redisdata:/data
app:
image: ghcr.io/openclaw/openclaw:latest
container_name: openclaw-app
restart: unless-stopped
env_file:
- .env
depends_on:
- postgres
- redis
ports:
- "127.0.0.1:${APP_PORT}:3000"
volumes:
pgdata:
redisdata:
Save and exit. Then validate the file before you start anything.
cd /opt/openclaw
docker compose configA clean output means Compose accepted the syntax and substituted your environment variables.
Start the stack.
docker compose up -dCheck container status and ports.
docker compose ps
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'You should see all three containers running, with the app bound only to 127.0.0.1:3000 on the server. That keeps the app off the public internet until Nginx is ready.
Configure Nginx as the HTTPS front end
On the VPS as the non-root sudo user, create a reverse proxy file for your domain.
sudo nano /etc/nginx/conf.d/openclaw.confUse this Nginx configuration. It proxies traffic to the local app port and keeps basic headers in place for AI apps that handle logins or API callbacks.
server {
listen 80;
server_name DOMAIN_NAME;
location / {
proxy_pass http://127.0.0.1:APP_PORT;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
}
}
Save the file and test the syntax before reload.
sudo nginx -tIf you see syntax is ok and test is successful, reload Nginx.
sudo systemctl reload nginxOpen the firewall before you ask users or QA to test the site.
Ubuntu and Debian with UFW
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verboseAlmaLinux and Rocky Linux with firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-allIssue TLS and complete the domain setup
Point DOMAIN_NAME to SERVER_IP at your DNS provider first. If you also manage DNS and regional routing through Hostperl, the IP and DNS resources page is a useful reference for planning stable endpoints and subdomains.
Once DNS resolves, install Certbot and issue a certificate.
Ubuntu and Debian
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d DOMAIN_NAMEAlmaLinux and Rocky Linux
sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx -d DOMAIN_NAMEChoose the redirect option so HTTP moves to HTTPS. Then verify renewal.
sudo certbot renew --dry-runRun the first OpenClaw smoke test
From your local computer, check the site over HTTPS. Replace the domain with yours.
curl -I https://DOMAIN_NAMEYou should get a 200, 301, or 302 depending on the app’s login flow. If you get a 502, jump to the troubleshooting section.
Now inspect the app logs on the server.
cd /opt/openclaw
docker compose logs --tail=100 appLook for database connection errors, missing keys, or failed migrations. If your deployment requires a one-time setup or admin bootstrap command, run it inside the app container exactly as your OpenClaw image documents it.
For a practical business check, send one test request through the bot UI or API and confirm that the answer is stored, retrieved, and returned with the expected source context. That is the real smoke test for OpenClaw RAG hosting, not just a green homepage.
Backup, rollback, and cost control
Private AI apps fail in boring ways: a bad model key, a schema change, or a full disk. Keep a backup of /opt/openclaw, the Docker volumes, and your DNS records. Hostperl’s backup testing guide is useful if you need a restore drill that your team can actually trust.
For cost control, watch three places: API spend, Redis memory use, and Postgres growth from embeddings. Smaller embedding models, short retrieval windows, and cached answers reduce token bills without changing the hosting stack. This is where a right-sized managed VPS hosting plan often beats overbuying a larger server.
If you later move to Next.js or a separate API worker, Hostperl has a clean Next.js deployment guide you can pair with the same VPS.
Troubleshooting the most common failures
- 502 Bad Gateway: run
sudo journalctl -u nginx -n 50 --no-pageranddocker compose logs --tail=100 app. If the app is not listening, confirm the Compose port mapping and that the container is healthy. - Database connection errors: run
docker compose logs --tail=100 postgres. If the password is wrong, update/opt/openclaw/.envand recreate the stack withdocker compose up -d. - Certificate issue: run
sudo certbot certificatesandsudo nginx -t. If DNS has not propagated yet, wait and retry. - Permissions problem: run
ls -l /opt/openclaw/.env. If it is readable by others, setchmod 600 /opt/openclaw/.envimmediately.
Final verification
Finish with one check from the server and one from your browser or local shell.
docker compose ps
sudo systemctl status nginx --no-pager
ss -tulpn | grep -E ':(80|443|3000)\b'You should see Nginx on 80 and 443, and the app only on localhost port 3000.
curl -s https://DOMAIN_NAME | headIf the page returns HTML or redirects correctly, the deployment is live. Reboot the VPS once to confirm persistence.
sudo rebootAfter the server comes back, reconnect and repeat docker compose ps and sudo systemctl status nginx. That confirms your OpenClaw RAG hosting stack survives a restart.
If you want a private, supportable deployment for bots, RAG, or workflow automation, Hostperl VPS gives you the room to run OpenClaw, pgvector, Redis, and Nginx on your own terms. For teams that care about APAC latency, data residency, and practical migration support, Hostperl VPS and our AI hosting buyer’s guide are the right place to start.
FAQ
Can I run OpenClaw RAG hosting without Docker?
Yes, but Docker Compose keeps the app, database, and Redis easier to move, back up, and hand over to support.
Should I keep embeddings in PostgreSQL or use Qdrant?
PostgreSQL with pgvector is simpler for smaller and mid-sized deployments. Qdrant is a better fit when your retrieval layer grows and you want a separate vector store.
How do I keep bot secrets out of the codebase?
Use a root-owned or admin-owned .env file with chmod 600, and never commit it to Git. For larger teams, store secrets in a managed secret manager and inject them at runtime.
What is the fastest way to reduce AI hosting cost?
Cache repeated answers, reduce prompt size, limit retrieval chunks, and choose a smaller embedding model when quality allows it.
Can I move this deployment to another Hostperl VPS later?
Yes. Back up the Compose file, the environment file, your database volume, and DNS records. That gives you a clean migration path with minimal downtime.
