Skip to content

Getting Started

Zephyr is a self-hosted Solana trading bot. This guide gets you running in under 10 minutes.

What you need

  • A Linux machine (your laptop works, or a VPS for 24/7 uptime)
  • A Solana RPC URL. Sign up at helius.dev
  • (Optional) A Solana gRPC URL + token. Helius LaserStream or shyft.to. Skip this and Zephyr falls back to a built-in Helius LaserStream endpoint, automatically picking the closer region (NY or Frankfurt) for your machine.
  • A Solana wallet with some SOL in it. Use a dedicated trading wallet, not your main

1. Download the binary

bash
curl -O https://releases.solanazephyr.com/releases/latest/zephyr
chmod +x zephyr

2. Create config.toml

Create a file called config.toml next to the zephyr binary and paste this in:

toml
[trade]
# Defaults used to seed new mints. Per-mint overrides live in positions.json.
entry_pct = -10.0                                # Entry target as % from reference price (negative = wait for dip)
exit_pct = 2.0                                   # Take-profit target as % above buy price
target_change_delay = 1000                       # Ms between reference price updates (auto-rebuy)

[buy]
slippage = 150                                   # Slippage in bps (150 = 1.5%)
max_block_difference = 3                         # Transaction freshness window in slots
nonce_delay = 25                                 # Nonce rotation interval in ms
panic_slippage = 1000                            # Slippage for panic buy in bps

[buy.dynamic_fee]
percentile = 7500                                # Fee percentile (×100, so 7500 = p75)
fee_multiplier = 1.0                             # Multiply raw fee by this factor
fee_cap = 500000                                 # Max fee in microlamports (0 = no cap)

[buy.dynamic_tip]
percentile = 8500                                # Must be in [general].tip_percentiles
tip_multiplier = 1.0                             # Multiply raw tip by this factor
tip_floor = 0.003                                # Minimum SOL tip (stream-fallback)
tip_cap = 0.005                                  # Maximum SOL tip; set == tip_floor to pin
adaptive = true                                  # Drop to lower percentile when congestion forces cap

[sell]
slippage = 200
max_block_difference = 5
nonce_delay = 25
panic_slippage = 2000

[sell.dynamic_fee]
percentile = 8500
fee_multiplier = 1.0
fee_cap = 800000

[sell.dynamic_tip]
percentile = 8500
tip_multiplier = 1.0
tip_floor = 0.003
tip_cap = 0.007
adaptive = true

[network]
rpc_url = "<your-rpc-url>"                       # Solana RPC endpoint (read-only) — leave empty to use the Zephyr-provided default
grpc_url = ""                                    # gRPC endpoint for real-time streaming (leave empty to use the Zephyr-provided default; Helius LaserStream NY/Frankfurt auto-picked by region)
grpc_token = ""                                  # Auth token for the gRPC endpoint (ignored when grpc_url is empty)
processor = "all"                                # "all" or a specific one: jito, helius, etc.

[network.node]
enabled = true                                   # Enable anonymous RPC sender
urls = [
    "http://rpc-slc1.thornode.io",
    "http://rpc-va-zesty.thornode.io",
    "http://rpc-ny.thornode.io",
    "https://rpc.shyft.to?api_key=<your-shyft-key>",
]                                                # Send endpoints. MUST NOT reuse network.rpc_url
buy_delay = 50
sell_delay = 50

[network.jito]
enabled = true
buy_delay = 100
sell_delay = 100
# Optional per-processor override. Empty = use Zephyr's default fan-out.
# Non-empty = exact list that fires (good for non-NY VPS — restrict to
# nearby regions). Available on every processor and each bifrost subprovider.
# endpoints = [
#   "https://frankfurt.mainnet.block-engine.jito.wtf",
#   "https://amsterdam.mainnet.block-engine.jito.wtf",
# ]

[network.nextblock]
enabled = true
buy_delay = 25
sell_delay = 25

[network.helius]
enabled = true
buy_delay = 25
sell_delay = 25

[network.zeroslot]
enabled = true
buy_delay = 25
sell_delay = 25

[network.nozomi]
enabled = true
buy_delay = 25
sell_delay = 25

[network.lunar]
enabled = true
buy_delay = 25
sell_delay = 25

[network.astralane]
enabled = true
buy_delay = 25
sell_delay = 25

[network.stellium]
enabled = true
buy_delay = 25
sell_delay = 25

[network.falcon]
enabled = true
buy_delay = 25
sell_delay = 25

[network.bifrost_bloxroute]
enabled = true
buy_delay = 50
sell_delay = 50

[network.bifrost_astralane]
enabled = false
buy_delay = 50
sell_delay = 50

[network.bifrost_blockrazor]
enabled = true
buy_delay = 100
sell_delay = 100

[network.bifrost_lunarlander]
enabled = false
buy_delay = 100
sell_delay = 100

# API keys live as array-of-tables. Each [[...api_keys]] adds one key with
# its own TPS budget. First-fit rotation; aggregate processor TPS = sum of
# per-key `tps` values. A send must clear BOTH the processor's
# buy_delay/sell_delay AND the selected key's `1000/tps`-ms interval.

