Skip to main content

Installation

BHTune has not made its first stable release. The Releases page includes validation-only release candidates, not supported stable installations. Build from source or use the pre-release Docker image for evaluation. The repository also contains the Windows NSIS installer workflow and validation sources; a stable release will attach the resulting installer beside the matching Windows archive.

Linux package definitions are prepared for the stable release but are not publicly installable until that release's assets exist. The Debian/Ubuntu and RPM packages are produced by the release packaging jobs; the bhtune-bin AUR metadata is generated and validated by .github/workflows/aur-publish.yml, with publication restricted to an exact stable vX.Y.Z tag. Prereleases and arbitrary refs are validation-only, and the first AUR publication is a manual post-release step.

Choose and verify a distribution path​

Before installing a stable release asset, use the release-verification guide to verify its checksum, Sigstore bundle, and provenance evidence. A checksum proves that the downloaded bytes match the published digest; Sigstore and GitHub provenance verify different parts of the build identity. Do not treat a successful health check as evidence that a live plant is safe to tune.

PathArtifact or sourceService modelPersistent state
Windows NSISbhtune-vX.Y.Z-windows-x86_64-installer.exe after stable release activationBhtuneServer (LocalService); optional OpcdaBridgeGateway (LocalSystem)%ProgramData%\ByteHound\bhtune\, including optional gateway state
Windows archiveWindows release archiveManual SCM registration, LocalSystemExplicit --config path recommended
Archbhtune-bin after the first verified AUR publicationsystemd, DynamicUser/etc/bhtune, /var/lib/bhtune
Debian/Ubuntu.deb from the stable releasesystemd, DynamicUser/etc/bhtune, /var/lib/bhtune
RPM Linux.rpm from the stable releasesystemd, DynamicUser/etc/bhtune, /var/lib/bhtune
Portable LinuxLinux release archiveManual systemd unit or foreground processOperator-selected paths
macOSApple Silicon release archiveSupplied launchd LaunchDaemon or foreground process/usr/local/etc/bhtune, /usr/local/var/bhtune
DockerGHCR edge or stable version tagContainer processDocker volume at /var/lib/bhtune

The NSIS installer, AUR package, and stable package assets are prepared in the repository but are not publicly installable until the first stable release and its publication steps are complete.

Windows NSIS installer​

After stable-release activation, run the verified installer as an administrator. It installs bhtune.exe and bhtune-server.exe under %ProgramFiles%\ByteHound\bhtune\, creates an automatic BhtuneServer service as NT AUTHORITY\LocalService, and stores configuration, data, logs, and one verified rollback backup under %ProgramData%\ByteHound\bhtune\. It starts the service by default and verifies both /api/health and the installed version.

The installer embeds a pinned, independently verified official 32-bit opcda-bridge-gateway. Interactive clean installs select this optional component by default after warning that it is unauthenticated and listens on 0.0.0.0:7600. Silent clean installs require /INSTALL_GATEWAY=1; /START_GATEWAY=0 installs and validates it without leaving it running. The installer never creates or modifies a firewall rule.

Silent installation also supports /S, /ADD_TO_PATH=0, /START_SERVICE=0, and /CUSTOM_DB_BACKUP_CONFIRMED=1. The last flag is only for an external BHTune database that the operator has backed up independently; the installer never claims ownership of that database.

Upgrades preserve each installer-managed service's previous running/stopped state and retain exactly one verified rollback backup. Gateway-free installations remain gateway-free unless explicitly opted in; an installer-owned gateway remains managed on later upgrades. The automatic BHTune database boundary covers only the installer-managed ProgramData database and its -wal/-shm companions, while gateway ProgramData remains inside the combined rollback transaction. An external, malformed, relative, ambiguous, missing, or inaccessible BHTune database path fails closed before either service is stopped. Uninstall removes only marker-proven Program Files and service ownership and preserves the entire ProgramData tree. See the operator runbook for acceptance, rollback, and incident procedures.

Windows release archive​

The Windows archive is the fallback when NSIS is not available. Verify the archive before extracting it, keep the two binaries together, and use an explicit absolute config with absolute database and log paths before registering the service:

