feat(install): license bundle approach — --license-file replaces pubkey fetch

Remove auto-fetching pubkey from license server. Instead the vendor ships
a bundle (license.lic + pubkey) and the installer reads both files from
the same directory. Works for both online and air-gapped deployments.
--license-server-url is now optional (heartbeats only, not required to start).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
amir-climy 2026-05-19 23:29:19 +08:00
parent bbdc8aa292
commit 9780ee3601
3 changed files with 60 additions and 36 deletions

View file

@ -4,31 +4,39 @@ Production installer for the Triton Manage Server. Container-based (Docker or Po
## Install
```bash
curl -fsSL https://raw.githubusercontent.com/primatekuntech/triton-install/main/get.sh | sudo bash
Your vendor provides a licence bundle — a folder containing two files:
```
triton-bundle/
├── license.lic # signed offline licence token
└── pubkey # vendor's Ed25519 public key
```
That's it. The setup wizard walks you through the rest.
Point the installer at the bundle:
```bash
curl -fsSL https://raw.githubusercontent.com/primatekuntech/triton-install/main/get.sh | sudo bash -s -- --license-file /path/to/triton-bundle/license.lic
```
## Setup wizard
After install, open `http://localhost:8082` and complete the wizard:
1. Set your manage server name
2. Enter your Triton licence server URL and licence ID — or upload an air-gap licence file
3. Create the admin account
2. Create the admin account
## Optional flags
Pass flags after `--`:
```bash
curl -fsSL https://raw.githubusercontent.com/primatekuntech/triton-install/main/get.sh | sudo bash -s -- [flags]
curl -fsSL https://raw.githubusercontent.com/primatekuntech/triton-install/main/get.sh | sudo bash -s -- --license-file /path/to/license.lic [flags]
```
| Flag | Description |
|------|-------------|
| `--license-server-url URL` | Vendor's License Server URL. Public key is fetched automatically. |
| `--license-file PATH` | Path to `license.lic` from your vendor bundle. **Required.** |
| `--license-server-url URL` | License Server URL for ongoing heartbeats (optional, omit for air-gap). |
| `--gateway-hostname HOST` | Agent mTLS hostname (defaults to current FQDN). |
| `--manage-host-ip IP` | Host LAN IP for "+ This machine" auto-registration. |
| `--port PORT` | Host port for the web UI (default: `8082`). |

View file

@ -54,12 +54,17 @@ TLS_CERT_HOST_DIR=/etc/triton/tls
# ─── Sessions ────────────────────────────────────────────────────────────
TRITON_MANAGE_SESSION_TTL=24h
# ─── License server ──────────────────────────────────────────────────────
# Vendor's Ed25519 public key (64 hex chars). Required — get this from
# your Triton vendor. The manage server refuses to start without it.
# ─── Licence ─────────────────────────────────────────────────────────────
# Offline licence token from your vendor bundle (license.lic). Set by
# install.sh automatically — do not edit manually.
TRITON_LICENSE_KEY=
# Vendor's Ed25519 public key (64 hex chars). Set by install.sh from the
# pubkey file in your vendor bundle — do not edit manually.
TRITON_MANAGE_LICENSE_SERVER_PUBKEY=
# Vendor's License Server URL. Required for activation and heartbeat.
# Vendor's License Server URL. Optional — enables ongoing heartbeats and
# binary sync. Leave empty for fully air-gapped deployments.
TRITON_LICENSE_SERVER_URL=
# ─── Image ───────────────────────────────────────────────────────────────

View file

@ -5,11 +5,16 @@
# Container-based via Podman or Docker (auto-detected).
#
# Usage:
# sudo bash install.sh
# sudo bash install.sh --license-file /path/to/bundle/license.lic
#
# Flags (all optional):
# --license-server-url URL Vendor's License Server URL. The public key is
# fetched automatically from the license server.
# The license bundle (provided by your vendor) contains two files:
# license.lic — signed offline licence token
# pubkey — vendor's Ed25519 public key (64 hex chars)
# Both files must be in the same directory.
#
# Flags:
# --license-file PATH Path to license.lic from your vendor bundle. Required.
# --license-server-url URL License Server URL for ongoing heartbeats (optional).
# --gateway-hostname HOST Agent mTLS hostname (defaults to current FQDN).
# --manage-host-ip IP Host LAN IP — used for "+ This machine".
# --port PORT Host port for the web UI (default: 8082).
@ -24,6 +29,7 @@ info() { printf '[manage-server] %s\n' "$*"; }
die() { printf '[manage-server] error: %s\n' "$*" >&2; exit 1; }
# ── arg parsing ──────────────────────────────────────────────────────────
LICENSE_FILE=""
LICENSE_SERVER_URL=""
GATEWAY_HOST=""
HOST_IP=""
@ -32,6 +38,7 @@ IMAGE=""
NO_TLS=0
while [[ $# -gt 0 ]]; do
case "$1" in
--license-file) LICENSE_FILE="$2"; shift 2 ;;
--license-server-url) LICENSE_SERVER_URL="$2"; shift 2 ;;
--gateway-hostname) GATEWAY_HOST="$2"; shift 2 ;;
--manage-host-ip) HOST_IP="$2"; shift 2 ;;
@ -45,6 +52,18 @@ done
[[ $EUID -eq 0 ]] || die "must run as root"
# ── validate license bundle ──────────────────────────────────────────────
[[ -n "$LICENSE_FILE" ]] || die "--license-file is required (path to license.lic from your vendor bundle)"
[[ -f "$LICENSE_FILE" ]] || die "license file not found: $LICENSE_FILE"
BUNDLE_DIR="$(cd -- "$(dirname -- "$LICENSE_FILE")" && pwd)"
PUBKEY_FILE="$BUNDLE_DIR/pubkey"
[[ -f "$PUBKEY_FILE" ]] || die "pubkey file not found: $PUBKEY_FILE (must be in the same directory as license.lic)"
LICENSE_TOKEN="$(cat "$LICENSE_FILE")"
LICENSE_PUBKEY="$(cat "$PUBKEY_FILE" | tr -d '[:space:]')"
[[ ${#LICENSE_PUBKEY} -eq 64 ]] || die "pubkey file must contain a 64 hex-char Ed25519 public key"
# ── runtime detection ────────────────────────────────────────────────────
if command -v podman-compose >/dev/null 2>&1; then
COMPOSE=(podman-compose)
@ -78,19 +97,15 @@ if [[ ! -f "$ENV_FILE" ]]; then
-e "s|^TRITON_MANAGE_WORKER_KEY=.*|TRITON_MANAGE_WORKER_KEY=$WORKER_KEY|" \
-e "s|^TRITON_VAULT_KEY=.*|TRITON_VAULT_KEY=$VAULT_KEY|" \
"$ENV_FILE"
info "vault key generated (PostgreSQL AES-256-GCM)"
info "secrets generated"
if [[ -n "$LICENSE_SERVER_URL" ]]; then
sed -i "s|^TRITON_LICENSE_SERVER_URL=.*|TRITON_LICENSE_SERVER_URL=$LICENSE_SERVER_URL|" "$ENV_FILE"
info "fetching public key from license server..."
LICENSE_PUBKEY=$(curl -fsSL "${LICENSE_SERVER_URL}/api/v1/license/pubkey" \
| grep -o '"pubkey":"[^"]*"' | cut -d'"' -f4) \
|| die "failed to fetch public key from ${LICENSE_SERVER_URL}"
[[ ${#LICENSE_PUBKEY} -eq 64 ]] \
|| die "license server returned an invalid public key (expected 64 hex chars)"
sed -i "s|^TRITON_MANAGE_LICENSE_SERVER_PUBKEY=.*|TRITON_MANAGE_LICENSE_SERVER_PUBKEY=$LICENSE_PUBKEY|" "$ENV_FILE"
info "public key configured"
fi
sed -i \
-e "s|^TRITON_MANAGE_LICENSE_SERVER_PUBKEY=.*|TRITON_MANAGE_LICENSE_SERVER_PUBKEY=$LICENSE_PUBKEY|" \
-e "s|^TRITON_LICENSE_KEY=.*|TRITON_LICENSE_KEY=$LICENSE_TOKEN|" \
"$ENV_FILE"
info "licence configured"
[[ -n "$LICENSE_SERVER_URL" ]] && sed -i "s|^TRITON_LICENSE_SERVER_URL=.*|TRITON_LICENSE_SERVER_URL=$LICENSE_SERVER_URL|" "$ENV_FILE"
[[ -n "$GATEWAY_HOST" ]] && sed -i "s|^TRITON_MANAGE_GATEWAY_HOSTNAME=.*|TRITON_MANAGE_GATEWAY_HOSTNAME=$GATEWAY_HOST|" "$ENV_FILE"
[[ -n "$HOST_IP" ]] && sed -i "s|^TRITON_MANAGE_HOST_IP=.*|TRITON_MANAGE_HOST_IP=$HOST_IP|" "$ENV_FILE"
[[ -n "$PORT" ]] && sed -i "s|^TRITON_MANAGE_HOST_PORT=.*|TRITON_MANAGE_HOST_PORT=$PORT|" "$ENV_FILE"
@ -117,7 +132,6 @@ HOST_PORT=${HOST_PORT:-8082}
info "waiting for manage server to become healthy on :${HOST_PORT}..."
for i in $(seq 1 30); do
CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/" || echo "000")
# 302 (redirect to setup or login) means the server is up.
if [[ "$CODE" == "302" || "$CODE" == "200" ]]; then
info "manage server is up"
break
@ -128,9 +142,6 @@ done
info ""
info "Installation complete. Next steps:"
info " 1. Open http://localhost:${HOST_PORT} (or your public URL)"
info " 2. Complete the setup wizard:"
info " - Set your manage server name"
info " - Enter your Triton licence server URL and licence ID"
info " - Or upload an air-gap licence file"
info " 2. Complete the setup wizard"
info " 3. Configure TLS via reverse proxy (see docs)"
info ""