What is OpenClaw – and what will you have at the end?
OpenClaw is an AI agent you run locally on your Synology DiskStation. Instead of running in the cloud, it runs at your home – you keep control of your data, pay only for the API requests you actually use, and access your personal assistant via Telegram or browser.
What OpenClaw actually is, and how gateway, runtime and skills work together, is explained in OpenClaw (ex Moltbot): How a WhatsApp Message Becomes an Acting AI Agent — this guide takes that as read.
At the end of this guide, you will have:
- A running OpenClaw container on your DiskStation
- A Telegram bot you can simply write to on your smartphone
- An optional web interface accessible via SSH tunnel in your browser
- Optional: Network isolation that denies the container access to your home network
- Optional: An embedded browser with which OpenClaw can also operate JavaScript-heavy websites
The basic installation – container running, Telegram responding – takes about 30 minutes. The optional steps come after, once the foundation is in place.
Prerequisites
Before you start – make sure you have the following on hand:
- Synology DS1621+ with current DSM 7.2 or newer
- Container Manager installed (from the Package Center)
- SSH access to the DiskStation (will be explained in this guide)
- An API key from Anthropic (Claude) or OpenAI
- Telegram on your smartphone
No API key yet? For Claude, go to console.anthropic.com, sign in, add a payment method, and create a key. It begins with sk-ant-...
Architecture at a glance
This is what the finished folder structure on your DiskStation will look like. It is created step by step – you don’t need to prepare anything manually.
/volume1/docker/openclaw/
├── compose.yaml ← Container configuration
├── openclaw-firewall.sh ← Network isolation (optional)
├── config/ ← API keys, settings
└── workspace/ ← Agent work files
OpenClaw consists of two services:
- openclaw-gateway – the permanently running service. It maintains the connection to Telegram, provides the web UI, and communicates with the AI API.
- openclaw-cli – a one-time container for administrative tasks (onboarding, configuration, pairing).
Container or VM? The first big decision
Monday morning scene with Bernd, Ulf, and Tanja debating Container vs VM.
Tanja is the IT expert. She has been managing Docker containers in production for years. She values reliability and understands the trade-offs.
Bernd is the self-proclaimed “expert” who always has an opinion but sometimes confuses enthusiasm with expertise.
Ulf is learning and asks the pragmatic questions.
Ulf: “Container or VM – what’s the difference anyway?”
Bernd: “VM, obviously! Total isolation – iron-clad security!”
Tanja: “For a home setup, containers are more practical. Faster to set up, less resource-hungry. Security depends on how you configure it.”
Ulf: “But is a container safe enough for an AI agent?”
Tanja: “Yes, if you’re careful. We’ll use network isolation – iptables rules that restrict what the container can reach. Combined with regular updates and careful image selection, that’s a solid foundation.”
Bernd: “But a VM is safer!”
Tanja: “True. But it also uses more memory and disk space, and it’s slower to manage. For a home setup running Claude – a trustworthy model – containers strike the right balance.”
Ulf: “Got it. So containers it is.”
| Criterion | Container (Docker) | VM (Synology VMM) |
|---|---|---|
| Performance | Better – no separate OS kernel needed | Worse – needs around 2 GB RAM minimum |
| Installation | Simple – the docker-compose.yml is ready to use | Laborious – install an OS, set up Node ≥22, configure autostart |
| Isolation | Process isolation at kernel level | Full kernel isolation, no direct host access |
| In short | Faster, lighter, closer to the official OpenClaw installation | Stronger isolation, but heavier and more resource-hungry |
This guide takes the container route. The iptables rules in the optional security chapter reduce risk. They do not replace VM isolation, patch management, or careful review of container images.
Part 1: Preparation on the DiskStation
Step 1.1: Install Container Manager
Tanja: “First things first – we need Container Manager. It’s in the Package Center.”
Ulf: “Is that the new Docker replacement?”
Tanja: “Exactly. Synology’s official container management tool. It handles Docker Compose, images, and networks.”
- Open the Package Center on your DiskStation
- Search for Container Manager
- Click Install
- Wait for the installation to complete (usually 1–2 minutes)
- Open Container Manager from your main menu
Step 1.2: Enable SSH
Ulf: “SSH is command-line access to the station?”
Tanja: “Right. We need it to create folders, upload files, and manage the container from the terminal.”
- Go to Control Panel → Terminal & SNMP
- Check the box Enable SSH service
- Note the port (usually 22, but can be different)
- Click Apply
Step 1.3: Connect via SSH
Open a terminal on your PC or Mac and connect to your DiskStation.
For Mac / Linux:
ssh your-username@DISKSTATION_IP
For Windows (PowerShell):
ssh your-username@DISKSTATION_IP
(Replace DISKSTATION_IP with your DiskStation’s IP address and 22 with the SSH port if different.)
Enter your root password when prompted.

