Aller au contenu

Faire tourner un nœud

Cette page s'adresse à vous une fois le nœud monté : le piloter, le sauvegarder, le régler, savoir quoi regarder quand il ne catalogue plus. Si vous n'avez pas encore de nœud, commencez par Installer un nœud. Si quelque chose est cassé, allez à Diagnostics avancés.


Cycle de vie & données

Un nœud est deux conteneurs, deux services compose :

  • p2pwatch, le crawler, qui sert aussi le catalogue web sur un thread dédié. Il tourne directement sous votre PUID:PGID.
  • ed2k, le client eMule. Dedans, le superviseur s6 fait tourner deux services : amuled, qui démarre à son tour amuleapi, l'interface web d'aMule, et le port-sync, arrêté hors de la variante VPN. Au démarrage, le conteneur crée l'utilisateur amule à partir de PUID et PGID, prend possession des dossiers montés, puis réconcilie amule.conf : il le crée s'il n'existe pas, et réécrit à chaque démarrage le mot de passe EC et la section [AmuleApi] (Enabled, BindAddress, HttpPort). Les autres clés sont gardées, mais les commentaires du fichier sont perdus à la réécriture.

Le crawler joint aMule par le nom ed2k, dans les deux variantes.

Quatre variables sont obligatoires : PUID, PGID, AMULE_EC_PASSWORD et AMULE_API_PASSWORD. Si l'une manque, docker compose up échoue avec un message clair, plutôt que de démarrer un conteneur qui meurt aussitôt.

Persistance. Tout vit dans des dossiers de votre dossier de travail, jamais dans des volumes Docker : le catalogue et l'état local dans data/ (catalog.db, local.db), la configuration d'aMule dans ed2k/amule/, les téléchargements dans ed2k/downloads/incoming et ed2k/downloads/temp. docker compose down n'y touche pas, et aucun -v ne peut effacer le catalogue par accident : pour l'effacer, vous supprimez data/ vous-même. Corollaire voulu, sqlite3 data/catalog.db marche directement depuis l'hôte, sans sudo : c'est le rôle de PUID et PGID.

Arrêter et mettre à jour. docker compose down arrête le nœud. Pour mettre à jour :

docker compose pull
docker compose up -d

Les commandes sont les mêmes sous les deux variantes : la ligne include: de compose.yml choisit. Une mise à jour qui réécrit une base en garde d'abord une copie dans data/ : voir La copie d'avant migration.

Redémarrage de l'hôte. Les conteneurs reviennent seuls au boot, aucune commande à relancer, à condition que Docker démarre en service système. Vérifiez avec docker compose ps.

Nœud 4.x. Suivez Migrer un nœud 4.x avant de lancer la 5.0 : elle range les dossiers d'aMule sous ed2k/, et refuse la section port_sync: de crawler.yml.

Nœud 1.x. Ne lancez pas la 2.0 par-dessus un nœud 1.x sans avoir suivi Migrer un nœud 1.x : les volumes nommés ne sont pas lus par la nouvelle pile, et le nœud semblera avoir perdu son catalogue. Les données, elles, sont toujours dans les volumes.

La copie d'avant migration

Une mise à jour peut apporter des migrations, que le crawler applique à son premier démarrage. Quand l'une d'elles supprime ou réécrit des lignes, il copie d'abord la base à côté d'elle, dans data/, par exemple catalog.db.pre-0006.2026-10-27_11-53-00_UTC : 0006 est la première migration en attente, et l'heure, en UTC, celle de la copie. Une copie par base, quel que soit le nombre de migrations en attente ; une base neuve n'est jamais copiée. Le journal l'annonce par pre-migration copy of /data/catalog.db: writing ....

Avant d'écrire quoi que ce soit, le crawler vérifie que la place libre de data/ couvre la copie et la migration, soit jusqu'à deux fois la base, et refuse de démarrer sinon (voir Limites connues).

  • Une migration qui échoue arrête le crawler, Docker le relance, et elle échoue de nouveau. La copie n'est faite qu'une fois : tant que la base n'a pas changé, les démarrages suivants la reprennent (reusing ... dans le journal).
  • Un retour à l'ancienne version, puis un nouvel essai : l'ancienne version écrit de nouvelles lignes, la base ne correspond plus à la copie, et le nouvel essai en fait une seconde, sans toucher à la première.