New-Item -ItemType Directory -Force C:\ProgramData\bhtune | Out-Null
@'
db = 'C:\ProgramData\bhtune\bhtune.db'

[log]
dir = 'C:\ProgramData\bhtune\logs'
'@ | Set-Content -Encoding utf8 C:\ProgramData\bhtune\bhtune.toml
& .\bhtune-server.exe --config C:\ProgramData\bhtune\bhtune.toml install
& .\bhtune-server.exe start
& .\bhtune-server.exe status
Invoke-RestMethod http://127.0.0.1:8787/api/health

The manual install command registers BhtuneServer as LocalSystem, unlike the NSIS installer's LocalService service. Pinning --config is essential because Windows service accounts resolve %APPDATA% differently from an interactive user. The manual path has no installer transaction or automatic database backup: stop the service before replacing binaries, retain the previous archive for rollback, and treat the database plus -wal/-shm files as one copy unit. bhtune-server.exe uninstall removes the manual service but does not delete the operator's config or database.

Linux packages​

The .deb, .rpm, and bhtune-bin packages install the bhtune CLI, bhtune-server, generated man pages, shell completions, and the canonical /usr/bin/bhtune-server systemd unit. They reload systemd metadata but do not enable or start the service. Enable it explicitly after verifying the configuration:

sudo systemctl enable --now bhtune-server
curl --fail http://127.0.0.1:8787/api/health
bhtune simulate --output json > /tmp/bhtune-simulator.json

The package-managed unit uses DynamicUser=true, /etc/bhtune for configuration, and /var/lib/bhtune for the database and logs. It binds to localhost by default and does not create firewall rules. Use systemctl status bhtune-server and journalctl -u bhtune-server -f for service diagnostics. Upgrades preserve configuration, database, logs, and the service's running/stopped state; keep one known-good package and a separate database backup for rollback. Removal preserves /etc/bhtune and /var/lib/bhtune, including SQLite sidecars.

Arch Linux (bhtune-bin)​

After the first stable release and verified AUR publication:

git clone https://aur.archlinux.org/bhtune-bin.git
cd bhtune-bin
makepkg -si
sudo systemctl enable --now bhtune-server
curl --fail http://127.0.0.1:8787/api/health

The package uses /usr/bin, installs the unit at /usr/lib/systemd/system/bhtune-server.service, and never compiles Rust or the frontend. For an upgrade, review the generated PKGBUILD/.SRCINFO, keep the service state in mind, and retain the previous package until the new version passes its health and simulator checks. The repository's generator validates exact tagged sources and checksums; .SRCINFO is generated by non-root makepkg --printsrcinfo, never hand-written. Dry-run workflow validation never publishes to AUR. Verify the exact remote commit after the first publication as described in the release-verification guide.

Debian or Ubuntu (.deb)​

After a stable release, verify the matching .deb and install it:

sudo apt install ./bhtune_<version>_amd64.deb
sudo systemctl enable --now bhtune-server
curl --fail http://127.0.0.1:8787/api/health

The Debian metadata uses depends = "$auto" so shared-library requirements come from the actual binaries through dpkg-shlibdeps. A package built on a non-Debian host with an empty Depends: field is not authoritative; do not replace adaptive dependency discovery with a hand-copied list. To roll back, stop or downgrade with the prior verified .deb, then recheck the health endpoint and preserve the database backup.

RPM-based Linux​

After a stable release, verify and install the matching RPM:

sudo dnf install ./bhtune-<version>-1.x86_64.rpm
sudo systemctl enable --now bhtune-server
curl --fail http://127.0.0.1:8787/api/health

The RPM declares its systemd requirement and reloads systemd metadata through package lifecycle scripts. systemctl try-restart preserves a stopped service during upgrades; final removal stops/disables the service but preserves configuration, database, SQLite sidecars, and logs. Keep the prior RPM and a separate database backup until the new version is accepted.

Portable Linux release archive​

Verify and extract the stable x86_64-unknown-linux-gnu archive into a versioned directory, then install the binaries and the separate manual systemd unit:

tag=vX.Y.Z
sudo mkdir -p /opt/bhtune/X.Y.Z
sudo tar -xzf bhtune-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gz \
-C /opt/bhtune/X.Y.Z
sudo install -m755 /opt/bhtune/X.Y.Z/bhtune /usr/local/bin/bhtune
sudo install -m755 /opt/bhtune/X.Y.Z/bhtune-server /usr/local/bin/bhtune-server
curl --fail --location --output /tmp/bhtune-server.service \
"https://raw.githubusercontent.com/bytehound-labs/bhtune/$tag/packaging/systemd/manual/bhtune-server.service"
sudo install -Dm644 /tmp/bhtune-server.service \
/etc/systemd/system/bhtune-server.service
rm -f /tmp/bhtune-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now bhtune-server
curl --fail http://127.0.0.1:8787/api/health

The release archive contains the binaries and product documentation, but not service-manager templates. Fetch the manual unit from the same immutable release tag as the archive, inspect it before installation, and then use it as shown above. The manual unit uses /usr/local/bin/bhtune-server, DynamicUser=true, /etc/bhtune, and /var/lib/bhtune; it is intentionally separate from package-managed units. Keep the previous versioned directory and binary until health and simulator checks pass. A rollback is a service stop, replacement of the two /usr/local/bin binaries with the previous verified pair, followed by systemctl start and a health check. Package removal semantics do not apply to this path: remove only files you installed, and preserve the data directories unless a separately verified backup and explicit destructive decision exist.

macOS release archive​

The release matrix currently provides an Apple Silicon archive. Verify and extract it, install the server under /usr/local/bin, and use the supplied LaunchDaemon template:

tag=vX.Y.Z
sudo install -m755 bhtune /usr/local/bin/bhtune
sudo install -m755 bhtune-server /usr/local/bin/bhtune-server
sudo mkdir -p /usr/local/etc/bhtune /usr/local/var/bhtune /usr/local/var/log
curl --fail --location --output /tmp/com.bytehound-labs.bhtune-server.plist \
"https://raw.githubusercontent.com/bytehound-labs/bhtune/$tag/packaging/launchd/com.bytehound-labs.bhtune-server.plist"
sudo install -m644 /tmp/com.bytehound-labs.bhtune-server.plist \
/Library/LaunchDaemons/
rm -f /tmp/com.bytehound-labs.bhtune-server.plist
sudo launchctl bootstrap system \
/Library/LaunchDaemons/com.bytehound-labs.bhtune-server.plist
curl --fail http://127.0.0.1:8787/api/health

The release archive contains the binaries and product documentation, but not the LaunchDaemon template. Fetch the plist from the same immutable release tag as the archive and inspect it before installation. The LaunchDaemon runs at boot and restarts the server, stores configuration under /usr/local/etc/bhtune, data under /usr/local/var/bhtune, and bootstrap/panic output under /usr/local/var/log. On Apple Silicon Homebrew-style layouts, adjust the plist's binary path consistently if /opt/homebrew is preferred. Inspect it with sudo launchctl print system/com.bytehound-labs.bhtune-server; stop it with sudo launchctl bootout system/com.bytehound-labs.bhtune-server. For an upgrade, boot it out, retain the previous binary, replace both binaries as one versioned pair, bootstrap again, and run the health and simulator checks. There is no package-managed rollback or data deletion; preserve /usr/local/var/bhtune explicitly.

Run via Docker​

A multi-stage image (frontend build → cargo build --release → slim Debian runtime) is published to GHCR on image-affecting pushes to main as edge, and under version tags plus latest after a release tag. For a pre-release smoke test, edge is the available image; use the immutable version tag for a stable deployment after release activation:

docker pull ghcr.io/bytehound-labs/bhtune:edge
docker run -d --name bhtune \
-p 8787:8787 \
-v bhtune-data:/var/lib/bhtune \
ghcr.io/bytehound-labs/bhtune:edge
curl --fail http://127.0.0.1:8787/api/health
docker exec bhtune bhtune-server healthcheck
docker inspect --format='{{.State.Health.Status}}' bhtune
docker exec bhtune bhtune simulate --output json

