VPS Setup (Hostinger)
How to set up a fresh Hostinger VPS for running OpenClaw.
Overview
| Script | Purpose | How to run |
|---|---|---|
provision-vps.sh | Full provisioning — creates VPS, configures everything | From your Mac (automated) |
setup-vps-1password.sh | Install 1Password CLI, configure secrets injection | On the VPS (or piped via provision-vps.sh) |
setup-vps-ssh.sh | Harden SSH — key-only auth, no passwords | On the VPS (or piped via provision-vps.sh) |
Quick Start
Run the orchestrator from your Mac — it handles everything:
bash provision-vps.sh
The script will:
- Prompt for plan, data center, and template (with sensible defaults)
- Fetch credentials from 1Password (API token, SSH key, service account token)
- Create the VPS via the Hostinger API with your SSH key injected
- Wait for the VPS to become ready
- Run
setup-vps-1password.shandsetup-vps-ssh.shremotely - Add an entry to
~/.ssh/config - Store VPS details in 1Password (Shared-Infrastructure vault)
- Verify SSH and
openclaw-runwork
After provisioning, connect with:
ssh <your-alias> # e.g. ssh openclaw-vps-3
ssh <your-alias> openclaw-run env # verify secrets injection
Manual Setup (Existing VPS)
If you need to re-run individual scripts on an existing VPS:
# 1. 1Password setup (interactive — prompts for token)
ssh root@<hostname> bash setup-vps-1password.sh
# 1b. Or non-interactive with --token flag
TOKEN=$(op item get "Hostinger VPS Service Account Token" \
--vault="Shared-Infrastructure" --fields credential)
ssh root@<hostname> "bash -s -- --token '${TOKEN}'" < setup-vps-1password.sh
# 2. SSH hardening (piped from Mac)
PUB_KEY=$(op item get "Hostinger SSH Key" \
--vault="Shared-Infrastructure" --fields "public key")
ssh root@<hostname> "bash -s -- '${PUB_KEY}'" < setup-vps-ssh.sh
# 3. Verify key-only login works (no password prompt)
ssh root@<hostname> "echo 'done'"
After this, password login is permanently disabled. You can only SSH in with your 1Password-managed key.
What Each Script Does
provision-vps.sh (Orchestrator — runs from Mac)
Automates the full provisioning flow. Requires op, curl, jq, ssh, and ssh-keyscan.
Fetches three credentials from 1Password (Shared-Infrastructure vault):
- Hostinger API Token — authenticates with the Hostinger API
- Hostinger SSH Key (public key) — injected into the VPS at creation
- Hostinger VPS Service Account Token — passed to
setup-vps-1password.shvia--token
setup-vps-1password.sh
Sets up secrets management so the app can access API keys without storing them in files or env vars:
- Installs 1Password CLI (
op) from the official apt repo - Creates
/etc/openclaw/for sensitive config (mode 700) - Stores the Service Account Token in
/etc/openclaw/op-token.env(mode 600) - Verifies access to the Deploy-Staging vault
- Creates
/opt/openclaw/.env.tpl— maps env vars toop://secret references - Creates
/usr/local/bin/openclaw-run— helper that injects secrets at runtime
Modes:
- Interactive (default): Prompts you to paste the service account token
- Non-interactive (
--token TOKEN): Uses the provided token directly - Non-interactive (
--token-env): Reads token fromOP_SA_TOKENenv var (used byprovision-vps.shto avoid exposing the token in process listings)
Note: The service account token only has access to the Deploy-Staging vault (app secrets), not Shared-Infrastructure (SSH keys, infra). This is intentional — the VPS doesn't need access to infra credentials.
setup-vps-ssh.sh (Piped from Mac)
Locks down SSH so only key-based auth works:
- Adds the provided SSH public key to
~/.ssh/authorized_keys - Backs up
/etc/ssh/sshd_config - Disables password authentication
- Disables empty passwords and PAM
- Sets root login to key-only (
prohibit-password) - Validates the config and restarts the SSH daemon (handles both
sshandsshdservice names)
Why piped from Mac: The script needs the SSH public key as an argument. Since the key is in the Shared-Infrastructure vault (which the VPS service account can't access), we fetch it locally with op and pass it in.
If running interactively (e.g., you're already on the VPS), the script will pause and ask you to verify key login works before disabling passwords. In non-interactive mode (piped), it skips this check — make sure key auth works first.
Hostinger API
The provisioning script uses the Hostinger API to create VPSes programmatically.
Authentication
API requests use a Bearer token stored in 1Password:
Shared-Infrastructure > Hostinger API Token
VPS Creation Endpoint
POST https://developers.hostinger.com/api/vps/v1/virtual-machines
Payload format:
{
"item_id": "hostingercom-vps-kvm2-usd-1m",
"setup": {
"data_center_id": 17,
"template_id": 1121,
"public_key": {
"name": "1password-ssh-key",
"key": "ssh-ed25519 AAAA..."
}
}
}
Common Values
| Field | Value | Meaning |
|---|---|---|
item_id | hostingercom-vps-kvm2-usd-1m | KVM 2 plan, monthly |
data_center_id | 17 | Boston |
template_id | 1121 | Ubuntu 24.04 with Docker |
Usage After Setup
# Run the app with all secrets injected
openclaw-run python main.py
# Verify secrets are available
openclaw-run env | grep -i api
Recovery
If locked out of SSH, use the Hostinger VPS console panel to:
cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
# Service name varies by distro
systemctl restart ssh || systemctl restart sshd
1Password Vault Structure
All secrets are stored in 1Password, organized by vault. Nothing is hardcoded in scripts or config files.
Vault Layout
| Vault | Purpose | Access |
|---|---|---|
| Shared-Infrastructure | Infra credentials (SSH keys, PATs, server details, service account tokens) | Your Mac only |
| Deploy-Staging | App runtime secrets (API keys, bot tokens) | VPS via service account |
| Deploy-Production | Production app secrets (mirrors staging structure) | Production VPS via service account |
Secret Reference Format
1Password uses op:// URIs to reference secrets without exposing values:
op://<Vault>/<Item Title>/<Field>
Examples:
op://Deploy-Staging/Anthropic API Key/credential
op://Shared-Infrastructure/Hostinger SSH Key/public key
These references are resolved at runtime by op run or op item get — the actual secret values never touch disk or source control.
Current Items
Shared-Infrastructure (accessed from your Mac):
| Item | Type | Used By |
|---|---|---|
| GitHub SSH Key | SSH Key | Git push/pull via 1Password SSH agent |
| Hostinger SSH Key | SSH Key | SSH into VPS via 1Password SSH agent |
| Hostinger API Token | API Credential | provision-vps.sh — creates VPSes via Hostinger API |
| Hostinger VPS | Server | VPS connection details (hostname, IP) |
| Hostinger VPS Service Account Token | API Credential | Authenticates op CLI on the VPS |
Deploy-Staging (accessed from VPS via service account):
| Item | Type | Used By |
|---|---|---|
| Telegram Bot Token | API Credential | App runtime via openclaw-run |
| Anthropic API Key | API Credential | App runtime via openclaw-run |
| OpenAI API Key | API Credential | App runtime via openclaw-run |
How Secrets Flow
1Password
│
├── Your Mac (Shared-Infrastructure vault)
│ ├── 1Password SSH Agent ──→ ~/.ssh/config ──→ git / ssh to VPS
│ └── Hostinger API Token ──→ provision-vps.sh ──→ Hostinger API
│
└── VPS (Deploy-Staging vault)
└── Service Account Token ──→ op CLI ──→ openclaw-run ──→ app env vars
On your Mac: The 1Password desktop app's SSH agent provides keys on demand. No private keys on disk. Keys must be registered in the agent config:
~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.toml
[[ssh-keys]]
item = "GitHub SSH Key"
vault = "Shared-Infrastructure"
[[ssh-keys]]
item = "Hostinger SSH Key"
vault = "Shared-Infrastructure"
Only keys listed here will be offered by the agent. Keys in the Private vault are enabled by default; keys in other vaults must be added explicitly.
On the VPS: A Service Account Token (stored in /etc/openclaw/op-token.env) authenticates the op CLI. The openclaw-run helper uses op run to inject secrets from the .env.tpl template into the app's environment at runtime. The token only grants access to Deploy-Staging — it cannot read SSH keys or other infra secrets.
Adding a New Secret
- Create the item in the appropriate vault (Deploy-Staging for app secrets, Shared-Infrastructure for infra)
- If it's an app runtime secret, add the
op://reference to/opt/openclaw/.env.tplon the VPS, e.g.MY_NEW_SECRET=op://Deploy-Staging/Item Name/credential - If it's an infra secret, reference it in scripts with
op item get - No redeployment needed —
openclaw-runpicks up changes automatically
File Locations on VPS
| Path | Purpose |
|---|---|
/etc/openclaw/op-token.env | Service Account Token (mode 600) |
/opt/openclaw/.env.tpl | Secret reference template |
/usr/local/bin/openclaw-run | Helper script |
/etc/ssh/sshd_config.bak | SSH config backup (pre-hardening) |