Troubleshooting
Deployment Issues
Section titled “Deployment Issues”Deploy script fails with “Missing required env var”
Section titled “Deploy script fails with “Missing required env var””Cause: Required variables not set in .env.prod.
Fix: Ensure all required variables are set:
# Required variables:BREEZE_DOMAIN, ACME_EMAIL, POSTGRES_PASSWORD, JWT_SECRET,AGENT_ENROLLMENT_SECRET, METRICS_SCRAPE_TOKEN, PUBLIC_API_URL,GRAFANA_ADMIN_PASSWORDAPI refuses to boot: RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS must be set in production
Section titled “API refuses to boot: RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS must be set in production”Cause: This variable is the trust anchor that the API uses to verify signed release manifests before serving binaries (so a compromised GitHub release alone can’t deliver tampered binaries). It is required in production for both BINARY_SOURCE=github and BINARY_SOURCE=local. Older .env templates shipped it empty, so upgrades can surface this on first boot.
Fix: For the official Breeze releases, use the published trust anchor:
RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS=yzx8ftmcls6uBetFC5SYnZhBo+cbur3IX50TbBthTso=This is a public key (also embedded in the agent and CI), so it is safe to commit. Only change it if you build and sign your own binaries. BREEZE_RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS is accepted as an alias.
Do not auto-rotate or overwrite this value. It is a deliberately pinned trust anchor — automatically replacing it with a “new” key defeats the protection, since the source of that key becomes the thing an attacker targets. If a real signing-key rotation ever ships, trust both keys during the overlap by comma-separating them (RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS=old,new) rather than replacing.
TLS certificate not provisioning
Section titled “TLS certificate not provisioning”Cause: DNS not pointing to server, or ports 80/443 blocked.
Fix:
- Verify DNS:
dig +short breeze.yourdomain.com - Check ports:
sudo ss -tlnp | grep -E ':(80|443)' - Check Caddy logs:
docker logs breeze-caddy
Database migration fails
Section titled “Database migration fails”Cause: PostgreSQL not ready or connection string incorrect.
Fix:
# Check PostgreSQL is runningdocker compose -f docker/docker-compose.prod.yml exec postgres pg_isready
# Check connection stringdocker compose -f docker/docker-compose.prod.yml exec api env | grep DATABASE_URLAgent Issues
Section titled “Agent Issues”Agent not appearing in dashboard
Section titled “Agent not appearing in dashboard”Causes:
- Enrollment failed
- WebSocket connection blocked
- Agent can’t resolve server hostname
Fix:
# Check agent logssudo journalctl -u breeze-agent -n 50
# Test connectivity from agentcurl -v https://breeze.yourdomain.com/health
# Verify enrollmentsudo cat /etc/breeze/config.jsonAgent shows “offline” despite running
Section titled “Agent shows “offline” despite running”Cause: WebSocket connection dropping or heartbeat not reaching API.
Fix:
- Check agent logs for reconnection messages
- Verify API WebSocket handling:
docker logs breeze-api | grep "ws" - Check if a firewall is terminating long-lived connections (increase WebSocket timeout)
Terminal not connecting
Section titled “Terminal not connecting”Common causes:
- Browser sends resize before server
onOpencompletes - WebSocket messages rejected by validation
Fix: Check API logs for WebSocket errors. The terminal uses term- prefixed command IDs that bypass database lookup.
Performance Issues
Section titled “Performance Issues”High API response times
Section titled “High API response times”Check:
# Prometheus metricscurl -H "Authorization: Bearer $TOKEN" \ http://localhost:9090/api/v1/query?query=histogram_quantile(0.95,rate(http_request_duration_seconds_bucket[5m]))
# Database slow queriesdocker compose -f docker/docker-compose.prod.yml exec postgres \ psql -U breeze -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"Redis memory growing
Section titled “Redis memory growing”Check:
docker compose -f docker/docker-compose.prod.yml exec redis redis-cli info memoryFix: Adjust REDIS_MAXMEMORY in .env.prod. Redis uses allkeys-lru eviction by default.
Disk space running low
Section titled “Disk space running low”# Check Docker volumesdocker system df
# Prune unused imagesdocker image prune -a
# Check backup retentionls -la /var/backups/breeze/Container Issues
Section titled “Container Issues”Container won’t start
Section titled “Container won’t start”# Check container logsdocker compose -f docker/docker-compose.prod.yml logs <service-name>
# Check resource limitsdocker stats --no-stream
# Recreate containerdocker compose -f docker/docker-compose.prod.yml up -d --force-recreate <service-name>Health check failing
Section titled “Health check failing”# Manual health checkdocker compose -f docker/docker-compose.prod.yml exec api \ wget --no-verbose --tries=1 --spider http://localhost:3001/health
# Check readinesscurl http://localhost:3001/health/readyWindows MSI Installer
Section titled “Windows MSI Installer”Most MSI problems come down to a failed enrollment during install. The agent is built to leave a trail in four places when enrollment fails, so you almost never have to guess:
| Sink | Where | How to read it |
|---|---|---|
| Installer log | install.log (only when you pass /l*v, see below) |
The agent’s stderr is captured here — look for Enrollment failed: |
| Agent log | C:\ProgramData\Breeze\logs\agent.log |
Full structured log of the agent, including the enroll attempt |
| Last-error marker | C:\ProgramData\Breeze\logs\enroll-last-error.txt |
One timestamped line with the friendly failure reason |
| Windows Event Log | Application log, source BreezeAgent |
Get-EventLog / Event Viewer |
Always install with a log
Section titled “Always install with a log”msiexec is silent by default. Pass /l*v to write a verbose log so you (and
whoever triages the issue) can see exactly what happened:
# Run from an elevated (Administrator) PowerShell or cmd prompt.# /i = install, /qn = no UI, /l*v = verbose log to install.logmsiexec /i "breeze-agent [ABCD1234XY@breeze.example.com].msi" /qn /l*v install.log/l*v <path> logs everything (the *) verbosely (the v) to the file you name.
Use an absolute path you can find afterwards, e.g. /l*v C:\breeze-install.log.
For a plain MSI, SERVER_URL and ENROLLMENT_KEY must be supplied together
(the installer aborts with SERVER_URL and ENROLLMENT_KEY must be provided together
if only one is present):
msiexec /i breeze-agent.msi /qn /l*v install.log ` SERVER_URL=https://breeze.yourdomain.com ` ENROLLMENT_KEY=YOUR_ENROLLMENT_KEYSupported MSI properties: SERVER_URL, ENROLLMENT_KEY, ENROLLMENT_SECRET,
BOOTSTRAP_TOKEN.
Reading the Breeze agent log
Section titled “Reading the Breeze agent log”After an install (successful or not), the agent’s own log is the richest source:
# Tail the agent log liveGet-Content C:\ProgramData\Breeze\logs\agent.log -Wait -Tail 50
# Just the enrollment outcome (one line, if the last enroll failed)Get-Content C:\ProgramData\Breeze\logs\enroll-last-error.txt
# Enrollment errors from the Windows Event LogGet-EventLog -LogName Application -Source BreezeAgent -Newest 20 | Format-List TimeGenerated, EntryType, MessageMSI exits non-zero / device never appears
Section titled “MSI exits non-zero / device never appears”Cause: Enrollment failed during install (bad key, wrong server URL, network blocked, or a usage-limited key that’s already exhausted).
Fix:
- Re-run with
/l*v install.log(above) and search the log forEnrollment failed:— the agent surfaces the underlying reason there rather than a generic Windows error. - Cross-check
enroll-last-error.txtfor the same message in one line. - Confirm the box can reach the server:
curl.exe -v https://breeze.yourdomain.com/health. - If the key is usage-limited, confirm it hasn’t hit
maxUsagein the dashboard.
MSI install succeeds but agent shows offline
Section titled “MSI install succeeds but agent shows offline”Enrollment succeeded (the row exists) but the service isn’t reporting in. Check the service and the log:
Get-Service BreezeAgentGet-Content C:\ProgramData\Breeze\logs\agent.log -Wait -Tail 50See Agent shows “offline” despite running for WebSocket/firewall causes.
Server-Side Installer Issues
Section titled “Server-Side Installer Issues”“Generate Link” fails with Server URL not configured (set PUBLIC_API_URL or API_URL)
Section titled ““Generate Link” fails with Server URL not configured (set PUBLIC_API_URL or API_URL)”Cause: The API container can’t see a PUBLIC_API_URL or API_URL env var, so it has no base URL to mint the installer share link against. The bundled docker-compose.yml derives this from BREEZE_DOMAIN (since #613 / v0.65.7+), so this only bites custom or older compose files.
Fix:
-
Set
PUBLIC_API_URL=https://<your-domain>in/opt/breeze/.env(or wherever your compose.envlives). -
If you use a custom compose file, explicitly map the variable into the
apiservice. Docker Compose only forwards env vars to a container when they appear in that service’senvironment:block — having the value in.envis necessary but not sufficient.api:environment:PUBLIC_API_URL: ${PUBLIC_API_URL} -
docker compose up -d apito recreate the container.
“Generate Link” fails with MSI build pipeline not reachable. Retry
Section titled ““Generate Link” fails with MSI build pipeline not reachable. Retry”Cause: The release-manifest verifier is rejecting the live MSI because the manifest’s repository field is LanternOps/breeze but the code default expects lanternops/breeze (case mismatch). Fix is on main (#867) and will ship in the next release after v0.67.0.
Fix (workaround on v0.67.0): add to .env and map into the api service.
BINARY_GITHUB_REPOSITORY=LanternOps/breezeapi: environment: BINARY_GITHUB_REPOSITORY: ${BINARY_GITHUB_REPOSITORY}Then docker compose up -d api. Same workaround unblocks Download Installer, which hits the same code path silently.
Reporting an Issue
Section titled “Reporting an Issue”Before opening a GitHub issue, search existing issues — your problem may already be tracked. When you do file one, include the following so it can be triaged without a back-and-forth:
-
What you were doing and what you expected vs. what happened.
-
Breeze version — server (
BREEZE_VERSIONin your.env) and agent (breeze-agent version). -
Platform — OS and architecture of the affected machine.
-
Relevant logs (redact secrets — tokens,
ENROLLMENT_SECRET, hostnames you don’t want public):Area Log to attach Windows MSI install install.logfrommsiexec /l*v, plusC:\ProgramData\Breeze\logs\agent.logAgent enrollment enroll-last-error.txtand theBreezeAgentEvent Log entriesAgent (Linux) sudo journalctl -u breeze-agent -n 200Agent (macOS) /Library/Application Support/Breeze/logs/agent.logServer / API docker compose -f docker/docker-compose.prod.yml logs -f api
- Join the community Discord for real-time help.