Once you’re logged in, you’re ready to create the folder structure and configuration files. All subsequent commands are typed into this terminal window.
Step 1.4: Create folders
Ulf: “Now I create the folder where OpenClaw will live?”
Tanja: “Yes. We’ll put everything in /volume1/docker/openclaw. This keeps it organized and makes backups easy.”
mkdir -p /volume1/docker/openclaw/config
mkdir -p /volume1/docker/openclaw/workspace
chown -R root:root /volume1/docker/openclaw
chmod -R 755 /volume1/docker/openclaw
Expected result
ls -la /volume1/docker/openclaw/
total 8
drwxr-xr-x 4 root root 4096 Mar 29 12:00 .
drwxr-xr-x 3 root root 4096 Mar 29 12:00 ..
drwxr-xr-x 2 root root 4096 Mar 29 12:00 config
drwxr-xr-x 2 root root 4096 Mar 29 12:00 workspace
Step 1.5: Create compose.yaml
Bernd: “YAML – yet another markup language?”
Tanja: “Close – but it’s a configuration format. Docker uses it to describe services, volumes, networks. Think of it as a blueprint for your container.”
Create a file named compose.yaml in /volume1/docker/openclaw/ with the following content:
cat > /volume1/docker/openclaw/compose.yaml << 'DATEIENDE'
services:
openclaw-gateway:
image: ghcr.io/openclaw/openclaw:latest
container_name: openclaw-gateway
restart: unless-stopped
user: "1000:1000"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp
- /run
pids_limit: 256
dns:
- 1.1.1.1
- 8.8.8.8
networks:
- openclaw-isolated
ports:
- "18789:18789"
volumes:
- /volume1/docker/openclaw/config:/home/node/.openclaw
- /volume1/docker/openclaw/workspace:/home/node/.openclaw/workspace
environment:
- HOME=/home/node
- TERM=xterm-256color
- NODE_ENV=production
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:18789/ >/dev/null 2>&1 || exit 1"]
interval: 60s
timeout: 10s
retries: 3
start_period: 30s
init: true
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"lan",
"--port",
"18789",
]
openclaw-cli:
image: ghcr.io/openclaw/openclaw:latest
container_name: openclaw-cli
user: "1000:1000"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
network_mode: "service:openclaw-gateway"
volumes:
- /volume1/docker/openclaw/config:/home/node/.openclaw
- /volume1/docker/openclaw/workspace:/home/node/.openclaw/workspace
environment:
- HOME=/home/node
- TERM=xterm-256color
- NODE_ENV=production
stdin_open: true
tty: true
init: true
entrypoint: ["node", "dist/index.js"]
profiles:
- cli
networks:
openclaw-isolated:
driver: bridge
ipam:
config:
- subnet: 172.30.0.0/24
gateway: 172.30.0.1
DATEIENDE
Configuration explained
| Setting | What it means |
|---|---|
user: "1000:1000" | The container does not run as root – no administrator access. |
cap_drop: ALL | All Linux special privileges (capabilities) are removed. |
read_only: true | The root filesystem is write-protected – malware cannot establish itself permanently. |
tmpfs: /tmp, /run | Temporary storage in RAM for programs that need to write somewhere. |
pids_limit: 256 | A maximum of 256 processes – protection against fork bombs. |
dns: 1.1.1.1 / 8.8.8.8 | DNS queries go straight out to the internet. Without this setting they would go to the router – which the optional firewall blocks, leaving the container with no internet. |
"18789:18789" | Web UI reachable on port 18789. |
No docker.sock volume | The container cannot control Docker or the host. |
subnet: 172.30.0.0/24 | A fixed subnet that the optional firewall chapter can block specifically. |
Verify the YAML syntax before starting the container:
cd /volume1/docker/openclaw
docker compose config
If there are no errors, you’ll see the validated configuration printed to the terminal.
Step 1.6: Run the OpenClaw Onboarding
Before you start the gateway service, you must complete the onboarding. This configures your API key, Telegram bot, and basic settings.
cd /volume1/docker/openclaw
docker compose run --rm openclaw-cli onboard
This launches an interactive setup wizard. Follow along:
Step 1 – Confirm security notice
The onboarding shows a disclaimer about running AI agents locally. Read it and type Yes to proceed.

