Installation
Tiyi is distributed as a signed Linux binary. Install it from the public release channel, write a small YAML config, and start the complete Controller runtime or enroll a remote Agent.
Replacing v3.4.0 or earlier with v3.5.3 requires a destructive full uninstall. Stop the old service, make and verify a complete backup, run sudo tiyi uninstall --purge, then install a fresh v3.5.3 service and re-enroll every Agent. Do not restore the old database into v3.5. Follow the dedicated upgrade guide before installing.
Install the signed binary
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.5.3 linux/amd64
The script downloads the platform-matched binary, verifies its SHA-256 against the manifest, and drops it into /usr/local/bin/tiyi. It tries GitHub first and falls back to the Gitee release mirror; force Gitee with TIYI_MIRROR=gitee when needed:
$ curl -fsSL https://gitee.com/tiyisec/tiyi/raw/main/install.sh | TIYI_MIRROR=gitee bash
Installer environment overrides: TIYI_MIRROR=auto|github|gitee, TIYI_REPO=zzmzm/tiyi, TIYI_GITEE_REPO=tiyisec/tiyi, TIYI_VERSION=v3.5.3, and TIYI_PREFIX=/usr/local/bin.
Public distribution repos: GitHub zzmzm/tiyi and Gitee tiyisec/tiyi.
linux/amd64 and linux/arm64 are first-class targets. Install the signed release from the public channel independently on every Controller, Agent, and dashboard host before configuring its role.
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
server:
addr: "0.0.0.0:8080"
store:
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. This config uses /var/lib/tiyi and ports 80/443, so run it as root (or under the systemd unit below):
$ sudo tiyi run --config /etc/tiyi/tiyi.yaml || sudo /usr/local/bin/tiyi run --config /etc/tiyi/tiyi.yaml
To try Tiyi as a normal user without sudo, skip the config file and pass writable paths and high ports on the command line instead — see the Quickstart.
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.
Config environment variables
Prefer /etc/tiyi/tiyi.yaml for persistent service configuration. Use environment variables only when your service manager, container runtime, or secret manager injects config at runtime. Precedence is built-in defaults, then tiyi.yaml, then config environment variables, then explicit CLI flags.
Environment names mirror config keys: prefix TIYI_, uppercase the key, and replace dots with underscores. For example, auth.jwt_secret becomes TIYI_AUTH_JWT_SECRET.
Common config overrides
| Variable | Config key | When to use |
|---|---|---|
TIYI_SERVER_ADDR | server.addr | Bind the API/dashboard to a different address. |
TIYI_STORE_STATE_DB | store.state_db | Move the SQLite state database. |
TIYI_LOG_LEVEL | log.level | Temporarily raise or lower process logging. |
TIYI_PROXY_HTTP_ADDR | proxy.http_addr | Change the HTTP data-plane listen address. |
TIYI_PROXY_HTTPS_ADDR | proxy.https_addr | Change the HTTPS data-plane listen address. |
TIYI_PROXY_CADDY_ADMIN_SOCKET | proxy.caddy_admin_socket | Move the embedded Caddy admin socket. |
TIYI_CRYPTO_KEK_FILE | crypto.kek_file | Pin the at-rest encryption KEK path for production. |
TIYI_AUTH_JWT_SECRET | auth.jwt_secret | Set a stable JWT signing secret for production. |
TIYI_AUTH_BOOTSTRAP_ADMIN_USERNAME | auth.bootstrap_admin_username | Choose the first admin username. |
TIYI_AUTH_BOOTSTRAP_ADMIN_PASSWORD | auth.bootstrap_admin_password | Choose the first admin password for automation. |
TIYI_LICENSE_KEY_PATH | license.key_path | Load a signed license file on boot. |
TIYI_UPDATE_REPO | update.repo | Override the GitHub release repo used by update checks. |
TIYI_UPDATE_CHANNEL | update.channel | Use stable or prerelease for tiyi update. |
TIYI_UPDATE_MIRROR | update.mirror | Use auto, github, or gitee for update checks/downloads. |
Less common config keys follow the same rule, including auth.access_token_ttl, auth.refresh_token_ttl, auth.refresh_cookie_secure, auth.bootstrap_admin_email, auth.bootstrap_admin_name, auth.provider, auth.ldap.*, auth.radius.*, and update.api_base_url. Prefer YAML for these unless your deployment platform requires env injection.
Runtime commands
The same binary has one complete runtime and two focused processes:
run- The Controller, built-in local data plane, API, and admin UI in one writable process. This is the normal install and five-minute path.
agent- A remote data plane: Caddy + Coraza receiving signed config bundles from one Controller URL over a long-lived ConnectRPC stream.
dashboard- A UI-only process for a host that does not own state or proxy traffic.
Enrolling an agent
Open Nodes → Install, issue a token, then follow the separate binary-download and systemd instructions. The same page also shows the raw token, a foreground command, and a complete download-and-start script:
$ sudo curl -fsSL -o /usr/local/bin/tiyi 'https://tiyi.example.com/download/tiyi'
$ sudo chmod 0755 /usr/local/bin/tiyi
$ sudo mkdir -p /etc/tiyi
$ printf 'TIYI_CONTROLLER_URL=https://tiyi.example.com\nTIYI_AGENT_ENROLLMENT_TOKEN=<one-use-token>\n' | sudo tee /etc/tiyi/tiyi-agent.env >/dev/null
$ sudo chmod 0600 /etc/tiyi/tiyi-agent.env
$ sudo tiyi install --mode agent --unit-name tiyi-agent --now
Lose the state directory and you'll need a fresh token to re-enroll.
Run as a systemd service
For a long-lived deployment, let Tiyi install itself as a hardened systemd service. tiyi install creates the tiyi service user and the tiyi-admin socket group, writes the unit, and with --now enables and starts it on boot:
$ sudo tiyi install --now
Running sudo tiyi install without --now intentionally leaves the unit disabled and stopped so you can finish mode-specific configuration. For the first Controller start, re-run the same install command with --now added; do not start the unit directly with systemctl. The installer can then create the administrator first and print the one-time login here instead of sending the password to the system journal.
The service runs unprivileged and binds ports 80/443 via CAP_NET_BIND_SERVICE. Before each start, a root-only pre-start hook re-owns the configured state directory and KEK file for the service user, so CRS caches, uploads, exclusion packages, release staging, logs, trust snapshots, and embedded-agent state left by a prior sudo foreground run cannot block runtime writes. On a first install, --now pre-creates the administrator and prints the one-time login itself — no journal scraping:
tiyi is enabled and running as tiyi.service.
Tiyi administrator created
URL: http://127.0.0.1:8080
username: admin
password: <generated-password>
This password is shown once; change it after signing in.
Preview the generated unit without touching the system using tiyi install --print. Its key directives:
# /etc/systemd/system/tiyi.service
[Service]
Type=simple
User=tiyi
Group=tiyi
PermissionsStartOnly=true
ExecStartPre=/usr/local/bin/tiyi systemd-prestart --config /etc/tiyi/tiyi.yaml --user tiyi --group tiyi
ExecStart=/usr/local/bin/tiyi run --config /etc/tiyi/tiyi.yaml --admin-socket /run/tiyi/admin.sock --admin-socket-group tiyi-admin --admin-socket-mode 0660 --caddy-admin-socket /run/tiyi/caddy.sock
Restart=on-failure
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
StateDirectory=tiyi
RuntimeDirectory=tiyi
ConfigurationDirectory=tiyi
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Run tiyi doctor to check sudo PATH, systemd, config loading, installed-service state ownership, and listeners on ports 80/443/8080. If no systemd unit is installed, state ownership is skipped unless you pass --service-user/--service-group or request repair. If it warns that sudo cannot find tiyi, use the printed full-path command or add /usr/local/bin to sudo secure_path. If it reports root-owned state, repair it explicitly with sudo tiyi doctor --fix-state-ownership. If it reports a port conflict, either stop the owning service or move Tiyi with proxy.http_addr, proxy.https_addr, or server.addr. Select --mode run for the Controller or --mode agent for a remote data plane. Remove the service with sudo tiyi uninstall: state under /var/lib/tiyi, config under /etc/tiyi, and the service user are preserved unless you add --purge.
What to read next
- Domain model — what sites, upstreams, certs, policies, and agents are.
- CLI reference — current v3.5.3 operator commands grouped by resource.
- Deployment — production hardening, remote Agents, outage boundaries, and SIEM egress.