[[network.jito.api_keys]]
api_key = "<your-jito-key>"
tps = 10

[[network.nextblock.api_keys]]
api_key = "<your-nextblock-key>"
tps = 50

[[network.helius.api_keys]]
api_key = "<your-helius-key>"
tps = 50

# Optional — Zephyr provides 40 TPS on 0slot by default, no api key
# required. Add your own here only if you need more capacity (it's used
# as spillover).
# [[network.zeroslot.api_keys]]
# api_key = "<your-zeroslot-key>"
# tps = 50

# Optional: Zephyr provides 40 TPS on Nozomi by default, no api key
# required. Add your own here only if you need more capacity (it's used
# as spillover).
# [[network.nozomi.api_keys]]
# api_key = "<your-nozomi-key>"
# tps = 50

# Optional — Zephyr provides a default Lunar key (TPS assigned per IP),
# no api key required. Add your own here only if you need more capacity
# (it's used as spillover).
# [[network.lunar.api_keys]]
# api_key = "<your-lunar-key>"
# tps = 50

[[network.astralane.api_keys]]
api_key = "<your-astralane-key>"
tps = 50

[[network.stellium.api_keys]]
api_key = "<your-stellium-key>"
tps = 50

# Optional — Zephyr provides 40 TPS on Falcon by default, no api key
# required. Add your own here only if you need more capacity (it's used
# as spillover).
# [[network.falcon.api_keys]]
# api_key = "<your-falcon-key>"
# tps = 50

[general]
private_key = "<your-base58-private-key>"                      # Set once; encrypted to wallet.enc + wallet.key on first start, then removed from this file
access_code = "<your-access-code>"                             # Required: bot refuses to start if empty. Use a long random string
fee_percentiles = [5500, 6500, 7000, 7500, 8000, 8500, 9000]   # Fee percentiles surfaced in the fee bar
tip_percentiles = [7000, 7500, 8000, 8500, 9000, 9800]         # Tip percentiles surfaced in the tip bar
debug = false                                                  # Verbose logging (set false in production if logs are noisy)
nonces = []                                                    # Nonce pubkeys (populated by --generate-nonces)

Now replace every <...> placeholder:

  • <your-base58-private-key>: your wallet's secret key (in Phantom: Settings → Security → Show Private Key). On first run Zephyr encrypts it into wallet.enc + wallet.key and removes the line from config.toml. Back up both files together — one without the other is useless.
  • <your-access-code>: any password; the extension types it to authenticate with the backend.
  • <your-rpc-url>: leave empty to use the Zephyr-provided default endpoint. To bring your own, paste the URL from your Helius dashboard.
  • grpc_url: leave empty to use the Zephyr-provided default endpoint (Helius LaserStream, with NY or Frankfurt auto-selected by your machine's location). To bring your own, paste the URL from your LaserStream/Shyft dashboard and put any auth token in grpc_token.
  • <your-shyft-key> and the per-processor <your-*-key> entries: paste the API key for each provider you have an account with. If you don't have a key for a processor, set enabled = false on its [network.<name>] section and leave its api_key alone.

See Configuration for the full field reference.

3. Generate nonce accounts

bash
./zephyr --generate-nonces 64

Pubkeys are appended to config.toml automatically. Rent is reclaimable; you get the SOL back when you're done.

4. Run it

bash
./zephyr

The backend is now listening on port 8080.

5. Install the extension

Install Zephyr from the Chrome Web Store, then:

  1. Click the Zephyr icon in the browser toolbar → Settings.
  2. Under Connection, set the WebSocket URL to ws://localhost:8080/ws (or ws://your-vps-ip:8080/ws for a remote server).
  3. Enter your access_code from config.toml.
  4. Open axiom.trade, gmgn.ai, or trade.padre.gg. The floating widget appears, and the dot turns green when connected.

See Extension Setup for full details.

6. Your first trade

Once the widget is connected:

  1. Fund the wallet: send some SOL to the wallet address shown in the widget.
  2. Set a mint: press A and paste a token's mint address, or press Ctrl+Alt+A on a token page to scrape it.
  3. Buy: press F1 for a 1 SOL buy. The bot waits until the price hits your entry_pct target (default: a 12% dip), then buys.
  4. Sell: after you're in a position, press 0 to lock the current price as your sell floor. The bot exits as soon as the pool is at or above that floor.
  5. Stop: press T to halt all bot activity.

See Usage for the full key reference.


Run 24/7 on a VPS

Install PM2 so the bot auto-starts on reboot:

bash
npm install -g pm2
pm2 start ./zephyr --name zephyr
pm2 startup
pm2 save

Open the firewall (allow SSH first so you don't lock yourself out):

bash
sudo ufw allow 22
sudo ufw allow 8080
sudo ufw enable

Point the extension at ws://your-vps-ip:8080/ws.

Updating

Stop the bot before overwriting the binary:

bash
pm2 stop zephyr
curl -O https://releases.solanazephyr.com/releases/latest/zephyr
chmod +x zephyr
pm2 start zephyr

Your config.toml and nonces are preserved.

Zephyr Docs

Enter the access code to continue.