Step 2 – Choose onboarding mode
Select QuickStart (the default option). This sets up essentials without extra configuration.
Step 3 – Choose AI provider and model
Ulf: “Which provider – Claude, OpenAI, or something else?”
Tanja: “It depends on cost and capability. Claude’s Haiku is very fast and cheap. Sonnet is more capable. OpenAI’s models work too, but Claude is generally more reliable for this use case.”

Select Anthropic (Claude).
Recommendation: take Anthropic, because Claude is often qualitatively stronger in longer conversations and with complex instructions. Choose Haiku if you want to save money, Sonnet if you want quality. You can switch at any time. If the lowest price matters most to you: OpenAI with GPT-4.1 mini or nano.
If you do not have an API key yet: for Claude, go to console.anthropic.com. If you do not want to set that up right now, choose Back, then Skip for now. You can add the provider later:
cd /volume1/docker/openclaw
docker compose run --rm openclaw-cli configure
Step 4 – Authentication method
Choose Anthropic API key.
Step 5 – Enter your API key
Paste your API key (starts with sk-ant-). Keep it secret – never share it or commit it to version control.

Step 6 – Confirm default model
| Model | Input (per million tokens) | Output (per million tokens) |
|---|---|---|
| OpenAI GPT-4.1 nano | ~$0.10 | ~$0.40 |
| OpenAI GPT-4.1 mini | ~$0.40 | ~$1.60 |
| Anthropic Haiku 3.5 | ~$0.80 | ~$4.00 |
| OpenAI GPT-4o | ~$2.50 | ~$10 |
| Anthropic Sonnet 4 | ~$3.00 | ~$15 |
Select Sonnet as your default (good balance of cost and capability).
Step 7 – Choose communication channel
Select Telegram. This lets you chat with OpenClaw from your phone.
Step 8 – Set up Telegram Bot
OpenClaw will guide you through creating a Telegram bot. You’ll need the BotFather app in Telegram:
- Open Telegram and search for @BotFather
- Start a chat and send
/newbot - Give your bot a name (e.g., “MyOpenClaw”)
- Give it a username (e.g., “my_openclaw_bot”)
- BotFather will give you a token – copy it
- Paste the token into the OpenClaw onboarding
Step 9 – Configure skills
Bernd: “What are skills?”
Tanja: “Extensions that give OpenClaw special abilities – web search, file access, etc. For now, skip them. We’ll add what we need later.”
Select No when asked about installing skills.

Steps 10–15
You’ll be asked about additional features (webhooks, integrations, etc.). For a first setup, answer No to all of these. You can add them later.
Step 16 – Hooks
Select Skip for now.
Onboarding complete!
The onboarding finishes and shows a Gateway Token. Save this token – you’ll need it if you add browser-based access.

If you plan to use the web UI, configure allowed origins:
cd /volume1/docker/openclaw
docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://localhost:18789"]'
Step 1.7: Start the container
Option A: Via Container Manager (GUI)
- Open Container Manager on your DiskStation
- Go to Projects
- Click Create
- Choose Create from compose file
- Navigate to
/volume1/docker/openclaw/compose.yamland upload it - Name the project
openclaw - Click Next, then Create
- Wait for the project to start

Important: Do not start the container before completing the onboarding. The gateway needs the config files from onboarding to run.

