<!-- https://zunder-design-preview.pages.dev/docs/deploy · Markdown version of the page -->

# Deploy Guard

Where Guard can run, what every install has in common, and which page to read for your platform.

:::note[Planned]
Guard has no release yet. Every command, image name, package name and template in this section is the plan for Guard 1.0. The GitHub organisation (`zunderlabs`), the image (`ghcr.io/zunderlabs/zunder-guard`) and the package names are planned names, not published ones.
:::

Guard runs where you run it: your laptop, a home server, or a server you rent. We host nothing that holds a key.

The setup below takes what you set on this site (your rules, the account you watched), detects your system, and writes one command to run on the machine where your bot runs (a server over SSH is the other way). Every command matches Guard's v1.0.0 release. Your key is typed on the machine where Guard runs, never on this page.

## The setup journey

1. **Choose the machine where the bot runs.** Use the setup below as the main route; it selects a platform-specific command.
2. **Verify the release.** Follow [Verify a release](https://zunder-design-preview.pages.dev/docs/deploy/verify) before running it. The names and commands here remain planned until Guard’s first release.
3. **Start in paper mode.** Follow [Quickstart](https://zunder-design-preview.pages.dev/docs/start/quickstart) and inspect the first decisions before considering testnet.
4. **Connect the bot.** Use its [integration guide](https://zunder-design-preview.pages.dev/docs/integrations), keeping the client key separate from the API wallet key.

Run it on the machine where your bot runs. With the default rules (the page fills in your own and detects your system); every command matches Guard's v1.0.0 release:

**macOS**

```sh
curl -fsSL https://zunder-design-preview.pages.dev/i | sh -s -- --rules zr1_eyJ2IjoxLCJtYXhMZXZlcmFnZSI6NSwibWF4TG9zc0F0U3RvcFBjdCI6Miwic3RvcFBvbGljeSI6ImF0dGFjaCIsImRlZmF1bHRTdG9wRGlzdGFuY2VQY3QiOjIsIm1pbkxpcURpc3RhbmNlUGN0IjoxMCwibWF4UG9zaXRpb25QY3QiOjIwMCwibWF4T3BlblJpc2tQY3QiOjYsImRhaWx5TG9zc1N0b3BQY3QiOjYsImRyYXdkb3duSGFsdFBjdCI6MjUsIm1hcmtldHMiOlsiKiJdfQ
```

**Linux**

```sh
curl -fsSL https://zunder-design-preview.pages.dev/i | sh -s -- --rules zr1_eyJ2IjoxLCJtYXhMZXZlcmFnZSI6NSwibWF4TG9zc0F0U3RvcFBjdCI6Miwic3RvcFBvbGljeSI6ImF0dGFjaCIsImRlZmF1bHRTdG9wRGlzdGFuY2VQY3QiOjIsIm1pbkxpcURpc3RhbmNlUGN0IjoxMCwibWF4UG9zaXRpb25QY3QiOjIwMCwibWF4T3BlblJpc2tQY3QiOjYsImRhaWx5TG9zc1N0b3BQY3QiOjYsImRyYXdkb3duSGFsdFBjdCI6MjUsIm1hcmtldHMiOlsiKiJdfQ
```

**Windows**

```
& ([scriptblock]::Create((irm https://zunder-design-preview.pages.dev/i.ps1))) -Rules zr1_eyJ2IjoxLCJtYXhMZXZlcmFnZSI6NSwibWF4TG9zc0F0U3RvcFBjdCI6Miwic3RvcFBvbGljeSI6ImF0dGFjaCIsImRlZmF1bHRTdG9wRGlzdGFuY2VQY3QiOjIsIm1pbkxpcURpc3RhbmNlUGN0IjoxMCwibWF4UG9zaXRpb25QY3QiOjIwMCwibWF4T3BlblJpc2tQY3QiOjYsImRhaWx5TG9zc1N0b3BQY3QiOjYsImRyYXdkb3duSGFsdFBjdCI6MjUsIm1hcmtldHMiOlsiKiJdfQ
```

**Docker**

```
# 1. guided setup: rules, account, mode and (testnet) the key, with hidden input
docker run -it --rm -v zunder-guard:/data ghcr.io/zunderlabs/zunder-guard:v1.0.0 init --interactive --rules zr1_eyJ2IjoxLCJtYXhMZXZlcmFnZSI6NSwibWF4TG9zc0F0U3RvcFBjdCI6Miwic3RvcFBvbGljeSI6ImF0dGFjaCIsImRlZmF1bHRTdG9wRGlzdGFuY2VQY3QiOjIsIm1pbkxpcURpc3RhbmNlUGN0IjoxMCwibWF4UG9zaXRpb25QY3QiOjIwMCwibWF4T3BlblJpc2tQY3QiOjYsImRhaWx5TG9zc1N0b3BQY3QiOjYsImRyYXdkb3duSGFsdFBjdCI6MjUsIm1hcmtldHMiOlsiKiJdfQ
# 2. run it, reachable from this machine only
docker run -d --name zunder-guard --init --restart unless-stopped -v zunder-guard:/data -e ZUNDER_GUARD_LISTEN=0.0.0.0:8547 -p 127.0.0.1:8547:8547 ghcr.io/zunderlabs/zunder-guard:v1.0.0
```

**On a server (SSH)**, from your computer:

```sh
ssh -t you@your-server "curl -fsSL https://zunder-design-preview.pages.dev/i | sh -s -- --rules zr1_eyJ2IjoxLCJtYXhMZXZlcmFnZSI6NSwibWF4TG9zc0F0U3RvcFBjdCI6Miwic3RvcFBvbGljeSI6ImF0dGFjaCIsImRlZmF1bHRTdG9wRGlzdGFuY2VQY3QiOjIsIm1pbkxpcURpc3RhbmNlUGN0IjoxMCwibWF4UG9zaXRpb25QY3QiOjIwMCwibWF4T3BlblJpc2tQY3QiOjYsImRhaWx5TG9zc1N0b3BQY3QiOjYsImRyYXdkb3duSGFsdFBjdCI6MjUsIm1hcmtldHMiOlsiKiJdfQ"
```

The API wallet key is typed into Guard's hidden prompt where Guard runs; it is never part of a command.

## What every install has in common

- **It starts in paper mode.** Real prices, no orders sent. Testnet next. Mainnet only when you type it ([Paper, testnet and mainnet](https://zunder-design-preview.pages.dev/docs/concepts/networks)).
- **It listens on localhost only** (`127.0.0.1:8547`) unless you configure otherwise.
- **It talks to Hyperliquid only.** The relay and telemetry are off unless you turn them on ([Network footprint](https://zunder-design-preview.pages.dev/docs/deploy/network-footprint)).
- **Every release can be verified** before you run it ([Verify a release](https://zunder-design-preview.pages.dev/docs/deploy/verify)).
- **The API wallet key is created by you** in the Hyperliquid app and given to Guard on your machine. It never passes through us.

## Alternatives to the main setup

| You have | Read |
|---|---|
| a Mac or Linux, where your bot runs | the one-liner above (`curl -fsSL https://zunder-design-preview.pages.dev/i \| sh -s -- --rules …`), or [Homebrew](https://zunder-design-preview.pages.dev/docs/deploy/packages) |
| Windows | the PowerShell one-liner above (`& ([scriptblock]::Create((irm https://zunder-design-preview.pages.dev/i.ps1))) -Rules …`), or [Docker](https://zunder-design-preview.pages.dev/docs/deploy/docker) |
| a server you reach over SSH | [One SSH command](https://zunder-design-preview.pages.dev/docs/deploy/ssh), run from your computer |
| Docker anywhere | [Docker](https://zunder-design-preview.pages.dev/docs/deploy/docker) |
| no server yet | [One-click templates](https://zunder-design-preview.pages.dev/docs/deploy/one-click) |

## Where it should run

Next to your bot. Guard listens on localhost, so the bot and Guard belong on the same machine, or in the same private network.

Close to Hyperliquid matters more than anything Guard does. Guard adds about 3 ms per order; the trip to Hyperliquid is the larger part: 4.5 ms there and back from Tokyo, 238 ms from Frankfurt (medians; [Latency](https://zunder-design-preview.pages.dev/docs/methods/latency)). When the account stream is not current Guard reads the account first, one more round trip. Run Guard and your bot in Tokyo (AWS `ap-northeast-1`), with Guard's data directory on a local SSD: its decision journal is synced to disk before each order goes out. Zunder's research treats a host in Tokyo (`ap-northeast-1`) as next to Hyperliquid (`docs/decisions.md`, 5 Oct 2026).

## Several Guards on one machine

One Guard guards one account. Hyperliquid allows 1,200 of request weight a minute per IP address, and a Guard alone sizes its budgets for all of it. Running several Guards on one machine (or behind one IP address)? **Give each `ip_share = 1/N`**, written as a decimal: `"0.5"` for two, `"0.3333"` for three (`init --ip-share 0.5`, or `ip_share` in `guard.toml`), every one of them, the first included, so that together they stay within the limit and each keeps a reserve for its own stops and closes ([Config keys](https://zunder-design-preview.pages.dev/docs/reference/config#top-level-keys)). Give each its own home and listen port, and start them a few seconds apart.

Guard refuses a share too small to keep it safe: at most three Guards per IP address with the main dex alone, two with one HIP-3 dex, one with two. Your bots' own calls to Hyperliquid and this site's browser tools spend the same 1,200, so leave them room.

## Where the key lives

:::note[Planned]
How Guard 1.0 stores the API wallet key, per install (`deploy/guard/README.md`):
:::

- **A Linux server (the SSH command):** encrypted with `systemd-creds` (systemd 250 or newer: Ubuntu 24.04, Debian 12 and later), with the host key and the TPM where there is one. systemd decrypts it only when it starts the service, into memory only the service can read. A copy of the disk without the host key is useless. Root on the running machine can still read it, as root can read any process's memory. On older systemd: a file readable only by Guard's own user, and the installer warns.
- **Docker:** a file in the volume, mode 0600, owned by the container's user.
- **macOS, and anywhere `systemd-creds` is not available:** the file `api-wallet-key` in Guard's home, mode 0600, readable only by you. Guard says at setup that the key lies there in plain text. There is no keychain support.
- **Mainnet, everywhere:** the key is never stored. It is checked once at setup and comes on standard input at every start (under systemd: from an encrypted `systemd-creds` credential).

Everywhere: the key belongs to an API wallet that can trade but cannot withdraw, on an account that holds only what you are willing to risk. It is typed into Guard's hidden prompt, never into a command line, a URL or this site.
