Riscrivi backend per hosting Node/MariaDB/PM2 (no Cloudflare)

L'utente ha un hosting Virtualmin esistente (musictools.djluza.com)
con Apache + Node 20 + MariaDB + PM2. Tutta l'infrastruttura
Cloudflare (Workers/D1/R2/Pages) e' rimpiazzata con un backend
Express che gira sul server gia' presente, a costo zero.

Cambia:
- server/src/*.ts (Workers) -> server/src/*.js (Node ESM puro)
- D1 (sqlite) -> MariaDB 10.11 via mysql2/promise
- R2 (storage) -> filesystem locale ~/builds/ + signed URL HMAC
- wrangler.toml -> ecosystem.config.cjs (PM2)
- Aggiunto src/migrate.js: runner SQL idempotente

Endpoints invariati - l'app desktop non vede differenze:
- POST /api/license/{activate,validate,deactivate}
- GET  /api/latest, /api/download
- POST /api/webhook/lemonsqueezy
- GET  /api/health

README riscritto con istruzioni complete: creazione DB,
deploy via rsync/git, config Apache reverse proxy via
Virtualmin, gestione PM2, backup, workflow release.

Email rimane su Resend (deliverability) - free tier sufficiente.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
luzadevandClaude Opus 4.7 committed 2026-06-09 00:15:53 +02:00
1 parent 339dd4f3cc
commit 2d8290579b
22 files changed
+892 -790

No files matched your search

+187 -60
View File
@@ -1,51 +1,190 @@
# MusicTools License & Update API
# MusicTools — License & Update API
Cloudflare Worker che gestisce attivazione licenze, validazione e distribuzione binari MusicTools.
Backend Node.js per gestire attivazione licenze, validazione e distribuzione binari MusicTools.
## Stack
- **Cloudflare Workers** (compute serverless, free tier 100k req/giorno)
- **Cloudflare D1** (sqlite gestito, free tier 5GB)
- **Cloudflare R2** (storage zip binari, free tier 10GB)
- **Lemon Squeezy** (Merchant of Record per i pagamenti, gestisce IVA UE)
- **Resend** (invio email license-key, free tier 3k email/mese)
## Setup iniziale
- **Node.js 20 + Express 4**
- **MariaDB 10.11** (locale, localhost:3306)
- **PM2** per process management
- **Apache 2.4** come reverse proxy verso `127.0.0.1:4002`
- **Resend** per email transazionali
- **Lemon Squeezy** per i pagamenti (webhook -> `/api/webhook/lemonsqueezy`)
Una volta sola, da terminale dentro `server/`:
Tutto gira sull'hosting esistente (`musictools@musictools.djluza.com`), zero costi aggiuntivi.
## Struttura
```
server/
src/
server.js # Express app
db.js # pool mysql2
license.js # activate / validate / deactivate
updates.js # /api/latest + /api/download
lemonsqueezy.js # webhook ordini
email.js # Resend client
jwt.js # JWT HS256 senza dipendenze
migrate.js # runner SQL idempotente
migrations/
0001_init.sql # schema licenses / activations / releases
ecosystem.config.cjs # PM2
.env.example
package.json
```
## Setup iniziale sul server
Una volta sola, da SSH `musictools@musictools.djluza.com`:
### 1) Crea database e utente MariaDB
Sul server (richiede root o l'utente master DB del tuo hosting — di solito Virtualmin lo crea per te dal pannello "Edit Databases"):
```sql
CREATE DATABASE musictools_licenses CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'musictools'@'localhost' IDENTIFIED BY 'PASSWORD_FORTE';
GRANT ALL PRIVILEGES ON musictools_licenses.* TO 'musictools'@'localhost';
FLUSH PRIVILEGES;
```
In alternativa via Virtualmin: **Edit Databases → Create a new database**, poi tab **Manage** → crea utente con password.
### 2) Clona o sincronizza il codice
Due opzioni:
**A. Via git** (consigliato):
```bash
cd ~
git clone https://github.com/luzadev/musicdownload.git app-src
ln -s app-src/server api
cd api
npm install --production
```
**B. Via rsync da locale** (più semplice se preferisci non lasciare codice client sul server):
```bash
# Da Mac:
rsync -avz --exclude node_modules /Users/luciano/Downloads/Progetti2026/MusicDownload/server/ musictools@musictools.djluza.com:~/api/
# Poi SSH e:
cd ~/api && npm install --production
```
### 3) Configura .env
```bash
npm install
npx wrangler login # autenticati a Cloudflare
# 1. Crea il database D1
npx wrangler d1 create musictools-licenses
# -> copia il database_id stampato nel wrangler.toml
# 2. Applica lo schema
npm run db:migrate:prod
# 3. Crea il bucket R2 per i binari
npx wrangler r2 bucket create musictools-builds
# 4. Imposta i secret (NON in chiaro nel wrangler.toml)
npx wrangler secret put JWT_SECRET # > openssl rand -base64 32
npx wrangler secret put LEMONSQUEEZY_SIGNING_SECRET # > dal dashboard LS
npx wrangler secret put RESEND_API_KEY # > dal dashboard Resend
# 5. Deploy
npm run deploy
cd ~/api
cp .env.example .env
nano .env # compila tutti i valori — vedi sotto
```
## DNS
Su Cloudflare Dashboard > djluza.com > DNS aggiungi:
```
musictools CNAME <subdomain-worker>.workers.dev proxied
Per generare `JWT_SECRET`:
```bash
openssl rand -base64 32
```
Poi vai su Workers & Pages > musictools-api > Settings > Triggers > Custom Domains
e aggiungi `musictools.djluza.com`.
### 4) Migrate
```bash
cd ~/api
npm run migrate
```
Output atteso:
```
[migrate] applico 0001_init.sql
[migrate] ok 0001_init.sql
[migrate] done
```
### 5) Avvia con PM2
```bash
cd ~/api
mkdir -p logs
pm2 start ecosystem.config.cjs
pm2 save
# Test:
curl -s http://127.0.0.1:4002/api/health
# -> {"ok":true,"version":"v1.5.2"}
```
### 6) Apache reverse proxy
Devi dire ad Apache che le richieste a `musictools.djluza.com/api/*` vanno a `127.0.0.1:4002`.
**Via Virtualmin** (consigliato):
1. Vai su **Webmin → Servers → Apache Webserver**
2. Clicca sul VirtualHost di `musictools.djluza.com` (porta 443)
3. Sezione **Aliases and redirects** o **Edit Directives**, aggiungi prima di `</VirtualHost>`:
```apache
# MusicTools API
ProxyPreserveHost On
ProxyRequests Off
# Webhook: passa raw body senza alterazioni
<Location /api/>
ProxyPass http://127.0.0.1:4002/api/
ProxyPassReverse http://127.0.0.1:4002/api/
</Location>
```
4. Apply changes.
**Verifica moduli Apache attivi** (da SSH se hai sudo):
```bash
apache2ctl -M | grep -E 'proxy|proxy_http'
# Devono comparire proxy_module e proxy_http_module
```
Se mancano, abilitali (sudo richiesto):
```bash
sudo a2enmod proxy proxy_http
sudo systemctl reload apache2
```
### 7) Verifica end-to-end
Da qualsiasi posto:
```bash
curl -s https://musictools.djluza.com/api/health
# -> {"ok":true,"version":"v1.5.2"}
```
## Workflow pubblicazione release
1. GitHub Actions builda i due zip (gia in place).
2. Carica gli zip sul server in `~/builds/<version>/`:
```bash
ssh musictools@musictools.djluza.com 'mkdir -p ~/builds/v1.5.3'
scp MusicTools-macOS.zip musictools@musictools.djluza.com:~/builds/v1.5.3/
scp MusicTools-Windows.zip musictools@musictools.djluza.com:~/builds/v1.5.3/
```
3. Inserisci il record in MariaDB:
```bash
ssh musictools@musictools.djluza.com 'mariadb musictools_licenses' <<SQL
INSERT INTO releases (version, platform, file_path, size_bytes, sha256, notes, published_at)
VALUES ('v1.5.3', 'macos', 'v1.5.3/MusicTools-macOS.zip', 12345, '<sha256>', 'Note...', UNIX_TIMESTAMP()),
('v1.5.3', 'windows', 'v1.5.3/MusicTools-Windows.zip', 67890, '<sha256>', 'Note...', UNIX_TIMESTAMP());
SQL
```
4. Aggiorna `LATEST_VERSION` nel `.env` e `pm2 reload musictools-api`.
In futuro: script o workflow GitHub Actions che fa tutto in automatico.
## Operazioni quotidiane
| Cosa | Comando |
|---|---|
| Reload codice dopo deploy | `pm2 reload musictools-api` |
| Vedere log live | `pm2 logs musictools-api` |
| Stato | `pm2 status` |
| Errori recenti | `pm2 logs musictools-api --err --lines 100` |
| Restart hard | `pm2 restart musictools-api` |
| Stop | `pm2 stop musictools-api` |
| Console DB | `mariadb -u musictools -p musictools_licenses` |
## Endpoints
@@ -55,34 +194,22 @@ e aggiungi `musictools.djluza.com`.
| POST | `/api/license/validate` | — (token nel body) | Rivalida + ruota token |
| POST | `/api/license/deactivate` | — (token nel body) | Libera uno slot |
| GET | `/api/latest?platform=…` | Bearer token (opzionale) | Versione + URL download firmato |
| GET | `/api/download?file=…&exp=…&sig=…` | Firma HMAC | Stream del binario |
| POST | `/api/webhook/lemonsqueezy` | X-Signature HMAC | Crea licenza dopo ordine |
| GET | `/api/health` | — | Healthcheck |
## Workflow pubblicazione release
## Backup
1. GitHub Actions builda macOS e Windows zip (gia in place).
2. Step manuale (per ora): scarica i due zip, caricali su R2:
```bash
npx wrangler r2 object put musictools-builds/v1.5.3/MusicTools-macOS.zip --file=MusicTools-macOS.zip
npx wrangler r2 object put musictools-builds/v1.5.3/MusicTools-Windows.zip --file=MusicTools-Windows.zip
```
3. Inserisci il record `releases`:
```sql
INSERT INTO releases (version, platform, r2_key, size_bytes, sha256, notes, published_at)
VALUES ('v1.5.3', 'macos', 'v1.5.3/MusicTools-macOS.zip', 12345, '<sha256>', 'Note...', strftime('%s','now'));
```
(eseguibile da `npx wrangler d1 execute musictools-licenses --remote --command "..."`)
Aggiungi un cronjob daily:
In futuro: workflow GitHub Actions che fa upload R2 + insert D1 in automatico.
## TODO
- [ ] Implementare `/api/download` che verifica firma e fa stream da R2
- [ ] Endpoint admin per emettere licenze a mano (es. recensori, refund)
- [ ] Rate limiting con KV su `/api/license/activate` (anti brute-force)
- [ ] Cron worker giornaliero che marca le licenze inattive da > 1 anno
```bash
# crontab -e
0 4 * * * mariadb-dump musictools_licenses | gzip > ~/backups/musictools-$(date +\%F).sql.gz && find ~/backups -name 'musictools-*.sql.gz' -mtime +30 -delete
```
## Costi
A 0 vendite: **0€/mese** (tutto in free tier).
A 100 vendite/mese: ~5€ Lemon Squeezy commission + 0€ Cloudflare = ~5€.
- **Hosting**: gia pagato (server condiviso esistente)
- **Lemon Squeezy**: 5% + $0.50 per transazione = ~5 EUR su un acquisto da 39,90 EUR
- **Resend**: free fino a 3k email/mese (= ~3k licenze/mese, oltre serve piano $20)
- **Totale fisso**: 0 EUR/mese