Option B: Via SSH
cd /volume1/docker/openclaw
docker compose up -d
Expected result
[+] Running 2/2
⠿ Network openclaw_openclaw-net Created
⠿ Container openclaw-gateway Started
Check the logs to see if the container is running:
docker compose logs -f
You should see output like:
openclaw-gateway | [INFO] Gateway started on http://0.0.0.0:8080
openclaw-gateway | [INFO] Connected to Telegram bot
openclaw-gateway | [INFO] Ready for requests
If you see errors, check the troubleshooting section.
| Model | Strength | Relative cost |
|---|---|---|
| Haiku | Fast, cheap – for simple tasks | ~1/4 of Sonnet |
| Sonnet | Best price-performance ratio | Medium |
| Opus | Most capable – for complex tasks | ~5× Sonnet |
Step 1.8: Test with Telegram
Once the gateway is running, you can test it via Telegram.
Tanja: “Your bot won’t respond until you pair your Telegram account with it. That happens with a special command.”
- In Telegram, search for your bot (the one you created with BotFather, e.g.,
@my_openclaw_bot) - Send the command
/pair - The bot will respond with a pairing request. Get the pairing code from the OpenClaw logs:
You’ll see something like:
Send this code back to the bot in Telegram. Once accepted, you can start chatting:
@my_openclaw_bot: "What is 2+2?"
The bot should respond with an answer. Congratulations – OpenClaw is alive!
The very first time, your bot answers with a pairing code. Pairing means you confirm once that this device – your smartphone – is allowed to chat with the bot. Without that confirmation the bot does not answer. Write anything to the bot in Telegram. It replies with a code. Then, in the SSH session:
cd /volume1/docker/openclaw
docker compose run --rm openclaw-cli pairing approve telegram <CODE>
Insert the code from the Telegram message. After that the chat works normally. Expected result: the bot answers your next message.
Part 2: Optional Enhancements
Optional A: Web interface via SSH tunnel
Alongside Telegram there is a browser-based interface. It is deliberately not reachable directly on the network – access runs through an SSH tunnel. That is not a detour but the point: the web UI should not sit open on your home network.
Open the SSH tunnel (on the Mac, in a new terminal window):
ssh -L 18789:127.0.0.1:18789 your-username@DISKSTATION_IP
The command forwards your local port 18789 encrypted through SSH to port 18789 on the DiskStation. The tunnel works for as long as this terminal window stays open.
Then open this in the browser (inserting your own token from step 1.6):
http://localhost:18789#token=2bbea678f.........................67003d38
Use localhost, not 127.0.0.1. That is not a typo – it makes a technical difference to how the token is recognised. The token has to come directly after the #, with no space.
If you get “channel: open failed: administratively prohibited”:
SSH port forwarding is disabled on the DiskStation. Enable it once (in another terminal session, as root):
sudo -i
echo "AllowTcpForwarding yes" >> /etc/ssh/sshd_config
sed -i '85s/AllowTcpForwarding no/AllowTcpForwarding yes/' /etc/ssh/sshd_config
systemctl restart sshd
If systemctl is not available:
synosystemctl restart sshd
Then restart the SSH tunnel and open the browser again. If it shows “pairing required”, the browser has to be paired once – exactly like Telegram in step 1.8. Show open pairing codes:
sudo docker exec -it openclaw-gateway node /app/openclaw.mjs devices list
Note the code from the “Pending → Request → Code” column and confirm it:
sudo docker exec -it openclaw-gateway node /app/openclaw.mjs devices approve YOUR_CODE