p2pwatch ne supprime jamais une copie. Supprimez-la vous-même une fois la mise à jour aboutie (le crawler tourne, le catalogue web montre vos fichiers) et quand vous ne comptez plus revenir à l'ancienne version. Tant qu'une mise à jour n'a pas abouti, gardez la copie qui tient la base telle que l'ancienne version l'a laissée : parmi les copies de cette mise à jour, celle qui porte le plus petit numéro, la plus récente s'il y en a plusieurs. Une copie de numéro plus grand tient une base à moitié migrée.

Pour revenir à une copie, arrêtez le crawler, renommez la copie au nom de la base, qu'elle remplace, puis supprimez les fichiers -wal et -shm de la base : laissés là, ils seraient rejoués sur la copie. Démarrez ensuite l'ancienne version : la nouvelle referait la migration. Restaurez seulement une base qui a une copie de cette mise à jour, et une base à la fois : une base supprimée avant que sa copie soit trouvée est perdue. Les commandes sont dans le retour arrière de la migration 4.x.

Redémarrer une pièce plutôt que tout le nœud

docker compose restart p2pwatch ne redémarre que le crawler, docker compose restart ed2k que le client eMule. Dans ed2k, pour ne toucher qu'amuled, adressez-vous à s6 :

docker compose exec ed2k s6-svstat /etc/services.d/amuled   # état
docker compose exec ed2k s6-svc -r /etc/services.d/amuled   # redémarrer
docker compose exec ed2k s6-svc -d /etc/services.d/amuled   # arrêter
docker compose exec ed2k s6-svc -u /etc/services.d/amuled   # démarrer

amuleapi n'est pas un service s6 : c'est amuled qui le démarre, donc redémarrer amuled le redémarre avec lui. Un amuled arrêté par -d le reste jusqu'au -u, ou jusqu'au prochain redémarrage du conteneur ed2k. Sous la variante VPN avec le port-sync, arrêtez d'abord le port-sync (s6-svc -d /etc/services.d/port-sync), sinon il relance amuled à son prochain changement de port ; relancez-le ensuite par s6-svc -u /etc/services.d/port-sync.

Quand le crawler s'arrête, quelle qu'en soit la raison, Docker le relance (restart: unless-stopped), et aMule garde ses sessions eD2k et Kad. C'est ce que fait le bouton de redémarrage du tableau de bord. Une configuration invalide le fait donc redémarrer en boucle : docker compose ps le montre Restarting, et l'erreur est dans son journal. Si amuled tombe, s6 le relance sur place.

Quand le nœud ne catalogue plus

Le crawler écrit dans docker compose logs p2pwatch, amuled et le port-sync dans docker compose logs ed2k. C'est toujours le premier endroit à regarder. amuleapi fait exception : démarré par amuled plutôt que par s6, il écrit dans ed2k/amule/amuleapi.log de votre dossier de travail. Pour aller du symptôme à la cause, voyez Diagnostics avancés.

Le compteur p2pwatch_search_results_skipped (exposé en p2pwatch_search_results_skipped_total), étiqueté client et channel comme p2pwatch_searches, compte les résultats de recherche qu'amuleapi renvoie mais que le crawler ne sait pas lire : sans hash, sans taille exploitable, sans aucun nom, ou qui ne sont pas un objet. Un même résultat revu à chaque recherche compte à chaque fois. Il devrait rester à zéro en temps normal. S'il monte, les réponses d'amuleapi ont peut-être changé de forme, et ces résultats ne sont pas catalogués.

Planification disque

