ATTinyCore >=1.5.0 declares ATTinyCore:micronucleus@2.5-azd1b as a tool
dependency, hosted at https://azduino.com/bin/micronucleus/. That host
has been unreachable (connection refused) for extended periods, causing
every ATtiny85 compile to fail at the core-install step with:
Download failed: performing HEAD request: ... dial tcp ...: connection refused
Failed to install required core: ATTinyCore:avr
micronucleus is only used for USB upload — never for compilation — but
arduino-cli refuses to install a core whose tool deps cannot fetch.
Pin to 1.4.1, the last release whose micronucleus binary is hosted on
github.com (digistump release, reachable). The FQBN clock options we
ship (clock=16pll on attinyx5, etc.) are unchanged across 1.4.x.
- backend/app/services/arduino_cli.py: new CORE_INSTALL_VERSIONS map
consulted by ensure_core_for_board so the runtime auto-install
passes "ATTinyCore:avr@1.4.1" instead of unversioned latest.
- backend/Dockerfile and docker/entrypoint.sh: same pin so a fresh
image bakes 1.4.1 in and never hits the runtime fallback path.
Existing regression tests in test/backend/unit/test_arduino_cli_attinycore.py
still pass (they assert presence, not version).
Browsers were reporting:
Unsafe attempt to load URL http://velxio.dev/examples/
from frame with URL https://velxio.dev/examples.
Repro:
curl -I https://velxio.dev/examples
→ 301 Location: http://velxio.dev/examples/ ← protocol downgraded
Why: docker/nginx.conf has the container listening on `:80` only — TLS
is terminated by the host nginx in front of it (which then proxies to
http://127.0.0.1:3080). When nginx generates a trailing-slash 301 it
uses the listening protocol (http) for the absolute Location header,
not the X-Forwarded-Proto. The browser correctly blocks the redirect.
Fix: `absolute_redirect off;` makes nginx emit relative Location
headers (`Location: /examples/`), so the browser resolves them
against the original request URL and HTTPS is preserved end-to-end.
After fix:
curl -I https://velxio.dev/examples
→ 301 Location: /examples/
Goes in the same branch as the BMP280 ninja-timeout fix because both
are deploy-blocking and small.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cold ESP-IDF compiles (esp32, esp32-cam, etc.) can legitimately take
5–10 minutes — first time the project is built, ninja has to compile
the entire IDF + Arduino-ESP32 component graph from scratch. Nginx was
cutting the connection at 5 min, which surfaced as 'No response from
server' in the frontend even though the build was still progressing.
Worse, since the backend doesn't cancel the compile on client
disconnect, repeated user clicks pile up parallel ninja jobs that
saturate CPU and slow every concurrent build further.
10 min covers cold builds with comfortable margin. Long-term we should
make compile a job (POST → job_id, GET status) and cancel duplicates
server-side, but the timeout bump unblocks users today.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The folder only holds the in-container nginx + entrypoint that the
standalone Dockerfile copies. Calling it "deploy" implied host-level
production glue, which now lives in github.com/velxio/velxio-prod.
"docker/" makes the build-time vs deploy-time split obvious.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>