Skip to main content

VPS Setup (Hostinger)

How to set up a fresh Hostinger VPS for running OpenClaw.

Overview

ScriptPurposeHow to run
provision-vps.shFull provisioning — creates VPS, configures everythingFrom your Mac (automated)
setup-vps-1password.shInstall 1Password CLI, configure secrets injectionOn the VPS (or piped via provision-vps.sh)
setup-vps-ssh.shHarden SSH — key-only auth, no passwordsOn 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:

  1. Prompt for plan, data center, and template (with sensible defaults)
  2. Fetch credentials from 1Password (API token, SSH key, service account token)
  3. Create the VPS via the Hostinger API with your SSH key injected
  4. Wait for the VPS to become ready
  5. Run setup-vps-1password.sh and setup-vps-ssh.sh remotely
  6. Add an entry to ~/.ssh/config
  7. Store VPS details in 1Password (Shared-Infrastructure vault)
  8. Verify SSH and openclaw-run work

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.sh via --token

setup-vps-1password.sh

Sets up secrets management so the app can access API keys without storing them in files or env vars:

  1. Installs 1Password CLI (op) from the official apt repo
  2. Creates /etc/openclaw/ for sensitive config (mode 700)
  3. Stores the Service Account Token in /etc/openclaw/op-token.env (mode 600)
  4. Verifies access to the Deploy-Staging vault
  5. Creates /opt/openclaw/.env.tpl — maps env vars to op:// secret references
  6. 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 from OP_SA_TOKEN env var (used by provision-vps.sh to 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:

  1. Adds the provided SSH public key to ~/.ssh/authorized_keys
  2. Backs up /etc/ssh/sshd_config
  3. Disables password authentication
  4. Disables empty passwords and PAM
  5. Sets root login to key-only (prohibit-password)
  6. Validates the config and restarts the SSH daemon (handles both ssh and sshd service 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

FieldValueMeaning
item_idhostingercom-vps-kvm2-usd-1mKVM 2 plan, monthly
data_center_id17Boston
template_id1121Ubuntu 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

VaultPurposeAccess
Shared-InfrastructureInfra credentials (SSH keys, PATs, server details, service account tokens)Your Mac only
Deploy-StagingApp runtime secrets (API keys, bot tokens)VPS via service account
Deploy-ProductionProduction 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):

ItemTypeUsed By
GitHub SSH KeySSH KeyGit push/pull via 1Password SSH agent
Hostinger SSH KeySSH KeySSH into VPS via 1Password SSH agent
Hostinger API TokenAPI Credentialprovision-vps.sh — creates VPSes via Hostinger API
Hostinger VPSServerVPS connection details (hostname, IP)
Hostinger VPS Service Account TokenAPI CredentialAuthenticates op CLI on the VPS

Deploy-Staging (accessed from VPS via service account):

ItemTypeUsed By
Telegram Bot TokenAPI CredentialApp runtime via openclaw-run
Anthropic API KeyAPI CredentialApp runtime via openclaw-run
OpenAI API KeyAPI CredentialApp 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

  1. Create the item in the appropriate vault (Deploy-Staging for app secrets, Shared-Infrastructure for infra)
  2. If it's an app runtime secret, add the op:// reference to /opt/openclaw/.env.tpl on the VPS, e.g. MY_NEW_SECRET=op://Deploy-Staging/Item Name/credential
  3. If it's an infra secret, reference it in scripts with op item get
  4. No redeployment needed — openclaw-run picks up changes automatically

File Locations on VPS

PathPurpose
/etc/openclaw/op-token.envService Account Token (mode 600)
/opt/openclaw/.env.tplSecret reference template
/usr/local/bin/openclaw-runHelper script
/etc/ssh/sshd_config.bakSSH config backup (pre-hardening)