# Install without the script

Verify the signed seller image yourself and set up the same Docker seller by hand.

Source: https://docs.gyblos.com/en/sellers/manual-install

The [installer](/en/sellers/beta-guide) does all of this for you. Use this page to check the image
signature yourself, or to set up the same seller step by step and keep full control of each file.

## Find the current release

Each installer pins one release of the seller image by version and digest. `gyblos.com/install.sh` serves
the installer attached to the latest [GitHub release](https://github.com/Gyblos/gyblos-node/releases/latest),
which also lists the image. Read it from the installer:

```sh
curl -fsSL https://gyblos.com/install.sh | grep '^DEFAULT_IMAGE='
```

It prints a line such as `DEFAULT_IMAGE=ghcr.io/gyblos/seller:0.1.0-beta.3@sha256:…`. Below,
replace `VERSION@sha256:DIGEST` with the part after `ghcr.io/gyblos/seller:`.

## Verify the image signature

Every release is built and signed by the Gyblos release workflow on GitHub, with no long-lived key: the
signature names that workflow at a version tag and is recorded in the public Sigstore log. Install
[cosign](https://docs.sigstore.dev/cosign/system_config/installation/) version 3 or later and verify the image:

```sh
cosign verify ghcr.io/gyblos/seller:VERSION@sha256:DIGEST \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github\.com/Gyblos/gyblos-node/\.github/workflows/release-seller-image\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$'
```

A verified image prints the signature details and exits without error. If verification fails, do not
run that image; report the image line through your invitation channel. The installer runs the same
check when cosign is installed and prints `Verified the Gyblos release signature`.

## Set up the seller by hand

Create a private folder:

```sh
mkdir -p ~/gyblos-seller && chmod 700 ~/gyblos-seller
```

Save this as `~/gyblos-seller/compose.yaml`, with your release in the seller `image:` line:

```yaml
# A seller with its own Ollama. Setup and use: docs/running-a-node.md#docker.
# The seller shares Ollama's network namespace because the Ollama engine accepts only a literal loopback
# URL; Ollama listens on 127.0.0.1 there and no port is published. Iroh connects outbound only.
services:
  ollama:
    image: ollama/ollama:0.40.0
    environment:
      OLLAMA_HOST: 127.0.0.1:11434
      OLLAMA_NO_CLOUD: '1'
      OLLAMA_NUM_PARALLEL: '1'
      OLLAMA_MAX_LOADED_MODELS: '1'
    volumes:
      - ollama:/root/.ollama
    restart: unless-stopped

  seller:
    image: ghcr.io/gyblos/seller:VERSION@sha256:DIGEST
    network_mode: service:ollama
    # A restarted Ollama gets a new network namespace; compose then restarts the seller into it.
    depends_on:
      ollama:
        condition: service_started
        restart: true
    # Forwards stop signals to the daemon even during startup, before it installs its own handler.
    init: true
    # GYBLOS_RELAY_TOKEN and any api_key_env variables, NAME=value per line; keep it private.
    env_file:
      - ./seller.env
    volumes:
      - gyblos:/data
      - type: bind
        source: ./gyblos.toml
        target: /config/gyblos.toml
        read_only: true
        bind:
          create_host_path: false
    # Startup needs 1.5 GiB of memory headroom above the seller itself.
    mem_limit: 2g
    cpus: 1.0
    stop_grace_period: 120s
    restart: unless-stopped

volumes:
  ollama:
  gyblos:
```

Save this as `~/gyblos-seller/gyblos.toml`:

```toml
# The seller daemon in Docker (compose.yaml): the pinned Qwen3 0.6B with reasoning off on the compose
# Ollama, given away free within daily token caps. Copy it next to compose.yaml as gyblos.toml; the seller
# shares Ollama's network namespace, so 127.0.0.1:11434 is that Ollama (docs/running-a-node.md#docker).
# Free by default. To charge, give an offer `price = {...}` instead of `free` (docs/configuration.md) and
# fund the fee payer `gyblos doctor` prints with devnet SOL.

version = 1

[node]
network = "devnet"

[discovery]
# Off so a test node is not listed by accident; set publish = true to appear in discovery.
publish = false

# Optional capacity limits; omitted keys keep these defaults (docs/configuration.md#seller-limits).
# [limits]
# max_connections = 8
# requests_per_minute = 30

[[offers]]
model = "qwen3:0.6b"
reasoning = ["off"]
engine = { kind = "ollama", url = "http://127.0.0.1:11434/" }
free = { daily_token_cap = 200000, per_buyer_cap = 50000 }
```

Create `~/gyblos-seller/seller.env` readable only by you (`chmod 600`), and in a private editor write one
line: the variable name `GYBLOS_RELAY_TOKEN`, an equals sign and your relay token, with no spaces or
quotes. The token is 32 to 512 printable characters, with no shell characters such as `$`, quotes or `#`. Never print that file or paste it into a terminal command.

Then pull the images and the model, create the keys, install the tokenizer, check and start:

```sh
cd ~/gyblos-seller
docker compose pull
docker compose up -d ollama
until docker compose exec -T ollama ollama list >/dev/null 2>&1; do sleep 2; done
docker compose exec -T ollama ollama pull qwen3:0.6b
docker compose run --rm seller setup --role seller --mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
docker compose run --rm seller tokenizer
docker compose run --rm seller gyblos doctor && docker compose up -d --force-recreate seller
```

The wait line returns once Ollama answers; if it keeps waiting, stop it with Ctrl+C and read
`docker compose logs ollama` privately. The last line starts the seller only when `gyblos doctor` reports
no failures; otherwise fix the named cause and run that line again. Continue with the
[status check](/en/sellers/beta-guide#confirm-the-service-state) and
[registration](/en/sellers/register-publish).
