Appearance
Déploiement VPS via Tailscale (sans domaine, sans TLS)
Objectif : faire passer le backend TCG du PC Windows au VPS, continuer à y accéder depuis le téléphone via Tailscale, et servir les images de cartes depuis notre propre nginx au lieu de TCGdex.
C'est le setup Option B — le chemin le plus rapide vers "VPS only" sans acheter de domaine ni configurer Let's Encrypt. Tout le tunnel entre le téléphone et le VPS reste à l'intérieur de votre tailnet Tailscale, donc HTTP en clair est acceptable.
Pour le setup production / domaine public (HTTPS via Caddy), voir le guide jumeau vps-public-deployment.md (à écrire quand vous serez prêt à quitter Tailscale).
Ce que veut dire "Option B" en pratique
| Aujourd'hui | Après ce guide | |
|---|---|---|
| Où tourne le backend | PC Windows, Docker Desktop | VPS (Linux) |
| Comment le téléphone l'atteint | http://100.76.15.57:8000/scan-compat (IP tailnet du PC) | http://<IP_TAILNET_VPS>:8000/scan-compat |
| D'où viennent les images de cartes | CDN TCGdex (assets.tcgdex.net) | Notre propre nginx sur le VPS, alimenté depuis data/images/ |
| Pré-requis téléphone | Tailscale activé | Tailscale activé (même contrainte) |
| Exposition publique | Aucune | Aucune — les services bind sur l'IP tailnet uniquement |
Vous gardez la dépendance Tailscale sur le téléphone (déjà le cas aujourd'hui), mais le laptop n'est plus dans la boucle.
Pré-requis
- Le VPS a déjà Docker Engine + plugin compose et le repo
snag-tcg/tcg-collector-backendcloné. - La PR qui introduit
LOCAL_IMAGE_BASE_URL(#92) est mergée dansmain. - Vous avez accès admin à votre tailnet Tailscale (pour ajouter le VPS comme node).
- Le téléphone est déjà sur le tailnet (c'est le cas, puisque le setup actuel marche).
Étape 1 — Installer Tailscale sur le VPS
Sur le VPS :
bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
# Suivez l'URL imprimée dans un navigateur pour authentifier le node sur votre tailnet.
# Taggez-le (console admin Tailscale → Machines) p. ex. "tcg-vps" pour la lisibilité.
# Notez l'IP tailnet — vous en aurez besoin partout désormais.
tailscale ip -4
# p. ex. 100.124.7.91À partir d'ici ce guide utilise <IP_TAILNET_VPS> comme placeholder pour cette IP. Remplacez par votre vraie valeur (ou exportez IP_TAILNET_VPS=100.124.7.91 dans votre shell pour copier-coller les blocs sans modification).
Sanity check depuis le laptop (aussi sur le tailnet) :
bash
ping -c 3 <IP_TAILNET_VPS>
ssh kael@<IP_TAILNET_VPS> # vérifier que SSH marche toujours via le tailnetÉtape 2 — Pull du dernier backend sur le VPS
SSH dans le VPS :
bash
cd ~/snag-tcg/tcg-collector-backend
git checkout main
git pullConfirmer que les nouvelles env vars sont bien visibles dans .env.example (ajoutées par la PR #92) :
bash
grep -A 2 LOCAL_IMAGE_BASE_URL .env.exampleÉtape 3 — Configurer .env sur le VPS
Ne pas copier le
.envdu laptop tel quel. Plusieurs valeurs changent (LOCAL_IMAGE_BASE_URLdoit pointer sur l'IP tailnet du VPS, pas du laptop ;CORS_ORIGINpeut différer ; etc.), et autant traiter le VPS comme un environnement séparé avec ses propres secrets. Le seul fichier.envqui compte côté VPS est celui detcg-collector-backend—poc-tcg-collectorreste sur le laptop,documentationn'a pas de secrets.Exception : si à l'Étape 6 vous décidez de transférer
data/pg/du laptop au lieu de relancer un ingest frais (~30 min gagnées), alorsPGPASSWORDcôté VPS doit être identique à celui du laptop, sinon Postgres refuse de monter le volume. Par défaut ce guide fait un ingest frais → cette contrainte ne s'applique pas, générez des secrets neufs.
bash
cp .env.example .env # uniquement si .env n'existe pas encore
# Générer des secrets frais directement sur le VPS, et les sauvegarder
# dans votre password manager AVANT d'éditer .env. Une fois Postgres
# initialisé avec PGPASSWORD, le changer demande de wiper data/pg/.
openssl rand -hex 32 # → PGPASSWORD
openssl rand -hex 32 # → API_WRITE_TOKEN
nano .envÀ régler au minimum :
bash
# Postgres — choisir un mot de passe fort AVANT le premier `compose up`.
# Une fois que Postgres a initialisé data/pg/ avec ce mot de passe, le
# changer demande soit un ALTER USER dans le container qui tourne, soit
# de wiper le dossier data. Donc autant le faire bien dès le départ.
PGUSER=tcg
PGPASSWORD=<chaine-aleatoire-longue>
# API
API_WRITE_TOKEN=<chaine-aleatoire-longue>
CORS_ORIGIN=* # acceptable sur un tailnet ; à resserrer quand on passera sur un domaine
# tcg-vision — images de cartes self-hosted.
# IMPORTANT : doit être joignable *depuis le téléphone*, donc utilisez
# l'IP tailnet du VPS, pas localhost (le téléphone résout cette URL
# après le scan).
LOCAL_IMAGE_BASE_URL=http://<IP_TAILNET_VPS>:8081/images
LOCAL_IMAGE_EXT=webp
LOCAL_IMAGE_QUALITY=high
# Ingest — premier run. Adaptez INGEST_SETS aux sets que vous voulez.
INGEST_SETS=base1,sv01
INGEST_IMAGES=true
INGEST_IMAGE_QUALITY=low,highÉtape 4 — Binder les ports Docker sur l'IP tailnet uniquement
Par défaut Docker publie les ports sur 0.0.0.0, ce qui veut dire que n'importe qui sur internet qui trouve le VPS peut taper sur :8000, :8080, :8081, :5432. On veut qu'ils soient atteignables uniquement sur le tailnet.
Éditer docker/compose.yml et préfixer chaque mapping ports: avec l'IP tailnet. Exemple pour tcg-vision :
yaml
ports:
- "<IP_TAILNET_VPS>:8000:8000" # avant : "${TCG_VISION_PORT:-8000}:8000"Faire pareil pour nginx (<IP_TAILNET_VPS>:8081:80), api (<IP_TAILNET_VPS>:8080:3000), et postgres (127.0.0.1:5432:5432 — Postgres ne devrait même pas être sur le tailnet).
Ne committez pas ce changement dans le repo — il est spécifique au VPS. Soit utilisez un
docker-compose.override.yml(gitignored sur le VPS), soit gardez-le comme un diff local. Lecompose.ymldu repo doit rester générique.
Alternative plus propre si vous ne voulez pas éditer le compose : laisser compose.yml tel quel et mettre une règle ufw sur le VPS qui autorise 8000/8080/8081 uniquement depuis 100.0.0.0/8 (la plage CGNAT Tailscale) :
bash
sudo ufw allow in on tailscale0
sudo ufw deny 8000
sudo ufw deny 8080
sudo ufw deny 8081
sudo ufw deny 5432
sudo ufw allow ssh
sudo ufw enableChoisissez une approche (binding des ports ou firewall) — les deux marchent mais une seule suffit.
Étape 5 — Démarrer le stack
bash
cd ~/snag-tcg/tcg-collector-backend
# Build et démarrer postgres + api + nginx + tcg-vision (on saute embeddings — obsolète)
docker compose -f docker/compose.yml up -d --build postgres api nginx tcg-vision
# Suivre les logs jusqu'à ce que tout soit healthy (Ctrl+C quitte le tail, pas le stack)
docker compose -f docker/compose.yml logs -fTemps de build attendu : ~5 à 15 min. Le plus long est tcg-vision (télécharge ~85 MB de poids DINOv2 et build PyTorch CPU).
Health checks depuis le laptop (toujours sur le tailnet) :
bash
curl http://<IP_TAILNET_VPS>:8000/health # tcg-vision
curl http://<IP_TAILNET_VPS>:8080/sets # api → postgres (vide tant que l'ingest n'a pas tourné)
curl -I http://<IP_TAILNET_VPS>:8081/ # nginxÉtape 6 — Premier ingest
Peuple Postgres avec sets/cartes et data/images/ avec les visuels. Long mais one-shot :
bash
docker compose -f docker/compose.yml run --rm ingestTail les logs dans un autre terminal si vous voulez suivre la progression. Comptez ~30 min selon INGEST_SETS et le rate-limit TCGdex.
Quand c'est fini, vérifier que les images sont bien sur disque :
bash
ls data/images/ | head
# A1 A1a A2 ...
ls data/images/A1/001/
# high.webp low.webpEt que nginx les sert sur le tailnet :
bash
curl -I http://<IP_TAILNET_VPS>:8081/images/A1/001/high.webp
# HTTP/1.1 200 OK
# Content-Type: image/webpÉtape 7 — Mettre à jour l'app mobile
Sur votre laptop, dans le repo poc-tcg-collector :
bash
cd ~/projects/poc-tcg-collector # ou là où il est sur votre machine
git checkout main && git pull
git checkout -b chore/repoint-scan-url-to-vpsÉditer src/scan/backendConfig.ts:45 :
ts
// Avant :
export const BACKEND_SCAN_URL = 'http://100.76.15.57:8000/scan-compat';
// Après (remplacez par l'IP tailnet de votre VPS) :
export const BACKEND_SCAN_URL = 'http://<IP_TAILNET_VPS>:8000/scan-compat';Commit, push, ouvrir une PR (per règles du repo, pas de push direct sur main) :
bash
git add src/scan/backendConfig.ts
git commit -m "chore(scan): repoint BACKEND_SCAN_URL to VPS tailnet IP"
git push -u origin chore/repoint-scan-url-to-vps
gh pr create --base mainAprès merge, rebuilder l'APK et réinstaller sur le téléphone :
bash
cd android
./gradlew assembleRelease
# Installer android/app/build/outputs/apk/release/app-release.apk sur le téléphoneÉtape 8 — Test bout-en-bout depuis le téléphone
Le téléphone doit être sur Tailscale (c'est déjà le cas). Ouvrez l'app, scannez une carte.
Attendu :
- Le scan revient en ~1-2 s.
- Un visuel de carte apparaît (servi par votre nginx VPS, pas TCGdex).
- Dans les logs
tcg-visioncôté VPS vous devriez voir un vraiPOST /scan-compat, et juste après, une ligne nginx du typeGET /images/A1/001/high.webp 200.
Si l'image reste blanche, vérifiez :
LOCAL_IMAGE_BASE_URLutilise bien l'IP tailnet du VPS (paslocalhostni127.0.0.1).- La carte matchée par FAISS appartient à un set que vous avez ingéré. Sinon l'URL 404 — relancez l'ingest avec le set manquant dans
INGEST_SETS. tailscale statussur le téléphone — Android le met parfois en veille. Tapez la notification Tailscale pour confirmer que le tunnel est up.
Étape 9 — Décommissionner le stack laptop (optionnel mais recommandé)
Une fois que vous avez confirmé que le téléphone parle bien au VPS :
powershell
# Sur le laptop
cd C:\Users\Kael\Documents\Claude\Projects\SKN\tcg-collector-backend
docker compose -f docker/compose.yml down
# Containers stoppés et supprimés ; data/pg et data/images restent sur disque comme backup.Les images Docker elles-mêmes peuvent rester (ça ne coûte rien tant qu'elles sont arrêtées) ; vous les supprimerez plus tard avec docker image prune -a une fois certain de ne pas vouloir rollback.
Maintenance récurrente
Les futures mises à jour côté VPS sont désormais en une ligne :
bash
cd ~/snag-tcg/tcg-collector-backend
git pull
docker compose -f docker/compose.yml up -d --buildPour un ingest frais (nouveaux sets) : docker compose -f docker/compose.yml run --rm ingest.
Quand passer à l'Option A (domaine public + HTTPS)
À basculer quand l'une de ces conditions devient vraie :
- Vous voulez que des utilisateurs hors Tailscale puissent scanner (vrais beta-testeurs, amis, public).
- La connexion Tailscale du téléphone devient un point de friction (batterie, coupures sur mauvais réseau mobile).
- Vous commencez à manipuler des données utilisateur que vous seriez mal à l'aise de transporter sur HTTP en clair, même sur un tailnet.
La migration est petite : installer Caddy sur le VPS, pointer un (sous-)domaine sur l'IP publique du VPS, swapper LOCAL_IMAGE_BASE_URL et BACKEND_SCAN_URL de http://<IP_TAILNET_VPS>:... vers https://scan.votre-domaine.com/.... Le stack compose lui-même ne change pas.