Optional B: Harden network isolation
Bernd: “The container is running – isn’t that secure enough?”
Tanja: “Not quite. By default, a container can access your home network. An iptables firewall blocks that. It’s like adding a second lock on the door.”
Ulf: “How does that work?”
Tanja: “We write a shell script that sets firewall rules. It runs at boot and again whenever we need it. The rules say: ‘This container can only reach the outside world – not your home network, not your other devices.'”
Step B.1: Create the firewall script
The script works in three phases:
- Phase 1: deletes its own rules, in case the script has run before.
- Phase 2: rebuilds the IPv4 rules.
- Phase 3: adds the IPv6 rules. The script is idempotent – you can run it as often as you like, it always rebuilds cleanly.
cat > /volume1/docker/openclaw/openclaw-firewall.sh << 'DATEIENDE'
#!/bin/bash
# =============================================================================
# openclaw-firewall.sh
# Network isolation script for OpenClaw on a Synology DS1621+
# =============================================================================
# Compatible with Synology DSM iptables 1.8.x (no comment module available).
#
# Blocks outbound traffic from the OpenClaw container to all private
# and reserved IPv4 networks. Internet access stays allowed.
# DNS goes through public servers (1.1.1.1 / 8.8.8.8, set in
# docker-compose.yml), because the router DNS is blocked by these rules.
#
# Idempotent: first deletes all of its own rules (by exact specification),
# then rebuilds the rules in a defined order.
# Can be run as often as you like.
#
# IPv6: blocks ULA (fc00::/7) and link-local (fe80::/10) globally for all
# Docker forward traffic, because the container has no fixed IPv6 prefix
# assigned. If you later want to run other containers with IPv6,
# adjust these rules.
#
# Usage:
# Set it up as a boot task in the Synology Task Scheduler:
# bash /volume1/docker/openclaw/openclaw-firewall.sh
# =============================================================================
sleep 30
DOCKER_SUBNET="172.30.0.0/24" # Must match compose.yaml
# ─────────────────────────────────────────────────────────────────────────────
# Phase 1: remove all of our own rules (exact specification)
# ─────────────────────────────────────────────────────────────────────────────
# IPv4
iptables -D DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null
iptables -D DOCKER-USER -s "$DOCKER_SUBNET" -d 192.168.0.0/16 -j DROP 2>/dev/null
iptables -D DOCKER-USER -s "$DOCKER_SUBNET" -d 10.0.0.0/8 -j DROP 2>/dev/null
iptables -D DOCKER-USER -s "$DOCKER_SUBNET" -d 172.16.0.0/12 -j DROP 2>/dev/null
iptables -D DOCKER-USER -s "$DOCKER_SUBNET" -d 169.254.0.0/16 -j DROP 2>/dev/null
iptables -D DOCKER-USER -s "$DOCKER_SUBNET" -d 100.64.0.0/10 -j DROP 2>/dev/null
# IPv6
ip6tables -D DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null
ip6tables -D DOCKER-USER -d fc00::/7 -j DROP 2>/dev/null
ip6tables -D DOCKER-USER -d fe80::/10 -j DROP 2>/dev/null
# ─────────────────────────────────────────────────────────────────────────────
# Phase 2: build the IPv4 rules in DOCKER-USER
# ─────────────────────────────────────────────────────────────────────────────
# Position 1: let reply packets of allowed connections through
iptables -I DOCKER-USER 1 \
-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Positions 2-6: block private and reserved networks
iptables -I DOCKER-USER 2 \
-s "$DOCKER_SUBNET" -d 192.168.0.0/16 -j DROP
iptables -I DOCKER-USER 3 \
-s "$DOCKER_SUBNET" -d 10.0.0.0/8 -j DROP
iptables -I DOCKER-USER 4 \
-s "$DOCKER_SUBNET" -d 172.16.0.0/12 -j DROP
iptables -I DOCKER-USER 5 \
-s "$DOCKER_SUBNET" -d 169.254.0.0/16 -j DROP
iptables -I DOCKER-USER 6 \
-s "$DOCKER_SUBNET" -d 100.64.0.0/10 -j DROP
# RETURN: only add it if none exists
if ! iptables -L DOCKER-USER -n 2>/dev/null | grep -q "RETURN"; then
iptables -A DOCKER-USER -j RETURN
fi
# ─────────────────────────────────────────────────────────────────────────────
# Phase 3: IPv6 rules (if DOCKER-USER exists in ip6tables)
# ─────────────────────────────────────────────────────────────────────────────
if ip6tables -L DOCKER-USER -n >/dev/null 2>&1; then
ip6tables -I DOCKER-USER 1 \
-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ip6tables -I DOCKER-USER 2 \
-d fc00::/7 -j DROP
ip6tables -I DOCKER-USER 3 \
-d fe80::/10 -j DROP
if ! ip6tables -L DOCKER-USER -n 2>/dev/null | grep -q "RETURN"; then
ip6tables -A DOCKER-USER -j RETURN
fi
fi
# ─────────────────────────────────────────────────────────────────────────────
# Ausgabe
# ─────────────────────────────────────────────────────────────────────────────
logger "openclaw-firewall: DOCKER-USER Regeln aktiv fuer $DOCKER_SUBNET"
echo ""
echo "========================================"
echo " OpenClaw Netzwerk-Isolation aktiviert"
echo "========================================"
echo ""
echo "IPv4 DOCKER-USER:"
iptables -L DOCKER-USER -n -v --line-numbers
echo ""
if ip6tables -L DOCKER-USER -n >/dev/null 2>&1; then
echo "IPv6 DOCKER-USER:"
ip6tables -L DOCKER-USER -n -v --line-numbers
echo ""
fi
echo "Erwartete Reihenfolge:"
echo " 1 ACCEPT ctstate RELATED,ESTABLISHED"
echo " 2 DROP 172.30.0.0/24 -> 192.168.0.0/16"
echo " 3 DROP 172.30.0.0/24 -> 10.0.0.0/8"
echo " 4 DROP 172.30.0.0/24 -> 172.16.0.0/12"
echo " 5 DROP 172.30.0.0/24 -> 169.254.0.0/16"
echo " 6 DROP 172.30.0.0/24 -> 100.64.0.0/10"
echo " 7 RETURN"
DATEIENDE
Then make the script executable:
# Switch to root
sudo -i
chmod +x /volume1/docker/openclaw/openclaw-firewall.sh
What these rules do
| Range | Protocol | What is it? |
|---|---|---|
192.168.0.0/16 | IPv4 | Home networks (routers such as the Fritzbox, etc.) |
10.0.0.0/8 | IPv4 | Corporate networks, VPNs |
172.16.0.0/12 | IPv4 | Further private networks |
169.254.0.0/16 | IPv4 | Link-local (mDNS devices, APIPA) |
100.64.0.0/10 | IPv4 | CGNAT (some providers/VPNs) |
fc00::/7 | IPv6 (global) | ULA (the IPv6 equivalent of private networks) |
fe80::/10 | IPv6 (global) | IPv6 link-local |
A note on IPv6: the IPv6 rules apply to all Docker forward traffic on the DiskStation, not only to OpenClaw. If you later want to run other containers with IPv6, these rules have to be adjusted.
Step B.2: Set up firewall as a boot task
The script must run every time the DiskStation boots (to restore rules after reboot) and whenever the container restarts. Set it up as a scheduled task:
- Open the DiskStation control panel
- Go to System → Task Scheduler
- Click Create → Triggered Task → User-defined script
- Configure:

