Keystone Gateway

Install a standalone Gateway on Linux

This guide installs Particle Horizon keystone-gateway on Linux from the .tar.gz release archive.

Complete host preparation first, and obtain the archive for the host architecture, a signed license, and a 32-byte state-key file. This procedure uses a private HTTP listener only to provide a copyable minimal installation; use HTTPS/mTLS for traffic beyond a tightly controlled host or network.

Supported Linux architectures

Release archives are produced for:

Supported Linux architectures
ArchitectureArchive suffix
AMD64 / x86-64Linux_x86_64.tar.gz
ARM64 / AArch64Linux_arm64.tar.gz

The archive contains the following runtime layout:

particle_horizon/
├── SOFTWARE/
│   └── keystone-gateway-<version>-linux-<arch>/
│       ├── BUILD_INFO.txt
│       ├── THIRDPARTY_NOTICES
│       └── bin/
│           └── keystone-gateway
├── keystone-gateway --> SOFTWARE/keystone-gateway-<version>-linux-<arch>/bin/keystone-gateway
├── local_config/
│   └── keystone-gateway/
│       └── gateway.yaml
├── local_data/
│   └── keystone-gateway/
└── logs/
    └── keystone-gateway/

The intended installation root on Linux is:

/opt/particle_horizon

Confirm the host architecture with:

uname -m

Typical results are x86_64 or aarch64.

Procedure

1. Extract the archive

Create a temporary extraction directory and unpack the release:

INSTALL_TMP="$(mktemp -d)"
tar -xzf "${ARCHIVE}" -C "${INSTALL_TMP}"
find "${INSTALL_TMP}/particle_horizon" -maxdepth 4 -print

2. Create the service account

sudo groupadd --system keystone-gateway
sudo useradd \
  --system \
  --gid keystone-gateway \
  --home-dir /opt/particle_horizon \
  --shell /usr/sbin/nologin \
  keystone-gateway

If the account already exists, useradd reports that condition and no further action is required.

3. Install the Gateway

Copy the extracted particle_horizon tree into the installation root:

sudo mkdir -p /opt/particle_horizon
sudo cp -a "${INSTALL_TMP}/particle_horizon/." /opt/particle_horizon/

The Gateway is now available through the stable path, which points at the binary beneath the version-specific SOFTWARE directory:

/opt/particle_horizon/keystone-gateway version

4. Set ownership and install the state key

The archive supplies local_config, local_data, and logs. Configuration holds secret material, so keep it owned by root and readable only by the service group; state, report, and log directories are written by the service account. Replace PATH/TO/... with transferred release material; do not generate or echo a key in a shell history.

sudo chown -R root:keystone-gateway /opt/particle_horizon/local_config/keystone-gateway
sudo chmod 0750 /opt/particle_horizon/local_config/keystone-gateway
sudo chmod 0640 /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml
sudo install -d -o keystone-gateway -g keystone-gateway -m 0700 \
  /opt/particle_horizon/local_data/keystone-gateway/state \
  /opt/particle_horizon/local_data/keystone-gateway/reports
sudo chown -R keystone-gateway:keystone-gateway /opt/particle_horizon/logs/keystone-gateway
sudo chmod 0750 /opt/particle_horizon/logs/keystone-gateway
sudo install -o root -g keystone-gateway -m 0640 PATH/TO/gateway-state-key \
  /opt/particle_horizon/local_config/keystone-gateway/state.key

5. Configure the Gateway

The archive installs a default configuration at /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml. Edit it in place for the environment, replacing gw-acme-production, gateway-a, and the address with your values. A minimal standalone configuration looks like this:

gateway_id: gw-acme-production
api:
  http:
    enabled: true
    listen: "127.0.0.1:8080"
    advertise_url: "http://gateway-a.internal:8080"
    allow_insecure_http: true
  auth:
    mode: none
    principal_id: local-operator
    allowed_license_type: phocol
    operator: true
storage:
  directory: /opt/particle_horizon/local_data/keystone-gateway/state
  encryption_key_file: /opt/particle_horizon/local_config/keystone-gateway/state.key
license: { file: /opt/particle_horizon/local_config/keystone-gateway/gateway-license.json }
ha: { enabled: false, replica_id: gateway-a, bootstrap_expect: 1, peer_loss_timeout_seconds: 5 }
leases: { default_ttl_seconds: 120, min_ttl_seconds: 30, max_ttl_seconds: 300, max_clock_skew_seconds: 5, expiry_sweep_seconds: 15 }
reports: { directory: /opt/particle_horizon/local_data/keystone-gateway/reports, retention_days: 90 }
logging: { level: info, format: json }

This minimal none-mode example creates one shared principal authorized only for PHOCOL leases. It cannot also authorize LMC Exporter leases. To distinguish installations or serve both product types, replace the fixed api.auth fields with the mTLS or bearer multi-principal setup in configuration examples.

6. Install the license and validate

Retrieve the identity as described in licensing, obtain the license, and install it mode 0600 owned by the service account. Validate the resolved configuration:

sudo /opt/particle_horizon/keystone-gateway config validate \
  --config /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml

Expected result: configuration is valid: /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml.

7. Install the systemd service

Create /etc/systemd/system/keystone-gateway.service:

sudo tee /etc/systemd/system/keystone-gateway.service >/dev/null <<'EOF'
[Unit]
Description=Particle Horizon Keystone Gateway
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/opt/particle_horizon/keystone-gateway serve --config /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml
Restart=on-failure
Type=simple
User=keystone-gateway
Group=keystone-gateway
WorkingDirectory=/opt/particle_horizon

[Install]
WantedBy=multi-user.target
EOF

Reload systemd, then start and enable the service:

sudo systemctl daemon-reload
sudo systemctl enable --now keystone-gateway

8. Verify the service

sudo systemctl status keystone-gateway
curl --fail http://127.0.0.1:8080/healthz
curl --fail http://127.0.0.1:8080/readyz

Both probes return JSON status values (ok, then ready). If readiness fails, use troubleshooting; do not route client traffic on /healthz alone.

Confirm which release is active with:

readlink -f /opt/particle_horizon/keystone-gateway

Rollback

Stop the service and restore the prior release, configuration, license, state key, and state directory from a tested backup as a matching set. Because the archive keeps each executable beneath a version-specific SOFTWARE directory, a previously installed version can be restored by repointing the stable path at it:

sudo systemctl stop keystone-gateway
sudo ln -sfn \
  SOFTWARE/keystone-gateway-<previous-version>-linux-<arch>/bin/keystone-gateway \
  /opt/particle_horizon/keystone-gateway
sudo systemctl start keystone-gateway

Do not restore encrypted state with a different key.

File locations

File locations
PurposeLocation
Stable executable/opt/particle_horizon/keystone-gateway
Versioned software/opt/particle_horizon/SOFTWARE/
Gateway configuration/opt/particle_horizon/local_config/keystone-gateway/gateway.yaml
Signed license/opt/particle_horizon/local_config/keystone-gateway/gateway-license.json
State-encryption key/opt/particle_horizon/local_config/keystone-gateway/state.key
Durable state/opt/particle_horizon/local_data/keystone-gateway/state/
Reports/opt/particle_horizon/local_data/keystone-gateway/reports/
Gateway logs/opt/particle_horizon/logs/keystone-gateway/
systemd unit/etc/systemd/system/keystone-gateway.service

Confirm