Skip to content
Small team, full backlog, zero orders dropped. Support replies are slower than we’d like. Read our status update → Zero orders dropped. Status → 📬 Check your spam folder — most of our replies land there. We do answer. Status update → 📬 Check your spam folder. Status →

Bitaxe Auto-Restart Watchdog: the AxeOS API Fix for Flatlines

A Bitaxe hit by the “Flatline of Death” keeps claiming it is hashing while finding no shares — and a restart fixes it every time. Until the root cause falls (ESP-Miner issue #1053 is still open), the practical answer is a watchdog: poll the AxeOS API, and when accepted shares stop moving for ~5 minutes, trigger a restart automatically. This is the mitigation owners in the thread confirmed working, and the idea the maintainers themselves endorsed for a future built-in status task (issue #272). No built-in share watchdog has shipped in stock AxeOS at last verification (see the record note at the end of this page), so you run one beside the miner.

Everything below uses exactly two API endpoints, both verified against the ESP-Miner source (main/http_server/http_server.c and main/http_server/system_api_json.c, master branch) and in community use since at least July 2025. You need: the Bitaxe’s IP address, and any always-on machine on the same LAN — a Raspberry Pi, a NAS, a desktop, anything that can run curl.

The two endpoints

Endpoint Method What it does Verified in
/api/system/info GET Returns live system JSON including sharesAccepted, sharesRejected, hashRate, power, responseTime, uptimeSeconds http_server.c (registration L1886, handler GET_system_info L1380) + system_api_json.c (field names, sharesAccepted at L69)
/api/system/restart POST Replies {"message":"System will restart shortly."}, waits ~1 second so the response can flush, then calls esp_restart() http_server.c (handler POST_restart L1157–1190, registration L1954) + openapi.yaml (“Restart the system”)

Access rule (verified in source): AxeOS accepts these requests only from private-range LAN addresses (the is_network_allowed check, http_server.c L310); anything else gets 401 Unauthorized. There is no token or password. If your watchdog machine reaches the Bitaxe through a VPN, a different subnet, or any NAT that rewrites the source to a non-private address, expect 401s — put the watchdog on the same LAN segment.

AxeOS exposes more endpoints than these (pause/resume, OTA, statistics, WebSocket streams) — the complete surface, pinned to the release tag, is in our AxeOS API reference; for workflow-level configuration see the AxeOS advanced configuration & API guide. The watchdog needs only the two above.

Verify both endpoints by hand first

Step 1 — Read the live counters.

  • Action: query the info endpoint from your watchdog machine (replace 192.168.1.37 with your Bitaxe’s IP throughout).
  • Command:
curl -s http://192.168.1.37/api/system/info
  • You should see: a JSON object containing, among many fields, "sharesAccepted": with a number, plus "hashRate", "power", and "uptimeSeconds".
  • What it proves: the API is reachable from this machine and your source IP passes the LAN check. Nothing to undo — this is read-only.

Step 2 — Watch the share counter move.

  • Action: sample sharesAccepted twice, a couple of minutes apart, while the miner is healthy.
  • Command (requires jq; apt install jq on Debian/Ubuntu/Raspberry Pi OS):
curl -s http://192.168.1.37/api/system/info | jq .sharesAccepted
# wait 2–3 minutes
curl -s http://192.168.1.37/api/system/info | jq .sharesAccepted
  • You should see: a bare number, higher on the second read. (At high pool difficulty a couple of minutes between shares is normal — if it takes longer, remember that when choosing your threshold below.)
  • What it proves: sharesAccepted is your heartbeat. During a flatline this number freezes while temperature and fan telemetry keep updating — that freeze is exactly what the watchdog detects. Read-only; nothing to undo.

Step 3 — Test the restart endpoint once, deliberately.

  • Action: trigger a manual restart while you are watching the dashboard. Do this once so you know what recovery looks like.
  • Command:
curl -s -X POST http://192.168.1.37/api/system/restart
  • You should see: {"message": "System will restart shortly."} — then the dashboard drops out and comes back; uptimeSeconds in Step 1’s output resets near zero and session share counters restart from 0.
  • What it proves / how to undo: your watchdog machine is allowed to restart this Bitaxe. The “undo” is time: the device reboots and resumes mining on its own (give it a minute or two). You lose the reboot window of hashing and your session stats — accepted-share accounting on the pool side is unaffected.

The Bash watchdog

Our minimal implementation: polls every 30 seconds, restarts if sharesAccepted has not changed for 5 minutes, then gives the device a 90-second grace period. Save as bitaxe-watchdog.sh:

#!/usr/bin/env bash
# bitaxe-watchdog.sh — restart a Bitaxe when accepted shares stop moving.
# Usage: ./bitaxe-watchdog.sh <bitaxe-ip> [threshold-seconds]
# Requires: curl, jq. Run from a machine on the same LAN as the Bitaxe.

IP="${1:?Usage: bitaxe-watchdog.sh <bitaxe-ip> [threshold-seconds]}"
THRESHOLD="${2:-300}"   # seconds without a new accepted share before restarting
POLL=30                 # seconds between checks
GRACE=90                # seconds to wait after a restart before monitoring again

last_shares=-1
last_change=$(date +%s)

while true; do
  shares=$(curl -sf --max-time 10 "http://${IP}/api/system/info" | jq -r '.sharesAccepted // empty')
  now=$(date +%s)
  if [ -z "$shares" ]; then
    echo "$(date -Is) API unreachable - a watchdog cannot fix a dead ESP32 (see smart-plug fallback)"
  elif [ "$shares" != "$last_shares" ]; then
    last_shares="$shares"; last_change=$now
    echo "$(date -Is) sharesAccepted=$shares"
  elif [ $((now - last_change)) -ge "$THRESHOLD" ]; then
    echo "$(date -Is) no new shares for $((now - last_change))s - restarting"
    curl -sf -X POST "http://${IP}/api/system/restart"; echo
    sleep "$GRACE"
    last_shares=-1; last_change=$(date +%s)
  fi
  sleep "$POLL"
done

Step 4 — Run it.

  • Action: make it executable and start it against your Bitaxe.
  • Command:
chmod +x bitaxe-watchdog.sh
./bitaxe-watchdog.sh 192.168.1.37
  • You should see: a timestamped sharesAccepted=N line at startup, then a new line each time the counter moves. During a flatline you will see the counter stall, then the restart line, then counting resume from 0.
  • What it proves / how to undo: the watchdog loop is live. Undo by stopping the script (Ctrl-C) — it changes nothing on the Bitaxe itself.

Step 5 — Keep it running after logout/reboot. Any supervisor works; the smallest correct systemd unit (on the watchdog machine, e.g. /etc/systemd/system/bitaxe-watchdog.service):

[Unit]
Description=Bitaxe flatline watchdog
After=network-online.target

[Service]
ExecStart=/home/pi/bitaxe-watchdog.sh 192.168.1.37
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Adjust the ExecStart path to wherever you actually saved the script — /home/pi/ is an example for a Raspberry Pi; on a NAS or desktop it will be somewhere else entirely.

sudo systemctl daemon-reload
sudo systemctl enable --now bitaxe-watchdog
journalctl -u bitaxe-watchdog -f

You should see: the same log lines as Step 4, now in the journal, surviving reboots of the watchdog machine.

Choosing the threshold: 300 seconds is the community default (it is the value in the original script from the #1053 thread). If your pool difficulty is set high enough that healthy gaps between accepted shares approach 5 minutes, raise the threshold (600–900 s) — otherwise the watchdog will restart a perfectly healthy miner. Check your typical share cadence in Step 2 before deciding.

The original: nymkappa’s Node.js watchdog

Credit where it is due — the first working watchdog for this bug was posted in the thread by nymkappa on 2025-07-13: a dependency-free Node.js script using the same two endpoints (5-second polls, 300-second threshold, 60-second post-restart grace), started as node bitaxe-monitor.js <BITAXE_IP>. If you already run Node on your LAN box, use theirs from the comment directly — it is the user-confirmed original, and our Bash version above is deliberately the same logic on the same endpoints for machines without Node.

What a watchdog cannot do

  • It cannot fix a hard-wedged ESP32. If the flatline variant you hit also kills the HTTP server, the API stops answering and no request can restart it. That is what the API unreachable log line means. Backstop: a smart plug — either on a scheduled daily power cycle or switched by your monitoring when the API goes silent. Cruder than an API restart (it cuts power without warning), so keep it as the second line, not the first. If the web UI freezing is your primary symptom, that is a different bug: AxeOS web UI freezes mid-session.
  • It cannot fix hardware. If restarts stop bringing the hashrate back, or the device boots to 0 GH/s, stop restarting and start diagnosing: Bitaxe not hashing / 0 GH/s.
  • It does not fix the underlying bug. It converts hours of silent downtime into a ~minute of reboot. For the full evidence record on the bug itself — affected boards, maintainer statements, what PR #1422 changed — see the pillar: Bitaxe “Flatline of Death”.

FAQ

How often will the watchdog restart my Bitaxe?

Only when accepted shares stall past your threshold. A healthy miner is never touched; a flatlined one is back inside about a minute and a half instead of hashing nothing until you notice.

Does an automatic restart lose mining progress?

You lose the reboot window of hashing time and the session counters reset. Pool-side accounting of already-accepted shares is untouched, and share-finding is memoryless — there is no “progress” inside the ASIC to lose.

Why does the restart call return 401 Unauthorized?

AxeOS only accepts API requests whose source address is in a private LAN range (verified in http_server.c‘s is_network_allowed). Run the watchdog on the same LAN as the Bitaxe — not across a VPN or NAT that presents a public source address.

Credits

The watchdog approach comes straight from the ESP-Miner community: nymkappa wrote and shared the original script, skot endorsed a share watchdog as the right shape for a future built-in status task, and the endpoint behavior documented here was verified against the ESP-Miner source (GPL-3.0) by D-Central. Thanks to Skot, WantClue, mutatrum, and every contributor keeping #1053 alive in public.

Record last verified: 2026-08-13. Endpoint paths, field names, and the LAN-only access rule were re-derived from ESP-Miner master source on that date.