- Task name:
OpenClaw Firewall Init - Event: Boot-up
- User:
root - Enabled: Check the box
- Go to the Task Settings tab
Image 11 – DiskStation – Task Scheduler – Task Settings Tab- In the Run command field, paste:
/bin/bash /volume1/docker/openclaw/openclaw-firewall.sh
- Add a small delay (wait for Docker to be fully ready):
sleep 30 && /bin/bash /volume1/docker/openclaw/openclaw-firewall.sh
- Click OK to save
Step B.3: Activate firewall immediately
Expected result – check the rules:
iptables -L DOCKER-USER -n -v --line-numbers
Image 12 – Terminal – OpenClaw network isolation activatedExpected output:
num target prot source destination
1 ACCEPT all 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 DROP all 172.30.0.0/24 192.168.0.0/16
3 DROP all 172.30.0.0/24 10.0.0.0/8
4 DROP all 172.30.0.0/24 172.16.0.0/12
5 DROP all 172.30.0.0/24 169.254.0.0/16
6 DROP all 172.30.0.0/24 100.64.0.0/10
7 RETURN all 0.0.0.0/0 0.0.0.0/0
If the order is not right, run the script again – it cleans up first and then rebuilds.
Step B.4: Test isolation
Verify that the container can’t reach your home network but can reach the outside:
docker exec openclaw-gateway ping -c 1 192.168.1.1
# Expected: UNREACHABLE (blocked by firewall)
docker exec openclaw-gateway ping -c 1 8.8.8.8
# Expected: REACHABLE (Google DNS – public internet)


