Ultra-Secure OpenClaw Setup on Raspberry Pi (The Right Way)
Deploy OpenClaw on Raspberry Pi with hardened SSH, zero public ports, Tailscale-only access, isolated system user, and systemd daemon setup. A complete production-grade walkthrough.
If you're going to self-host an AI agent, do it properly.
In this guide, we deploy OpenClaw on a Raspberry Pi with:
- No password authentication
- No root login
- No public ports
- Firewall deny-all
- Tailscale-only access
- Isolated system user
- systemd daemon
- Git-enabled self-modifying agent
This is a production-grade setup. You can reproduce everything in 60-90 minutes. Although this guide is written for installing openclaw on raspberry pi, but the concepts learned in this can be used to do a similar setup on VPS, Mac or any other Linux machine. For the record, I used my old Raspberry Pi 4 (8GB) model.
Why this matters
Many openclaw guides prioritize speed and simplicity — get SSH running, expose a port, install the tool, done.
That works for experiments.
But the moment you attach API keys and an AI agent, your system becomes a remote execution system. It can read files, write code, trigger actions, and potentially spend money.
At that point, security isn’t optional. It’s part of the setup.
Architecture
Laptop
↓ (Tailscale encrypted tunnel)
Raspberry Pi
↓
OpenClaw (isolated user)
↓
Telegram + OpenAI/Codex
Public internet sees nothing.1. SSH into Raspberry Pi
Before you try to connect, your Raspberry Pi must:
- Have SSH enabled
- Be connected to your network
- Have an IP address assigned
There are two simple ways to do this.
Option 1: Using a Monitor (if you have one)
- Connect the Pi to a monitor and keyboard.
- Boot into Raspberry Pi OS.
- Enable SSH:
sudo raspi-configGo to:
Interface Options → SSH → Enable
Then run:
ifconfigNote the IP address (usually something like 192.168.x.x).
Option 2: Headless Setup (No Monitor)
If you don't have a monitor:
- Insert the SD card into your laptop.
- In the boot partition, create an empty file named:
ssh- Insert the SD card back into the Pi and power it on.
SSH will be enabled automatically.
You can then find the IP address from:
- Your router admin panel
- A network scanner app
- Your router's connected devices list
Once you have ssh enabled and the ipaddress of your device.
SSH:
ssh pi@<raspberry_ip>2. Fix SSH key mismatch
In my case I had the old ssh keys from my previous install and thus my ssh failed. Running this command will generate new keys. This might not be required in your case.
ssh-keygen -R <raspberry_ip>3. Update system
sudo apt update
sudo apt upgrade -y4. Install Node.js with NVM [https://nodejs.org/en/download]
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 24
# Verify the Node.js version:
node -v # Should print "v24.14.0".
# Verify npm version:
npm -v # Should print "11.9.0".5. Secure SSH (Key-Based Only)
We’re switching from password login to cryptographic key authentication so only someone with your private key can access the server.
ssh-keygen -t ed25519 -a 100On Raspberry Pi:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysCommand breakdown
Creates the .ssh directory if it doesn’t exist.
Sets directory permissions.
7= read, write, execute (owner)0= no access (group)0= no access (others)
Only the owner can access this directory.
Opens the file where SSH checks allowed public keys. You paste your public key here.
Sets file permissions.
6= read + write (owner)0= no access (group)0= no access (others)
SSH refuses to use this file if permissions are too open.
6. Disable Password Authentication
Edit the sshd_config file :
sudo nano /etc/ssh/sshd_configSet:
PasswordAuthentication no PermitRootLogin no ChallengeResponseAuthentication no
You might have to add ChallengeResponseAuthentication no, for the other two, just uncomment the lines and change the value to no.
Restart ssh:
sudo systemctl restart ssh7. Install Firewall
We will use UFW (Uncomplicated Firewall) to secure our Raspberry Pi server. First, install it:
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable- Deny all incoming connections to the server by default.
- Allow all outgoing connections from the server.
- Allow only SSH as the single permitted incoming connection.
- Enable the firewall — you'll see a confirmation: "Firewall is active and enabled on system startup."
At this stage, your server has:
- ❌ No password authentication
- ❌ No root login
- ✅ Only SSH exposed
- ✅ Firewall blocking everything else
Even if someone scans your public IP address, they cannot brute force your system. The only way in is possession of your private cryptographic key, securely saved on your laptop.
8. Install Tailscale
SSH is still technically exposed to the network. To remove this public exposure entirely, we use Tailscale — a free VPN service that creates a private, encrypted mesh network, making your Raspberry Pi invisible to the outside internet.
⚠️ Some tutorials suggest port forwarding on your router — avoid this, as it exposes your device to the entire internet. Tailscale uses a zero-trust encrypted tunnel instead.
Only devices on your Tailscale network can access your server. No one else can reach it.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh- You will be prompted to authenticate via your Tailscale account — log in or create a free account.
- The
--sshflag enables SSH access through the Tailscale network.
Install Tailscale on your laptop too.
Once installed on both devices, they will appear together in your Tailscale account. Copy the Tailscale IP address of your Pi and SSH into it:
ssh pi@<tailscale_ip>💡 This is not a public IP — it exists only inside an encrypted VPN tunnel, accessible solely by devices on your Tailnet. Nobody else can see it or find it.
Step 9: Close Public SSH
Once you have confirmed that you can successfully log in to your Raspberry Pi via the Tailscale IP address, you can now close the TCP SSH port through the firewall:
sudo ufw deny ssh- This closes all incoming ports to your Raspberry Pi server.
- Attempting to SSH via the original (public) IP address of the Pi will now fail — it is no longer accessible.
- The only way to log in is through the Tailscale IP address, inside the encrypted private tunnel.
- Your device becomes completely invisible to port scanners on the public internet.
Step 10: Create Isolated OpenClaw User
Running OpenClaw under the root account is risky — it would have access to all system files and could modify or delete them. Instead, we create a dedicated system user named openclaw with its own working directory and strictly limited permissions.
sudo adduser --system --home /opt/openclaw openclawOnce the user is created, verify it does not have sudo access:
id openclaw✅ A user ID below 1000 confirms this is a system account with no sudo privileges.
Now assign ownership of the OpenClaw directory to the openclaw user, recursively for all files inside it:
sudo chown -R openclaw:openclaw /opt/openclawGive the openclaw user read, write, and execute access to its own directory:
sudo chmod 750 /opt/openclawRestrict access to the main home directory so openclaw cannot reach other users' files:
sudo chmod 700 /home/piFinally, switch into the openclaw user session:
sudo -u openclaw -h bashVerify you are now operating as the correct user:
whoami # should print: openclaw
pwd # should print: /home/openclaw or similarChange your working directory to the OpenClaw directory:
cd /opt/openclawWhy Isolation Matters
This approach is called Least Privilege Architecture — OpenClaw:
- ❌ Does not run as root
- ❌ Does not have sudo access
- ❌ Cannot modify system files
- ❌ Cannot access other users' home directories
- ✅ Can only operate inside
/opt/openclaw
So even if something goes wrong or OpenClaw is compromised, the damage is fully contained to its own directory. Your system files, configs, and other users remain completely safe.
💡 Security is inversely proportional to convenience — this setup requires manual configuration, but that is intentional. You do not want OpenClaw accidentally deleting important files, modifying system configs, or exposing anything to the internet.
Step 11: Install Node Inside OpenClaw User
Even though Node.js was installed earlier system-wide, that was under a different user. Because openclaw is a fully isolated system user, it cannot access Node installed elsewhere. So we install it again — this time locally under the openclaw user using NVM (Node Version Manager). This ensures Node lives at /opt/openclaw/.nvm and is fully self-contained.
Make sure you are switched to the openclaw user and inside the /opt/openclaw directory before running these commands:
I later realised that it is important to install Node version 22 inside the openclaw user, otherwise it will not be possible to update openclaw (if installed on nodejs 24), as discordjs toolchain is not available for nodejs 24 for arm64 processor (which powers raspberry pi).
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 22
# Verify the Node.js version:
node -v # Should print "v22.22.0".
# Verify npm version:
npm -v # Should print "10.9.4".💡 Isolation means full separation — every dependency must be reinstalled within the user's own environment. This is by design.
Step 12: Install OpenClaw
Now install OpenClaw from inside the /opt/openclaw directory. Head to the OpenClaw website, select Linux, copy the install command, and paste it in the terminal.
Make sure you are in the right place before running the installer:
cd /opt/openclawThen run the OpenClaw install command from their website.
curl -fsSL https://openclaw.ai/install.sh | bash⚠️ If you see a Node error during installation, NVM may not be loading correctly in the current shell. Proceed to Step 13 to fix this before retrying.
Step 13: Ensure NVM Loads Correctly
Because we installed Node via NVM, we must make sure it loads automatically for the openclaw user in every shell session. Without this, Node won't be found and OpenClaw won't run.
Edit both shell config files using nano:
nano ~/.bashrc
nano ~/.profileAdd the following lines to both files:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"Now switch into the openclaw user using a login shell to ensure these files are properly executed:
sudo -u openclaw -h bash -l💡 The
-lflag is critical — it loads a login shell, which ensures.profileand.bashrcare both executed. Without it, NVM and Node will not be available.
Verify the environment is correct:
node -v # should print a Node version
openclaw -v # should print the OpenClaw versionIf both return version numbers, your environment is set up correctly.
Step 14: Onboard OpenClaw
With Node working, run the OpenClaw onboarding wizard with the daemon installer:
openclaw onboard --install-daemonFollow these choices during the interactive setup:
- Onboarding mode → Manual
- Config handling → Full reset
- Workspace directory → Keep default
- Model provider → OpenAI Codex (or your preferred LLM provider)
- For Codex: You'll receive an OAuth URL — open it in a browser, log in, and copy the code from the redirect URL (the part after
code=and before&), then paste it back in the terminal. - Gateway port → Keep default
- Gateway bind →
127.0.0.1(loopback only) - Gateway auth → Token
- Tailscale exposure → No
🔒 Binding the gateway to loopback (
127.0.0.1) ensures the dashboard is only accessible from inside the server — it is never exposed to the network directly. We'll access it securely via an SSH tunnel in Step 18.
You will need either:
- A paid ChatGPT plan with Codex access, or
- An API key from OpenAI, Anthropic, or another supported LLM provider.
Step 15: Setup Telegram Bot
Telegram is the easiest and most recommended way to interact with your OpenClaw agent remotely. Let's set it up.
- Open Telegram and search for BotFather.
- Start a new chat and run:
/newbot- Give your bot a name and a unique username.
- BotFather will give you a token — paste it into OpenClaw when prompted.
- Configure DM access policies when asked (skip skills and hooks for now).
Once the bot is configured, start the gateway:
openclaw gatewaySend a message to your bot on Telegram. You'll receive an access not configured message — this is expected. Copy the pairing code and approve it:
openclaw pairing approve telegram <pairing_code>Your Telegram bot is now live and connected to your OpenClaw instance.
💬 Telegram acts as your secure remote interface — you can interact with your agent from anywhere, without ever exposing your server to the internet.
Step 16: Enable Bash Shell and Git Identity
Because we created openclaw as a Linux system user, it was set up with a no-login shell by default — this prevents shell execution. However, since OpenClaw can self-modify its own code (one of its core features), we need Git to work. We can enable this without granting any sudo privileges by simply changing the shell to /bin/bash:
sudo chsh -s /bin/bash openclawNow configure Git identity for the openclaw user so it can commit changes:
git config --global user.name "OpenClaw"
git config --global user.email "bot@example.com"💡 You can use any name and email here — this is just the identity Git uses when tracking code changes made by your agent.
OpenClaw can now safely modify and commit its own code, which is the foundation of its self-improvement capability.
Step 17: Create a systemd Service
Right now, the gateway and TUI have to be run manually in separate terminals — that is not ideal. We want OpenClaw to start automatically on boot, restart if it crashes, and keep running even when our SSH session disconnects.
To achieve this, we create a systemd service file:
sudo nano /etc/systemd/system/openclaw.serviceAdd the following contents:
[Unit]
Description=OpenClaw Service
After=network.target
[Service]
User=openclaw
WorkingDirectory=/opt/openclaw
ExecStart=/bin/bash -lc 'openclaw tui'
Restart=always
[Install]
WantedBy=multi-user.target💡 This file tells Linux: which user to run as, where to run from, how to load NVM (via the login shell
-lflag), and how to restart automatically.
Now enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable openclaw
sudo systemctl start openclawVerify it is running:
sudo systemctl status openclaw- ✅ Auto-start on every boot
- ✅ Automatic restart on crash
- ✅ Full independence from any SSH session
Step 18: Access the Gateway Dashboard via SSH Tunnel
The OpenClaw gateway binds to 127.0.0.1 — meaning it is only accessible from inside the server. To access the dashboard from your laptop, we create a secure SSH tunnel that forwards the internal port to your local machine:
ssh -N -L 18789:127.0.0.1:<gateway_port> pi@<tailscale_ip>Now open this in your browser:
http://localhost:18789If prompted for a gateway token, ask your Telegram bot, it will give you a command, paste is inside the openclaw directory.
Copy the returned token, paste it into the dashboard login screen, and click Connect.
🔒 The SSH tunnel securely forwards the internal dashboard to your laptop without ever exposing it to the public internet. Only you — through your Tailscale network — can access it.
Security Summary
Here is a complete picture of what we have built:
- ❌ No password login
- ❌ No root login
- ❌ No public ports open
- ❌ Firewall denies all inbound connections
- ✅ Tailscale-only remote access via encrypted tunnel
- ✅ Dedicated
openclawsystem user - ❌ No sudo privileges for OpenClaw
- ✅ Restricted directory permissions
- ✅ Loopback-only gateway (never network-exposed)
- ✅ Git-controlled self-modifications
Final Thought
Security is always inversely proportional to convenience —
but convenience without security becomes regret.
Your Raspberry Pi is now:
- 🔒 Invisible to the public internet
- 🤖 Running OpenClaw safely in an isolated environment
- 🔄 Automatically restarting if anything goes wrong
- 🛡️ Fully contained — if something fails, the damage stays inside its own directory
In the next part, you can explore skills to give your agent real-world abilities — and turn this hardened Raspberry Pi into a true autonomous system.