The image bundles both binaries, sets BHTUNE_BIND=0.0.0.0:8787 and BHTUNE_DB=/var/lib/bhtune/bhtune.db, and requires explicit host port publication. Full-mode browser mutations still need a trusted network; BHTUNE_ORIGIN is needed when a reverse proxy rewrites Host or a single external origin must be pinned. This is CSRF protection, not authentication. Docker's built-in health check runs bhtune-server healthcheck, which sends a bounded request to the loopback /api/health endpoint using the resolved bind port. It checks HTTP liveness only, not database readiness, migrations, proxy reachability, or tuning safety. Docker may report starting until its first scheduled probe completes.

To upgrade, pull the new image, stop/remove only the container, and reuse the same volume:

docker pull ghcr.io/bytehound-labs/bhtune:<version>
docker rm -f bhtune
docker run -d --name bhtune \
-p 8787:8787 \
-v bhtune-data:/var/lib/bhtune \
ghcr.io/bytehound-labs/bhtune:<version>

Keep the previous image tag or digest until the new health and simulator checks pass. A rollback repeats the run command with that prior tag. docker stop/docker rm do not remove bhtune-data; docker volume rm bhtune-data is destructive and must follow an explicit, verified database backup. Use docker logs -f bhtune for container output.

When OPC DA gateway names are maintained in the Linux host's /etc/hosts, bind that file into the container so the server resolves the same names as the host:

docker run -d --name bhtune \
-p 8787:8787 \
--mount type=bind,source=/etc/hosts,target=/etc/hosts,readonly \
-v bhtune-data:/var/lib/bhtune \
ghcr.io/bytehound-labs/bhtune:edge

Docker does not copy arbitrary host /etc/hosts entries into containers automatically. On Docker Desktop, or when aliases are provided by DNS, use the platform's DNS configuration or explicit --add-host entries instead. The public simulator Demo deployment does not need OPC gateway host mappings.

Skip to Prerequisites below to build from source instead.

