cadence / DEPLOY.md
Vincisteel's picture
Upload 45 files
568e7b7 verified
|
Raw History Blame Contribute Delete
5.97 kB

Deploying Cadence

No credit card? See DEPLOY-FREE.md β€” your own machine plus a free https tunnel, or static hosting. Everything below uses platforms that may ask for card verification.

The app is a single Flask service: it serves the dashboard, the installable PWA assets (/manifest.webmanifest, /sw.js, icons) and the JSON/audio API from one origin. That matters β€” a same-origin deployment means no CORS setup and no mixed-content problems, and the installed Android app talks to the same URL it was installed from.

Everything below is prepared and tested; only the account-level clicks are yours.

File Used by
Dockerfile Render, Railway, Fly, any container host
render.yaml Render Blueprint (includes a 5 GB persistent disk)
railway.json Railway (Dockerfile builder + health check)
fly.toml Fly.io (volume mount, https redirect, scale-to-zero)
Procfile Heroku-style hosts
/healthz health probe for all of them ({"status":"ok"})

0. Put the code in a git repo

All three platforms deploy from git.

cd cadence
git init
git add .
git commit -m "Cadence: dashboard, API, PWA"
# create an empty repo on GitHub first, then:
git remote add origin https://github.com/<you>/cadence.git
git push -u origin main

standalone/, run.sh, the platform files and *.zip are excluded from the image by .dockerignore; __pycache__ and .venv are in .gitignore.


1. Render (recommended, and the simplest)

  1. Sign in at https://render.com, click New β†’ Blueprint.
  2. Pick your repo. Render reads render.yaml and shows a cadence web service with a /data disk.
  3. Apply β€” first build takes ~3–5 minutes, mostly pip install.

You get https://cadence-xxxx.onrender.com.

Notes:

  • plan: starter (paid) keeps the service warm. The free plan sleeps after 15 minutes of inactivity, so the first request afterwards takes ~30 s β€” the health check absorbs it.
  • Change region: in render.yaml if you prefer a different one; frankfurt is closest to Switzerland.
  • The disk keeps the audio cache across restarts. 5 GB is plenty (the cache self-evicts at 3 GB).

Without the blueprint, creating a plain Web Service also works: Render detects the Dockerfile automatically. Add env vars CADENCE_CACHE=/data and PORT=10000, and a disk mounted at /data.


2. Railway

npm i -g @railway/cli
railway login
railway init                      # create a new project
railway up                        # builds the Dockerfile and deploys

# persistent cache (otherwise it's rebuilt after every deploy)
railway volume add --mount-path /data
railway variables set CADENCE_CACHE=/data
railway domain                    # gives you an https URL

railway.json already sets the start command, /healthz health check and single-replica policy. Keep one replica: the download locks and telemetry counters live in-process.


3. Fly.io

curl -L https://fly.io/install.sh | sh
fly auth login

cd cadence
fly launch --copy-config --name cadence-<something-unique> --region zrh
fly volumes create cadence_cache --size 5 --region zrh
fly deploy

fly.toml sets force_https = true, mounts the volume at /data, and stops the machine when idle (auto_stop_machines = "stop") β€” a cold start costs a couple of seconds.


After deploying β€” check these three things

BASE=https://your-app.example

curl -s $BASE/healthz                       # {"status":"ok",...}
curl -s -o /dev/null -w '%{http_code}\n' $BASE/manifest.webmanifest   # 200
curl -s $BASE/api/stats                     # JSON, cached_tracks etc.

Then open $BASE on your phone β†’ Install Cadence appears β†’ install. The installed app is same-origin with the API, so search and playback work with no extra configuration (no βš™ backend URL needed).

Expectations on cloud hosting

Audio downloads may be blocked. YouTube rate-limits media fetches from datacenter IPs. Render, Railway and Fly all run in datacenters, so playback can fail with

{"error":"YouTube refused to serve this audio to the server's IP address.","code":"youtube_blocked"}

The dashboard says so explicitly and pauses instead of skipping. Search, charts, genres, artist pages and suggestions all keep working β€” only the audio bytes are refused. Options:

  • Route yt-dlp through a residential proxy: set HTTPS_PROXY in the service's environment.
  • Keep playback local (./run.sh on your machine) and use the deployed instance for browsing.
  • Some regions/IPs are not blocked β€” it's worth simply testing your deployment.

Memory. yt-dlp plus Flask sits around 150–250 MB; the Fly config requests 512 MB. The audio is streamed from disk, not buffered in RAM.

Cold starts. Free tiers sleep. The service worker means the interface opens instantly even then; only live data waits for the wake-up.

Single worker. --workers 1 --threads 16 is deliberate. Multiple worker processes would each keep their own cache index, download locks and stats, so the engine panel would flicker and two workers could download the same track. Scale with threads, not workers.


Updating a deployment

git add -A && git commit -m "..." && git push     # Render/Railway auto-deploy
fly deploy                                         # Fly

The service worker caches the shell, so after an update users get the new version on their next navigation (network-first for pages). To force it, bump VERSION in static/pwa/sw.js and standalone/pwa/sw.js.

Rebuilding the PWA from the dashboard sources

python3 standalone/build_standalone.py     # β†’ cadence-dashboard.html + cadence-android/
python3 standalone/make_icons.py           # if you change the icon design
cp standalone/pwa/sw.js static/pwa/sw.js   # keep the served worker in sync