deploy: VPS + Cloudflare bundle (nginx vhosts, release script, setup guide)
The wadamesh.com distribution stack, ready to drop onto a new VPS behind Cloudflare: - deploy/nginx/tiles.wadamesh.com.conf — OSM tile proxy (HTTP origin, double-quoted location regex, resolver + variable proxy_pass, OSM UA, 14d disk cache) - deploy/nginx/firmware.wadamesh.com.conf — bins + the beta_<N> update-check listing - scripts/release.sh — build both boards tagged, refresh the listing, rsync to the VPS - deploy/README.md — VPS + Cloudflare DNS/SSL/cache setup, publish flow VPS target supplied via $WADAMESH_VPS at publish time — no IP/SSH in the repo (Cloudflare fronts the origin). Web flasher + OTA re-enable are the remaining pre-launch pieces (noted in deploy/README.md). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kaj Schittecat <kaj@schittecat.com>
This commit is contained in:
1 parent
bc8344b219
commit
eb07184c3e
4 files changed
+216
No files matched your search
@@ -0,0 +1,67 @@
|
||||
# wadamesh.com infrastructure
|
||||
|
||||
Distribution stack for wadamesh: a **VPS nginx origin behind Cloudflare**.
|
||||
|
||||
```
|
||||
tiles.wadamesh.com →CF (HTTP, edge-cached) → nginx → tile.openstreetmap.org
|
||||
firmware.wadamesh.com →CF (cache bins) → nginx → /srv/wadamesh/firmware
|
||||
flasher.wadamesh.com →CF (HTTPS) → web flasher (TODO — see below)
|
||||
wadamesh.com →CF (HTTPS) → landing page (later)
|
||||
```
|
||||
|
||||
The firmware fetches **tiles + the update-check over plain HTTP** (on-device HTTPS
|
||||
isn't viable — mbedTLS needs ~30 KB heap, only ~5 KB is free post-Wi-Fi), so the
|
||||
tile + firmware hosts must stay reachable over HTTP. Cloudflare provides the edge
|
||||
cache, HTTPS for the flasher, and hides the origin IP (so no IP lives in this repo
|
||||
or the firmware).
|
||||
|
||||
## 1. VPS (origin)
|
||||
|
||||
```bash
|
||||
sudo apt install nginx
|
||||
sudo mkdir -p /srv/wadamesh/firmware/releases/TOUCH /var/cache/nginx/wadamesh-tiles
|
||||
sudo cp deploy/nginx/tiles.wadamesh.com.conf /etc/nginx/sites-available/
|
||||
sudo cp deploy/nginx/firmware.wadamesh.com.conf /etc/nginx/sites-available/
|
||||
sudo ln -s /etc/nginx/sites-available/tiles.wadamesh.com.conf /etc/nginx/sites-enabled/
|
||||
sudo ln -s /etc/nginx/sites-available/firmware.wadamesh.com.conf /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## 2. Cloudflare
|
||||
|
||||
- **DNS:** `A`/`AAAA` records for `tiles`, `firmware`, `flasher`, `@` → the VPS IP,
|
||||
all **Proxied** (orange cloud).
|
||||
- **SSL/TLS:** mode **Flexible** (CF↔origin HTTP) is enough since the origin is
|
||||
HTTP-only. **Do NOT enable "Always Use HTTPS"** on `tiles.` or `firmware.` — the
|
||||
firmware needs plain HTTP there.
|
||||
- **Cache Rules:**
|
||||
- `tiles.wadamesh.com/*` → Eligible for cache, Edge TTL ~14d.
|
||||
- `firmware.wadamesh.com/releases/*/*.bin` → cache, Edge TTL ~1d.
|
||||
- `firmware.wadamesh.com/releases/TOUCH` (the listing) → short TTL (~60s) or
|
||||
Bypass, so new releases appear promptly.
|
||||
|
||||
## 3. Publishing a release
|
||||
|
||||
From a wadamesh checkout (builds both boards, refreshes the listing, rsyncs up):
|
||||
|
||||
```bash
|
||||
WADAMESH_VPS=user@your-vps scripts/release.sh beta_2
|
||||
```
|
||||
|
||||
The on-device check GETs `http://firmware.wadamesh.com/releases/TOUCH`, finds the
|
||||
highest `beta_<N>`, and (once OTA-over-Wi-Fi is re-enabled) pulls
|
||||
`…/releases/TOUCH/beta_<N>/<board>.bin`.
|
||||
|
||||
## TODO before public launch
|
||||
|
||||
- **Web flasher** (`flasher.wadamesh.com`) — esptool-js / Web Serial install page
|
||||
with a board picker. Not yet built; the firmware already points "update manually
|
||||
at flasher.wadamesh.com" here.
|
||||
- **Re-enable OTA-over-Wi-Fi** in the firmware (currently it version-checks then
|
||||
defers to manual flashing).
|
||||
- **Landing page** at `wadamesh.com`.
|
||||
- Decide tile-proxy sharing: dedicated `tiles.wadamesh.com` (this config) vs
|
||||
reusing the meshcomod proxy.
|
||||
|
||||
> Never commit the VPS IP, SSH keys, or `WADAMESH_VPS`. Cloudflare fronts the
|
||||
> origin; the deploy target is supplied via the environment at publish time.
|
||||
@@ -0,0 +1,42 @@
|
||||
# firmware.wadamesh.com — wadamesh firmware bins + the update-check feed.
|
||||
#
|
||||
# Layout on disk (populated by scripts/release.sh, rsynced to the VPS):
|
||||
# /srv/wadamesh/firmware/
|
||||
# releases/TOUCH/index.json <- listing the firmware scans for beta_<N>
|
||||
# releases/TOUCH/beta_1/wadamesh-heltec-v4-tft.bin
|
||||
# releases/TOUCH/beta_1/wadamesh-heltec-v4-tft-merged.bin
|
||||
# releases/TOUCH/beta_1/wadamesh-tdeck.bin
|
||||
# releases/TOUCH/beta_1/wadamesh-tdeck-merged.bin
|
||||
#
|
||||
# The on-device version check GETs http://firmware.wadamesh.com/releases/TOUCH and
|
||||
# scans the body for the highest beta_<N>. We serve index.json at exactly that
|
||||
# path (no trailing-slash redirect, which the on-device HTTPClient may not follow).
|
||||
#
|
||||
# Cloudflare: firmware.wadamesh.com proxied; SSL "Full". Plain HTTP must remain
|
||||
# reachable (the firmware checks over HTTP) — do NOT force HTTPS on this host.
|
||||
# Cache Rule: cache .bin aggressively (Edge TTL ~1d); index.json short TTL (~60s)
|
||||
# or bypass, so a new release shows up promptly.
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name firmware.wadamesh.com;
|
||||
|
||||
root /srv/wadamesh/firmware;
|
||||
|
||||
# The update-check feed — served at the no-slash path the firmware requests.
|
||||
location = /releases/TOUCH {
|
||||
default_type application/json;
|
||||
alias /srv/wadamesh/firmware/releases/TOUCH/index.json;
|
||||
add_header Cache-Control "public, max-age=60";
|
||||
}
|
||||
|
||||
# Bins + everything else under /releases/.
|
||||
location /releases/ {
|
||||
autoindex off;
|
||||
types { application/octet-stream bin; }
|
||||
add_header Cache-Control "public, max-age=86400";
|
||||
}
|
||||
|
||||
location / { return 404; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# tiles.wadamesh.com — OSM tile proxy for the wadamesh map tab.
|
||||
#
|
||||
# The firmware fetches plain HTTP (on-device HTTPS isn't workable: mbedTLS wants
|
||||
# ~30 KB heap for a handshake and only ~5 KB is free after Wi-Fi associates), so
|
||||
# this vhost is HTTP-only by design. Cloudflare sits in front and caches the
|
||||
# .png tiles at the edge; this origin keeps a second 14-day disk cache.
|
||||
#
|
||||
# Deploy: copy to /etc/nginx/sites-available/, symlink into sites-enabled/, then
|
||||
# nginx -t && systemctl reload nginx
|
||||
# Cloudflare: tiles.wadamesh.com proxied (orange cloud), SSL/TLS mode "Flexible"
|
||||
# (CF<->origin HTTP), and a Cache Rule: Eligible for cache + Edge TTL ~14d for
|
||||
# path "/*". Do NOT enable "Always Use HTTPS" on this hostname.
|
||||
|
||||
proxy_cache_path /var/cache/nginx/wadamesh-tiles levels=1:2
|
||||
keys_zone=wadamesh_tiles:10m max_size=4g inactive=14d use_temp_path=off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name tiles.wadamesh.com;
|
||||
|
||||
# Re-resolve the upstream at request time. A literal hostname in proxy_pass
|
||||
# fails with "no resolver defined" on a fresh box; a variable + resolver works.
|
||||
resolver 1.1.1.1 8.8.8.8 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# The location regex is DOUBLE-QUOTED on purpose: nginx's lexer otherwise
|
||||
# treats { and } (quantifiers) as block delimiters and refuses to start.
|
||||
location ~ "^/(\d{1,2})/(\d{1,7})/(\d{1,7})\.png$" {
|
||||
set $osm_upstream "tile.openstreetmap.org";
|
||||
|
||||
proxy_pass https://$osm_upstream/$1/$2/$3.png;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_set_header Host tile.openstreetmap.org;
|
||||
# OSM tile usage policy requires a valid, identifying User-Agent.
|
||||
proxy_set_header User-Agent "wadamesh-tile-proxy/1.0 (+https://wadamesh.com)";
|
||||
proxy_set_header Referer "https://wadamesh.com/";
|
||||
|
||||
proxy_cache wadamesh_tiles;
|
||||
proxy_cache_valid 200 302 14d;
|
||||
proxy_cache_valid 404 1h;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
proxy_cache_lock on;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
expires 14d;
|
||||
}
|
||||
|
||||
location / { return 404; }
|
||||
}
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# wadamesh release: build tagged bins for both touch boards, refresh the
|
||||
# update-check listing, and publish to the firmware VPS (behind Cloudflare).
|
||||
#
|
||||
# Usage:
|
||||
# WADAMESH_VPS=user@your-vps WADAMESH_VPS_PATH=/srv/wadamesh/firmware \
|
||||
# scripts/release.sh beta_2
|
||||
#
|
||||
# The VPS target comes from the environment — never commit it (Cloudflare fronts
|
||||
# the origin, so the IP isn't needed in the firmware anyway).
|
||||
set -euo pipefail
|
||||
|
||||
TAG="${1:?usage: release.sh <tag> e.g. beta_2}"
|
||||
PIO="${PIO:-$HOME/Library/Python/3.9/bin/pio}"
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
OUT="$ROOT/out/firmware" # local mirror of the VPS firmware root
|
||||
REL="$OUT/releases/TOUCH"
|
||||
DEST="${WADAMESH_VPS:-}"; DEST_PATH="${WADAMESH_VPS_PATH:-/srv/wadamesh/firmware}"
|
||||
|
||||
declare -A ENVS=(
|
||||
[heltec_v4_tft_companion_radio_usb_tcp_touch]=wadamesh-heltec-v4-tft
|
||||
[LilyGo_TDeck_companion_radio_touch]=wadamesh-tdeck
|
||||
)
|
||||
|
||||
# 1. Pull the current published tree so the listing stays complete across tags.
|
||||
if [ -n "$DEST" ]; then
|
||||
mkdir -p "$OUT"
|
||||
rsync -a "$DEST:$DEST_PATH/" "$OUT/" 2>/dev/null || echo "note: first publish (nothing to pull yet)"
|
||||
fi
|
||||
mkdir -p "$REL/$TAG"
|
||||
|
||||
# 2. Build both boards (app + merged), tag + version embedded.
|
||||
export PLATFORMIO_BUILD_FLAGS="-DFIRMWARE_RELEASE_TAG='\"${TAG}\"' -DFIRMWARE_VERSION='\"wadamesh ${TAG}\"'"
|
||||
for env in "${!ENVS[@]}"; do
|
||||
name="${ENVS[$env]}"
|
||||
"$PIO" run -t mergebin -e "$env"
|
||||
cp ".pio/build/$env/firmware.bin" "$REL/$TAG/$name.bin"
|
||||
cp ".pio/build/$env/firmware-merged.bin" "$REL/$TAG/$name-merged.bin"
|
||||
done
|
||||
|
||||
# 3. Regenerate the update-check listing (the firmware scans the body for the
|
||||
# highest beta_<N>). JSON array of dir names — GitHub-contents shape.
|
||||
python3 - "$REL" > "$REL/index.json" <<'PY'
|
||||
import os, sys, json
|
||||
rel = sys.argv[1]
|
||||
betas = sorted(d for d in os.listdir(rel)
|
||||
if d.startswith("beta_") and os.path.isdir(os.path.join(rel, d)))
|
||||
print(json.dumps([{"name": b, "type": "dir"} for b in betas], indent=2))
|
||||
PY
|
||||
echo "listing: $(python3 -c 'import json,sys;print(", ".join(x["name"] for x in json.load(open(sys.argv[1]))))' "$REL/index.json")"
|
||||
|
||||
# 4. Publish to the VPS (Cloudflare caches at the edge).
|
||||
if [ -n "$DEST" ]; then
|
||||
rsync -av "$OUT/" "$DEST:$DEST_PATH/"
|
||||
echo "published $TAG -> $DEST:$DEST_PATH"
|
||||
else
|
||||
echo "WADAMESH_VPS not set — built + staged in $REL/$TAG only (no publish)."
|
||||
fi
|
||||
Reference in new issue
Block a user