Des ordres de grandeur, à ajuster selon votre trafic eMule réel et le nombre de cibles :

  • data/catalog.db grossit lentement, de l'ordre de 0,25 Go par trimestre au rythme d'un nœud réel (estimation du 2026-10-09). Une mise à jour qui le réécrit demande en plus jusqu'à deux fois sa taille, et laisse sa copie d'avant migration.
  • ed2k/downloads/ s'accumule sans borne, rien ne le purge. Le crawler mesure l'espace libre et refuse un nouveau candidat si cela passerait sous download.min_free_bytes (10 Gio par défaut). C'est un plancher, pas un ménage : il bloque les nouveaux téléchargements quand le disque se tend, il n'efface rien. Le tri reste à votre charge. La jauge p2pwatch_download_disk_free_bytes publie l'espace libre mesuré à chaque cycle, et l'audience operations est notifiée une fois quand il passe sous le plancher, puis de nouveau seulement après être remonté au-dessus.
  • ed2k/amule/ tient en quelques mégaoctets : amule.conf, server.met, nodes.dat, préférences.

Le crawler ne fait qu'un statvfs sur /downloads, il n'ouvre jamais un fichier téléchargé. C'est aussi pourquoi ./ed2k/downloads lui est monté en entier, et en lecture seule, plutôt que par ses deux sous-dossiers : sans cela, la mesure porterait sur le mauvais système de fichiers.

Si votre machine approche de la saturation, lancez du -sh ed2k/downloads/ data/ ed2k/amule/ pour identifier le coupable, puis faites le ménage dans ed2k/downloads/incoming.


Outils de catalogue

Ces deux outils sont ponctuels et jamais déclenchés par le crawler. La fusion n'écrit que dans sa destination : un fichier neuf (--output), ou le catalogue que vous désignez par --into. Seule exception : quand elle met à niveau une destination existante par une migration qui réécrit des lignes, elle en garde d'abord une copie d'avant migration à côté d'elle. Une source est ouverte en lecture seule : son contenu reste intact, même quand un -wal en attente l'accompagne, comme sur la copie du catalogue d'un nœud en marche.

Valider la configuration, sans rien démarrer. À lancer avant un déploiement. Affiche Config valid si les trois fichiers sont valides. Sinon elle sort en erreur (code 1) : un fichier absent, illisible, qui n'est pas du YAML, ou qui contient un texte qui n'est pas de l'UTF-8 valide ("\ud800") ou un alias qui se contient (&k [keroro, *k]) donne error: <fichier>: <raison>, un fichier lisible au contenu faux donne Invalid config: <fichier>: <clé>: <message> (sans clé pour targets.yml et matcher.yml).

docker compose run --rm p2pwatch python -m p2pwatch validate-config \
  --config /app/config/crawler.yml --targets /app/config/targets.yml \
  --matcher /app/config/matcher.yml

Fusionner des catalogues, pour consolider ceux de plusieurs chercheurs en un seul. La fusion est idempotente et n'écrase rien sans --force ; --into <catalogue> fusionne dans un catalogue existant. Une sortie --output qui est aussi l'une des sources est refusée avant toute écriture, même avec --force : fusionnez dans ce catalogue par --into. Elle réunit l'historique des sources comme le reste, par l'union des lignes : deux copies du catalogue d'un même nœud se fusionnent toujours, même quand l'une a été restaurée d'une sauvegarde ou remplacée par un catalogue fusionné entre-temps. Le cycle de partage est décrit sur la page d'accueil.

docker compose exec p2pwatch python -m p2pwatch merge \
  --output /data/catalog-merged.db /data/catalog.db /data/catalog-b.db

Un catalogue source doit être au même schéma que votre version : la fusion refuse une copie faite par une version plus ancienne (has schema version 5, expected 15), car elle ne migre jamais un catalogue source. Migrez-le d'abord en le fusionnant dans lui-même, qui l'ouvre et le met à niveau sur place. Si une migration en attente réécrit des lignes, la fusion le copie d'abord à côté de lui, comme le crawler au démarrage. Travaillez tout de même de préférence sur une copie, puisqu'une version plus ancienne ne pourra plus lire le catalogue migré :

docker compose exec p2pwatch python -m p2pwatch merge \
  --into /data/catalog-b.db /data/catalog-b.db

