Is Homebox Down? Real-Time Status & Outage Checker
Is Homebox Down? Real-Time Status & Outage Checker
Homebox is an open-source home inventory and asset management application with over 5,000 GitHub stars. Written in Go with a SvelteKit frontend, it tracks household items, locations, labels, warranties, purchase information, and file attachments. Homebox exposes a REST API, supports CSV import/export, and delivers a mobile-friendly PWA that works well on phones for scanning and cataloging items around the house. Used by homeowners, renters, and families who want a self-hosted alternative to commercial inventory apps, Homebox is particularly popular for insurance documentation — maintaining a detailed record of household belongings with photos, serial numbers, and purchase receipts. Self-hosted via Docker with a single SQLite database file, Homebox is designed to be simple to run and easy to back up.
Because Homebox stores irreplaceable asset data — purchase records, warranty expiry dates, item photos, and insurance documentation — an undetected outage can have real consequences. A Go binary crash behind a reverse proxy silently returns 502 errors to users, and a corrupted SQLite database or unmounted storage volume can make months of inventory work inaccessible precisely when you need it most, such as during an insurance claim after a home incident.
Quick Status Check
#!/bin/bash
# Homebox health check
# Checks API status endpoint, process, port, and data directory
HOMEBOX_HOST="${HOMEBOX_HOST:-localhost}"
HOMEBOX_PORT="${HOMEBOX_PORT:-7745}"
HOMEBOX_DATA="${HOMEBOX_DATA:-/data}"
FAIL=0
echo "=== Homebox Status Check ==="
echo "Host: ${HOMEBOX_HOST}:${HOMEBOX_PORT}"
echo ""
# Check API status endpoint
STATUS_RESP=$(curl -sf --max-time 5 \
"http://${HOMEBOX_HOST}:${HOMEBOX_PORT}/api/v1/status" 2>&1)
if echo "${STATUS_RESP}" | grep -qiE '"ok"|"healthy"|"status"'; then
echo "[OK] API status endpoint responded"
echo " Response: $(echo "${STATUS_RESP}" | head -c 120)"
else
HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" --max-time 5 \
"http://${HOMEBOX_HOST}:${HOMEBOX_PORT}/api/v1/status" 2>/dev/null)
echo "[FAIL] API status endpoint returned HTTP ${HTTP_CODE}"
FAIL=1
fi
# Check root/frontend loads
HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" --max-time 5 \
"http://${HOMEBOX_HOST}:${HOMEBOX_PORT}/" 2>/dev/null)
if [ "$HTTP_CODE" = "200" ]; then
echo "[OK] Frontend root returned HTTP 200"
else
echo "[WARN] Frontend root returned HTTP ${HTTP_CODE}"
fi
# Check Homebox process
if pgrep -f "homebox\|hb-backend" > /dev/null 2>&1; then
echo "[OK] Homebox process is running"
elif docker inspect homebox > /dev/null 2>&1; then
STATE=$(docker inspect -f '{{.State.Status}}' homebox 2>/dev/null)
[ "$STATE" = "running" ] && echo "[OK] Homebox Docker container running" \
|| { echo "[FAIL] Homebox Docker state: ${STATE}"; FAIL=1; }
else
echo "[WARN] Homebox process/container not detected via pgrep"
fi
# Check port is listening
if ss -tlnp 2>/dev/null | grep -q ":${HOMEBOX_PORT}" || \
netstat -tlnp 2>/dev/null | grep -q ":${HOMEBOX_PORT}"; then
echo "[OK] Port ${HOMEBOX_PORT} is listening"
else
echo "[FAIL] Port ${HOMEBOX_PORT} not listening"
FAIL=1
fi
# Check data directory exists and is writable
if [ -d "${HOMEBOX_DATA}" ]; then
if [ -w "${HOMEBOX_DATA}" ]; then
DB_FILE=$(find "${HOMEBOX_DATA}" -name "*.db" -o -name "*.sqlite" 2>/dev/null | head -1)
if [ -n "${DB_FILE}" ]; then
DB_SIZE=$(du -sh "${DB_FILE}" 2>/dev/null | cut -f1)
echo "[OK] Data directory writable; DB found: ${DB_FILE} (${DB_SIZE})"
else
echo "[WARN] Data directory writable but no .db file found at ${HOMEBOX_DATA}"
fi
else
echo "[FAIL] Data directory not writable: ${HOMEBOX_DATA}"
FAIL=1
fi
else
echo "[WARN] Data directory not found at ${HOMEBOX_DATA}"
fi
echo ""
if [ "$FAIL" -eq 0 ]; then
echo "Result: Homebox appears healthy"
else
echo "Result: Homebox has failures — review output above"
exit 1
fi
Python Health Check
#!/usr/bin/env python3
"""
Homebox health check
Verifies API health, authenticates to test DB access, checks locations/items, and storage
"""
import json
import os
import shutil
import sys
import time
from pathlib import Path
try:
import urllib.request as urlreq
import urllib.error as urlerr
except ImportError:
print("ERROR: urllib not available")
sys.exit(1)
HOST = os.environ.get("HOMEBOX_HOST", "localhost")
PORT = int(os.environ.get("HOMEBOX_PORT", "7745"))
EMAIL = os.environ.get("HOMEBOX_EMAIL", "")
PASSWORD = os.environ.get("HOMEBOX_PASSWORD", "")
DATA_DIR = Path(os.environ.get("HOMEBOX_DATA", "/data"))
BASE_URL = f"http://{HOST}:{PORT}"
TIMEOUT = 8
results = []
auth_token = None
def check(label, ok, detail=""):
status = "OK" if ok else ("WARN" if ok is None else "FAIL")
msg = f"[{status}] {label}"
if detail:
msg += f" — {detail}"
print(msg)
if ok is not None:
results.append(ok)
return ok
def fetch(path, method="GET", data=None, token=None, timeout=TIMEOUT):
try:
url = f"{BASE_URL}{path}"
headers = {"Content-Type": "application/json", "Accept": "application/json"}
if token:
headers["Authorization"] = f"Bearer {token}"
body = json.dumps(data).encode() if data else None
req = urlreq.Request(url, data=body, headers=headers, method=method)
with urlreq.urlopen(req, timeout=timeout) as resp:
return resp.status, resp.read().decode("utf-8", errors="replace")
except urlerr.HTTPError as e:
return e.code, e.read().decode("utf-8", errors="replace")
except Exception as e:
return 0, str(e)
print(f"=== Homebox Python Health Check ===")
print(f"Target: {BASE_URL}")
print()
# 1. API status endpoint
t0 = time.time()
status, body = fetch("/api/v1/status")
latency_ms = (time.time() - t0) * 1000
if status == 200:
try:
data = json.loads(body)
version = data.get("version", data.get("data", {}).get("version", "unknown"))
check("API status endpoint", True, f"HTTP 200, version={version} ({latency_ms:.0f}ms)")
except json.JSONDecodeError:
check("API status endpoint", True, f"HTTP 200 ({latency_ms:.0f}ms)")
else:
check("API status endpoint", False, f"HTTP {status}")
# 2. Authenticate to verify database access
if EMAIL and PASSWORD:
status, body = fetch("/api/v1/users/login", method="POST",
data={"username": EMAIL, "password": PASSWORD})
if status == 200:
try:
data = json.loads(body)
auth_token = (data.get("token") or
data.get("data", {}).get("token") or
data.get("access_token"))
check("Authentication (DB access)", bool(auth_token),
"JWT token obtained — database accessible" if auth_token
else "HTTP 200 but no token in response")
except json.JSONDecodeError:
check("Authentication (DB access)", False, "HTTP 200 but invalid JSON")
elif status == 401:
check("Authentication (DB access)", False,
"HTTP 401 — invalid credentials or DB unreadable")
else:
check("Authentication (DB access)", False, f"HTTP {status}")
else:
check("Authentication (DB access)", None,
"HOMEBOX_EMAIL/HOMEBOX_PASSWORD not set — skipping auth check")
# 3. Location count (requires auth)
if auth_token:
status, body = fetch("/api/v1/locations", token=auth_token)
if status == 200:
try:
data = json.loads(body)
items = data if isinstance(data, list) else data.get("data", data.get("items", []))
count = len(items) if isinstance(items, list) else "unknown"
check("Locations API", True, f"{count} location(s) in inventory")
except json.JSONDecodeError:
check("Locations API", False, "HTTP 200 but invalid JSON")
else:
check("Locations API", False, f"HTTP {status}")
# 4. Item count (requires auth)
if auth_token:
status, body = fetch("/api/v1/items", token=auth_token)
if status == 200:
try:
data = json.loads(body)
items = data if isinstance(data, list) else data.get("data", data.get("items", []))
total = data.get("total", len(items) if isinstance(items, list) else "unknown")
check("Items API", True, f"{total} item(s) in inventory")
except json.JSONDecodeError:
check("Items API", False, "HTTP 200 but invalid JSON")
else:
check("Items API", False, f"HTTP {status}")
# 5. SQLite database file
db_files = list(DATA_DIR.glob("*.db")) + list(DATA_DIR.glob("*.sqlite")) if DATA_DIR.exists() else []
if db_files:
db = db_files[0]
size_mb = db.stat().st_size / (1024 * 1024)
check("SQLite database file", True, f"{db.name} ({size_mb:.2f} MB)")
else:
check("SQLite database file", False if DATA_DIR.exists() else None,
f"No .db file found in {DATA_DIR}")
# 6. Storage / attachments directory writable
if DATA_DIR.exists():
try:
test_file = DATA_DIR / ".homebox_health_check"
test_file.write_text("ok")
test_file.unlink()
check("Data directory writable", True, str(DATA_DIR))
except PermissionError:
check("Data directory writable", False,
f"Permission denied at {DATA_DIR} — item photos and attachments may fail")
else:
check("Data directory", None, f"Not found at {DATA_DIR} — may be mounted differently")
# 7. Disk usage check
if DATA_DIR.exists():
try:
usage = shutil.disk_usage(DATA_DIR)
pct = usage.used / usage.total * 100
free_gb = usage.free / (1024 ** 3)
ok = pct < 90
check("Disk usage", ok,
f"{pct:.1f}% used, {free_gb:.1f} GB free"
+ (" — WARNING: disk nearly full" if not ok else ""))
except Exception as e:
check("Disk usage", None, f"Could not determine: {e}")
print()
failures = [r for r in results if r is False]
if not failures:
print("Result: Homebox appears healthy")
sys.exit(0)
else:
print(f"Result: {len(failures)} check(s) failed — review output above")
sys.exit(1)
Common Homebox Outage Causes
| Symptom | Likely Cause | Resolution |
|---|---|---|
| All inventory data inaccessible, API returns 500 | SQLite database file corrupted — typically from power loss or disk error during write | Restore from backup; run sqlite3 homebox.db "PRAGMA integrity_check;" to assess damage; enable WAL mode and regular automated backups |
| 502 Bad Gateway from reverse proxy | Homebox Go binary crashed — OOM, panic, or startup error | Check container/process logs for panic trace; restart the container; ensure sufficient memory allocation (256 MB minimum) |
| All users suddenly logged out | JWT secret rotated or lost — new container deployment without persisting the secret | Set HBOX_OPTIONS_SECRET environment variable explicitly and persist it across container restarts; users re-login after secret change |
| Item photos missing or broken image links | Attachment storage volume unmounted or path changed after Docker volume remount | Verify the data volume is mounted at the correct path; check docker volume inspect; ensure the data directory path matches HBOX_STORAGE_DATA |
| CSV import fails silently or produces wrong data | CSV schema mismatch after Homebox version update changed expected column headers | Check the Homebox changelog for import format changes; export a test item as CSV first to get the current expected format; use the import preview feature |
| API returns 403 or data directory unreadable after update | Docker volume remount changed file ownership — container runs as non-root but files owned by root | Fix with docker exec homebox chown -R app:app /data or set PUID/PGID environment variables to match the volume's file ownership |
Architecture Overview
| Component | Function | Failure Impact |
|---|---|---|
| Go Backend API | Serves REST API for all CRUD operations on items, locations, labels, and attachments | All inventory operations fail; frontend becomes non-functional |
| SvelteKit Frontend | PWA web interface for browsing, searching, and editing inventory data | Users cannot access inventory via browser; API continues working for programmatic access |
| SQLite Database | Single-file persistent store for all inventory items, locations, users, and metadata | Complete data loss if corrupted and no backup exists; entire application non-functional |
| Attachment Storage (filesystem) | Stores uploaded item photos, receipts, manuals, and warranty documents | Item attachments return 404; file upload fails; existing photos inaccessible |
| JWT Authentication | Issues and validates session tokens using a configured secret key | All users logged out if secret changes; API returns 401 for all authenticated requests |
| REST API (/api/v1) | Programmatic interface for import/export, third-party integrations, and mobile clients | Automated workflows and integrations break; CSV import/export unavailable |
Uptime History
| Date | Incident Type | Duration | Impact |
|---|---|---|---|
| 2026-02 | Breaking API changes in Homebox v0.13 — endpoint paths restructured | Until manually updated | Custom integrations and scripts using old API paths returned 404; frontend auto-updated |
| 2025-11 | SQLite WAL file corruption after ungraceful container shutdown | Variable (user-managed) | Database read-only until WAL recovery; some users required restore from backup |
| 2025-09 | Docker volume permission regression after host OS upgrade | Until manually fixed | Homebox unable to write to data directory; item uploads and DB writes failed |
| 2025-07 | Go 1.23 build regression in a point release causing panic on startup | ~2 days until patch | Homebox crashed immediately on start for users pulling the latest Docker image |
Monitor Homebox Automatically
Homebox stores data you may only need in an emergency — insurance records, warranty documents, serial numbers for stolen items — which means a silent outage is especially costly to discover at the worst possible time. ezmon.com monitors your Homebox endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the API status endpoint returns an error or the application becomes unreachable.