Here's what it took to make OpenClaw bulletproof
From local Docker container to DigitalOcean VPS
Part two of the OpenClaw marketing bot saga. Part one here.
In the last post, I got the bot working locally — OpenClaw running in Docker on Windows, talking to Telegram, posting TikTok content through the Genviral skill. It worked. Until it didn't.
The problem with "works on my machine" is that my machine runs WSL2, and WSL2's networking has opinions about long-lived connections. The Telegram polling loop would die every few hours — silently, with no errors, while the health check kept reporting everything was fine. I'd notice hours later when I checked my phone and saw the bot had gone quiet.
That's not going to cut it for a month on a trail with no laptop.
Leaving Windows Behind
The fix was obvious: get off WSL2 entirely. A proper Linux VPS with real networking, real Docker, and no virtualization layer randomly killing TCP connections.
I went with DigitalOcean — a 2 vCPU, 2GB RAM droplet running Ubuntu 24.04. Twelve dollars a month. The entire provisioning took one doctl command:
doctl compute droplet create mystic-bot \
--image ubuntu-24-04-x64 \
--size s-2vcpu-2gb \
--region nyc1 \
--ssh-keys <fingerprint>
Forty seconds later I had a server. SSH in, install Docker, clone the repo, docker compose up -d. The gateway came up healthy on the first try. Telegram connected immediately and stayed connected. No stale sockets, no silent drops, no hourly restarts.
The WSL2 networking issue that consumed most of my debugging time in part one just... wasn't a thing anymore. Turns out the fix for unreliable virtualized networking is to not use virtualized networking.
Building the Safety Net
A working bot is step one. A bot that stays working for a month without human intervention is a different problem. I needed to think about every way it could fail and build recovery for each one.
Docker handles process crashes. The compose file already had restart: unless-stopped, so if the gateway process dies, Docker restarts it automatically. I tested this by killing PID 1 inside the container — it was back up and healthy in under twenty seconds.
Systemd handles server reboots. systemctl enable docker means Docker starts on boot, and Docker starts the container because of the restart policy. I rebooted the droplet to test — the bot was responding on Telegram within forty seconds of the server coming back up.
Unattended upgrades handle OS patches. Ubuntu's unattended-upgrades package applies security updates automatically. I disabled automatic reboots — a kernel update shouldn't take the bot offline. If a reboot is genuinely needed, the restart chain handles it anyway.
A watchdog cron handles the sneaky failures. This is the one that matters most. Sometimes everything looks healthy but the Telegram connection has gone stale. The health check passes, Docker thinks the container is fine, but the bot isn't receiving messages.
The watchdog runs every five minutes. It checks three things: is the container running, is it healthy, and has there been any Telegram activity in the logs recently. If the container is down, it starts it. If it's unhealthy or Telegram has gone quiet, it does a full down/up cycle — the same fix that works manually, just automated.
UFW locks down the attack surface. The only inbound port is SSH. The gateway doesn't need to be publicly accessible because Telegram uses outbound polling — the bot calls Telegram, not the other way around.
The Panic Button
All that automation covers normal failures. But what about the scenario where I'm on a trail, I check Telegram, and the bot isn't responding? I can't SSH in from my iPhone without an unreasonable amount of setup.
So I built a webhook. A tiny Python HTTP server running on the droplet behind a secret URL. Open it in Safari, it restarts the bot. One tap.
The important part is making it safe to use carelessly. Tapping the link twice shouldn't cause two overlapping restarts. Tapping it while the watchdog is already restarting shouldn't create a conflict. So the webhook has a lockfile that prevents concurrent restarts and a five-minute cooldown after each restart. If you hit it during cooldown, it tells you when to try again instead of doing anything.
The URL is a 40-character random hex string — essentially a password in the path. Wrong URL gets a 404 with no information. It runs as a systemd service so it survives reboots, same as everything else.
I bookmarked it on my phone. Hopefully I never use it.
Keeping It Clean
The last concern is disk space. The droplet has 50GB, and Docker logs plus OpenClaw session files could theoretically fill that over a month. Two mitigations:
Docker's log rotation caps each container's logs at 150MB (three 50MB files, auto-rotated). That's configured in /etc/docker/daemon.json and applies globally.
Session files — the conversation logs that give the bot context about previous chats — get pruned weekly, but only if they exceed 5GB total. Under that threshold, everything is preserved. I wanted the bot to keep as much context as possible in case it needs to reference something from a conversation two weeks ago, but not at the risk of filling the disk while I'm unreachable.
The Final Checklist
Before calling this done, I verified every recovery path:
- Kill the gateway process → Docker restarts it in 20 seconds
- Reboot the entire server → everything comes back in 40 seconds
- Hit the webhook → clean restart with cooldown protection
- Leave it running overnight → still responding in the morning
genviral accounts→ TikTok account active, API working
The bot is live on the VPS now. The local Docker setup on my Windows machine is shut down. Everything runs from a server in a New York data center that doesn't care about WSL2 networking quirks.
What's Left
The TikTok account is still in its warmup period — new accounts need organic-looking activity before the algorithm will distribute their content. Once that's done, I need to set up the actual content scheduling. OpenClaw has a built-in cron system, and Genviral has its own calendar layer. I haven't wired those up yet.
But the core infrastructure is done. The bot is running, the recovery paths are tested, and the server is ready for the real work.
This is part two of a series about building an autonomous marketing bot. Part one covers the initial setup, the Telegram debugging nightmare, and the skill detection issues.