Aller au contenu principal

Déploiement parallèle de RSSHub en production

Ce que cette phase prouve

RSSHub est la première vraie charge applicative du VPS. Il possède un nom HTTPS public, une route réelle fonctionnelle, un contrôle d’accès et une supervision, mais reste un déploiement parallèle car aucun consommateur de production n’a migré :

Canari public
`-- HTTPS -> Caddy -> infra-edge -> RSSHub du VPS

consommateur de feeds existant
`-- RSSHub local -> production actuelle et solution de repli

Le chemin serveur est donc prouvé avant que la phase 4 ne change le consommateur. Une instance parallèle défaillante peut quitter l’entrée publique sans interrompre le consommateur existant.

Carte des responsabilités

ComposantResponsabilitéCe qu’il ne fait pas
DNS faisant autoritéRésoudre le sous-domaine RSS vers le VPSNe mandate pas l’application et ne gère pas les conteneurs
CaddyPosséder 80/443, TLS, les redirections et le proxyNe stocke pas l’ACCESS_KEY brute de RSSHub
infra-edgeRelier Caddy et RSSHub et fournir la découverte de serviceNe publie pas le port 1200 sur l’hôte ou Internet
RSSHubRécupérer les sources, produire RSS et protéger les vraies routesNe stocke pas les données du consommateur
Uptime KumaVérifier /healthz publiquement sans cléNe contient pas l’ACCESS_KEY et n’expose pas son interface
RSSHub localContinuer à servir le consommateur actuelN’est ni arrêté ni supprimé en phase 3

Le chemin public est :

rss.example.com
|
v
Caddy :80/:443
|
v
infra-edge
|
v
rsshub-prod:1200

Seul Caddy publie des ports d’hôte. Le 1200/tcp de RSSHub reste dans Docker ; ni l’adresse publique ni l’adresse Tailscale de l’hôte ne l’accepte directement.

Pourquoi l’architecture reste minimale

La route Bilibili représentative produisait déjà un RSS valide et non vide sur l’instance locale sans Redis, Browserless ni Chromium. Le VPS démarre donc avec le même minimum :

  • image RSSHub officielle épinglée par digest immuable ;
  • CACHE_TYPE=memory ;
  • aucun Redis ;
  • aucun Browserless ou Chromium ;
  • aucune base ni volume de données applicatives.

La présence d’un service facultatif dans un exemple amont ne prouve pas qu’un nœud personnel en a besoin. On ne l’ajoute qu’après qu’une route requise a démontré cette dépendance.

Fichiers et frontière des secrets

/srv/rsshub/
├── compose.yaml # image, santé, réseau et redémarrage vérifiables
└── .env # mode 600 ; jamais commité ni développé dans un rapport

Le fichier d’environnement ne contient que les variables nécessaires : une nouvelle ACCESS_KEY et la paire UID/cookie exigée par la route Bilibili représentative. Les noms peuvent être documentés ; les valeurs ne doivent jamais entrer dans le chat, Git, le site ou une sortie Compose partagée.

La forme importante de Compose reste volontairement petite :

services:
rsshub:
image: diygod/rsshub@sha256:<immutable-digest>
restart: unless-stopped
env_file: [.env]
environment:
NODE_ENV: production
CACHE_TYPE: memory
DISALLOW_ROBOT: "1"
networks:
infra-edge:
aliases: [rsshub-prod]

networks:
infra-edge:
external: true

Il n’y a volontairement aucun ports:, réseau hôte, mode privilégié, socket Docker, base de données ou volume applicatif persistant.

Santé et contrôle d’accès ont des rôles distincts

Les vraies routes RSS exigent une ACCESS_KEY valide et répondent 403 sans elle. La supervision doit rester sans clé pour que Kuma ne conserve aucun identifiant de grande valeur.

La version actuelle de RSSHub protège aussi /healthz quand ACCESS_KEY est définie. Le déploiement ne copie pas la clé brute dans Caddy. Il utilise le code dérivé et lié à la route que RSSHub prend en charge : le healthcheck le calcule à l’exécution, et Caddy injecte seulement celui qui vaut pour /healthz.

GET /healthz -> 200, aucune clé fournie par l’appelant
GET /vraie/route/rss -> 403
GET /vraie/route/rss?key=<valid-key> -> 200

La santé publique traverse toujours Caddy, infra-edge et RSSHub ; Caddy ne fabrique pas une réponse statique. La valeur du code dérivé n’est pas publiée non plus.

Contrôles courants

Sur le VPS :

[REMOTE: VPS]
cd /srv/rsshub
docker compose ps
docker compose logs --tail 100 rsshub

RSSHUB_ID=$(docker compose ps -q rsshub)
docker inspect "$RSSHUB_ID" \
--format '{{.State.Status}} {{.State.Health.Status}} {{json .HostConfig.PortBindings}}'

docker network inspect infra-edge

Le résultat accepté est running healthy, une table {}, et Caddy avec RSSHub sur infra-edge.

Depuis WSL2 :

[LOCAL: WSL2]
curl --fail https://rss.example.com/healthz
curl -I http://rss.example.com/healthz

# Les deux doivent expirer ou refuser, sans jamais renvoyer RSSHub.
curl --connect-timeout 5 --max-time 7 \
"http://$VPS_PUBLIC_IPV4:1200/"
curl --connect-timeout 5 --max-time 7 \
"http://$TAILSCALE_IPV4:1200/"

Une vérification de route réelle ne doit rapporter que le statut, le format du flux, la correspondance d’identité du canal et le nombre d’éléments. Ne collez jamais une URL complète contenant clé, UID privé ou cookie dans un journal ou une note.

Redémarrage contrôlé

La phase 3 ne redémarre pas tout le VPS. Redémarrez uniquement la nouvelle application :

[REMOTE: VPS]
cd /srv/rsshub
docker compose restart rsshub
docker compose ps

Après le retour de la santé, revérifiez la santé publique, le 403 sans authentification, le flux authentifié, Caddy, Kuma, SSH via Tailscale et le blocage du SSH public. Les identifiants et heures de démarrage de Caddy et Kuma ne doivent pas changer.

Retour arrière

Un déploiement sain n’a pas besoin d’une démonstration destructive. La séquence mécanique est :

  1. Restaurer Caddyfile depuis /srv/caddy/Caddyfile.pre-rsshub-p3.
  2. Valider toute la configuration Caddy restaurée.
  3. Recharger Caddy sans redémarrer son conteneur.
  4. Exécuter docker compose -f /srv/rsshub/compose.yaml down.
  5. Conserver /srv/rsshub/compose.yaml et le .env protégé.
  6. Laisser tourner le RSSHub local ; retirer le DNS plus tard seulement si souhaité.

N’utilisez jamais docker system prune -a, volume prune ou network prune pour ce retour arrière.

Ce qui n’a pas eu lieu

La phase 3 n’a modifié ni l’endpoint du consommateur, ni ses données persistantes, son planificateur ou sa configuration des sources, et n’a pas arrêté RSSHub local. La phase 4 doit traiter ensemble la bascule du consommateur, la sauvegarde et restauration des données persistantes, la migration du planificateur et le retrait éventuel du repli.