La fusion vérifie chaque source avant d'écrire quoi que ce soit. Elle refuse une source qui contient une valeur que le nœud n'écrirait pas : un texte qui n'est pas de l'UTF-8 valide, un raw_metadata qui n'est pas un objet JSON écrit comme le nœud l'écrit (ses clés triées, chacune une fois), un caractère de contrôle dans un identifiant de cible ou un nom de règle. Elle refuse aussi une ligne qui contredit ses clés, et qui bloquerait les écritures du nœud : un file_id ou un source_id que son réseau et son identifiant natif ne donnent pas, un content_hash qui n'est pas celui de sa variante. Le refus nomme la source, la table, la colonne et la première ligne en cause, en code 2 : Merge failed: source catalog /data/catalog-b.db refused: match_decisions.target_id holds a control character, first at id 12. La destination reste alors telle quelle : --output ne crée aucun fichier, et --into ne met pas son catalogue à niveau.

Une ligne que le schéma de la destination refuse pendant la copie arrête la fusion sur sa source, qui n'est pas copiée du tout : une valeur qui n'est pas du type de sa colonne (un texte dans size_bytes), une taille, une durée, un débit ou un nombre de sources négatif, un tier, un connectable ou un rôle de source inconnu, un instant hors de la plage que le nœud sait lire. Si c'est la première, rien n'est copié, et une sortie --output neuve est supprimée. Sinon les sources fusionnées avant elle restent dans la destination, --output compris : le message, en code 2, nomme la table en cause et ces sources. Avec --output, il indique aussi comment poursuivre une fois la source fautive corrigée ou écartée : --into <sortie> <sortie> suivi des sources non fusionnées. Relancer ne copie pas deux fois une ligne déjà présente.

Le journal de la fusion nomme chaque catalogue source, suivi de merged, ou de skipped: it is the output pour celui que désigne --into : il n'est jamais fusionné en lui-même, et sa mise à niveau a lieu à son ouverture.

