Get started

Quickstart

Five minutes from a clean Linux host to a Tiyi instance blocking real OWASP CRS attacks against a real upstream. We'll install the signed binary, start tiyi run, create one site, and watch the WAF do its job.

Prerequisites

1. Install the signed binary

Use the canonical public installer. It selects the matching Linux release, verifies its SHA-256 manifest, and installs tiyi into /usr/local/bin:

$ curl -fsSL https://www.tiyisec.com/install.sh | bash
$ tiyi --version

See Installation for version pinning, install-prefix overrides, and the Gitee mirror.

Existing v3.4.0 or earlier installation? Do not continue with the new-install flow or restart after a generic update. First make a complete verified backup, then follow the v3.5.3 full-uninstall upgrade.

2. Run in complete runtime

Pick the option that matches your privileges. As root the defaults work — state lands in /var/lib/tiyi and the proxy binds ports 80/443:

$ sudo tiyi run

As a normal user (no sudo), point Tiyi at writable paths and high ports:

$ tiyi run \
    --state-db /tmp/tiyi.db \
    --caddy-admin-socket /tmp/tiyi-caddy.sock \
    --admin-socket /tmp/tiyi-admin.sock \
    --proxy-http-addr 127.0.0.1:18080 \
    --proxy-https-addr 127.0.0.1:18443

Tiyi prints a banner with the API URL, the bootstrap admin password (printed once on first run), and the Caddy admin socket path:

tiyi v3.5.3 run
  api      http://127.0.0.1:8080
  proxy    http://127.0.0.1:18080  https://127.0.0.1:18443
  state    /tmp/tiyi.db
  bootstrap admin password: <random-shown-once>

Open http://127.0.0.1:8080/ in a browser. Log in as admin with the password above. The console opens at Overview. Its stable task areas are Overview, Application Delivery, Protection, Fleet, Events & Logs, Detection & Response, Monitoring, and Administration; permission filtering hides empty groups without changing deep links.

The bootstrap password is shown exactly once. Copy it from the terminal. If it is lost, do not delete state.db: on the Tiyi host run tiyi user list, then tiyi user reset-password <user-id> --password <new> over the local admin socket.

Choose your own admin password (optional)

For automation, container images, or CI, skip the generated password: set TIYI_AUTH_BOOTSTRAP_ADMIN_PASSWORD before the first boot and Tiyi uses it verbatim — no banner is printed. The username defaults to admin, and auto-generation only fires when no users exist yet, so restarts are no-ops.

$ mkdir -p /tmp/waf
$ TIYI_AUTH_BOOTSTRAP_ADMIN_PASSWORD='admin123@xxxxxxm' \
    tiyi run \
    --addr 0.0.0.0:8080 \
    --state-db /tmp/waf/state.db \
    --caddy-admin-socket /tmp/waf/caddy.sock \
    --proxy-http-addr 0.0.0.0:8180 \
    --proxy-https-addr 0.0.0.0:18443 \
    --admin-socket /tmp/waf/admin.sock

3. Stand up a backend

In a second terminal, start something Tiyi can proxy to. Anything HTTP works — for the demo we'll use Python:

$ python3 -m http.server 9000

4. Create your first site

You can do this in the UI or via the CLI. The CLI uses the local admin socket and needs no token:

# 1. Create the site pointing at the demo server
$ tiyi site create \
    --name demo \
    --host demo.local \
    --upstream-url http://127.0.0.1:9000 \
    --tls none

# The site is active immediately after create.

The one-step path creates an upstream pool, uses the built-in Standard policy, translates the site into Caddy JSON, and hot-reloads Caddy through its admin socket. If anything fails, the previous config stays active and the site row is restored.

5. Verify the WAF blocks attacks

From a third terminal, send a baseline request and three classic attacks against the proxy port:

# Baseline — should pass
$ curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: demo.local" http://127.0.0.1:18080/
200

# SQL injection
$ curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: demo.local" \
    "http://127.0.0.1:18080/?id=1'%20OR%20'1'='1"
403

# XSS
$ curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: demo.local" \
    "http://127.0.0.1:18080/?q=<script>alert(1)</script>"
403

# Path traversal
$ curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: demo.local" \
    "http://127.0.0.1:18080/../../../../etc/passwd"
403

In the dashboard at http://127.0.0.1:8080/#/logs/security, the three blocked requests appear immediately with the Coraza rule id, severity, attack tag, and the matching CRS message. The dashboard's traffic chart shows the 1:3 baseline-to-block ratio in real time.

What to read next