# OpenClaw VPS Setup
Operational reference for the first low-risk [[OpenClaw]] VPS deployment.
## Server
- Provider: Hetzner Cloud
- Project: `openclaw`
- Server name: `openclaw-01`
- Public IP: `178.104.156.215`
- OS: Ubuntu 24.04 LTS
- Server type: `CX23`, x86, 40 GB disk
- SSH user: `nick`
- Local SSH key: `~/.ssh/openclaw_vps`
## OpenClaw
- Installed version: `OpenClaw 2026.4.24`
- Install location: user-local npm install under `nick`
- CLI path on VPS: `/home/nick/.npm-global/bin/openclaw`
- Balance helper on VPS: `/home/nick/bin/deepseek-balance`
- Gateway QuickStart settings:
- Port: `18789`
- Bind: `127.0.0.1`
- Auth: token
- Tailscale exposure: off
## Model Provider
- Provider: DeepSeek
- Default model: `deepseek/deepseek-v4-flash`
- Model alias for easier tasks: `flash` -> `deepseek/deepseek-v4-flash`
- Model alias for harder tasks: `pro` -> `deepseek/deepseek-v4-pro`
- DeepSeek API base URL: `https://api.deepseek.com`
- API key location: stored in OpenClaw configuration on the VPS, not in this vault.
- Key status: valid as of 2026-04-26
- DeepSeek balance checked after setup: `$19.98`
- Fallbacks: none. Pro is not configured as an automatic fallback, to avoid surprise spend.
Do not store raw API keys in the vault. If the key is needed again, use the DeepSeek dashboard to inspect, revoke, or create a replacement key.
For Google Workspace / Gmail authentication context, see [[Google Workspace Authentication Context]] before creating new OAuth clients.
## Using Flash and Pro
OpenClaw defaults to `flash`, which is the cheap everyday model.
From Telegram, switch the current chat/session model with:
```text
/model flash
```
```text
/model pro
```
```text
/model status
```
Use `flash` for ordinary chat, lightweight planning, short drafting, reminders, and small agent experiments.
Use `pro` deliberately for harder reasoning: multi-step project design, difficult debugging, dense philosophical analysis, or anything where a wrong answer would waste time. Switch back to `flash` afterwards.
From SSH:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected]
openclaw models status
openclaw models set flash
openclaw models set pro
```
## Monitoring DeepSeek Spend
Official dashboard:
- Balance/top-up: <https://platform.deepseek.com>
- Usage by API key: DeepSeek's FAQ says to use the Usage page, pick the month, export, unzip the package, and inspect the `amount` CSV for usage broken down by key.
On the VPS, check current remaining balance with:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/deepseek-balance'
```
The helper reads the DeepSeek key from OpenClaw's local auth profile and calls DeepSeek's `/user/balance` endpoint. It does not store the raw key in this vault.
Cost policy for the trial:
- Keep `flash` as default.
- Use `/model pro` only for named hard tasks.
- Do not add Pro as an automatic fallback unless Nick explicitly asks.
- Check balance after a day or two of actual use.
## Current Setup State
As of 2026-04-26, the server is created, OpenClaw is installed, DeepSeek is configured, and the gateway daemon is running.
- Gateway health: reachable on local loopback
- Gateway bind: `127.0.0.1` / `::1` only
- OpenClaw security audit: `0 critical`, `1 warn`
- Remaining audit warning: reverse-proxy trusted headers are not configured; this is acceptable while the Control UI stays local-only.
- Bonjour plugin: disabled, because it crashed on the VPS with `CIAO PROBING CANCELLED`
- Bootstrap: completed manually; `BOOTSTRAP.md` removed
- Local operator device: approved for CLI operator scopes
- Smoke test: DeepSeek returned `OpenClaw ready`
- Telegram channel: configured and connected as `@bloodonnicksclawbot`
- Telegram mode: polling
- Telegram user paired: Nick's Telegram user id `2139973327`
- First Telegram reply: succeeded, though initial reply was slow
## Guardrails
Added 2026-04-27 from the laptop, after the original VPS setup had been done from the desktop.
Emergency stop quick reference: [[OpenClaw Emergency Stop]].
### Daily Telegram heartbeat
- Script: `/home/nick/bin/openclaw-heartbeat`
- Timer: `/home/nick/.config/systemd/user/openclaw-heartbeat.timer`
- Service: `/home/nick/.config/systemd/user/openclaw-heartbeat.service`
- Schedule: daily at 09:00 Europe/Rome
- Telegram target: Nick's Telegram user id `2139973327`
- Last manual test: sent successfully on 2026-04-27 as Telegram message `152`
The heartbeat reports:
- VPS hostname and UTC time
- OpenClaw gateway service state
- OpenClaw gateway health
- Default model
- DeepSeek balance
- Note that 24h token/spend is unavailable from current OpenClaw provider usage
Check the timer:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'systemctl --user list-timers --all | grep openclaw-heartbeat'
```
Run the heartbeat manually:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-heartbeat'
```
### Gmail triage digest
OpenClaw has read-only Gmail access through `gog`, the Google Workspace CLI.
- Gmail account: `
[email protected]`
- `gog` binary wrapper: `/home/nick/bin/gog`
- Real `gog` binary: `/home/nick/bin/gog.real`
- OAuth client JSON on VPS: `/home/nick/.config/gog/client_secret.json`
- Keyring password file on VPS: `/home/nick/.config/gog/keyring-password`
- Digest script: `/home/nick/bin/openclaw-gmail-digest`
- Timer: `/home/nick/.config/systemd/user/openclaw-gmail-digest.timer`
- Service: `/home/nick/.config/systemd/user/openclaw-gmail-digest.service`
- OpenClaw workspace skill: `/home/nick/.openclaw/workspace/skills/gmail-triage/SKILL.md`
- Schedule: weekdays at 08:00, 14:00, and 19:00 Europe/Rome
- Telegram target: Nick's Telegram user id `2139973327`
- Default query: `is:important newer_than:2d -from:me`
- Message count: no fixed maximum; the script uses `gog gmail messages search --all --full`
- Last manual test: sent successfully on 2026-04-27 with one summary and one separate reply message
Safety boundary:
- Gmail authorization is read-only.
- The digest reads full bodies for messages that pass the skip filter.
- It sends detailed, non-verbatim summaries first, including an explicit `Open original email in Gmail:` thread link for each message.
- It sends suggested reply text in separate Telegram messages for copy/paste, also including `Open original email in Gmail:`.
- It does not mark messages read.
- It does not label or archive messages.
- It does not draft or send email.
- Raw OAuth tokens are not stored in this vault.
The skip filter removes obvious no-reply senders, newsletters/updates, receipts/bookings, and security/account alerts. Gmail category labels such as `CATEGORY_UPDATES` are not used as a skip reason, because academic/editorial mail can land there.
Model generation uses the local DeepSeek API key already configured for OpenClaw. The script reads that key from OpenClaw's local auth profile on the VPS; it does not copy the key into this vault.
Check the timer:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'systemctl --user list-timers --all | grep openclaw-gmail-digest'
```
Run the digest manually:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-gmail-digest'
```
Run a no-send dry run:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'GMAIL_TRIAGE_SEND=0 ~/bin/openclaw-gmail-digest'
```
Inspect the last digest on the VPS:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'sed -n "1,160p" ~/.local/state/openclaw-gmail-triage/last-digest.txt'
```
Inspect the last generated reply text on the VPS:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'sed -n "1,160p" ~/.local/state/openclaw-gmail-triage/last-reply-1.txt'
```
### PHILOS-L CFP and job digest
OpenClaw has a separate PHILOS-L digest for new CFPs and jobs that fit Nick's profile and research interests.
- Gmail account: `
[email protected]`
- Digest script: `/home/nick/bin/openclaw-philos-digest`
- Timer: `/home/nick/.config/systemd/user/openclaw-philos-digest.timer`
- Service: `/home/nick/.config/systemd/user/openclaw-philos-digest.service`
- OpenClaw workspace skill: `/home/nick/.openclaw/workspace/skills/philos-digest/SKILL.md`
- Schedule: weekdays at 12:00 Europe/Rome
- Telegram target: Nick's Telegram user id `2139973327`
- Default query: `subject:PHILOS-L newer_than:7d`
- State file: `/home/nick/.local/state/openclaw-philos-digest/seen.json`
- Last manual bootstrap: sent successfully on 2026-04-27 from a verified dry-run digest, then marked 126 current PHILOS-L messages as seen
The digest uses Gmail rather than scraping a web archive, because Nick already receives PHILOS-L by email. This gives the script message bodies, message ids, labels, and direct `Open original email in Gmail:` links.
It filters in stages:
- Gmail query finds recent PHILOS-L messages.
- Subject-line filter keeps likely CFPs, calls, jobs, postdocs, fellowships, and similar opportunities.
- DeepSeek checks fit against Nick's research profile: aesthetics, AI aesthetics, environmental aesthetics, design, generative AI, perception/audition, temporal phenomenology, philosophy of mind, philosophy of technology, and LLMs/philosophy.
- Code-level deadline filtering removes opportunities whose deadline has already passed.
- Seen-state prevents previously evaluated messages from reappearing every weekday.
Safety boundary:
- Gmail authorization is read-only.
- The digest reads PHILOS-L message bodies for triage.
- It sends Telegram summaries with `Open original email in Gmail:` links.
- It does not mark read, label, draft, apply, or send email.
Check the timer:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'systemctl --user list-timers --all | grep openclaw-philos-digest'
```
Run the digest manually:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-philos-digest'
```
Run a no-send dry run:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'PHILOS_DIGEST_SEND=0 ~/bin/openclaw-philos-digest'
```
Inspect the last digest on the VPS:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'sed -n "1,180p" ~/.local/state/openclaw-philos-digest/last-digest.txt'
```
### Google Calendar digest
OpenClaw has read-only Google Calendar access through `gog`.
- Google account: `
[email protected]`
- Digest script: `/home/nick/bin/openclaw-calendar-digest`
- Timer: `/home/nick/.config/systemd/user/openclaw-calendar-digest.timer`
- Service: `/home/nick/.config/systemd/user/openclaw-calendar-digest.service`
- OpenClaw workspace skill: `/home/nick/.openclaw/workspace/skills/calendar-digest/SKILL.md`
- Schedule: weekdays at 08:00 Europe/Rome
- Telegram target: Nick's Telegram user id `2139973327`
- Default window: next 7 days
- Included calendars:
- default calendar: `
[email protected]`
- PEA/work calendar: `7fe5934f1010abb4a94d0c57bec0693b4b7416cfcbd5f9ac264a797039bd67fb@group.calendar.google.com`
- Last manual test: sent successfully on 2026-04-27 with Google Calendar event links included
Safety boundary:
- Calendar authorization is read-only.
- The digest reads event metadata: date, time, title, calendar name, and Google Calendar event link.
- It does not create, edit, delete, or RSVP to calendar events.
- Raw OAuth tokens are not stored in this vault.
The 2026-04-27 manual test confirmed that the next-week digest picked up both PEA reading groups that week, using weekday-style date headings:
- Wednesday 29th April, `RG: Shelley (2022) "Intelligibile Beauty)`
- Thursday 30th April, `RG: Montero (2016) "The Pleasure of Movement and the Awereness of the Self"`
Check the timer:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'systemctl --user list-timers --all | grep openclaw-calendar-digest'
```
Run the digest manually:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-calendar-digest'
```
Inspect the last digest on the VPS:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'sed -n "1,160p" ~/.local/state/openclaw-calendar-digest/last-digest.txt'
```
### Phone stop path
This is the reliable kill path. It stops the OpenClaw gateway service on the VPS. Telegram will stop responding after this, because the Telegram channel runs through the gateway.
Stop OpenClaw:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-stop'
```
Start OpenClaw again:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] '~/bin/openclaw-start'
```
Check status:
```bash
ssh -i ~/.ssh/openclaw_vps
[email protected] 'systemctl --user is-active openclaw-gateway.service'
```
Test result on 2026-04-27:
- `openclaw-stop` moved the gateway to `inactive`
- `openclaw-start` moved the gateway back to `active`
- OpenClaw health check then succeeded and Telegram reported connected
## Continuation Notes for Another AI Session
The core setup is complete. Do not restart from provisioning unless something is broken.
Known intentional choices:
- Hetzner VPS, not local Mac.
- Gateway stays loopback-only.
- Telegram uses polling; no public webhooks.
- Gmail read-only triage and Google Calendar read-only digesting are enabled through `gog`; vault sync and write-capable Google actions are not enabled.
- Bonjour plugin is disabled because it crashed on VPS startup.
- Raw API keys and bot tokens must not be copied into this note.
If continuing:
1. SSH to the VPS with `ssh -i ~/.ssh/openclaw_vps
[email protected]`.
2. Check OpenClaw with `openclaw status --all`.
3. Check Telegram with `openclaw channels status --deep`.
4. Check DeepSeek balance with `~/bin/deepseek-balance`.
5. Use Telegram bot `@bloodonnicksclawbot` for normal interaction.