Prerequisites​

  • A Rust toolchain supporting the 2024 edition (Rust 1.94 or newer — this is BHTune's declared MSRV, verified in CI).
  • Use the stable Rust toolchain for local builds to match the regular CI jobs. CI separately checks Rust 1.94.0 as the MSRV; on rustup-managed hosts, rustup update stable refreshes an older selected toolchain.
  • The Protocol Buffers compiler, protoc, on PATH — needed transitively by opcda-bridge's gRPC codegen build script. On Windows, choco install protoc is the most reliable option (winget can fail on hosts where its msstore source prompts for a one-time terms-of-service acceptance). On Linux, install your distro's protobuf-compiler package; on macOS, brew install protobuf.
  • pnpm 11.22.0 if you want to build or develop the web GUI's frontend. The repository's package.json declares this version for Corepack. The CLI and server both build and run without it — the frontend is only needed to serve the browser UI from bhtune-server.

No Windows, no Docker, and no proprietary SDKs are required beyond the above — every dependency, protoc included, is open-source (machine-enforced in CI via cargo deny).

Build the CLI and server​

git clone https://github.com/bytehound-labs/bhtune.git
cd bhtune
cargo build --workspace --release --locked

This produces target/release/bhtune (the headless CLI) and target/release/bhtune-server (the HTTP API + web GUI). Both link the same tuning engine and read/write the same SQLite database — see Introduction.

Build the web frontend (optional)​

Skip this if you only want the CLI, or if you're developing the frontend itself with Vite's dev server (see Web GUI quickstart).

pnpm install --frozen-lockfile
pnpm --filter bhtune-frontend run build
cargo build -p bhtune-server --release --locked

bhtune-server embeds the built frontend/dist/ directory directly into its own binary via rust-embed. Build the frontend before rebuilding the release server, and rebuild after each frontend change. The resulting bhtune-server is a single self-contained executable — no separate static file server, Node runtime, or reverse proxy required on the target host.

Where BHTune stores its data​

Both the CLI and the server resolve the same default, platform-standard data directory (unless overridden — see Configuration precedence):

PlatformDefault data directory
Linux, macOS$XDG_DATA_HOME/bhtune/, falling back to ~/.local/share/bhtune/
Windows%APPDATA%\bhtune\

(BHTune resolves this the same way on macOS as Linux — a plain XDG-style fallback, not ~/Library/Application Support/ — see default_db_path_from in crates/bhtune-runtime/src/config/paths.rs if you need the exact precedence.)

This holds bhtune.db (the SQLite database — every template, loop, tune run, sample, result, and write-back audit row) and logs/ (structured tracing output). Nothing here is encrypted or hidden — it's a plain SQLite file you can open with any SQLite tool.

Every run is kept forever unless you opt in to a retention policy (retention_days must be a positive whole number in bhtune.toml, or use bhtune history prune on demand) — see CLI quickstart.

Run as a background service​

Running bhtune-server from an interactive terminal is fine for trying it out, but a shared, always-on deployment should register it with the host OS's own service manager instead, so it starts at boot and restarts automatically without anyone needing to keep a terminal open.

Windows​

NSIS installer​

A production Windows release uses an installer named bhtune-vX.Y.Z-windows-x86_64-installer.exe. It installs the release payload under %ProgramFiles%\ByteHound\bhtune\, stores configuration, SQLite data, logs, installer state, and one verified rollback backup under %ProgramData%\ByteHound\bhtune\, and registers BhtuneServer as an automatic NT AUTHORITY\LocalService service. The registered command line contains an absolute --config path under ProgramData, so service startup does not depend on the interactive user's profile.

The installer starts the service by default and checks http://127.0.0.1:8787/api/health for both status: "ok" and the expected package version. It also embeds the official 32-bit gateway release pinned by installer/windows/opcda-gateway-release.json. The optional component installs gateway\opcda-bridge-gateway.exe plus its release contract, verification manifest, MIT license, and notice under Program Files; registers OpcdaBridgeGateway as an automatic LocalSystem service; and stores its configuration, persistent search index, SQLite sidecars, build metadata, and logs under %ProgramData%\ByteHound\bhtune\gateway\. Only the production installer is a release artifact; the separate lifecycle-test build is restricted to CI validation.

Interactive clean installs select and start the gateway by default after displaying its security warning. Silent clean installs require an explicit /INSTALL_GATEWAY=1, because /S cannot display that warning. The gateway is unauthenticated and listens on 0.0.0.0:7600; the installer never creates or modifies a Windows Firewall rule. Interactive installation also keeps machine PATH and clean-install BHTune service startup enabled by default. Silent installation supports:

/S
/ADD_TO_PATH=0
/START_SERVICE=0
/INSTALL_GATEWAY=1|0
/START_GATEWAY=1|0
/CUSTOM_DB_BACKUP_CONFIRMED=1

For example:

# Install BHTune only.
.\bhtune-vX.Y.Z-windows-x86_64-installer.exe /S

# Install and start BHTune plus the local gateway.
.\bhtune-vX.Y.Z-windows-x86_64-installer.exe /S /INSTALL_GATEWAY=1

# Install and validate the gateway, then leave it stopped.
.\bhtune-vX.Y.Z-windows-x86_64-installer.exe /S /INSTALL_GATEWAY=1 /START_GATEWAY=0

An empty clean install has no prior database to protect, so it does not create a rollback backup. Once installer-managed data exists, upgrades retain exactly one verified rollback backup under the ProgramData installer state directory; the existing backup is replaced only after the new manifest has been verified.

Silent installs use the same ownership, health, listener, gateway compatibility, and rollback checks as interactive installs. /START_GATEWAY controls the final state only for a new gateway installation or add-on; a managed gateway upgrade preserves its prior running/stopped state. An installation that predates gateway support, or that previously opted out, remains gateway-free until /INSTALL_GATEWAY=1 is supplied. Once the gateway is installer-owned, /INSTALL_GATEWAY=0 cannot abandon or remove it during an upgrade. Fatal errors in silent mode return a nonzero installer exit code instead of waiting for an interactive error dialog, so scheduled-task and CI callers can detect failure without a desktop session.

The PowerShell installer writes transaction diagnostics to %ProgramData%\ByteHound\bhtune\installer\install-trace.jsonl and %ProgramData%\ByteHound\bhtune\installer\uninstall-trace.jsonl when those paths are available. The install trace includes module-import and entrypoint errors as well as transaction stages.

Upgrades validate ownership, both service definitions, gateway payload/configuration, and TCP 7600 ownership before stopping anything. The installer then stops both managed services, creates one verified snapshot of BHTune Program Files and the complete gateway ProgramData tree, replaces and validates the candidate payloads, transiently starts the candidates for BHTune health and read-only gateway checks, and restores each service's prior state. Automatic BHTune database backup and rollback apply only when the top-level db setting resolves to the installer-managed ProgramData database. An external, malformed, relative, ambiguous, missing, or inaccessible database path fails closed; the installer does not create an external database file or its parent directory. After preparing and independently backing up an existing external database, an operator may rerun with /CUSTOM_DB_BACKUP_CONFIRMED=1. That override permits binary/service upgrade but does not claim to back up or roll back the external database. Gateway configuration, index database and sidecars, build metadata, logs, and evidence remain inside the installer rollback boundary regardless of the BHTune database location.

Rollback capture rejects reparse points and rechecks each source before copying; a redirected path must not broaden the backup or replacement boundary. Installer/uninstaller helpers form one complete module payload: private-file paths come from its manifest, unexpected or missing files fail closed, and each copied module file is SHA-256 checked. Keep those helpers with their matching installer rather than replacing individual scripts during recovery.

The external database is opened by the installed service as NT AUTHORITY\LocalService, not by the elevated installer account. The database file's parent directory and the database file itself therefore need to grant that account enough access to read and update SQLite state and to create or update the bhtune.db-wal and bhtune.db-shm sidecars. Installer preflight can confirm that the file exists and is readable in the installer context, but only the subsequent service startup and health check proves that the service account can use the path. A confirmed external database that fails that startup check is an operator configuration/ACL problem; the installer does not broaden permissions on arbitrary operator-owned paths.

If an installer process is interrupted, the next installer invocation validates the recorded transaction journal and either completes the safe recovery or refuses to continue without guessing about ownership or data.

Uninstall is a two-pass transaction. The first pass removes marker-proven BhtuneServer and OpcdaBridgeGateway registrations, the shortcut, registry-facing uninstall state, and exact machine PATH entry, then leaves the transaction journal and ownership metadata in place while NSIS removes the fixed Program Files tree. A guarded finalization pass removes that metadata and the journal only after the tree is verified absent; an interrupted or incomplete cleanup therefore remains retryable instead of being reported as finished. Service removal uses a bounded SCM disappearance wait with transient service-query retries, which allows older Windows versions to complete delayed service deregistration without treating a still-pending removal as success. Uninstall removes only installer-owned binaries and state, and preserves the entire %ProgramData%\ByteHound\bhtune\ tree, including BHTune configuration/database/logs, gateway configuration/index/sidecars/logs, and rollback evidence. There is no automated data-deletion option.

After installation, verify both services when the gateway component was selected:

sc.exe qc BhtuneServer
sc.exe qc OpcdaBridgeGateway
Invoke-RestMethod http://127.0.0.1:8787/api/health
& "$env:ProgramFiles\ByteHound\bhtune\bhtune.exe" opc --output json gateway-info `
--bridge-host 127.0.0.1:7600
& "$env:ProgramFiles\ByteHound\bhtune\bhtune.exe" opc --output json servers `
--bridge-host 127.0.0.1:7600

gateway-info must report the pinned application version and compatible core, namespace, and indexed-search protocol ranges. It does not contact an OPC server, so it is the installer-level gateway validation even on a host without OPCEnum. servers is a separate target-host check; its empty array is valid when no OPC DA servers are registered.

Manual archive installation​

The release archive is also usable without the installer. bhtune-server.exe registers itself directly with the Service Control Manager (SCM):

bhtune-server.exe install # registers the service (does not start it)
bhtune-server.exe start
bhtune-server.exe status
bhtune-server.exe stop
bhtune-server.exe uninstall # stops it first if still running, then removes it

install registers a service named BhtuneServer ("BHTune Server" in services.msc), set to start automatically and run as LocalSystem. This manual fallback is intentionally distinct from the NSIS installer, which uses LocalService and an installer-owned ProgramData layout.

A config/database gotcha worth knowing before you install. BHTune's default config and data paths live under %APPDATA% (see above), which resolves per user account. A Windows service normally runs as LocalSystem, whose %APPDATA% is a hidden system-profile folder — a different location entirely from the one your own interactive login resolves to. If you've been testing bhtune-server from your own terminal and then install it as a service with no further changes, the service will not see the config or database you were using: it will look like a fresh install, with an empty database and only the four built-in templates.

The fix is to pin an explicit, absolute config file at install time, and have that file itself name absolute (not default-relative) paths for the database and logs, so nothing about it depends on which account ends up running the service:

mkdir C:\ProgramData\bhtune
# C:\ProgramData\bhtune\bhtune.toml
db = 'C:\ProgramData\bhtune\bhtune.db'

[log]
dir = 'C:\ProgramData\bhtune\logs'
bhtune-server.exe --config C:\ProgramData\bhtune\bhtune.toml install
bhtune-server.exe start

--config is captured into the service's own registered launch command at install time (not just used once, interactively), so every future start of the service — after a reboot, after stop/start, after a Windows update — resolves the same config file and the same database, regardless of which account the SCM happens to run it as.

Linux (systemd)​

sudo install -m755 target/release/bhtune-server /usr/local/bin/bhtune-server
sudo install -Dm644 packaging/systemd/manual/bhtune-server.service \
/etc/systemd/system/bhtune-server.service
sudo systemctl daemon-reload
sudo systemctl enable --now bhtune-server

The provided packaging/systemd/manual/bhtune-server.service unit uses DynamicUser=true (an ephemeral, unprivileged account systemd creates for the service's lifetime — no separate useradd step), /usr/local/bin/bhtune-server, and StateDirectory=/ ConfigurationDirectory= so the database and logs live at /var/lib/bhtune/ and an optional config file at /etc/bhtune/bhtune.toml, both owned correctly with no manual chown needed. Unlike the Windows service above, this sidesteps the per-account path problem entirely — a systemd-managed service's environment is set once, in the unit file itself, not inherited from whichever user happens to be logged in. Check on it with systemctl status bhtune-server and journalctl -u bhtune-server -f; stop it with sudo systemctl disable --now bhtune-server.

macOS (launchd)​

sudo install -m755 target/release/bhtune-server /usr/local/bin/bhtune-server
sudo mkdir -p /usr/local/etc/bhtune /usr/local/var/bhtune /usr/local/var/log
sudo install -m 644 packaging/launchd/com.bytehound-labs.bhtune-server.plist \
/Library/LaunchDaemons/
sudo launchctl bootstrap system /Library/LaunchDaemons/com.bytehound-labs.bhtune-server.plist

The provided packaging/launchd/com.bytehound-labs.bhtune-server.plist registers a LaunchDaemon (not a per-user LaunchAgent, since this is a network service that should run regardless of login state) pointed at the Homebrew-style /usr/local/etc/ /usr/local/var paths (Apple Silicon Homebrew installs use /opt/homebrew instead — adjust the binary path in the plist to match). Check on it with sudo launchctl print system/com.bytehound-labs.bhtune-server and tail -f /usr/local/var/log/bhtune-server.log; stop and unload it with sudo launchctl bootout system/com.bytehound-labs.bhtune-server.

Next steps​

  • CLI quickstart — run your first tune from the command line, no plant connection required.
  • Web GUI quickstart — run the server and drive a tune from a browser.
  • Operator runbook — service control, smoke tests, upgrades, rollback, backups, and incident response.
  • Safety guide — live-loop guardrails, database boundaries, and recovery requirements.
  • Release verification — checksums, Sigstore, provenance, SBOM, installer, and AUR evidence.