Step 0 of 26

Just Use a VPS.

The simplest way to deploy your personal AI assistant.
It's like a one-click install.

Based on the mass psychosis tutorial by Kai Lentit

Spin Up a Server

🧔
Just use a VPS. It's like a one-click install.
😕
Oh, I was just gonna buy a Mac Mini.
🧔
No. You need to use a fresh Linux VPS. It's like what everybody does.
🧔
Let's start by spinning up a server on your cloud VPS provider. You know, just a 1 vCPU, 4GB RAM, 100GB drive.
$ ssh root@203.0.113.42
Welcome to Ubuntu 24.04 LTS
root@vps:~#
🧔
Then you'll get a public IP and root SSH access.

You're Already Under Attack

🧔
Then immediately we're under attack.
😨
I haven't even logged in yet.
🧔
Yeah, SSH scans started 12 seconds ago. Now it's a fight against time. Do not install anything before securing your VPS.
SSH brute force port scan script kiddie botnet CVE exploit crypto miner DDoS probe password spray
0
SSH login attempts since you started reading

Update Everything. Trust Nothing.

🧔
First we make sure we have the latest state of the internet on our VPS.
root@vps:~# sudo apt update && sudo apt upgrade -y
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease
178 packages can be upgraded. Run 'apt list --upgradable' to see them.
🧔
Then we'll install essential security & networking tools.
root@vps:~# sudo apt install -y curl wget ufw fail2ban ca-certificates gnupg
😕
Why aren't these installed by default?
🧔
Well, that's because Linux was designed to be composable, transparent, minimal, scalable, and reusable in millions of environments.
😕
And it was not designed to be secure?
🧔
Think about it. Secure... Well for a server.
😕
See, you can't answer that question.
🧔
For a server!

Harden the Tunnel

🧔
Second, we create a non-root user with a strong password.
root@vps:~# sudo adduser claw
root@vps:~# sudo usermod -aG sudo claw
🧔
Then we DELETE password access and create an SSH key instead.
# On your local machine
local$ ssh-keygen -t ed25519
local$ ssh-copy-id claw@203.0.113.42
😕
I cannot use the password I use everywhere?
🧔
No, we need to harden the SSH tunnel.
root access disabled password auth off port 2222 ed25519 key only MaxAuthTries 3
# /etc/ssh/sshd_config
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers claw
MaxAuthTries 3
LoginGraceTime 30
root@vps:~# sudo sshd -t && sudo systemctl reload ssh
root@vps:~# sudo systemctl restart ssh
🧔
Then log out and log in with your SSH key again.
🧔
You didn't save your SSH key?
😬
I was supposed to be paying attention?
🧔
Restart from scratch.

The Elimination Diet

🧔
Next, firewall. This is an elimination diet. We block everything, then slowly reintroduce what we really need.
😕
And what do I need?
🧔
Well, that depends. Let's check what the tutorial says...
🧔
The tutorial won't mention it, because I wrote that tutorial.
2222 👾 🤖 💀 🕷 × × :)
claw@vps:~$ sudo ufw default deny incoming
claw@vps:~$ sudo ufw default allow outgoing
claw@vps:~$ sudo ufw allow 2222/tcp
claw@vps:~$ sudo ufw enable
😕
Why four twos?
🧔
Oh, it's just an arbitrary number.
😕
You could choose any. Six, seven?
🧔
No. The standard for arbitrary numbers is 2222.

Autoban the Guessers

🧔
Then we autoban IPs that guess passwords.
claw@vps:~$ sudo systemctl enable --now fail2ban
😕
I thought we don't use passwords?
🧔
Well, not today, but what about tomorrow?
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 1h
findtime = 10m
claw@vps:~$ sudo systemctl restart fail2ban
🧔
Restart it, verify it, press ls -la a hundred...
fail2ban-client status sshd:

Automatic Everything

😕
And now I will not get hacked?
🧔
No, I'm freaking out right now. Because it didn't enable automatic security updates.
claw@vps:~$ sudo apt install -y unattended-upgrades
claw@vps:~$ sudo dpkg-reconfigure unattended-upgrades
🧔
Now congrats, your server can reboot itself at 3am.
🧔
What kind of working environment would this be without a properly set time and date?
claw@vps:~$ sudo timedatectl set-timezone UTC
claw@vps:~$ sudo systemctl enable --now systemd-timesyncd
🧔
Now let's control entropy.
claw@vps:~$ sudo apt install -y haveged

Install OpenClaw—

🧔
And now we get to the most interesting part.
😍
Install openClaw...
🧔
Installing...
🧔
Installing a private VPN mesh.
😭
NordVPN? NordVPN?
🧔
Tailscale.
THE HOSTILE INTERNET TAILSCALE MESH laptop VPS phone 🔒 🔒
claw@vps:~$ curl -fsSL https://tailscale.com/install.sh | sh
claw@vps:~$ sudo tailscale up
claw@vps:~$ sudo tailscale status
🧔
Public SSH is now gone. All public inbound traffic is now gone.
claw@vps:~$ sudo ufw delete allow 2222/tcp
🧔
Except future IPv6 noise. So we disable IPv6 in UFW and apply kernel settings.
claw@vps:~$ sudo sed -i 's/IPV6=yes/IPV6=no/' /etc/default/ufw
claw@vps:~$ echo "net.ipv6.conf.all.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf
claw@vps:~$ sudo sysctl -p && sudo ufw reload
🧔
You know, just so we can sleep better.
This wasn't even the installation?

THE ACTUAL INSTALLATION