What you’ll see:
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
--- 192.168.1.1 statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=119 time=15.3 ms
--- 8.8.8.8 statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
Perfect – your home network is blocked, but the internet is accessible. OpenClaw can call the Claude API but can’t snoop on your local devices.
Optional C: Retrofit a Playwright browser
Up to now OpenClaw communicates over APIs and text. With an embedded Playwright browser it can also load real web pages, scroll, fill in forms and make use of JavaScript rendering.
Ulf: “OpenClaw should be able to browse by itself? Like a sweeper who suddenly goes on the attack?”
Tanja: “Exactly! The LLM plans, Playwright executes. That lets OpenClaw read content from dynamic pages that plain HTTP requests cannot reach.”
Bernd: “I just used the system Chromium. It didn’t run. Tried three times. Never worked.”
Tanja: “That is exactly why you ship the browser binaries with the container. Then it works reproducibly – every time.”
A Playwright browser inside the Docker container brings its own browser binaries and dependencies with it. That avoids conflicts with system libraries and version incompatibilities.
Step C.1: Create a Dockerfile
Create /volume1/docker/openclaw/Dockerfile:
FROM ghcr.io/openclaw/openclaw:latest
USER root
# System libraries for Chromium / Playwright
RUN apt-get update && apt-get install -y \
libnspr4 \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2 \
ca-certificates \
wget \
&& rm -rf /var/lib/apt/lists/*
USER node
Then, in compose.yaml, replace the image line for both services (openclaw-gateway and openclaw-cli):
# Before:
image: ghcr.io/openclaw/openclaw:latest
# After:
build:
context: /volume1/docker/openclaw
dockerfile: Dockerfile
Step C.2: Install Chromium
cd /volume1/docker/openclaw
sudo docker compose -p openclaw run --rm --entrypoint sh \
-e PLAYWRIGHT_BROWSERS_PATH=/home/node/.openclaw/workspace/.browser \
openclaw-cli -c 'mkdir -p /home/node/.openclaw/workspace/.browser && \
node /app/node_modules/playwright-core/cli.js install chromium'
Expected result – check the installation:
sudo docker exec -it openclaw-gateway sh -c 'ls -la /home/node/.openclaw/workspace/.browser'
You should see a folder such as chromium-1208. Then test the browser itself:
sudo docker exec -it openclaw-gateway sh -c '/home/node/.openclaw/workspace/.browser/chromium-1208/chrome-linux64/chrome --version'
If a Chrome version number is printed, Chromium is installed and runnable.
Step C.3: Set the browser path in openclaw.json
Open /volume1/docker/openclaw/config/openclaw.json and add the browser block:
"browser": {
"enabled": true,
"defaultProfile": "openclaw",
"headless": true,
"noSandbox": true,
"executablePath": "/home/node/.openclaw/workspace/.browser/chromium-1208/chrome-linux64/chrome",
"profiles": {
"openclaw": {
"cdpPort": 18800,
"color": "#FF4500"
}
}
}
Step C.4: Test it
sudo docker exec -it openclaw-gateway sh -c '/home/node/.openclaw/workspace/.browser/chromium-1208/chrome-linux64/chrome --version'
Then, in OpenClaw (via Telegram or the web UI):
Use the browser profile "openclaw" and open https://example.com.
If OpenClaw answers and describes the page content, everything is set up correctly.
Useful commands – the cheat sheet
| What | Command |
|---|---|
| Stop | Container Manager → Project → openclaw → Stop |
| Start | Container Manager → Project → openclaw → Start |
| Logs | Container Manager → Project → openclaw → Logs |
| Stop (SSH) | cd /volume1/docker/openclaw && docker compose down |
| Start (SSH) | cd /volume1/docker/openclaw && docker compose up -d openclaw-gateway |
| Logs (SSH) | docker logs openclaw-gateway --tail 20 |
| Update | cd /volume1/docker/openclaw && docker compose pull && docker compose down && docker compose up -d openclaw-gateway |
| SSH tunnel (from the Mac) | ssh -L 18789:127.0.0.1:18789 Teddy@192.168.2.10 |
| Check the firewall | sudo iptables -L DOCKER-USER -n -v --line-numbers |
| Reload the firewall | sudo bash /volume1/docker/openclaw/openclaw-firewall.sh |
Troubleshooting
Container won’t start
| Error message | Cause | Fix |
|---|---|---|
Missing config | Onboarding not completed | Work through step 1.6 |
non-loopback Control UI requires allowedOrigins | The config set command is missing | Run the command at the end of step 1.6 |
EACCES: permission denied | Folder permissions are wrong | sudo chown -R 1000:1000 /volume1/docker/openclaw |
pids_limit discarded | The Synology kernel does not support it | Harmless, ignore it |
Web interface not reachable
| Possible cause | Check command / fix |
|---|---|
| The container is not running | docker compose up -d openclaw-gateway |
| The SSH tunnel is not active | Open ssh -L 18789:127.0.0.1:18789 user@NAS_IP in a terminal |
| Port forwarding is disabled | Error “administratively prohibited” → enable SSH forwarding (see Optional A) |
allowedOrigins is not set | docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://localhost:18789"]' |
| The browser is not paired yet | devices list and devices approve (see Optional A) |
| Wrong URL | http://localhost:18789 – not 127.0.0.1, and not the NAS IP |
Telegram bot doesn’t respond
| Possible cause | Fix |
|---|---|
| Pairing not completed | Work through step 1.8 |
| No internet | Run the test below |
| Wrong bot token | Enter the token again in the onboarding (configure) |
To test internet connectivity from the container:
docker exec openclaw-gateway curl -I https://api.anthropic.com
# Should return HTTP 200 or similar (not connection refused)
Firewall rules missing after DSM update
Synology sometimes resets iptables during system updates. Reapply the rules:
/volume1/docker/openclaw/openclaw-firewall.sh
# Verify:
iptables -L FORWARD -n | grep DROP
If the scheduled task stopped working, check:
grep openclaw /var/log/cron
# Look for successful runs
“Read-only file system” error
The disk might be full or corrupted. Check available space:
df -h /volume1
# If usage is >95%, you need to free space
Clean up old Docker layers:
docker system prune -a --volumes
“non-loopback Control UI” error
The web UI is trying to listen on a public IP instead of localhost. This is rare but fixable:
cat /volume1/docker/openclaw/config/webclient.json
# Should contain "localhost" or "127.0.0.1"
# If not, edit to add: {"allowedOrigins": ["http://localhost:18789"]}
“Permission denied” errors
You’re probably not running as root. Check:
whoami
# Should print your user name
# If not, connect again:
ssh your-username@DISKSTATION_IP
For files, fix ownership:
chown -R root:root /volume1/docker/openclaw
chmod -R 755 /volume1/docker/openclaw
DNS / no internet in container
The container can’t reach the outside world. Check:
docker exec openclaw-gateway cat /etc/resolv.conf
# Should list nameservers (8.8.8.8, etc.)
docker exec openclaw-gateway ping -c 1 1.1.1.1
# Should succeed (Cloudflare DNS)
If DNS is broken, your DiskStation network is misconfigured. Check:
cat /etc/resolv.conf
# Your host should also have working DNS
“PIDs limit discarded” warning
This is harmless. It means the container’s process limit is not enforced. You can ignore it, or add this to compose.yaml if it bothers you:
pids_limit: 256
Maintenance and updates
Update OpenClaw to the latest version
cd /volume1/docker/openclaw
docker compose pull
docker compose up -d
# The new image will be pulled and the container restarted
Change your API key or Telegram token
Edit the config files directly:
nano /volume1/docker/openclaw/config/api_key.txt
# Update the key, save (Ctrl+O, Enter, Ctrl+X)
docker compose restart
Backup your configuration
tar -czf /volume1/backups/openclaw-config-$(date +%Y%m%d).tar.gz /volume1/docker/openclaw/config
# Creates a dated backup of your config and API keys
Keep backups safe – they contain your API keys.
Done!
One week later. Ulf is chatting with OpenClaw through Telegram. Bernd is impressed. Tanja is sipping coffee.
Ulf: “This is amazing. I asked it to summarize a long article – done in seconds. And everything stays on my network!”
Bernd: “I told you containers were the way to go. Well, Tanja told us. But I agreed.”
Tanja: “You’ve got a solid foundation. Now you can extend it – add more skills, connect other services, maybe integrate with your NAS backups. The possibilities are endless.”
Ulf: “What about security updates?”
Tanja: “Run docker compose pull once a month. Keep your DSM updated. Monitor the logs. And don’t expose the gateway to the internet – always use SSH tunnels for remote access.”
Bernd: “So we’re done?”
Tanja: “You’re done with setup. But this is just the beginning. Your personal AI assistant is now running 24/7 on your DiskStation. Treat it well, and it’ll serve you well.”
What you’ve built
- An OpenClaw container running permanently on your DiskStation
- A Telegram bot integrated and ready to chat
- SSH tunnel access to a web interface (optional)
- Network isolation that protects your home devices (optional)
- Browser automation via Playwright + Chromium (optional)
- Proper logging, monitoring, and update procedures
- A foundation for future expansion
Your data stays with you. Your costs are predictable. Your AI assistant is always available. Welcome to OpenClaw on Synology.
FOUNDIC.org is ad-free and has no paywall. If this guide helped you:
Treat us to a coffee
