# Overview

Source: https://docs.gryt.chat/docs/cli

gryt, the terminal manager for self-hosted Gryt servers

`gryt` creates and runs self-hosted Gryt servers from a terminal. Run it with no
arguments and it opens a keyboard-driven manager: create a server profile, edit
its settings with validation, and start, stop or inspect the Docker deployment
it writes for you.

## Install

```bash
curl -fsSL https://get.gryt.chat | sh
```

The script picks the build for your platform, checks it against the release
checksums, and installs to `/usr/local/bin` if that is writable or
`~/.local/bin` if not. Two variables change what it does:

| Variable | Effect |
|----------|--------|
| `GRYT_VERSION` | Install a specific tag, such as `v0.1.0`, instead of the newest release |
| `GRYT_INSTALL_DIR` | Install somewhere other than the default |

The script does not cover Windows. Download the `.zip` from the
[releases page](https://github.com/Gryt-chat/cli/releases) instead.

From source, with Go 1.25 or newer:

```bash
go install github.com/Gryt-chat/cli/cmd/gryt@latest
```

Starting a deployment needs Docker Desktop, or Docker Engine with the Compose
plugin. Creating profiles and writing their files works without Docker.

## Features

- **Server profiles**: named local servers, each with its own settings, data directory and generated Compose file
- **Validated settings**: ports, bind addresses, voice seats and proxy hops are checked as you type rather than when the container fails to start
- **Security presets**: `strict`, `balanced` and `community`, which set the identity tiers and discoverability together
- **Deployment control**: start, stop, restart, health and recent logs, without leaving the manager
- **Live and restart labels**: every setting says whether saving it takes effect now or needs a restart
- **Private storage**: profiles and generated `.env` files live in your user config directory, readable only by you
- **Scriptable output**: `gryt list` and `gryt env` print plain text for use outside the manager

## Using the manager

```bash
gryt
```

| Key | Action |
|-----|--------|
| `↑` `↓` or `k` `j` | Select a server |
| `n` | New server wizard |
| `e` | Edit the selected server |
| `s` | Start |
| `x` | Stop |
| `r` | Restart |
| `l` | Recent logs |
| `g` | Refresh health |
| `q` | Quit |

## The wizard

Press `n` for a new server, or `e` to edit one. `Enter` advances and saves on
the last step, `Shift+Tab` goes back, `←` and `→` change a choice, and `Esc`
cancels.

| Step | Setting | Default | Notes |
|------|---------|---------|-------|
| 1 | Server name | none | Required. Also becomes the profile ID, lowercased and hyphenated |
| 2 | Bind address | `0.0.0.0` | Reachable from other machines. Use `127.0.0.1` to keep it on this one |
| 3 | Port | `5000` | The port Docker publishes and clients connect to |
| 4 | Security level | `balanced` | See the table below |
| 5 | Voice seats | `0` | No limit, matching the server's own default. See below |
| 6 | Trusted proxy hops | `0` | Set to `1` behind one reverse proxy or tunnel |
| 7 | SFU WebSocket URL | empty | Voice stays unavailable until this points at a running SFU |
| 8 | Storage backend | `filesystem` | `filesystem` or `s3`. Choosing `s3` adds six more steps |

Choosing `s3` asks for the object store next. These six only appear for that
backend, and they cover every variable the server reads:

| Step | Setting | Default | Notes |
|------|---------|---------|-------|
| 9 | S3 endpoint | none | Full URL of the S3 API. Must start with `http://` or `https://` |
| 10 | Bucket | `gryt` | Has to exist already. Gryt does not create it |
| 11 | Region | `auto` | Works for MinIO and most S3-compatible services |
| 12 | Access key ID | none | Needs read and write access to the bucket |
| 13 | Secret access key | none | Typed behind asterisks, and masked in `gryt env` |
| 14 | Path-style addressing | `true` | On for MinIO and most self-hosted gateways, off for AWS |

Switching an existing server back to `filesystem` clears these, so credentials
do not stay in the file for a backend nothing is using.

### Security levels

Every level is invite-only. What changes between them is who may hold an
identity on the server, and whether the server advertises itself over mDNS on
the local network.

| Level | Identities | LAN discovery |
|-------|-----------|---------------|
| `strict` | Gryt accounts only | Not advertised |
| `balanced` | Gryt accounts only | Advertised |
| `community` | Gryt accounts and local identities | Advertised |

A **Gryt account** is an identity from [auth.gryt.chat](https://docs.gryt.chat/docs/guide/accounts)
that works across servers. A **local identity** is a keypair generated on the
device, which never leaves it and is known only to this server. Allowing local
identities means somebody can join without an account anywhere.

**LAN discovery** is mDNS advertising, so a Gryt client on the same network
lists the server without being given its address. Turning it off stops the
advertisement; it is not an access control, since an invite still works either
way.

### Voice seats

`0`, the default, means no cap, which is what the server does on its own.

A cap is about the machine running the SFU, not about ports. With
`ICE_UDP_MUX_PORT` set, which is the recommended arrangement, every participant
shares one UDP port, so there is no per-person port to run out of. What runs
out first is CPU and upload bandwidth.

## Commands

| Command | What it does |
|---------|--------------|
| `gryt` | Open the manager |
| `gryt doctor` | Check Docker and the config directory, and say what to fix. Exits non-zero when something is wrong |
| `gryt list` | Print each server's ID, address and name |
| `gryt env <server>` | Print the server's settings, each marked `live` or `restart`. Secrets are masked |
| `gryt version` | Print the CLI version |
| `gryt help` | Print usage |

## Where things live

Profiles go in your user config directory, under `gryt/servers/<id>/`:

| Platform | Path |
|----------|------|
| macOS | `~/Library/Application Support/gryt` |
| Linux | `~/.config/gryt` |
| Windows | `%AppData%\gryt` |

Set `GRYT_CONFIG_DIR` to put them somewhere else.

Each server directory holds `profile.json`, a generated `.env`, a generated
`compose.yaml`, and a `data/` directory mounted into the container. The
directory is created readable only by your user, and `.env` is written the same
way, because it can hold secrets.

Both generated files carry a header saying they are managed by `gryt`. Editing
them by hand works, but the next save from the manager overwrites them.

## What gets generated

`compose.yaml` defines a single service: the Gryt server, from
`ghcr.io/gryt-chat/server:latest`, published on the address and port you chose,
with `data/` mounted at `/data` and a health check against `/health`. Starting
it runs `docker compose up --detach`, and the manager reads the same `/health`
endpoint to show whether a server is up.

<Callout type="warn" title="The generated deployment is the server alone">
It contains no SFU, no object storage and no image worker. In practice:

Voice does not work out of the box. Run an [SFU](https://docs.gryt.chat/docs/sfu) yourself and put its
WebSocket URL in step 7 of the wizard.

Uploads do work, either on the filesystem or against an S3 store you already
have, but nothing here builds one for you.

For a deployment with every component wired together, use
[Docker Compose](https://docs.gryt.chat/docs/deployment/docker-compose) instead.
</Callout>

<Callout title="Live settings still need a restart today">
Settings marked `live` are ones that belong in the server's own database rather
than its environment. The label tells you which is which. Applying them without
a restart needs a local management API in the server, which does not exist yet,
so for now every change takes effect on restart.
</Callout>
