Get started

Installation

Tiyi is a single Go binary. Pick a build path, drop the binary on your host, write a small YAML config, and choose the operational mode that matches the role this host should play in the cluster.

Build from source

From a fresh checkout of the Tiyi repo:

$ make proto       # regenerate Connect Go + Protobuf Go from proto/
$ make web         # build the Vben Admin frontend into web/dist/
$ make build       # compile bin/tiyi with the frontend embedded

For a release artifact, use the guarded one-shot target. It refuses a dirty worktree, verifies the embedded vendor-license public-key fingerprint, rebuilds proto/frontend outputs, and produces the same single binary:

$ make release

Build inputs:

Prebuilt binaries

Tiyi is one signed binary — free and full-featured on a single node. The canonical install script is published at https://www.tiyisec.com/install.sh:

$ curl -fsSL https://www.tiyisec.com/install.sh | bash
$ tiyi --version
tiyi v3.0.0-rc.1-57-gf297a22 linux/amd64

The script downloads the platform-matched binary, verifies its SHA-256 against the manifest, and drops it into /usr/local/bin/tiyi. linux/amd64 and linux/arm64 are first-class targets.

Bootstrap an agent from a running server

A running Tiyi server exposes GET /download/tiyi, an unauthenticated endpoint that streams the running binary. Use it to bootstrap agents on fresh machines:

$ curl -fsSL -o /usr/local/bin/tiyi http://primary:8080/download/tiyi
$ chmod +x /usr/local/bin/tiyi

For cross-platform downloads, append ?os=linux&arch=arm64 to serve an imported binary release instead of the running binary.

Config file

Tiyi reads a Koanf-based YAML config. Start from this minimal config and let the defaults handle the rest:

# /etc/tiyi/tiyi.yaml
api:
  addr: "0.0.0.0:8080"

storage:
  state_db: "/var/lib/tiyi/state.db"

crypto:
  kek_file: "/etc/tiyi/kek.bin"      # 32-byte at-rest encryption key

auth:
  jwt_secret: "<32+ random bytes>"      # HS256 signing secret

proxy:
  http_addr:  ":80"
  https_addr: ":443"
  caddy_admin_socket: "/var/lib/tiyi/caddy-admin.sock"

Pass it with --config:

$ tiyi standalone --config /etc/tiyi/tiyi.yaml

Two fields are mandatory before going live. crypto.kek_file and auth.jwt_secret have dev-friendly fallbacks that explicitly do not survive a restart. See Deployment → Production hardening for the contract.

Operational modes

The same binary exposes five subcommands. Pick the one that matches the host's role:

standalone
Master + agent in one process. Default for single-host installs. Mutations RW; data plane proxies on the same node. Five-minute install path.
server
Cluster control-plane leader plus its own embedded agent. Accepts agent registrations, serves the API and dashboard, proxies traffic.
secondary
Warm CP replica plus its own embedded agent. Read-only API, proxies traffic, gets promoted manually on failover with tiyi promote.
agent
Pure data plane: Caddy + Coraza receiving signed config bundles from the primary over a long-lived gRPC stream. No CP responsibility.
dashboard
UI-only mode for split deployments where the dashboard host doesn't proxy traffic.

Enrolling an agent

Agents enroll with a one-use token issued by the primary. From the primary host:

$ TOKEN="$(tiyi agents issue-token --tag edge-c | jq -r .token)"

On the agent host, with the binary already in place:

$ tiyi agent \
    --api http://primary:8080 \
    --enrollment-token "$TOKEN" \
    --state-dir /var/lib/tiyi/agent \
    --proxy-http-addr 0.0.0.0:80 \
    --proxy-https-addr 0.0.0.0:443

The token is consumed on first contact. After enrollment, the agent persists its identity in <state-dir>/identity.json and the token is no longer needed. Lose the state directory and you'll need a fresh token to re-enroll.

systemd unit

For a long-lived deployment, run Tiyi under your init system. A minimal systemd unit:

# /etc/systemd/system/tiyi.service
[Unit]
Description=Tiyi WAF
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=tiyi
Group=tiyi
ExecStart=/usr/local/bin/tiyi server --config /etc/tiyi/tiyi.yaml
Restart=on-failure
RestartSec=2s
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/tiyi /etc/tiyi
ProtectHome=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

What to read next