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.
| Path | Artifact or source | Service model | Persistent state |
|---|---|---|---|
| Windows NSIS | bhtune-vX.Y.Z-windows-x86_64-installer.exe after stable release activation | BhtuneServer (LocalService); optional OpcdaBridgeGateway (LocalSystem) | %ProgramData%\ByteHound\bhtune\, including optional gateway state |
| Windows archive | Windows release archive | Manual SCM registration, LocalSystem | Explicit --config path recommended |
| Arch | bhtune-bin after the first verified AUR publication | systemd, DynamicUser | /etc/bhtune, /var/lib/bhtune |
| Debian/Ubuntu | .deb from the stable release | systemd, DynamicUser | /etc/bhtune, /var/lib/bhtune |
| RPM Linux | .rpm from the stable release | systemd, DynamicUser | /etc/bhtune, /var/lib/bhtune |
| Portable Linux | Linux release archive | Manual systemd unit or foreground process | Operator-selected paths |
| macOS | Apple Silicon release archive | Supplied launchd LaunchDaemon or foreground process | /usr/local/etc/bhtune, /usr/local/var/bhtune |
| Docker | GHCR edge or stable version tag | Container process | Docker 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
stableRust 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 stablerefreshes an older selected toolchain. - The Protocol Buffers compiler,
protoc, onPATH— needed transitively byopcda-bridge's gRPC codegen build script. On Windows,choco install protocis the most reliable option (wingetcan fail on hosts where itsmsstoresource prompts for a one-time terms-of-service acceptance). On Linux, install your distro'sprotobuf-compilerpackage; on macOS,brew install protobuf. pnpm11.22.0 if you want to build or develop the web GUI's frontend. The repository'spackage.jsondeclares this version for Corepack. The CLI and server both build and run without it — the frontend is only needed to serve the browser UI frombhtune-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):
| Platform | Default 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.