🧔
Not for this, first we need to install its dependencies.
🧔
Node.js. Never trust node version distros. Install Node.js from the official repo.
claw@vps:~$ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
claw@vps:~$ sudo apt install -y nodejs
🧔
But this of course doesn't work because we didn't install git.
claw@vps:~$ sudo apt install -y git
🧔
Now verify the repo isn't compromised by trusting GitHub and 900 random NPM dependencies.
claw@vps:~$ curl -fsSL https://get.pnpm.io/install.sh | sh -
claw@vps:~$ git clone https://github.com/openclaw/openclaw.git
claw@vps:~$ cd openclaw && pnpm install
added 1 of 900: left-pad@1.0.0
added 2 of 900: is-odd@3.0.1
added 3 of 900: is-even@1.0.0 (depends on is-odd)
added 4 of 900: is-number@7.0.0
added 5 of 900: kind-of@6.0.3
added 6 of 900: isobject@4.0.0
added 7 of 900: for-in@1.0.2
added 8 of 900: pascalcase@0.1.1
added 9 of 900: map-cache@0.2.2
added 10 of 900: arr-diff@4.0.0
added 11 of 900: regex-not@1.0.2
added 12 of 900: extend-shallow@3.0.2
added 13 of 900: existential-dread@0.0.1
added 14 of 900: has-values@1.0.0
added 15 of 900: unset-value@1.0.0
added 16 of 900: fragment-cache@0.2.1
warn: 247 moderate vulnerabilities found
...
added 900 of 900: openclaw@0.1.0-beta.3
🧔
Meanwhile we create a credentials directory. Because we don't dump production apps into $HOME like crazy people.
claw@vps:~$ sudo mkdir -p /opt/openclaw
claw@vps:~$ sudo chown claw:claw /opt/openclaw
claw@vps:~$ sudo chmod 640 /etc/openclaw.env
😕
Why are they broken?
🧔
Broken is the de facto standard.
claw@vps:~$ openclaw doctor
✓ All checks passed
🧔
And now... We are done.

SYSTEMD

🧔
We configure the systemd service so if it breaks, it doesn't crash.
systemd PID 1 init journald networkd logind udevd timedatd resolved
🧔
You know systemd is a controversial idea that hasn't been recognized widely in the Linux community because initially it started as an init system. Then it became a scheduler, a debugger, a login manager, a device manager, a process manager. So if it crashes, basically everything crashes. But since 2015 basically every major Linux distribution has decided for this argument and we lost.
🧔
But there are still people who use runit, OpenRC or s6 but you know we don't talk to these people.
🧔
But for now systemd is an optimal but non-optimal solution.
🧔
So we create this small unit file.
# /etc/systemd/system/openclaw.service
[Unit]
Description=OpenClaw Bot
After=network.target
 
[Service]
Type=simple
User=claw
EnvironmentFile=/etc/openclaw.env
WorkingDirectory=/opt/openclaw
ExecStart=/usr/bin/node index.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
 
[Install]
WantedBy=multi-user.target
claw@vps:~$ sudo systemctl daemon-reexec
claw@vps:~$ sudo systemctl daemon-reload
claw@vps:~$ sudo systemctl enable openclaw
claw@vps:~$ sudo systemctl start openclaw
claw@vps:~$ sudo systemctl status openclaw
● openclaw.service - OpenClaw Bot
  Active: active (running)

LOGGING. BACKUPS. AUDIT.

🧔
Now make sure we're logging everything to observe runtime behavior,
$ sudo journalctl -u openclaw -f
🧔
disk protection,
$ sudo apt install -y logrotate
🧔
backups.
$ crontab -e
# 0 3 * * * rsync -a /opt/openclaw /backups/openclaw
😕
Backups?
🧔
And then... run your application security audit.
$ openclaw security audit --deep
🧔
If it has one.

Security Is a Mindset

😕
I thought we did security already?
You don't DO security. Security needs to live rent free in your mind at all times.
🧔
And now you have the setup with no public SSH, no public web ports and server only reachable via Tailscale.
98.1%
uptime
...if you ignore the weekly kernel panics.

And This Was Simple?

😕
And this... was simple?
🧔
Yes, this was the Ubuntu version. Now I can show you how you would do this on Arch, btw.
😭
No, no, no. Thank you. But now we're ready?
🧔
Well, now you'd start configuring the application security measures so it doesn't start deleting your Gmail, leak your Ethereum wallet and start joining online cults when somebody messages benevolent commands to your Telegram bot.
😕
What VPS are you running it on?

Mac Mini

From $599
Plug in. Turn on. Done.
No systemd. No fail2ban. No 26 steps.
🧔
Oh, I'm just running it on an isolated Mac Mini.
🧔
Oh, I didn't say you should follow as I do.
😭
Claude, give me a new agent! I don't like this agent! Give me a new agent!
🧔
Have you heard about Kubernetes?
😕
No.
🧔
No problem. I will teach you.
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
KERNEL PANIC — not syncing: Tutorial overflow
CPU: 0 PID: 1 Comm: systemd Tainted: G      E 6.5.0-generic
Hardware name: Generic VPS Provider KVM Virtual Machine
Call Trace:
 step_overflow+0x1a/0x26
 tutorial_spiral+0xff/0x100
 patience_exhausted+0x00/0x01
 just_buy_a_mac_mini+0x599/0x599
 kubernetes_mentioned+0xdead/0xbeef
 kai_lentit_was_right+0xffff/0x0000
 
---[ end trace 0000000000000000 ]---
Kernel Offset: 0x1e800000 from 0xffffffff81000000
---[ end Kernel panic — use a Mac Mini ]---
Step 1