Pour valider en profondeur (suites d'intégration, smoke, CI), voyez Lancer les tests.


Ré-évaluation du catalogue au démarrage

À chaque démarrage, le crawler ré-évalue tout le catalogue contre le matcher courant (matcher.yml et targets.yml), mais seulement s'ils ont changé. Il stocke une empreinte sha256 des deux fichiers dans local.db : empreinte identique, passe entièrement sautée, donc un simple redémarrage ne coûte rien. Éditer l'un des deux, même un commentaire, déclenche une passe au prochain démarrage.

Deux effets possibles pour un fichier déjà catalogué :

  • Rétractation. Un fichier que le nouveau matcher n'attrape plus reçoit une ligne tier="retracted" : le catalogue reste append-only, rien n'est supprimé. Le catalogue web le traite alors comme non identifié et il sort de la file de téléchargement. On ne « dé-télécharge » jamais : un fichier déjà récupéré reste.
  • Re-classement. Un fichier qui change de palier déclenche l'action du nouveau palier : le palier download le met en file. Un fichier qui monte à notify ou download notifie l'audience community (configurez une cible audience: community sous observability.notifications dans crawler.yml) : un seul message par fichier, avec son nom, sa taille, son lien ed2k et les segments concernés. Une baisse, un passage à catalog, une rétractation ou un changement de règle sans changement de palier restent dans les logs, sans notification.

Un gros changement de règles peut donc émettre une rafale de notifications, une par fichier dont le palier a monté. C'est voulu. La passe est idempotente et tourne que le téléchargement soit activé ou non.

L'audience operations reçoit l'état du nœud, et rien d'autre :

  • le démarrage du nœud, en précisant si le téléchargement est activé ;
  • l'espace disque passé sous le plancher (voir Planification disque) ;
  • un canal d'un client (ed2k ou kad pour aMule) hors de son réseau ou non joignable par les pairs depuis 5 minutes, puis son retour ;
  • l'API d'un client injoignable depuis 2 minutes, puis son retour. Tant qu'elle l'est, l'état de ses canaux est inconnu et ne déclenche aucune alerte de canal.

Une alerte part sur un état dégradé qui dure, quel que soit l'état d'avant, démarrage compris : un nœud qui démarre en Low-ID est signalé au bout de 5 minutes, et la fenêtre où Kad se croit derrière un pare-feu après chaque reconnexion ne l'est pas tant qu'elle dure moins de 5 minutes. Le retour n'est notifié que si l'alerte est partie. Ces durées sont fixes, et un redémarrage du crawler remet ces délais à zéro.

Les messages partent en markdown : Discord les affiche en embed, signé p2pwatch - <node-id> en ligne d'auteur, bleu pour une découverte (🔎 Notify, 📥 Download) ou une source (📥 Source useful for the first time, 🔁 Source reappeared), vert pour un téléchargement terminé (✅ Downloaded, avec les segments et le nom du fichier). Aucun message ne mentionne qui que ce soit : un @everyone dans un nom de fichier ne notifie personne.

Chaque cible préfixe le titre de ses messages de l'identifiant du nœud ([node-id]), utile aux services qui n'affichent pas d'auteur (syslog, ntfy). Une cible Discord le porte déjà dans sa ligne d'auteur et peut s'en passer avec node_prefix: false.


Historique des sources

En mode téléchargement, toutes les download.sources_interval_seconds (5 minutes par défaut, voir Régler le nœud), le crawler relève les sources de chacun de ses téléchargements en cours : les pairs qui détiennent le fichier, sous leur user hash eD2k, avec leur nom, leur logiciel et leur rôle. Chaque relevé ajoute un point par source : son instant et le compteur d'octets qu'aMule tient pour elle. Le catalogue web en tire, à l'affichage, des périodes de présence : une période dure tant que la source est revue avec les mêmes propriétés, sans plus de webui.source_period_gap_seconds entre deux points (16,5 minutes par défaut, une lecture manquée comprise). Un téléchargement ajouté à la main dans aMule n'est pas relevé. Ce qui est enregistré, et ce qui ne l'est jamais, est détaillé dans Légalité et vie privée.

Le rôle dit ce que le nœud sait de ce que la source détient :

Rôle Utilité Sens
sending utile elle nous envoie des parties qui nous manquent
queued utile elle en détient, et nous attendons dans sa file
nothing_new pas utile elle ne détient rien qui nous manque
standby inconnu elle détient le fichier, mais aMule lui demande un autre de nos fichiers
undetermined inconnu aMule ne sait pas encore ce qu'elle détient

Le catalogue web montre cet historique par fichier, par source et par nom (Routes disponibles), sur un intervalle de 7 jours au plus (L'intervalle des pages de détail). Chaque période y nomme le nœud qui l'a relevée : un catalogue fusionné en réunit plusieurs.

Deux alertes partent vers l'audience community, toutes deux quand une source devient utile :

  • first_useful : la source est utile pour la première fois sur ce nœud, tous fichiers confondus ;
  • reappeared : la source est de nouveau utile après plus de download.reappeared_after_seconds (12 h par défaut, voir Régler le nœud) pendant lesquelles le nœud n'a rien appris de ce qu'elle détient : absente, ou vue sans réponse.

Le message donne le nom de la source, les 8 premiers caractères de son user hash, le fichier et ses cibles. Il part au premier relevé qui la voit utile, jusqu'à un intervalle de relevé après qu'elle l'est devenue. Le nœud d'un équipier qui détient les mêmes fichiers partiels que vous reste nothing_new, et n'alerte donc pas. Une source sans user hash n'alerte jamais, pas plus que le tout premier relevé du nœud : tout y serait nouveau. Les deux alertes mesurent la vue de ce nœud, pas la présence du pair sur le réseau : une source « réapparaît » aussi quand vous mettez en file un fichier qu'elle partageait déjà, ou après un arrêt du nœud de plus de 12 h. Chacune incrémente p2pwatch_source_alerts, étiqueté network et kind (first_useful, reappeared). Un arrêt brutal entre l'écriture et l'envoi perd l'alerte : elle part au plus une fois.


WebUI (consultation du catalogue)

Un nœud publie deux surfaces web, qui n'ont pas la même posture :

Port Ce que c'est Authentification
8080 l'interface de catalogue p2pwatch AUCUNE, D'AUCUNE SORTE
4711 amuleapi, l'interface propre à aMule le mot de passe admin AMULE_API_PASSWORD

Le port 8080 n'a aucune authentification, d'aucune sorte. Quiconque l'atteint obtient le catalogue, historique des sources compris, les contrôles du tableau de bord qui modifient l'état, une console SQL en lecture seule et les métriques du nœud (/metrics). AMULE_API_PASSWORD ne protège que le 4711. Mettez le 8080 derrière un reverse proxy ou un VPN, ou gardez-le sur un réseau de confiance, et ne le posez jamais sur l'Internet ouvert.

Le catalogue web est servi en lecture seule, dans le processus p2pwatch lui-même : il démarre et s'arrête avec lui, il n'y a rien de spécial à lancer. Il ne modifie jamais les bases, parce qu'il ouvre ses propres connexions SQLite en lecture seule (mode=ro et PRAGMA query_only=ON), jamais une connexion en écriture. Toute tentative d'écriture est refusée par SQLite avant d'atteindre le disque, ce qui protège votre catalogue même d'une régression du code.

Il est toujours servi, aucun réglage ne le coupe. Retirer la ligne "8080:8080" des ports: de compose.yml le retire du réseau de l'hôte ; le réseau compose l'atteint toujours. Pour couper le crawl en gardant aMule vivant, c'est docker compose stop p2pwatch.

Routes disponibles

Route Description
/ Tableau de bord : état de chaque client (version, API joignable, et par canal : connecté à son réseau, joignable par les pairs), d'après la dernière lecture de moins de deux minutes ; état du crawl, avec les boutons pause, reprise et redémarrage du crawler seul (aMule garde ses sessions) ; couverture par cible (épisodes trouvés et manquants)
/files Liste paginée des fichiers ; filtres ?target_id=, ?tier=, ?search=
/files/{file_id} Détail d'un fichier, désigné par son file_id en 32 caractères hexadécimaux minuscules, tel que la console SQL l'affiche : réseau, identifiant natif, observations et historique des sources dans l'intervalle choisi, décisions, explication du matching, avec la valeur de chaque token coverage (à deux décimales, sur l'échelle de son min_coverage)
/sources Liste paginée des sources qui ont un user hash, la plus récemment vue d'abord : dernier nom, début du user hash, dernière vue, nombre de fichiers ; ?search= cherche un début de user hash ou un morceau de n'importe quel nom porté
/sources/{source_id} Une source, désignée par son source_id en 32 caractères hexadécimaux minuscules : son user hash, chaque nom qu'elle a porté, et ses périodes sur tous les fichiers, dans l'intervalle choisi
/sources/name?source_name= Un nom : les user hashes qui l'ont porté, et les périodes relevées sous ce nom sans user hash, dans l'intervalle choisi. Les liens s'arrêtent là : la page d'un nom ne montre pas les autres noms de ces user hashes, pour ne pas confondre en une seule personne des inconnus qui partagent un nom par défaut
/targets/{target_id} Fichiers d'une cible (alias de /files?target_id=)
/node État du crawler : node_id, backoff des recherches (le client entier ou l'un de ses canaux, le nombre de tentatives et le prochain essai prévu, en UTC) et téléchargements (voir Suivre un téléchargement).
POST /controls/pause, /controls/resume, /controls/restart Les boutons du tableau de bord, qui y renvoient. La pause n'arrête pas les recherches en cours, ni celles qui attendent déjà leur créneau réseau : avec K mots-clés, jusqu'à K-1 recherches ed2k, espacées d'une minute, et la prochaine de chaque mot Kad partent encore, puis le crawler se tait.
/console Console SQL en lecture seule : un unique SELECT sur catalog.db ou local.db, avec export CSV. Toujours active.
/metrics Les métriques du nœud pour Prometheus, au format texte 0.0.4 (voir Métriques Prometheus)
/health Healthcheck JSON : répond {"status": "ok"} si le service est opérationnel

Les POST /controls/* déclenchent des actions qui modifient l'état, sans jeton CSRF ni authentification, par conception. /console est structurellement en lecture seule et bornée contre le déni de service (délai maximum, plafond de lignes rendues, une seule instruction). Ces deux surfaces ne sont défendables que derrière votre propre périmètre : réseau privé, VPN ou reverse proxy authentifié, jamais sur Internet.

L'intervalle des pages de détail

La page d'un fichier, celle d'une source et celle d'un nom lisent leurs périodes, et la page d'un fichier ses observations, dans un seul intervalle de temps, de 7 jours au plus : au-delà, calculer les périodes à chaque affichage coûterait trop. Le bloc « Interval » de ces pages le choisit :

  • sans rien choisir, les 7 derniers jours ;
  • quatre préréglages : la dernière heure, les 6 dernières heures, les 24 dernières heures et les 7 derniers jours ;
  • un intervalle libre, par les champs « From (UTC) » et « To (UTC) », lus en UTC comme toutes les heures du catalogue web ;
  • Previous et Next, qui décalent l'intervalle de sa propre longueur ; Next disparaît une fois le présent atteint.

L'intervalle vit dans l'adresse de la page (?from= et ?to=) : un lien le garde. Un intervalle demandé de plus de 7 jours est ramené aux 7 jours qui finissent à sa fin, et la page le dit. Les périodes sont coupées aux bords de l'intervalle : une période commencée avant montre son premier point dans l'intervalle. Les listes de ces pages, les noms d'une source et les user hashes d'un nom, restent paginées et ne dépendent pas de l'intervalle.

Suivre un téléchargement

La table des téléchargements de /node montre pourquoi un téléchargement avance ou non :

  • Dernier progrès : la dernière fois que le crawler a vu le nombre d'octets reçus augmenter. Vide tant qu'il ne l'a jamais vu augmenter, ce qui vaut aussi pour un téléchargement antérieur à la mise à niveau, jusqu'à son prochain progrès.
  • Attente : no_source (aucune source connue), remote_queue (des sources, aucune n'envoie), local_processing (aMule vérifie ou alloue le fichier), paused (en pause dans aMule), disk_full (disque plein côté aMule).
  • Échec : error (aMule signale le fichier en erreur), rejected (aMule a refusé de le démarrer), lost (aMule ne le montre plus depuis download.lost_after_seconds).

Attendre n'est pas échouer : un téléchargement sans source pendant des mois reste downloading avec sa raison d'attente. Seul un échec le passe en failed, et un fichier qu'aMule signale en erreur y reste tant qu'aMule le signale ainsi.

Adresse d'écoute et chemins de bases

Le catalogue web ne lit aucune variable d'environnement : il dérive tout de crawler.yml. Son adresse d'écoute interne est figée à 0.0.0.0:8080 dans le code, donc c'est le port publié par compose qui gouverne l'accès.

Réglage Où Valeur par défaut Rôle
catalog_db_path crawler.yml aucune : clé obligatoire, /data/catalog.db dans le crawler.yml livré Base catalogue, lue en lecture seule (= data/catalog.db côté hôte)
local_db_path crawler.yml aucune : clé obligatoire, /data/local.db dans le crawler.yml livré Base état local, lue en lecture seule (= data/local.db côté hôte)
webui.amule_url crawler.yml http://localhost:4711 Cible du lien « aMule » dans la navigation. À changer uniquement derrière un reverse proxy : c'est le navigateur qui résout cette URL, pas le conteneur.
port publié du catalogue compose.yml (ports:) 8080 Dans le mapping "8080:8080", changez le nombre de gauche pour publier ailleurs. Ne change pas le port d'écoute interne.
port publié d'amuleapi ed2k/direct.compose.yml (ports:) 4711 Idem pour amuleapi. Sous la variante VPN, il est porté par le service ed2k-gluetun, dans ed2k/vpn.compose.yml.

Exposition derrière un reverse proxy

Le catalogue web n'a ni TLS ni authentification : mettez un reverse proxy devant dès qu'il est accessible sur le réseau. Exemple minimal avec Caddy, pointant sur le port publié par le nœud :

Caddyfile
webui.example.com {
    basicauth /* {
        alice $2a$14$...  # bcrypt généré par caddy hash-password
    }
    reverse_proxy node.example.lan:8080
}

Pensez alors à webui.amule_url dans crawler.yml : le lien « aMule » est résolu par le navigateur, donc http://localhost:4711 ne veut plus rien dire pour un visiteur distant. Pointez-le sur l'hôte réel, ou sur un second reverse_proxy. amuleapi, lui, a bien un mot de passe.