Update Failures
The Settings → License → Check for Updates flow downloads a signed package from license.proxrad.com, verifies the SHA-256 checksum, extracts new binaries and frontend assets to /opt/proxpanel/, then restarts the API and RADIUS containers. Four common failure modes — pick the matching log line and apply the fix.
Symptoms
Section titled “Symptoms”- “Checksum mismatch — refusing to install” toast in the UI
- Update downloaded successfully, but containers never restart
- Binary expired (30-day limit) and the update flow itself fails to start
- “Failed to restart containers: Docker socket not available”
- After a successful update, the panel returns 404 on every frontend asset
Diagnostic flow
Section titled “Diagnostic flow”-
Look at the update log first.
Terminal window docker logs proxpanel-api 2>&1 | grep -E "Update|update" | tail -50The handler logs every step: download URL, file size, checksum compare, extraction, restart attempt.
-
Confirm the package is on disk. Both the API container path and the host path matter:
Terminal window docker exec proxpanel-api ls -la /app/updates/ls -la /opt/proxpanel/updates/ -
Check container ages. A successful update bumps
StartedAt:Terminal window docker inspect proxpanel-api --format '{{.State.StartedAt}}'docker inspect proxpanel-radius --format '{{.State.StartedAt}}'Both should reflect the time you ran the update. If only one bumped, the second container didn’t restart.
-
Verify the running binary version:
Terminal window curl -s http://localhost:8080/health | jq '.version'docker exec proxpanel-api /app/proisp-api -versionThese should agree after a successful update.
Cause 1 — Checksum mismatch
Section titled “Cause 1 — Checksum mismatch”The handler computes SHA-256 of the downloaded .tar.gz and compares it against the value the license server returned in the update metadata. A mismatch means the file is corrupted in transit (rare) or the license server is serving a stale checksum (more common, after a re-publish).
Log line:
Update: checksum mismatch (expected=abc123..., got=def456...) - refusing to installDiagnostic:
# What does the license server say the checksum should be?curl -s -X POST "https://license.proxrad.com/api/v1/update/check" \ -H "Content-Type: application/json" \ -d '{"license_key":"PROXP-XXXXX-XXXXX-XXXXX-XXXXX","current_version":"v1.0.500"}' | jq
# What's the actual file's checksum?sha256sum /opt/proxpanel/updates/proxpanel-v1.0.510.tar.gzFix:
-
Clear the cached download and retry. The handler will fetch fresh:
Terminal window rm -f /opt/proxpanel/updates/proxpanel-v*.tar.gzThen click Check for Updates → Install again.
-
If retry produces the same mismatch, the license server has a bad checksum stored. Email
info@proxrad.comwith the version and the two checksums (expected vs got). The fix on the server side is to re-upload + re-publish the build. -
Sanity-check by manually downloading the package and verifying both:
Terminal window curl -sLo /tmp/update.tar.gz "https://license.proxrad.com/api/v1/update/download?license_key=PROXP-XXXXX-XXXXX-XXXXX-XXXXX&version=v1.0.510"sha256sum /tmp/update.tar.gz
Cause 2 — Binary expired before update could run
Section titled “Cause 2 — Binary expired before update could run”Panels are designed to be kept current and may stop running if they fall too far behind on updates. If that happens before you click Install Update, the API may not stay up long enough to run the updater.
Log line:
Container exits within seconds of start.
Fix — install the update manually:
-
Download from the license server, off-band:
Terminal window curl -sLo /opt/proxpanel/updates/proxpanel-latest.tar.gz \"https://license.proxrad.com/api/v1/update/download?license_key=PROXP-XXXXX-XXXXX-XXXXX-XXXXX&version=latest" -
Verify checksum (the license server’s
/update/checkendpoint returnschecksum):Terminal window curl -s -X POST "https://license.proxrad.com/api/v1/update/check" \-H "Content-Type: application/json" \-d '{"license_key":"PROXP-XXXXX-XXXXX-XXXXX-XXXXX","current_version":"unknown"}' | jq '.checksum'sha256sum /opt/proxpanel/updates/proxpanel-latest.tar.gz -
Extract over the existing tree. The package contains
backend/,frontend/dist/,docker-compose.yml,VERSION:Terminal window cd /opt/proxpaneltar -xzf updates/proxpanel-latest.tar.gz -
Restart containers:
Terminal window docker compose restart api radiusdocker exec proxpanel-frontend nginx -s reload -
Confirm:
Terminal window curl -s http://localhost:8080/health | jq '.version'
Cause 3 — Restart-watcher service missing
Section titled “Cause 3 — Restart-watcher service missing”The update handler tries three ways to restart containers, in order: Docker Engine API via the mounted socket, the docker CLI inside the container, and finally a host-level systemd watcher that triggers on /opt/proxpanel/.update-complete. If you’re on an older install that never had the watcher units installed, and the Docker socket isn’t reachable, the update completes on disk but the running containers never bounce.
Log line:
Update: containers extracted but restart failed (no docker socket, no CLI, no watcher) — restart manuallyDiagnostic:
# Is the watcher service installed?systemctl status proxpanel-update-watcher.path proxpanel-update-watcher.service
# Is the docker socket mounted into the API container?docker inspect proxpanel-api | grep -A2 docker.sockFix — install the watcher units:
-
Create the service unit:
Terminal window cat > /etc/systemd/system/proxpanel-update-watcher.service << 'EOF'[Unit]Description=ProxPanel Update WatcherAfter=docker.service[Service]Type=oneshotExecStart=/bin/bash -c 'if [ -f /opt/proxpanel/.update-complete ]; then cd /opt/proxpanel && docker compose restart api radius && rm -f /opt/proxpanel/.update-complete; fi'[Install]WantedBy=multi-user.targetEOF -
Create the path-watcher unit:
Terminal window cat > /etc/systemd/system/proxpanel-update-watcher.path << 'EOF'[Unit]Description=Watch for ProxPanel update completion[Path]PathExists=/opt/proxpanel/.update-completeUnit=proxpanel-update-watcher.service[Install]WantedBy=multi-user.targetEOF -
Enable:
Terminal window systemctl daemon-reloadsystemctl enable --now proxpanel-update-watcher.path -
Retry the update. The handler will drop
/opt/proxpanel/.update-completeon disk; systemd picks it up and restarts the containers from the host.
Cause 4 — Docker socket not mounted
Section titled “Cause 4 — Docker socket not mounted”The primary restart path uses /var/run/docker.sock from inside the API container. On older docker-compose files this volume mount is absent, so the API can’t call docker restart.
Log line:
Update: Docker API restart failed: dial unix /var/run/docker.sock: no such file or directoryDiagnostic:
docker inspect proxpanel-api --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}' | grep docker.sockExpected line: /var/run/docker.sock -> /var/run/docker.sock. If empty, the mount is missing.
Fix:
-
Edit
/opt/proxpanel/docker-compose.yml. Under theapi:service’svolumes:list, add:- /var/run/docker.sock:/var/run/docker.sock -
Apply by recreating the API container (the network re-attaches cleanly):
Terminal window docker compose -f /opt/proxpanel/docker-compose.yml up -d api -
Confirm:
Terminal window docker exec proxpanel-api ls -la /var/run/docker.sock -
Retry the update.
Cause 5 — Frontend 404 after successful update
Section titled “Cause 5 — Frontend 404 after successful update”Update completed, version bumped, but every page in the browser returns 404. The Docker volume mount for frontend/dist/ got broken by an overzealous rm -rf somewhere in the install path.
Symptom:
curl -s http://localhost/returns nginx’s default 404docker exec proxpanel-frontend ls /usr/share/nginx/html/is empty
Fix:
-
Re-sync the frontend without removing the directory:
Terminal window cd /opt/proxpaneltar -xzf updates/proxpanel-latest.tar.gz frontend/ -
Do not
rm -rf frontend/dist— that breaks the Docker bind mount and nginx serves stale FS handles. Just overwrite in place. -
Reload nginx to pick up the new index.html cache headers:
Terminal window docker exec proxpanel-frontend nginx -s reload -
Confirm:
Terminal window curl -sI http://localhost/ | head -5
Cause 6 — nginx.conf overwritten, SSL gone
Section titled “Cause 6 — nginx.conf overwritten, SSL gone”Older versions of the frontend-only deploy path stomped the customer’s nginx.conf with the package’s default (HTTP-only) version, wiping the SSL listener. Symptom: panel comes back on port 80 but HTTPS is dead.
Diagnostic:
grep -E "listen 443 ssl|ssl_certificate" /opt/proxpanel/frontend/nginx.confIf you get no output, the SSL block is gone.
Fix:
The update handler since v1.0.95 skips overwriting nginx.conf if listen 443 ssl or ssl_certificate is present. If you’re on an older version that already wiped it, restore from a backup of /opt/proxpanel/frontend/nginx.conf and reload nginx. Then upgrade to a current version so the protection kicks in next time.
Still stuck?
Section titled “Still stuck?”# Full update logdocker logs --since=24h proxpanel-api 2>&1 | grep -iE "update|version" > /tmp/update.log
# What was downloadedls -la /opt/proxpanel/updates/
# Compose file (check volumes / mounts)cat /opt/proxpanel/docker-compose.yml > /tmp/compose.yml
# What the license server says is currentcurl -s -X POST "https://license.proxrad.com/api/v1/update/check" \ -H "Content-Type: application/json" \ -d '{"license_key":"PROXP-XXXXX-XXXXX-XXXXX-XXXXX","current_version":"unknown"}' > /tmp/update-check.json
# Running versioncurl -s http://localhost:8080/health > /tmp/health.jsonEmail info@proxrad.com.
Related pages
Section titled “Related pages”- License Errors — binary-expired errors that prevent the in-place updater from running.
- Backup / Restore Errors — take a backup before any major update.