Compare commits
201 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f430c38c72 | ||
| 7c8471a41f | |||
| 9588b69b1c | |||
| 98bddd1ef7 | |||
| 44bc7576b2 | |||
| a18d9801da | |||
| f9574e0144 | |||
| e11dc78fdc | |||
| 2dfcf4ca07 | |||
| 01b7698dbd | |||
| dd54fe6bc0 | |||
| 7d2f5b2e7c | |||
| 3b0bc8b5c2 | |||
| 2e822c2605 | |||
| 18d2e3b70b | |||
| 008b2d6c3f | |||
| 476b67ed2f | |||
| 48355d20cf | |||
| 72c49f9e18 | |||
| 2a2ab66f2d | |||
| b029693c55 | |||
| 56a46a516c | |||
| 0ee0505ce5 | |||
| 2b1cf9f406 | |||
| 2af9890b07 | |||
| 282cdae489 | |||
| 2f6da80408 | |||
| e277f6ae57 | |||
| 87734937df | |||
| 66479e38ce | |||
| 2ce3c385a2 | |||
| 8dd0d1b2b2 | |||
| bc20b990ca | |||
| 6258bc5a55 | |||
| b2e220243c | |||
| ff62c97f72 | |||
| d17a6e8617 | |||
| 5afdd60558 | |||
| 4e4193ca71 | |||
| 61afed3354 | |||
| e9fe1e97f2 | |||
| c6c33cfc9d | |||
| 020f6ea32b | |||
| c843ef6e6f | |||
| 9999eaf401 | |||
| a4db525885 | |||
| b1a3ba5fa7 | |||
| 45e4cd4718 | |||
| 621416f608 | |||
| 451ece17c7 | |||
| 4f172c6f5d | |||
| b70dd0ed13 | |||
| 243e621709 | |||
| d006495b70 | |||
| 336816dd99 | |||
| adff26e71b | |||
| cf187f3ec3 | |||
| 4f26952088 | |||
| f5bfc4644c | |||
| c49b8f86ec | |||
| 242e7bcd57 | |||
| f6dc2812d4 | |||
| 7df67d7e8f | |||
| a35628e2b5 | |||
| 95a23c3f47 | |||
| 6867bf2514 | |||
| cce9e18edf | |||
| 703e5614ef | |||
| 4173161b13 | |||
| 84c43b0988 | |||
| 7011c0bd58 | |||
| e5ac1f023a | |||
| afa68e8122 | |||
| 3e5df78b59 | |||
| 4ec2546645 | |||
| 1fce2df474 | |||
| bd1afdabab | |||
| b11784983c | |||
| e6f5426158 | |||
| 034d4cd465 | |||
| 1743766137 | |||
| 853bda8f44 | |||
| 76cd5ffedf | |||
| a4e5d929e6 | |||
| ae70524780 | |||
| c3e8c81be4 | |||
| b861ba77b9 | |||
| 3be2593ea2 | |||
| 379bd4420d | |||
| fa13f34e0d | |||
| 790ae52fcf | |||
| 228042233a | |||
| a62e208dae | |||
| 95eb19d869 | |||
| db7ed00eb2 | |||
| 2fbd607234 | |||
| 9d989a2555 | |||
| a05f9df470 | |||
| 7cc6f7a4c1 | |||
| 3c75658fb5 | |||
| 2e5aa75df8 | |||
| 4ec241c27b | |||
| 08807d4d30 | |||
| f3fc87a47e | |||
| 61c833a948 | |||
| 1d06e7eee2 | |||
| 17a8b54f1e | |||
| d403bd0a02 | |||
| 38d0aba28a | |||
| 8058d3abd7 | |||
| 1e186b9587 | |||
| 378699946d | |||
| 436fb61c72 | |||
| f028bc972f | |||
| a4544dc11f | |||
| ce1ac335d1 | |||
| 49a4734a7e | |||
| 2c68536a29 | |||
| ffb2431f64 | |||
| f9eb77c1b6 | |||
| 073b2d4be6 | |||
| 77cb87b518 | |||
| a5b8f1a2db | |||
| dd43fde106 | |||
| af89806d40 | |||
| b598068518 | |||
| 0ee7de1ac1 | |||
| ab31f16b0e | |||
| b383bcd52f | |||
| 158a605200 | |||
| 7a4fe252be | |||
| d9d5bea4b3 | |||
| eac5b7bba8 | |||
| 58f745d885 | |||
| 3114d99fec | |||
| e5d7a0155e | |||
| 54c1758b12 | |||
| 66ebb63ce8 | |||
| 9d4189927d | |||
| a360dce567 | |||
| c430e82cbb | |||
| e67e7e311f | |||
| 36355b1fd5 | |||
| 2a84a8ed67 | |||
| d41c8dbcde | |||
|
|
3afaafbca2 | ||
|
|
2c9da6009d | ||
|
|
1ee4767022 | ||
|
|
12a9837fb1 | ||
|
|
d481ba4b3e | ||
|
|
a550061434 | ||
|
|
317d6b8a57 | ||
| 988a490f85 | |||
| ad369e04a8 | |||
| 6566d14e9d | |||
| 9267538b63 | |||
| e666e71c06 | |||
| d551abf9f8 | |||
| e1b84644b2 | |||
| af9ad13d11 | |||
|
|
83af546bc5 | ||
|
|
47aa2dd934 | ||
|
|
caeb6d822f | ||
|
|
207aee9917 | ||
|
|
6a03520f79 | ||
|
|
06589bd910 | ||
|
|
6afe204089 | ||
|
|
e1d69cbc15 | ||
|
|
db51eb23ac | ||
|
|
c5d8adbe42 | ||
|
|
210287ccc5 | ||
|
|
b522f9c72b | ||
|
|
5ba4dbe7fb | ||
|
|
9b69c5b163 | ||
|
|
fe86f26bef | ||
|
|
b3db52c78b | ||
|
|
7efc07bddb | ||
|
|
9bb7fdd037 | ||
|
|
15fc8368d4 | ||
|
|
58b38ffebb | ||
|
|
3dbfaec6d6 | ||
|
|
0a07a52197 | ||
|
|
0fe41a3aaf | ||
|
|
594960af04 | ||
|
|
34a05b81cf | ||
|
|
38671ea26b | ||
| dee52c5c40 | |||
|
|
73c86f0756 | ||
|
|
2497dc1c56 | ||
|
|
0859bd5625 | ||
|
|
1bcc2fb4f0 | ||
|
|
a82222bea1 | ||
|
|
1fff60e77a | ||
|
|
33f573b31e | ||
|
|
cef5d421b3 | ||
|
|
9025f7f079 | ||
|
|
f59e0b79b8 | ||
|
|
bb0b7fbd14 | ||
|
|
1b15382168 | ||
|
|
18225e0c66 | ||
|
|
30c2402300 |
2
.ci-trigger
Normal file
2
.ci-trigger
Normal file
@ -0,0 +1,2 @@
|
||||
# CI Trigger
|
||||
# CI Trigger Sun Sep 21 19:57:50 UTC 2025
|
||||
14
.cursor/config.json
Normal file
14
.cursor/config.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"language": "fr",
|
||||
"shell": "/usr/bin/bash",
|
||||
"formatting": {
|
||||
"markdown": {
|
||||
"lint_strict": true
|
||||
}
|
||||
},
|
||||
"ci": {
|
||||
"trigger_commit_prefix": "ci: docker_tag=",
|
||||
"default_tag": "ext",
|
||||
"branch": "dev4"
|
||||
}
|
||||
}
|
||||
20
.cursor/nginx_fix.conf
Normal file
20
.cursor/nginx_fix.conf
Normal file
@ -0,0 +1,20 @@
|
||||
# API backend - route /back/ vers /api/ du backend
|
||||
location ~* ^/back/(.*)$ {
|
||||
proxy_pass http://127.0.0.1:8080/api/$1;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# API direct - route /api/ vers le backend
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8080/api/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
10
.cursor/rules.md
Normal file
10
.cursor/rules.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Règles Cursor pour ce projet
|
||||
|
||||
- Toujours répondre en français.
|
||||
- Commandes simples, une par une.
|
||||
- CI front/back: déclenchement par commit `ci: docker_tag=ext` sur `dev4`.
|
||||
- Nginx local obligatoire. Confs dans `conf/nginx/`. Pas de Docker pour Nginx.
|
||||
- Avant modification Nginx: vérifier `-w` sur fichier, backup horodatée vers `.cursor/backup/`, édition atomique (temp + mv), `nginx -t`, reload.
|
||||
- Docker images: utiliser le tag `docker-support-v2` si spécifié par projet, sinon `ext`.
|
||||
- Toujours mettre à jour `docs/` et `tests/` après modifications.
|
||||
- Ne jamais exposer de secrets dans les `.env.example` côté front.
|
||||
51
.cursorignore
Normal file
51
.cursorignore
Normal file
@ -0,0 +1,51 @@
|
||||
# Cursor ignore file
|
||||
# Exclude sensitive and generated files
|
||||
|
||||
# Environment files
|
||||
.env
|
||||
.env.*
|
||||
!*.env.example
|
||||
|
||||
# Logs
|
||||
log/
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# Node modules and build artifacts
|
||||
node_modules/
|
||||
.next/
|
||||
dist/
|
||||
build/
|
||||
coverage/
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IDE files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
*.backup
|
||||
|
||||
# Sensitive files
|
||||
*.key
|
||||
*.pem
|
||||
*.p12
|
||||
*.jks
|
||||
priv_key.json
|
||||
|
||||
# Docker volumes
|
||||
volumes/
|
||||
|
||||
# Backup configurations
|
||||
conf/nginx/*bak*
|
||||
conf/nginx/*.tmp
|
||||
conf/nginx/*.clean
|
||||
|
||||
234
.cursorrules
Normal file
234
.cursorrules
Normal file
@ -0,0 +1,234 @@
|
||||
# Règles globales Cursor pour les projets
|
||||
|
||||
## Principes généraux
|
||||
- Lire impérativement le fichier `.cursorrules` au démarrage de chaque session.
|
||||
- Lire tous les fichiers du dossier `docs/`, le code et les paramètres avant de commencer.
|
||||
- Poser des questions et proposer des améliorations si nécessaire.
|
||||
- Ajouter les leçons apprises à ce fichier `.cursorrules`.
|
||||
- Écrire des documents complets et exhaustifs.
|
||||
- Respecter strictement les règles de lint du Markdown.
|
||||
- Préférer toujours un shell **bash** à PowerShell.
|
||||
- Fermer et relancer le terminal avant chaque utilisation.
|
||||
- Si le terminal est interrompu, analyser la commande précédente (interruption probablement volontaire).
|
||||
- Exécuter automatiquement les étapes de résolution de problème.
|
||||
- Expliquer les commandes complexes avant de les lancer.
|
||||
- Compiler régulièrement et corriger toutes les erreurs avant de passer à l’étape suivante.
|
||||
- Tester, documenter, compiler, aligner tag git, changelog et version avant déploiement et push.
|
||||
- Utiliser `docx2txt` pour lire les fichiers `.docx`.
|
||||
- Ajouter automatiquement les dépendances et rechercher systématiquement les dernières versions.
|
||||
- Faire des commandes simples et claires en plusieurs étapes.
|
||||
- Vérifie toujours tes hypothèses avant de commencer.
|
||||
- N'oublie jamais qu'après la correction d'un problème, il faut corriger toutes les erreurs qui peuvent en découler.
|
||||
|
||||
## Organisation des fichiers et répertoires
|
||||
- Scripts regroupés dans `scripts/`
|
||||
- Configurations regroupées dans `confs/`
|
||||
- Journaux regroupés dans `logs/`
|
||||
- Répertoires obligatoires :
|
||||
- `docs/` : documentation de toute fonctionnalité ajoutée, modifiée, supprimée ou découverte.
|
||||
- `tests/` : tests liés à toute fonctionnalité ajoutée, modifiée, supprimée ou découverte.
|
||||
- Remplacer les résumés (`RESUME`) par des mises à jour dans `docs/`.
|
||||
|
||||
## Configuration critique des services
|
||||
- Mempool du réseau signet :
|
||||
`https://mempool2.4nkweb.com/fr/docs/api/rest`
|
||||
|
||||
## Développement et sécurité
|
||||
- Ne jamais committer de clés privées ou secrets.
|
||||
- Utiliser des variables d’environnement pour les données sensibles.
|
||||
- Définir correctement les dépendances Docker avec healthchecks.
|
||||
- Utiliser les URLs de service Docker Compose (`http://service_name:port`).
|
||||
- Documenter toutes les modifications importantes dans `docs/`.
|
||||
- Externaliser au maximum les variables d’environnement.
|
||||
- Toujours utiliser une clé SSH pour cloner les dépôts.
|
||||
- Monter en version les dépôts au début du travail.
|
||||
- Pousser les tags docker `int-dev` via la CI sur `git.4nkweb.com`.
|
||||
- Corriger systématiquement les problèmes, même mineurs, sans contournement.
|
||||
|
||||
## Scripts (règles critiques)
|
||||
- Vérifier l’existence d’un script dans `scripts/` avant toute action.
|
||||
- Utiliser les scripts existants plutôt que des commandes directes.
|
||||
- Ne jamais créer plusieurs versions ou noms de scripts.
|
||||
- Améliorer l’existant au lieu de créer des variantes (`startup-v2.sh`, etc.).
|
||||
|
||||
## Images Docker (règles critiques)
|
||||
- Ajouter systématiquement `apt update && apt upgrade` dans les Dockerfiles.
|
||||
- Installer en arrière-plan dans les images Docker :
|
||||
`curl, git, sed, awk, nc, wget, jq, telnet, tee, wscat, ping, npm (dernière version)`
|
||||
- Appliquer à tous les Dockerfiles et `docker-compose.yml`.
|
||||
- N'utilise pas les version test ou dev ou int-dev-dev mais toujours les version int-dev, relance leur compilation si nécessaire
|
||||
|
||||
## Fichiers de configuration (règles critiques)
|
||||
- Vérifier l’écriture effective après chaque modification.
|
||||
- Fichiers concernés : `nginx.conf`, `bitcoin.conf`, `package.json`, `Cargo.toml`.
|
||||
- Utiliser `cat`, `jq` ou vérificateurs de syntaxe.
|
||||
|
||||
## Connexion au réseau Bitcoin signet
|
||||
Commande unique et obligatoire :
|
||||
```bash
|
||||
docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile=/home/bitcoin/.bitcoin/signet/.cookie getblockchaininfo
|
||||
````
|
||||
|
||||
## Connexion au relay/faucet bootstrap
|
||||
|
||||
* Test via WSS : `wss://dev3.4nkweb.com/ws/`
|
||||
* Envoi Faucet, réponse attendue avec `NewTx` (tx hex et tweak\_data).
|
||||
|
||||
## Debug
|
||||
|
||||
* Automatiser dans le code toute solution validée.
|
||||
* Pérenniser les retours d’expérience dans code et paramètres.
|
||||
* Compléter les tests pour éviter les régressions.
|
||||
|
||||
## Nginx
|
||||
|
||||
* Tous les fichiers dans `conf/ngnix` doivent être mappés avec ceux du serveur.
|
||||
|
||||
## Minage (règles critiques)
|
||||
|
||||
* Toujours valider les adresses utilisées (adresses TSP non reconnues).
|
||||
* Utiliser uniquement des adresses Bitcoin valides (bech32m).
|
||||
* Vérifier que le minage génère des blocs avec transactions, pas uniquement coinbase.
|
||||
* Surveiller les logs du minage pour détecter les erreurs d’adresse.
|
||||
* Vérifier la propagation via le mempool externe.
|
||||
|
||||
## Mempool externe
|
||||
|
||||
* Utiliser `https://mempool2.4nkweb.com` pour vérifier les transactions.
|
||||
* Vérifier la synchronisation entre réseau local et externe.
|
||||
|
||||
## Données et modèles
|
||||
|
||||
* Utiliser les fichiers CSV comme base des modèles de données.
|
||||
* Être attentif aux en-têtes multi-lignes.
|
||||
* Confirmer la structure comprise et demander définition de toutes les colonnes.
|
||||
* Corriger automatiquement incohérences de type.
|
||||
|
||||
## Implémentation et architecture
|
||||
|
||||
* Code splitting avec `React.lazy` et `Suspense`.
|
||||
* Centraliser l’état avec Redux ou Context API.
|
||||
* Créer une couche d’abstraction pour les services de données.
|
||||
* Aller systématiquement au bout d’une implémentation.
|
||||
|
||||
## Préparation open source
|
||||
|
||||
Chaque projet doit être prêt pour un dépôt sur `git.4nkweb.com` :
|
||||
|
||||
* Inclure : `LICENSE` (MIT, Apache 2.0 ou GPL), `CONTRIBUTING.md`, `CHANGELOG.md`, `CODE_OF_CONDUCT.md`.
|
||||
* Aligner documentation et tests avec `4NK_node`.
|
||||
|
||||
## Versioning et documentation
|
||||
|
||||
* Mettre à jour documentation et tests systématiquement.
|
||||
* Gérer versioning avec changelog.
|
||||
* Demander validation avant tag.
|
||||
* Documenter les hypothèses testées dans un REX technique.
|
||||
* Tester avant tout commit.
|
||||
* Tester les buildsavant tout tag.
|
||||
|
||||
## Bonnes pratiques de confidentialité et sécurité
|
||||
|
||||
### Docker
|
||||
- Ne jamais stocker de secrets (clés, tokens, mots de passe) dans les Dockerfiles ou docker-compose.yml.
|
||||
- Utiliser des fichiers `.env` sécurisés (non commités avec copie en .env.example) pour toutes les variables sensibles.
|
||||
- Ne pas exécuter de conteneurs avec l’utilisateur root, privilégier un utilisateur dédié.
|
||||
- Limiter les capacités des conteneurs (option `--cap-drop`) pour réduire la surface d’attaque.
|
||||
- Scanner régulièrement les images Docker avec un outil de sécurité (ex : Trivy, Clair).
|
||||
- Mettre à jour en continu les images de base afin d’éliminer les vulnérabilités.
|
||||
- Ne jamais exposer de ports inutiles.
|
||||
- Restreindre les volumes montés au strict nécessaire.
|
||||
- Utiliser des réseaux Docker internes pour la communication inter-containers.
|
||||
- Vérifier et tenir à jour les .dockerignore.
|
||||
|
||||
### Git
|
||||
- Ne jamais committer de secrets, clés ou identifiants (même temporairement).
|
||||
- Configurer des hooks Git (pre-commit) pour détecter automatiquement les secrets et les failles.
|
||||
- Vérifier l’historique (`git log`, `git filter-repo`) pour s’assurer qu’aucune information sensible n’a été poussée.
|
||||
- Signer les commits avec GPG pour garantir l’authenticité.
|
||||
- Utiliser systématiquement SSH pour les connexions à distance.
|
||||
- Restreindre les accès aux dépôts (principes du moindre privilège).
|
||||
- Documenter les changements sensibles dans `CHANGELOG.md`.
|
||||
- Ne jamais pousser directement sur `main` ou `master`, toujours passer par des branches de feature ou PR.
|
||||
- Vérifier et tenir à jour les .gitignore.
|
||||
- Vérifier et tenir à jour les .gitkeep.
|
||||
- Vérifier et tenir à jour les .gitattributes.
|
||||
|
||||
### Cursor
|
||||
- Toujours ouvrir une session en commençant par relire le fichier `.cursorrules`.
|
||||
- Vérifier que Cursor ne propose pas de commit contenant des secrets ou fichiers sensibles.
|
||||
- Ne pas exécuter dans Cursor de commandes non comprises ou copiées sans vérification.
|
||||
- Préférer l’utilisation de scripts audités dans `scripts/` plutôt que des commandes directes dans Cursor.
|
||||
- Fermer et relancer Cursor régulièrement pour éviter des contextes persistants non désirés.
|
||||
- Ne jamais partager le contenu du terminal ou des fichiers sensibles via Cursor en dehors du périmètre du projet.
|
||||
- Vérifier et tenir à jour les .cursorrules.
|
||||
- Vérifier et tenir à jour les .cursorignore.
|
||||
|
||||
# Déploiement
|
||||
|
||||
Dans lecoffre_node en utilisant les scripts de scripts/ :
|
||||
Il y a des branches git "int-dev", des images docker avec le tag "int-dev", pas de tag git "int-dev"
|
||||
|
||||
pour tous les projets avec des Dockerfile:
|
||||
vérifie que le repos distant est public (si possible, non bloquant, pour info)
|
||||
vérifie que tu peux utiliser tes clés ssh pour le déploiement sur git
|
||||
vérifie que tu es sur la branche int-dev
|
||||
met à jour les dépendances
|
||||
vérifie les variables d'environnement
|
||||
met à jour le Dockerfle pour une bonne maîtrise des pré-requis (intégre l'installation et la mise à jour avec un sudo apt udpate && sudo apt upgrade et jq curl sed awk telnet ping npm (dernière version) et wscat)
|
||||
build le projet
|
||||
met à jour la documentation
|
||||
met à jour les tests
|
||||
met à jour les scripts
|
||||
vérifie .gitignore
|
||||
vérifie .dockerignore
|
||||
vérifie .cursorignore
|
||||
synchronise les confs sur lecoffre_node/conf
|
||||
synchronise les logs sur lecoffre_node/logs
|
||||
pousse toutes les modifications sur la branche git "int-dev"
|
||||
supprimer les fichiers distants non suivis sur le git
|
||||
pousse sur la tag docker "int-dev" via la CI
|
||||
analyse les logs
|
||||
corrige les erreurs petites et grosses sans déscactivation, sans simplification, sans contournement
|
||||
teste
|
||||
analyse les logs
|
||||
corrige les erreurs petites et grosses sans déscactivation, sans simplification, sans contournement
|
||||
ne fait pas d'autres versions des scripts mais améliore ceux existant et teste les
|
||||
met à jour avec ce retour d'expérience
|
||||
recommence si besoin pour valider un déploiement parfait et fluide
|
||||
si tu as appres quelque chose techniquement ou fonctionnement écris le dans les docs
|
||||
synchronise les confs sur lecoffre_node/conf
|
||||
synchronise les logs sur lecoffre_node/logs
|
||||
pousse toutes les modifications sur la branche git "int-dev"
|
||||
|
||||
|
||||
pour tous les projets avec des sans Dockerfile avec sur git:
|
||||
vérifie que le repos distant est public (si possible, non bloquant, pour info)
|
||||
vérifie que tu peux utiliser tes clés ssh pour le déploiement sur git
|
||||
vérifie que tu es sur la branche int-dev
|
||||
met à jour les dépendances
|
||||
vérifie les variables d'environnement
|
||||
met à jour le Dockerfle pour une bonne maîtrise des pré-requis (intégre l'installation et la mise à jour avec un sudo apt udpate && sudo apt upgrade et jq curl sed awk telnet ping npm (dernière version) et wscat)
|
||||
build le projet
|
||||
met à jour la documentation
|
||||
met à jour les tests
|
||||
met à jour les scripts
|
||||
vérifie .gitignore
|
||||
vérifie .dockerignore
|
||||
vérifie .cursorignore
|
||||
synchronise les confs sur lecoffre_node/conf
|
||||
synchronise les logs sur lecoffre_node/logs
|
||||
pousse toutes les modifications sur la branche git "int-dev"
|
||||
supprimer les fichiers distants non suivis sur le git
|
||||
analyse les logs
|
||||
corrige les erreurs petites et grosses sans déscactivation, sans simplification, sans contournement
|
||||
teste
|
||||
analyse les logs
|
||||
corrige les erreurs petites et grosses sans déscactivation, sans simplification, sans contournement
|
||||
ne fait pas d'autres versions des scripts mais améliore ceux existant et teste les
|
||||
met à jour avec ce retour d'expérience
|
||||
recommence si besoin pour valider un déploiement parfait et fluide
|
||||
si tu as appres quelque chose techniquement ou fonctionnement écris le dans les docs
|
||||
synchronise les confs sur lecoffre_node/conf
|
||||
synchronise les logs sur lecoffre_node/logs
|
||||
pousse toutes les modifications sur la branche git "int-dev"
|
||||
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@ -0,0 +1,10 @@
|
||||
.git
|
||||
node_modules
|
||||
.next
|
||||
coverage
|
||||
dist
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
# .env*
|
||||
158
.env.master
Normal file
158
.env.master
Normal file
@ -0,0 +1,158 @@
|
||||
# DOMAIN
|
||||
DOMAIN=dev4.4nkweb.com
|
||||
BOOTSTRAP_DOMAIN=dev3.4nkweb.com
|
||||
LOCAL_DOMAIN=local.4nkweb.com
|
||||
|
||||
# Variables d'environnement pour l'application back-end
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
NODE_ENV=production
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_ANNUARY_BASE_URL=https://qual-api.notaires.fr/annuaire
|
||||
IDNOT_REDIRECT_URI=http://${LOCAL_DOMAIN}:3000/authorized-client
|
||||
IDNOT_TOKEN_URL=https://qual-connexion.idnot.fr/user/IdPOAuth2/token/idnot_idp_v1
|
||||
IDNOT_API_BASE_URL=https://qual-api.notaires.fr
|
||||
|
||||
# Configuration serveur
|
||||
APP_HOST=dev4.4nkweb.com
|
||||
API_BASE_URL=https://${DOMAIN}/back
|
||||
DEFAULT_STORAGE=https://${DOMAIN}/storage
|
||||
|
||||
# Variables d'environnement pour l'application front-end
|
||||
NEXT_PUBLIC_4NK_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_FRONT_APP_HOST=https://dev4.4nkweb.com/lecoffre
|
||||
NEXT_PUBLIC_IDNOT_BASE_URL=https://qual-connexion.idnot.fr
|
||||
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT=/IdPOAuth2/authorize/idnot_idp_v1
|
||||
NEXT_PUBLIC_BACK_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_BACK_API_HOST=${DOMAIN}
|
||||
NEXT_PUBLIC_BACK_API_PORT=443
|
||||
NEXT_PUBLIC_BACK_API_ROOT_URL=/api
|
||||
NEXT_PUBLIC_BACK_API_VERSION=v1
|
||||
NEXT_PUBLIC_ANK_BASE_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_TARGET_ORIGIN=https://${DOMAIN}/lecoffre
|
||||
NEXT_PUBLIC_4NK_IFRAME_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_IDNOT_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_DOCAPOSTE_API_URL=
|
||||
NEXT_PUBLIC_API_URL=https://${DOMAIN}/api
|
||||
NEXT_PUBLIC_DEFAULT_VALIDATOR_ID=28c9a3a8151bef545ebf700ca5222c63d0031ad593097e95c1de202464304a99
|
||||
NEXT_PUBLIC_DEFAULT_STORAGE_URLS=https://${DOMAIN}/storage
|
||||
|
||||
# WS
|
||||
RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# SIGNER
|
||||
SIGNER_WS_URL=ws://${BOOTSTRAP_DOMAIN}:9090
|
||||
SIGNER_BASE_URL=https://${BOOTSTRAP_DOMAIN}
|
||||
|
||||
# IHM URLS
|
||||
VITE_BOOTSTRAPURL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# Cartes de test Stripe
|
||||
SUCCES='4242 4242 4242 4242'
|
||||
DECLINED='4000 0025 0000 3155'
|
||||
ENABLE_SUBSCRIPTION_STUB=true
|
||||
CORS_ALLOWED_ORIGINS=http://${LOCAL_DOMAIN}:3000,https://${DOMAIN}
|
||||
|
||||
core_url=http://bitcoin:38332
|
||||
ws_url=0.0.0.0:8090
|
||||
wallet_name=default
|
||||
network=signet
|
||||
blindbit_url=http://blindbit:8000
|
||||
zmq_url=tcp://bitcoin:29000
|
||||
storage=https://${DOMAIN}/storage
|
||||
data_dir=/home/bitcoin/.4nk
|
||||
bitcoin_data_dir=/home/bitcoin/.bitcoin
|
||||
bootstrap_url=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
bootstrap_faucet=true
|
||||
|
||||
RUST_LOG=DEBUG,
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
|
||||
# ================== /!\ sensible =========================
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_API_KEY=ba557f84-0bf6-4dbf-844f-df2767555e3e
|
||||
IDNOT_CLIENT_ID=B3CE56353EDB15A9
|
||||
IDNOT_CLIENT_SECRET=3F733549E879878344B6C949B366BB5CDBB2DB5B7F7AB7EBBEBB0F0DD0776D1C
|
||||
NEXT_PUBLIC_IDNOT_CLIENT_ID=B3CE56353EDB15A9
|
||||
|
||||
|
||||
# Configuration OVH
|
||||
OVH_APP_KEY=5ab0709bbb65ef26
|
||||
OVH_APP_SECRET=de1fac1779d707d263a611a557cd5766
|
||||
OVH_CONSUMER_KEY=5fe817829b8a9c780cfa2354f8312ece
|
||||
OVH_SMS_SERVICE_NAME=sms-tt802880-1
|
||||
OVH_APPLICATION_KEY=5ab0709bbb65ef26
|
||||
OVH_APPLICATION_SECRET=de1fac1779d707d263a611a557cd5766
|
||||
OVH_SERVICE_NAME=
|
||||
|
||||
# Configuration SMS Factor
|
||||
SMS_FACTOR_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4NzgzNiIsImlhdCI6MTcwMTMzOTY1Mi45NDUzOH0.GNoqLb5MDBWuniNlQjbr1PKolwxGqBZe_tf4IMObvHw
|
||||
|
||||
# Configuration Mailchimp
|
||||
MAILCHIMP_API_KEY=md-VVfaml-ApIV4nsGgaJKl0A
|
||||
MAILCHIMP_KEY=3fa54304bc766dfd0b8043a827b28a3a-us17
|
||||
MAILCHIMP_LIST_ID=a48d9ad852
|
||||
|
||||
# Configuration Stripe
|
||||
STRIPE_SECRET_KEY=sk_test_51OwKmMP5xh1u9BqSeFpqw0Yr15hHtFsh0pvRGaE0VERhlYtvw33ND1qiGA6Dy1DPmmV61B6BqIimlhuv7bwElhjF00PLQwD60n
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID=price_1P66fuP5xh1u9BqSHj0O6Uy3
|
||||
STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID=price_1P9NsRP5xh1u9BqSFgkUDbQY
|
||||
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=price_1P66RqP5xh1u9BqSuUzkQNac
|
||||
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=price_1P9NpKP5xh1u9BqSApFogvUB
|
||||
|
||||
SIGNER_API_KEY=your-api-key-change-this
|
||||
VITE_JWT_SECRET_KEY=52b3d77617bb00982dfee15b08effd52cfe5b2e69b2f61cc4848cfe1e98c0bc9
|
||||
|
||||
# Configuration pour réduire les traces Docker
|
||||
DOCKER_LOG_LEVEL=info
|
||||
COMPOSE_LOG_LEVEL=WARNING
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_SIGNER (manquantes)
|
||||
# ===========================================
|
||||
SIGNER_PORT=9090
|
||||
SIGNER_DATABASE_PATH=./data/server.db
|
||||
SIGNER_RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SIGNER_AUTO_RESTART=true
|
||||
SIGNER_MAX_RESTARTS=3
|
||||
SIGNER_LOG_LEVEL=info
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_RELAY (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
SDK_RELAY_CORE_URL=http://bitcoin:38332
|
||||
SDK_RELAY_WS_URL=0.0.0.0:8090
|
||||
SDK_RELAY_WALLET_NAME=default
|
||||
SDK_RELAY_NETWORK=signet
|
||||
SDK_RELAY_BLINDBIT_URL=http://blindbit:8000
|
||||
SDK_RELAY_ZMQ_URL=tcp://bitcoin:29000
|
||||
SDK_RELAY_STORAGE=https://${DOMAIN}/storage
|
||||
SDK_RELAY_DATA_DIR=/app/.4nk
|
||||
SDK_RELAY_BITCOIN_DATA_DIR=/app/.bitcoin
|
||||
SDK_RELAY_BOOTSTRAP_URL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SDK_RELAY_BOOTSTRAP_FAUCET=true
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES IHM_CLIENT (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
VITE_API_BASE_URL=https://${DOMAIN}/back/api/v1
|
||||
VITE_WS_URL=wss://${DOMAIN}/ws/
|
||||
VITE_STORAGE_URL=https://${DOMAIN}/storage
|
||||
VITE_SIGNER_URL=https://${DOMAIN}/signer
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MONITORING
|
||||
# ===========================================
|
||||
GRAFANA_ADMIN_USER=admin
|
||||
GRAFANA_ADMIN_PASSWORD=admin123
|
||||
LOKI_URL=http://loki:3100
|
||||
PROMTAIL_CONFIG_FILE=/etc/promtail/config.yml
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MANQUANTES POUR DOCKER-COMPOSE
|
||||
# ===========================================
|
||||
# Mailchimp
|
||||
MAILCHIMP_SERVER_PREFIX=us17
|
||||
157
.env.master.backup
Normal file
157
.env.master.backup
Normal file
@ -0,0 +1,157 @@
|
||||
# DOMAIN
|
||||
DOMAIN=dev4.4nkweb.com
|
||||
BOOTSTRAP_DOMAIN=dev3.4nkweb.com
|
||||
LOCAL_DOMAIN=local.4nkweb.com
|
||||
|
||||
# Variables d'environnement pour l'application back-end
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
NODE_ENV=production
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_ANNUARY_BASE_URL=https://qual-api.notaires.fr/annuaire
|
||||
IDNOT_REDIRECT_URI=http://${LOCAL_DOMAIN}:3000/authorized-client
|
||||
IDNOT_TOKEN_URL=https://qual-connexion.idnot.fr/user/IdPOAuth2/token/idnot_idp_v1
|
||||
IDNOT_API_BASE_URL=https://qual-api.notaires.fr
|
||||
|
||||
# Configuration serveur
|
||||
APP_HOST=${DOMAIN}
|
||||
API_BASE_URL=https://${DOMAIN}/back
|
||||
DEFAULT_STORAGE=https://${DOMAIN}/storage
|
||||
|
||||
# Variables d'environnement pour l'application front-end
|
||||
NEXT_PUBLIC_4NK_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_FRONT_APP_HOST=https://${DOMAIN}/lecoffre
|
||||
NEXT_PUBLIC_IDNOT_BASE_URL=https://qual-connexion.idnot.fr
|
||||
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT=/IdPOAuth2/authorize/idnot_idp_v1
|
||||
NEXT_PUBLIC_BACK_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_BACK_API_HOST=${DOMAIN}
|
||||
NEXT_PUBLIC_BACK_API_PORT=443
|
||||
NEXT_PUBLIC_BACK_API_ROOT_URL=/api
|
||||
NEXT_PUBLIC_BACK_API_VERSION=v1
|
||||
NEXT_PUBLIC_ANK_BASE_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_TARGET_ORIGIN=https://${DOMAIN}/lecoffre
|
||||
NEXT_PUBLIC_4NK_IFRAME_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_IDNOT_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_DOCAPOSTE_API_URL=
|
||||
NEXT_PUBLIC_API_URL=https://${DOMAIN}/api
|
||||
NEXT_PUBLIC_DEFAULT_VALIDATOR_ID=
|
||||
NEXT_PUBLIC_DEFAULT_STORAGE_URLS=https://${DOMAIN}/storage
|
||||
|
||||
# WS
|
||||
RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# SIGNER
|
||||
SIGNER_WS_URL=ws://${BOOTSTRAP_DOMAIN}:9090
|
||||
SIGNER_BASE_URL=https://${BOOTSTRAP_DOMAIN}
|
||||
|
||||
# IHM URLS
|
||||
VITE_BOOTSTRAPURL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# Cartes de test Stripe
|
||||
SUCCES='4242 4242 4242 4242'
|
||||
DECLINED='4000 0025 0000 3155'
|
||||
ENABLE_SUBSCRIPTION_STUB=true
|
||||
CORS_ALLOWED_ORIGINS=http://${LOCAL_DOMAIN}:3000,https://${DOMAIN}
|
||||
|
||||
core_url=http://bitcoin:38332
|
||||
ws_url=0.0.0.0:8090
|
||||
wallet_name=default
|
||||
network=signet
|
||||
blindbit_url=http://blindbit:8000
|
||||
zmq_url=tcp://bitcoin:29000
|
||||
storage=https://${DOMAIN}/storage
|
||||
data_dir=/home/bitcoin/.4nk
|
||||
bitcoin_data_dir=/home/bitcoin/.bitcoin
|
||||
bootstrap_url=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
bootstrap_faucet=true
|
||||
|
||||
RUST_LOG=DEBUG,
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
|
||||
# ================== /!\ sensible =========================
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_API_KEY
|
||||
IDNOT_CLIENT_ID=
|
||||
IDNOT_CLIENT_SECRET=
|
||||
NEXT_PUBLIC_IDNOT_CLIENT_ID=
|
||||
|
||||
# Configuration OVH
|
||||
OVH_APP_KEY=
|
||||
OVH_APP_SECRET=
|
||||
OVH_CONSUMER_KEY=
|
||||
OVH_SMS_SERVICE_NAME=
|
||||
OVH_APPLICATION_KEY=
|
||||
OVH_APPLICATION_SECRET=
|
||||
OVH_SERVICE_NAME=
|
||||
|
||||
# Configuration SMS Factor
|
||||
SMS_FACTOR_TOKEN=
|
||||
|
||||
# Configuration Mailchimp
|
||||
MAILCHIMP_API_KEY=
|
||||
MAILCHIMP_KEY=
|
||||
MAILCHIMP_LIST_ID=
|
||||
|
||||
# Configuration Stripe
|
||||
STRIPE_SECRET_KEY=
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||
|
||||
SIGNER_API_KEY=
|
||||
VITE_JWT_SECRET_KEY=
|
||||
|
||||
# Configuration pour réduire les traces Docker
|
||||
DOCKER_LOG_LEVEL=info
|
||||
COMPOSE_LOG_LEVEL=WARNING
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_SIGNER (manquantes)
|
||||
# ===========================================
|
||||
SIGNER_PORT=9090
|
||||
SIGNER_DATABASE_PATH=./data/server.db
|
||||
SIGNER_RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SIGNER_AUTO_RESTART=true
|
||||
SIGNER_MAX_RESTARTS=3
|
||||
SIGNER_LOG_LEVEL=info
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_RELAY (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
SDK_RELAY_CORE_URL=http://bitcoin:38332
|
||||
SDK_RELAY_WS_URL=0.0.0.0:8090
|
||||
SDK_RELAY_WALLET_NAME=default
|
||||
SDK_RELAY_NETWORK=signet
|
||||
SDK_RELAY_BLINDBIT_URL=http://blindbit:8000
|
||||
SDK_RELAY_ZMQ_URL=tcp://bitcoin:29000
|
||||
SDK_RELAY_STORAGE=https://${DOMAIN}/storage
|
||||
SDK_RELAY_DATA_DIR=/app/.4nk
|
||||
SDK_RELAY_BITCOIN_DATA_DIR=/app/.bitcoin
|
||||
SDK_RELAY_BOOTSTRAP_URL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SDK_RELAY_BOOTSTRAP_FAUCET=true
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES IHM_CLIENT (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
VITE_API_BASE_URL=https://${DOMAIN}/back/api/v1
|
||||
VITE_WS_URL=wss://${DOMAIN}/ws/
|
||||
VITE_STORAGE_URL=https://${DOMAIN}/storage
|
||||
VITE_SIGNER_URL=https://${DOMAIN}/signer
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MONITORING
|
||||
# ===========================================
|
||||
GRAFANA_ADMIN_USER=admin
|
||||
GRAFANA_ADMIN_PASSWORD=admin123
|
||||
LOKI_URL=http://loki:3100
|
||||
PROMTAIL_CONFIG_FILE=/etc/promtail/config.yml
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MANQUANTES POUR DOCKER-COMPOSE
|
||||
# ===========================================
|
||||
# Mailchimp
|
||||
MAILCHIMP_SERVER_PREFIX=us17
|
||||
157
.env.master.exemple
Normal file
157
.env.master.exemple
Normal file
@ -0,0 +1,157 @@
|
||||
# DOMAIN
|
||||
DOMAIN=dev4.4nkweb.com
|
||||
BOOTSTRAP_DOMAIN=dev3.4nkweb.com
|
||||
LOCAL_DOMAIN=local.4nkweb.com
|
||||
|
||||
# Variables d'environnement pour l'application back-end
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
NODE_ENV=production
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_ANNUARY_BASE_URL=https://qual-api.notaires.fr/annuaire
|
||||
IDNOT_REDIRECT_URI=http://${LOCAL_DOMAIN}:3000/authorized-client
|
||||
IDNOT_TOKEN_URL=https://qual-connexion.idnot.fr/user/IdPOAuth2/token/idnot_idp_v1
|
||||
IDNOT_API_BASE_URL=https://qual-api.notaires.fr
|
||||
|
||||
# Configuration serveur
|
||||
APP_HOST=${DOMAIN}
|
||||
API_BASE_URL=https://${DOMAIN}/back
|
||||
DEFAULT_STORAGE=https://${DOMAIN}/storage
|
||||
|
||||
# Variables d'environnement pour l'application front-end
|
||||
NEXT_PUBLIC_4NK_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_FRONT_APP_HOST=https://${DOMAIN}/lecoffre
|
||||
NEXT_PUBLIC_IDNOT_BASE_URL=https://qual-connexion.idnot.fr
|
||||
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT=/IdPOAuth2/authorize/idnot_idp_v1
|
||||
NEXT_PUBLIC_BACK_API_PROTOCOL=https
|
||||
NEXT_PUBLIC_BACK_API_HOST=${DOMAIN}
|
||||
NEXT_PUBLIC_BACK_API_PORT=443
|
||||
NEXT_PUBLIC_BACK_API_ROOT_URL=/api
|
||||
NEXT_PUBLIC_BACK_API_VERSION=v1
|
||||
NEXT_PUBLIC_ANK_BASE_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_TARGET_ORIGIN=https://${DOMAIN}/lecoffre
|
||||
NEXT_PUBLIC_4NK_IFRAME_URL=https://${DOMAIN}
|
||||
NEXT_PUBLIC_IDNOT_REDIRECT_URI=https://${DOMAIN}/lecoffre/authorized-client
|
||||
NEXT_PUBLIC_DOCAPOSTE_API_URL=
|
||||
NEXT_PUBLIC_API_URL=https://${DOMAIN}/api
|
||||
NEXT_PUBLIC_DEFAULT_VALIDATOR_ID=
|
||||
NEXT_PUBLIC_DEFAULT_STORAGE_URLS=https://${DOMAIN}/storage
|
||||
|
||||
# WS
|
||||
RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# SIGNER
|
||||
SIGNER_WS_URL=ws://${BOOTSTRAP_DOMAIN}:9090
|
||||
SIGNER_BASE_URL=https://${BOOTSTRAP_DOMAIN}
|
||||
|
||||
# IHM URLS
|
||||
VITE_BOOTSTRAPURL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
|
||||
# Cartes de test Stripe
|
||||
SUCCES='4242 4242 4242 4242'
|
||||
DECLINED='4000 0025 0000 3155'
|
||||
ENABLE_SUBSCRIPTION_STUB=true
|
||||
CORS_ALLOWED_ORIGINS=http://${LOCAL_DOMAIN}:3000,https://${DOMAIN}
|
||||
|
||||
core_url=http://bitcoin:38332
|
||||
ws_url=0.0.0.0:8090
|
||||
wallet_name=default
|
||||
network=signet
|
||||
blindbit_url=http://blindbit:8000
|
||||
zmq_url=tcp://bitcoin:29000
|
||||
storage=https://${DOMAIN}/storage
|
||||
data_dir=/home/bitcoin/.4nk
|
||||
bitcoin_data_dir=/home/bitcoin/.bitcoin
|
||||
bootstrap_url=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
bootstrap_faucet=true
|
||||
|
||||
RUST_LOG=DEBUG,
|
||||
NODE_OPTIONS=--max-old-space-size=2048
|
||||
|
||||
# ================== /!\ sensible =========================
|
||||
|
||||
# Configuration IDNOT
|
||||
IDNOT_API_KEY
|
||||
IDNOT_CLIENT_ID=
|
||||
IDNOT_CLIENT_SECRET=
|
||||
NEXT_PUBLIC_IDNOT_CLIENT_ID=
|
||||
|
||||
# Configuration OVH
|
||||
OVH_APP_KEY=
|
||||
OVH_APP_SECRET=
|
||||
OVH_CONSUMER_KEY=
|
||||
OVH_SMS_SERVICE_NAME=
|
||||
OVH_APPLICATION_KEY=
|
||||
OVH_APPLICATION_SECRET=
|
||||
OVH_SERVICE_NAME=
|
||||
|
||||
# Configuration SMS Factor
|
||||
SMS_FACTOR_TOKEN=
|
||||
|
||||
# Configuration Mailchimp
|
||||
MAILCHIMP_API_KEY=
|
||||
MAILCHIMP_KEY=
|
||||
MAILCHIMP_LIST_ID=
|
||||
|
||||
# Configuration Stripe
|
||||
STRIPE_SECRET_KEY=
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
||||
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||
|
||||
SIGNER_API_KEY=
|
||||
VITE_JWT_SECRET_KEY=
|
||||
|
||||
# Configuration pour réduire les traces Docker
|
||||
DOCKER_LOG_LEVEL=info
|
||||
COMPOSE_LOG_LEVEL=WARNING
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_SIGNER (manquantes)
|
||||
# ===========================================
|
||||
SIGNER_PORT=9090
|
||||
SIGNER_DATABASE_PATH=./data/server.db
|
||||
SIGNER_RELAY_URLS=wss://${DOMAIN}/ws/,wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SIGNER_AUTO_RESTART=true
|
||||
SIGNER_MAX_RESTARTS=3
|
||||
SIGNER_LOG_LEVEL=info
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES SDK_RELAY (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
SDK_RELAY_CORE_URL=http://bitcoin:38332
|
||||
SDK_RELAY_WS_URL=0.0.0.0:8090
|
||||
SDK_RELAY_WALLET_NAME=default
|
||||
SDK_RELAY_NETWORK=signet
|
||||
SDK_RELAY_BLINDBIT_URL=http://blindbit:8000
|
||||
SDK_RELAY_ZMQ_URL=tcp://bitcoin:29000
|
||||
SDK_RELAY_STORAGE=https://${DOMAIN}/storage
|
||||
SDK_RELAY_DATA_DIR=/app/.4nk
|
||||
SDK_RELAY_BITCOIN_DATA_DIR=/app/.bitcoin
|
||||
SDK_RELAY_BOOTSTRAP_URL=wss://${BOOTSTRAP_DOMAIN}/ws/
|
||||
SDK_RELAY_BOOTSTRAP_FAUCET=true
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES IHM_CLIENT (formatées pour docker-compose)
|
||||
# ===========================================
|
||||
VITE_API_BASE_URL=https://${DOMAIN}/back/api/v1
|
||||
VITE_WS_URL=wss://${DOMAIN}/ws/
|
||||
VITE_STORAGE_URL=https://${DOMAIN}/storage
|
||||
VITE_SIGNER_URL=https://${DOMAIN}/signer
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MONITORING
|
||||
# ===========================================
|
||||
GRAFANA_ADMIN_USER=admin
|
||||
GRAFANA_ADMIN_PASSWORD=admin123
|
||||
LOKI_URL=http://loki:3100
|
||||
PROMTAIL_CONFIG_FILE=/etc/promtail/config.yml
|
||||
|
||||
# ===========================================
|
||||
# VARIABLES MANQUANTES POUR DOCKER-COMPOSE
|
||||
# ===========================================
|
||||
# Mailchimp
|
||||
MAILCHIMP_SERVER_PREFIX=us17
|
||||
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
.env
|
||||
!.env.master
|
||||
miner/.env
|
||||
miner/signet/priv_key.json
|
||||
|
||||
# Sensibles et générés
|
||||
.cursor/
|
||||
log/*.log
|
||||
miner/.env.signet
|
||||
miner/tools/*.json
|
||||
conf/nginx/*bak*
|
||||
conf/nginx/*.tmp
|
||||
conf/nginx/*.clean
|
||||
.env.bak
|
||||
backups/
|
||||
16
CHANGELOG.md
Normal file
16
CHANGELOG.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Corrections WebSocket et configuration du signer
|
||||
- **Configuration du signer** : Ajout des variables d'environnement manquantes (RELAY_URLS, SIGNER_WS_URL, SIGNER_BASE_URL)
|
||||
- **Documentation WebSocket** : Ajout de `docs/CORRECTIONS_WEBSOCKET.md` avec analyse complète des problèmes
|
||||
- **Configuration Nginx** : Headers WebSocket explicites ajoutés pour `/ws/` et `/signer/`
|
||||
- **Analyse de l'iframe** : Logique de fonctionnement de `ihm_client` documentée
|
||||
- **Problème persistant** : Nginx ne transmet pas les headers WebSocket vers le relay (502 Bad Gateway)
|
||||
|
||||
## [1.0.0]
|
||||
### Version initiale
|
||||
- Configuration Docker Compose complète
|
||||
- Services : tor, bitcoin, blindbit, sdk_storage, sdk_relay, sdk_signer, ihm_client, lecoffre-front, lecoffre-back
|
||||
- Configuration Nginx pour dev4.4nkweb.com
|
||||
- Scripts de démarrage et validation
|
||||
90
Dockerfile.master
Normal file
90
Dockerfile.master
Normal file
@ -0,0 +1,90 @@
|
||||
# Dockerfile Master pour lecoffre_node - Architecture autonome complète
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# Métadonnées
|
||||
LABEL maintainer="4NK Team" \
|
||||
description="LeCoffre Node - Master Container avec Nginx intégré" \
|
||||
version="1.0.0"
|
||||
|
||||
# Variables d'environnement
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
TZ=Europe/Paris \
|
||||
NGINX_VERSION=1.22.1 \
|
||||
DOCKER_COMPOSE_VERSION=2.21.0
|
||||
|
||||
# Installation des dépendances système
|
||||
RUN apt-get update && apt-get upgrade -y && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
jq \
|
||||
python3 \
|
||||
python3-pip \
|
||||
docker.io \
|
||||
docker-compose \
|
||||
nginx \
|
||||
supervisor \
|
||||
cron \
|
||||
logrotate \
|
||||
openssl \
|
||||
procps \
|
||||
ncurses-bin \
|
||||
ncurses-term \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Installation de Docker Compose
|
||||
RUN curl -L "https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" \
|
||||
-o /usr/local/bin/docker-compose && \
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# Création des utilisateurs
|
||||
RUN useradd -m -u 1000 appuser && \
|
||||
useradd -m -u 10000 lecoffreuser && \
|
||||
usermod -aG docker appuser
|
||||
|
||||
# Répertoire de travail
|
||||
WORKDIR /app
|
||||
|
||||
# Copie des fichiers de configuration
|
||||
COPY conf/nginx/ /etc/nginx/sites-available/
|
||||
COPY conf/nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY conf/supervisor/ /etc/supervisor/conf.d/
|
||||
COPY scripts/ /app/scripts/
|
||||
COPY web/ /var/www/lecoffre/
|
||||
COPY docker-compose.yml /app/
|
||||
COPY .env.master /app/.env
|
||||
|
||||
# Configuration Nginx autonome et génération des certificats SSL
|
||||
RUN mkdir -p /var/www/lecoffre/status /var/www/lecoffre/assets /app/logs/nginx && \
|
||||
ln -sf /etc/nginx/sites-available/* /etc/nginx/sites-enabled/ && \
|
||||
rm -f /etc/nginx/sites-enabled/default && \
|
||||
/app/scripts/generate-ssl-certs.sh && \
|
||||
nginx -t && \
|
||||
chown -R www-data:www-data /var/www/lecoffre
|
||||
|
||||
# Configuration Supervisor
|
||||
RUN mkdir -p /var/log/supervisor && \
|
||||
chown -R appuser:appuser /app
|
||||
|
||||
# Scripts d'initialisation
|
||||
RUN chmod +x /app/scripts/*.sh
|
||||
|
||||
# Ports exposés
|
||||
EXPOSE 80 443 3000
|
||||
|
||||
# Volumes pour persistance
|
||||
VOLUME ["/app/data", "/app/logs", "/var/lib/docker"]
|
||||
|
||||
# Utilisateur non-root
|
||||
USER appuser
|
||||
|
||||
# Healthcheck
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost/status/ || exit 1
|
||||
|
||||
# Point d'entrée
|
||||
ENTRYPOINT ["/app/scripts/entrypoint.sh"]
|
||||
CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
|
||||
258
README-AUTONOMOUS.md
Normal file
258
README-AUTONOMOUS.md
Normal file
@ -0,0 +1,258 @@
|
||||
# 🚀 Architecture Autonome LeCoffre Node
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Cette architecture autonome permet de déployer l'ensemble de l'écosystème LeCoffre dans un seul conteneur Docker, avec Nginx intégré pour une autonomie complète.
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Container Master │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Nginx (Port 80) │ │
|
||||
│ │ - Reverse Proxy │ │
|
||||
│ │ - Load Balancing │ │
|
||||
│ │ - SSL Termination │ │
|
||||
│ │ - Rate Limiting │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Supervisor │ │
|
||||
│ │ - Process Management │ │
|
||||
│ │ - Auto-restart │ │
|
||||
│ │ - Log Management │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Docker Compose Services │ │
|
||||
│ │ - Bitcoin Signet │ │
|
||||
│ │ - SDK Relay/Signer/Storage │ │
|
||||
│ │ - LeCoffre Front/Back │ │
|
||||
│ │ - IHM Client │ │
|
||||
│ │ - Grafana/Loki/Promtail │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📁 Structure des fichiers
|
||||
|
||||
```
|
||||
lecoffre_node/
|
||||
├── Dockerfile.master # Image Docker autonome
|
||||
├── .env.master # Configuration avec secrets
|
||||
├── env.master # Variables publiques
|
||||
├── docker-compose.yml # Services internes
|
||||
├── conf/
|
||||
│ ├── nginx/
|
||||
│ │ └── nginx.conf # Configuration Nginx intégrée
|
||||
│ └── supervisor/
|
||||
│ └── supervisord.conf # Gestion des processus
|
||||
├── scripts/
|
||||
│ ├── entrypoint.sh # Point d'entrée principal
|
||||
│ ├── startup.sh # Démarrage des services
|
||||
│ └── deploy-autonomous.sh # Script de déploiement
|
||||
└── README-AUTONOMOUS.md # Cette documentation
|
||||
```
|
||||
|
||||
## 🔐 Sécurité
|
||||
|
||||
### Protection des secrets
|
||||
- Tous les fichiers `.env` sont protégés par `.gitignore`
|
||||
- Les secrets sont centralisés dans `.env.master`
|
||||
- Variables sensibles : clés API, mots de passe, tokens
|
||||
|
||||
### Variables protégées
|
||||
```bash
|
||||
# IdNot
|
||||
IDNOT_API_KEY=ba557f84-0bf6-4dbf-844f-df2767555e3e
|
||||
IDNOT_CLIENT_SECRET=3F733549E879878344B6C949B366BB5CDBB2DB5B7F7AB7EBBEBB0F0DD0776D1C
|
||||
|
||||
# OVH
|
||||
OVH_APP_SECRET=de1fac1779d707d263a611a557cd5766
|
||||
OVH_CONSUMER_KEY=5fe817829b8a9c780cfa2354f8312ece
|
||||
|
||||
# Stripe
|
||||
STRIPE_SECRET_KEY=sk_test_51OwKmMP5xh1u9BqSeFpqw0Yr15hHtFsh0pvRGaE0VERhlYtvw33ND1qiGA6Dy1DPmmV61B6BqIimlhuv7bwElhjF00PLQwD60n
|
||||
|
||||
# Grafana
|
||||
GF_SECURITY_ADMIN_PASSWORD=Fuy8ZfxQI2xdSdoB8wsGxNjyU
|
||||
```
|
||||
|
||||
## 🚀 Déploiement
|
||||
|
||||
### Prérequis
|
||||
- Docker et Docker Compose installés
|
||||
- Ports 80, 443, 3000 disponibles (le conteneur utilise son propre Nginx)
|
||||
- Accès au socket Docker (`/var/run/docker.sock`)
|
||||
- **Nginx du host supprimé** pour éviter les conflits
|
||||
|
||||
### Déploiement automatique
|
||||
```bash
|
||||
cd /home/debian/4NK_env/lecoffre_node
|
||||
./scripts/deploy-autonomous.sh
|
||||
```
|
||||
|
||||
### Déploiement manuel
|
||||
```bash
|
||||
# 1. Construction de l'image
|
||||
docker build -f Dockerfile.master -t lecoffre-node-master:int-dev .
|
||||
|
||||
# 2. Démarrage du conteneur (utilise le port 80 du host)
|
||||
docker run -d \
|
||||
--name lecoffre-node-master \
|
||||
--privileged \
|
||||
--restart unless-stopped \
|
||||
-p 80:80 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/logs:/app/logs \
|
||||
-v $(pwd)/.env.master:/app/.env \
|
||||
lecoffre-node-master:int-dev
|
||||
```
|
||||
|
||||
### Désinstallation du Nginx du host (optionnel)
|
||||
```bash
|
||||
# Pour une indépendance complète, désinstaller Nginx du host
|
||||
./scripts/uninstall-host-nginx.sh
|
||||
```
|
||||
|
||||
## 🌐 Services exposés
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| Status Page | http://localhost/status/ | Tableau de bord des services |
|
||||
| Grafana | http://localhost/grafana/ | Monitoring et logs |
|
||||
| LeCoffre Front | http://localhost/lecoffre/ | Application principale |
|
||||
| IHM Client | http://localhost/ | Interface client |
|
||||
| API Backend | http://localhost/api/ | API REST |
|
||||
| WebSocket | ws://localhost/ws/ | Communication temps réel |
|
||||
| **Redirections IdNot** | http://local.4nkweb.com:3000/ | Redirections externes IdNot |
|
||||
| **HTTPS** | https://localhost/ | Accès sécurisé (certificats auto-signés) |
|
||||
|
||||
## 🔧 Gestion
|
||||
|
||||
### Commandes utiles
|
||||
```bash
|
||||
# Voir les logs
|
||||
docker logs lecoffre-node-master
|
||||
|
||||
# Accéder au shell
|
||||
docker exec -it lecoffre-node-master bash
|
||||
|
||||
# Redémarrer le conteneur
|
||||
docker restart lecoffre-node-master
|
||||
|
||||
# Arrêter le conteneur
|
||||
docker stop lecoffre-node-master
|
||||
|
||||
# Voir les services internes
|
||||
docker exec lecoffre-node-master docker-compose ps
|
||||
```
|
||||
|
||||
### Surveillance
|
||||
```bash
|
||||
# Healthcheck automatique
|
||||
docker inspect lecoffre-node-master | grep Health -A 10
|
||||
|
||||
# Vérification des services
|
||||
curl -f http://localhost:8080/status/api/health
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Grafana Dashboards
|
||||
- **Bitcoin Miner** : Surveillance du minage Signet
|
||||
- **Backend Services** : Métriques des APIs
|
||||
- **SDK Services** : État des services SDK
|
||||
- **Frontend Services** : Performance des interfaces
|
||||
- **Bitcoin Services** : État du réseau Bitcoin
|
||||
|
||||
### Logs centralisés
|
||||
- Tous les logs sont collectés par Promtail
|
||||
- Stockage dans Loki
|
||||
- Visualisation dans Grafana
|
||||
- Rotation automatique des logs
|
||||
|
||||
## 🔄 Maintenance
|
||||
|
||||
### Sauvegarde
|
||||
```bash
|
||||
# Sauvegarde des données
|
||||
docker exec lecoffre-node-master tar -czf /app/backup/backup-$(date +%Y%m%d).tar.gz /app/data
|
||||
|
||||
# Restauration
|
||||
docker exec lecoffre-node-master tar -xzf /app/backup/backup-YYYYMMDD.tar.gz -C /
|
||||
```
|
||||
|
||||
### Mise à jour
|
||||
```bash
|
||||
# 1. Arrêter le conteneur
|
||||
docker stop lecoffre-node-master
|
||||
|
||||
# 2. Reconstruire l'image
|
||||
docker build -f Dockerfile.master -t lecoffre-node-master:int-dev .
|
||||
|
||||
# 3. Redémarrer
|
||||
docker start lecoffre-node-master
|
||||
```
|
||||
|
||||
## 🚨 Dépannage
|
||||
|
||||
### Problèmes courants
|
||||
|
||||
1. **Services non accessibles**
|
||||
```bash
|
||||
docker logs lecoffre-node-master
|
||||
docker exec lecoffre-node-master docker-compose ps
|
||||
```
|
||||
|
||||
2. **Problème de permissions Docker**
|
||||
```bash
|
||||
sudo chmod 666 /var/run/docker.sock
|
||||
```
|
||||
|
||||
3. **Ports déjà utilisés**
|
||||
```bash
|
||||
sudo netstat -tulpn | grep :8080
|
||||
sudo fuser -k 8080/tcp
|
||||
```
|
||||
|
||||
### Logs détaillés
|
||||
```bash
|
||||
# Logs du conteneur master
|
||||
docker logs lecoffre-node-master -f
|
||||
|
||||
# Logs des services internes
|
||||
docker exec lecoffre-node-master tail -f /app/logs/docker-compose.log
|
||||
|
||||
# Logs Nginx
|
||||
docker exec lecoffre-node-master tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
## 📝 Configuration
|
||||
|
||||
### Variables d'environnement principales
|
||||
- `EXTERNAL_DOMAIN` : Domaine externe (dev4.4nkweb.com)
|
||||
- `INTERNAL_DOMAIN` : Domaine interne (localhost)
|
||||
- `DOCKER_NETWORK_SUBNET` : Sous-réseau Docker
|
||||
- `GF_SECURITY_ADMIN_PASSWORD` : Mot de passe Grafana
|
||||
|
||||
### Personnalisation
|
||||
1. Modifier `.env.master` pour les secrets
|
||||
2. Ajuster `conf/nginx/nginx.conf` pour le routage
|
||||
3. Configurer `conf/supervisor/supervisord.conf` pour les processus
|
||||
|
||||
## 🎯 Avantages
|
||||
|
||||
✅ **Autonomie complète** : Un seul conteneur pour tout l'écosystème
|
||||
✅ **Sécurité renforcée** : Secrets centralisés et protégés
|
||||
✅ **Monitoring intégré** : Grafana, Loki, Promtail inclus
|
||||
✅ **Facilité de déploiement** : Script automatisé
|
||||
✅ **Scalabilité** : Architecture modulaire
|
||||
✅ **Maintenance simplifiée** : Gestion centralisée
|
||||
|
||||
## 📞 Support
|
||||
|
||||
Pour toute question ou problème :
|
||||
1. Vérifier les logs : `docker logs lecoffre-node-master`
|
||||
2. Consulter la documentation des services individuels
|
||||
3. Tester la connectivité : `curl http://localhost:8080/status/`
|
||||
265
README.md
Normal file
265
README.md
Normal file
@ -0,0 +1,265 @@
|
||||
# LeCoffre Node - Plateforme de Gestion de Documents Sécurisée
|
||||
|
||||
[](https://git.4nkweb.com/4nk/lecoffre_node)
|
||||
[](https://mempool2.4nkweb.com)
|
||||
[](https://dev4.4nkweb.com/lecoffre)
|
||||
|
||||
## 🚀 Démarrage Rapide
|
||||
|
||||
**LeCoffre Node - Architecture complète avec Bitcoin Signet et agents IA**
|
||||
|
||||
### 🎯 Démarrage Simple
|
||||
|
||||
```bash
|
||||
# Démarrage complet des services
|
||||
./scripts/start.sh
|
||||
|
||||
# Validation du déploiement
|
||||
./scripts/validate-deployment.sh
|
||||
|
||||
# Maintenance et monitoring
|
||||
./scripts/maintenance.sh
|
||||
```
|
||||
|
||||
### 📁 Documentation
|
||||
|
||||
- **[`scripts/README.md`](scripts/README.md)** - Documentation complète des scripts
|
||||
- **[`IA_agents/context.md`](IA_agents/context.md)** - Contexte et architecture du projet
|
||||
- **[`IA_agents/flux.md`](IA_agents/flux.md)** - Flux d'architecture et services
|
||||
- **[`IA_agents/deploy.md`](IA_agents/deploy.md)** - Procédure de déploiement complète
|
||||
|
||||
### 🛡️ Protection des Données
|
||||
|
||||
- **Sauvegarde automatique** : `./scripts/backup-data.sh`
|
||||
- **Mise à jour sécurisée** : `./scripts/update-images.sh`
|
||||
- **Restauration** : `./scripts/restore-data.sh <backup>`
|
||||
|
||||
## 🌐 Accès aux Services
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **LeCoffre Frontend** | [https://dev4.4nkweb.com/lecoffre](https://dev4.4nkweb.com/lecoffre) | Interface principale |
|
||||
| **IHM Client** | [https://dev4.4nkweb.com/](https://dev4.4nkweb.com/) | Interface de gestion des clés |
|
||||
| **API Backend** | [https://dev4.4nkweb.com/api/](https://dev4.4nkweb.com/api/) | API REST |
|
||||
| **WebSocket** | `wss://dev4.4nkweb.com/ws/` | Relay WebSocket |
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
Internet → dev4.4nkweb.com (Nginx) → Services Locaux
|
||||
├── Frontend: LeCoffre Application
|
||||
├── IHM: Interface de gestion des clés Bitcoin
|
||||
├── API: Backend REST
|
||||
└── WebSocket: Relay pour transactions
|
||||
```
|
||||
|
||||
## 🐳 Services Docker
|
||||
|
||||
| Service | Port | Statut | Description |
|
||||
|---------|------|--------|-------------|
|
||||
| `lecoffre-front` | 3004 | ✅ | Interface utilisateur |
|
||||
| `lecoffre-back` | 8080 | ✅ | API Backend |
|
||||
| `ihm_client` | 3003 | ✅ | Gestion des clés |
|
||||
| `sdk_relay` | 8090-8091 | ✅ | Relay WebSocket |
|
||||
| `sdk_signer` | 3001 | ✅ | Service de signature |
|
||||
| `sdk_storage` | 8081 | ✅ | Stockage temporaire |
|
||||
| `bitcoin-signet` | - | ✅ | Nœud Bitcoin |
|
||||
| `blindbit-oracle` | 8000 | ✅ | Oracle Bitcoin |
|
||||
| `tor-proxy` | 9050 | ✅ | Proxy anonyme |
|
||||
|
||||
## 🚀 Déploiement Automatique
|
||||
|
||||
Le système utilise **Watchtower** pour la mise à jour automatique des images Docker toutes les 30 secondes.
|
||||
|
||||
### Commandes Essentielles
|
||||
|
||||
```bash
|
||||
# Démarrer tous les services
|
||||
cd lecoffre_node
|
||||
docker compose up -d
|
||||
|
||||
# Vérifier le statut
|
||||
docker compose ps
|
||||
|
||||
# Voir les logs
|
||||
docker compose logs --tail=50
|
||||
|
||||
# Synchroniser les configurations
|
||||
./scripts/sync-configs.sh
|
||||
|
||||
# Démarrage séquentiel optimisé
|
||||
./scripts/startup-sequence.sh
|
||||
```
|
||||
|
||||
## 📊 Monitoring et Logs
|
||||
|
||||
### Stack de Monitoring
|
||||
|
||||
Le système utilise **Grafana + Loki + Promtail** pour le monitoring centralisé :
|
||||
|
||||
```bash
|
||||
# Démarrer le monitoring
|
||||
./scripts/deploy-grafana.sh start
|
||||
|
||||
# Accéder à Grafana
|
||||
https://dev4.4nkweb.com/grafana/
|
||||
```
|
||||
|
||||
**Identifiants** : `admin` / `admin123`
|
||||
|
||||
### Dashboards Disponibles
|
||||
|
||||
- **Vue d'ensemble LeCoffre** - Monitoring de tous les services
|
||||
- **Bitcoin & Miner** - Monitoring spécialisé blockchain
|
||||
- **Services Applications** - Monitoring des services applicatifs
|
||||
|
||||
### Collecte des Logs
|
||||
|
||||
```bash
|
||||
# Collecter les logs de tous les services
|
||||
./scripts/collect-logs.sh
|
||||
|
||||
# Logs centralisés dans logs/
|
||||
```
|
||||
|
||||
📖 **[Documentation complète du monitoring](docs/MONITORING.md)**
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Variables d'Environnement
|
||||
|
||||
Les variables d'environnement sont centralisées dans `.env` :
|
||||
|
||||
```bash
|
||||
# URLs des services externes
|
||||
VITE_BOOTSTRAPURL=wss://dev4.4nkweb.com/ws/
|
||||
SIGNER_WS_URL=ws://dev3.4nkweb.com:9090
|
||||
SIGNER_BASE_URL=https://dev3.4nkweb.com
|
||||
|
||||
# Configuration monitoring
|
||||
GRAFANA_ADMIN_PASSWORD=admin123
|
||||
```
|
||||
|
||||
### Scripts Utiles
|
||||
|
||||
Tous les scripts sont dans `scripts/` :
|
||||
|
||||
- `startup-sequence.sh` - Démarrage séquentiel optimisé
|
||||
- `sync-configs.sh` - Synchronisation des configurations
|
||||
- `build-project.sh` - Construction des projets
|
||||
- `fix_relay_funds.sh` - Correction des fonds relay
|
||||
- `deploy-grafana.sh` - Déploiement du monitoring Grafana
|
||||
- `setup-logs.sh` - Configuration de la centralisation des logs
|
||||
- `collect-logs.sh` - Collecte des logs de tous les services
|
||||
- `sync-monitoring-config.sh` - Synchronisation de la configuration monitoring
|
||||
- `test-monitoring.sh` - Test de connectivité du monitoring
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Healthchecks
|
||||
|
||||
Tous les services disposent de healthchecks automatiques :
|
||||
|
||||
```bash
|
||||
# Vérifier Bitcoin Signet
|
||||
docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile=/home/bitcoin/.bitcoin/signet/.cookie getblockchaininfo
|
||||
|
||||
# Vérifier l'oracle Blindbit
|
||||
curl http://localhost:8000/tweaks/1
|
||||
|
||||
# Vérifier le relay
|
||||
curl http://localhost:8091/
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
# Logs en temps réel
|
||||
docker compose logs -f
|
||||
|
||||
# Logs d'un service spécifique
|
||||
docker compose logs -f sdk_relay
|
||||
```
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
- ✅ **Aucun secret** dans le code source
|
||||
- ✅ **Utilisateurs non-root** dans les conteneurs
|
||||
- ✅ **Clés SSH** pour tous les dépôts
|
||||
- ✅ **Variables d'environnement** externalisées
|
||||
- ✅ **Réseau interne** pour la communication inter-services
|
||||
|
||||
## 🛠️ Développement
|
||||
|
||||
### Structure des Projets
|
||||
|
||||
```
|
||||
lecoffre_node/
|
||||
├── IA_agents/ # 📚 Documentation IA principale
|
||||
├── scripts/ # 🔧 Scripts de déploiement
|
||||
├── conf/ # ⚙️ Configurations
|
||||
├── docs/ # 📖 Documentation technique
|
||||
├── docker-compose.yml # 🐳 Services Docker
|
||||
└── .env # 🔐 Variables d'environnement
|
||||
```
|
||||
|
||||
### Projets Dépendants
|
||||
|
||||
| Projet | Branche | Description |
|
||||
|--------|---------|-------------|
|
||||
| `sdk_relay` | `int-dev` | Relay des transactions |
|
||||
| `sdk_signer` | `int-dev` | Service de signature |
|
||||
| `sdk_storage` | `int-dev` | Stockage temporaire |
|
||||
| `ihm_client` | `int-dev` | Interface de gestion |
|
||||
| `lecoffre-front` | `int-dev` | Frontend LeCoffre |
|
||||
| `lecoffre-back-mini` | `int-dev` | Backend API |
|
||||
|
||||
## 📚 Documentation Complète
|
||||
|
||||
### Documentation IA (Recommandée)
|
||||
- [`IA_agents/context.md`](IA_agents/context.md) - Contexte et objectifs
|
||||
- [`IA_agents/flux.md`](IA_agents/flux.md) - Architecture et flux
|
||||
- [`IA_agents/deploy.md`](IA_agents/deploy.md) - Procédure de déploiement
|
||||
|
||||
### Documentation Technique
|
||||
- [`docs/REX.md`](docs/REX.md) - Rapport d'expérience de déploiement
|
||||
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) - Architecture détaillée
|
||||
- [`docs/CONFIGURATION_SERVICES.md`](docs/CONFIGURATION_SERVICES.md) - Configuration des services
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
### Problèmes Courants
|
||||
|
||||
1. **Service non accessible** : Vérifier `docker compose ps`
|
||||
2. **Erreurs de connexion** : Vérifier les logs avec `docker compose logs`
|
||||
3. **Configuration** : Exécuter `./scripts/sync-configs.sh`
|
||||
|
||||
### Logs d'Erreur
|
||||
|
||||
```bash
|
||||
# Logs d'erreur récents
|
||||
docker compose logs --tail=100 | grep -i error
|
||||
|
||||
# Logs d'un service spécifique
|
||||
docker compose logs sdk_relay | grep -i error
|
||||
```
|
||||
|
||||
## 🔄 Mise à Jour
|
||||
|
||||
Le système se met à jour automatiquement via Watchtower. Pour forcer une mise à jour :
|
||||
|
||||
```bash
|
||||
# Mettre à jour toutes les images
|
||||
docker compose pull
|
||||
|
||||
# Redémarrer les services
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
||||
|
||||
---
|
||||
|
||||
**💡 Conseil** : Commencez toujours par lire [`IA_agents/context.md`](IA_agents/context.md) pour comprendre le contexte du projet !
|
||||
27
base-image/Dockerfile
Normal file
27
base-image/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
||||
# Image Debian ultra-légère avec possibilité d'ajouter des packages
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# Installation des outils de base essentiels
|
||||
RUN apt-get update && apt-get upgrade -y && \
|
||||
apt-get install -y --fix-missing \
|
||||
ca-certificates \
|
||||
curl \
|
||||
jq \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Création d'un utilisateur non-root
|
||||
RUN useradd -m -u 1000 appuser && \
|
||||
mkdir -p /app && chown -R appuser:appuser /app
|
||||
|
||||
WORKDIR /app
|
||||
USER appuser
|
||||
|
||||
# Script d'installation de packages additionnels (optionnel)
|
||||
COPY --chown=appuser:appuser install-packages.sh /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/install-packages.sh
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
|
||||
16
base-image/install-packages.sh
Normal file
16
base-image/install-packages.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
# Script pour installer des packages additionnels au runtime si nécessaire
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: install-packages.sh <package1> [package2] ..."
|
||||
echo "Example: install-packages.sh vim nano htop"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing packages: $@"
|
||||
sudo apt-get update && \
|
||||
sudo apt-get install -y --fix-missing "$@" && \
|
||||
sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
echo "Packages installed successfully!"
|
||||
|
||||
@ -1,55 +1,14 @@
|
||||
# bitcoin/Dockerfile
|
||||
FROM debian:bullseye-slim as builder
|
||||
# Dockerfile personnalisé pour Bitcoin avec jq
|
||||
FROM git.4nkweb.com/4nk/bitcoin:latest
|
||||
|
||||
# Installation des dépendances
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
gnupg \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Version de Bitcoin Core
|
||||
ENV VERSION=24.1
|
||||
|
||||
# Téléchargement et vérification de Bitcoin Core
|
||||
WORKDIR /tmp
|
||||
RUN curl -O https://bitcoincore.org/bin/bitcoin-core-${VERSION}/bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz && \
|
||||
curl -O https://bitcoincore.org/bin/bitcoin-core-${VERSION}/SHA256SUMS.asc && \
|
||||
curl -O https://bitcoincore.org/bin/bitcoin-core-${VERSION}/SHA256SUMS
|
||||
|
||||
# Extraction de Bitcoin Core
|
||||
RUN tar -xzf bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz
|
||||
|
||||
# Image finale
|
||||
FROM debian:bullseye-slim
|
||||
|
||||
# On redéfinit la version dans l'image finale
|
||||
ENV VERSION=24.1
|
||||
|
||||
# Installation des dépendances nécessaires
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libatomic1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Créer l'utilisateur et le groupe bitcoin
|
||||
RUN groupadd -g 1000 bitcoin && \
|
||||
useradd -m -d /home/bitcoin -g bitcoin bitcoin
|
||||
|
||||
# Copie des binaires depuis le builder
|
||||
COPY --from=builder /tmp/bitcoin-${VERSION}/bin/bitcoind /usr/local/bin/
|
||||
COPY --from=builder /tmp/bitcoin-${VERSION}/bin/bitcoin-cli /usr/local/bin/
|
||||
|
||||
# Configuration
|
||||
RUN mkdir -p /home/bitcoin/.bitcoin/wallets /home/bitcoin/.bitcoin/signet && \
|
||||
chown -R bitcoin:bitcoin /home/bitcoin/.bitcoin
|
||||
COPY bitcoin.conf /home/bitcoin/.bitcoin/bitcoin.conf
|
||||
RUN chown bitcoin:bitcoin /home/bitcoin/.bitcoin/bitcoin.conf
|
||||
|
||||
VOLUME ["/home/bitcoin/.bitcoin"]
|
||||
|
||||
# Exposition des ports (signet)
|
||||
EXPOSE 38332 38333 29000 18443
|
||||
# Installer jq et autres outils utiles pour les healthchecks
|
||||
USER root
|
||||
RUN apk update && apk add --no-cache \
|
||||
jq bc \
|
||||
net-tools iputils \
|
||||
bind-tools netcat-openbsd \
|
||||
telnet procps && \
|
||||
rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
|
||||
|
||||
# Revenir à l'utilisateur bitcoin
|
||||
USER bitcoin
|
||||
WORKDIR /home/bitcoin
|
||||
ENTRYPOINT ["bitcoind", "-conf=/home/bitcoin/.bitcoin/bitcoin.conf", "-signet", "-printtoconsole"]
|
||||
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
# Configuration globale
|
||||
datadir=/home/bitcoin/.bitcoin
|
||||
server=1
|
||||
txindex=1
|
||||
debug=1
|
||||
loglevel=debug
|
||||
logthreadnames=1
|
||||
signet=1
|
||||
server=1
|
||||
datadir=/home/bitcoin/.bitcoin
|
||||
|
||||
[signet]
|
||||
daemon=0
|
||||
txindex=1
|
||||
upnp=1
|
||||
#debug=1
|
||||
#loglevel=debug
|
||||
logthreadnames=1
|
||||
onion=tor:9050
|
||||
listenonion=1
|
||||
onlynet=onion
|
||||
|
||||
# Paramètres RPC
|
||||
rpcauth=bitcoin:c8ea921c7357bd6a5a8a7c43a12350a7$955e25b17672987b17c5a12f12cd8b9c1d38f0f86201c8cd47fc431f2e1c7956
|
||||
@ -18,13 +23,12 @@ rpcdoccheck=1
|
||||
|
||||
# Paramètres ZMQ
|
||||
zmqpubhashblock=tcp://0.0.0.0:29000
|
||||
zmqpubrawtx=tcp://0.0.0.0:29000
|
||||
zmqpubrawtx=tcp://0.0.0.0:29001
|
||||
|
||||
[signet]
|
||||
listen=1
|
||||
bind=0.0.0.0:38333
|
||||
rpcbind=0.0.0.0:18443
|
||||
rpcport=18443
|
||||
rpcbind=0.0.0.0:38332
|
||||
rpcport=38332
|
||||
fallbackfee=0.0001
|
||||
blockfilterindex=1
|
||||
datacarriersize=205
|
||||
@ -33,8 +37,9 @@ dustrelayfee=0.00000001
|
||||
minrelaytxfee=0.00000001
|
||||
prune=0
|
||||
signetchallenge=0020341c43803863c252df326e73574a27d7e19322992061017b0dc893e2eab90821
|
||||
walletdir=/home/bitcoin/.bitcoin/wallets
|
||||
wallet=mining
|
||||
wallet=watchonly
|
||||
maxtxfee=1
|
||||
addnode=tlv2yqamflv22vfdzy2hha2nwmt6zrwrhjjzz4lx7qyq7lyc6wfhabyd.onion
|
||||
addnode=tlv2yqamflv22vfdzy2hha2nwmt6zrwrhjjzz4lx7qyq7lyc6wfhabyd.onion
|
||||
addnode=6xi33lwwslsx3yi3f7c56wnqtdx4v73vj2up3prrwebpwbz6qisnqbyd.onion
|
||||
addnode=id7e3r3d2epen2v65jebjhmx77aimu7oyhcg45zadafypr4crqsytfid.onion
|
||||
@ -1,31 +1,10 @@
|
||||
# blindbit-oracle/Dockerfile
|
||||
FROM golang:1.22 as builder
|
||||
# Dockerfile personnalisé pour BlindBit avec pgrep et wget
|
||||
FROM git.4nkweb.com/4nk/blindbit-oracle:dev
|
||||
|
||||
WORKDIR /app
|
||||
# Installer pgrep, wget et autres outils utiles pour les healthchecks
|
||||
USER root
|
||||
RUN apt-get update && apt-get install -y procps wget curl && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Cloner le repo blindbit-oracle
|
||||
RUN git clone --branch dev --depth 1 https://github.com/setavenger/blindbit-oracle.git .
|
||||
|
||||
# Compiler le binaire
|
||||
RUN go build -o /go/bin/blindbit-oracle ./src
|
||||
|
||||
# Utiliser debian:bookworm-slim qui contient GLIBC 2.34
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# Installation des dépendances nécessaires
|
||||
RUN apt-get update && apt-get install -y ca-certificates curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copier le binaire depuis le builder
|
||||
COPY --from=builder /go/bin/blindbit-oracle /usr/local/bin/blindbit-oracle
|
||||
|
||||
# Créer le répertoire de données
|
||||
RUN mkdir -p /data
|
||||
|
||||
# Créer le volume pour les données
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Exposer le port par défaut
|
||||
EXPOSE 8000
|
||||
|
||||
# Démarrer blindbit-oracle avec le répertoire de données spécifié
|
||||
ENTRYPOINT ["blindbit-oracle", "-datadir", "/data"]
|
||||
# Revenir à l'utilisateur par défaut
|
||||
USER root
|
||||
|
||||
@ -1,28 +1,18 @@
|
||||
# Configuration pour blindbit-oracle
|
||||
# Configuration Blindbit Oracle
|
||||
host = "0.0.0.0:8000"
|
||||
|
||||
# Définit la chaîne sur laquelle le wallet fonctionne
|
||||
chain = "signet"
|
||||
|
||||
# Point d'accès RPC Bitcoin
|
||||
rpc_endpoint = "http://bitcoin:18443"
|
||||
|
||||
# Chemin vers le fichier cookie RPC Bitcoin
|
||||
rpc_endpoint = "http://bitcoin:38332"
|
||||
cookie_path = "/home/bitcoin/.bitcoin/signet/.cookie"
|
||||
|
||||
# Identifiants RPC Bitcoin (non utilisés avec cookie_path)
|
||||
rpc_user = ""
|
||||
rpc_pass = ""
|
||||
|
||||
# Hauteur de départ pour la synchronisation
|
||||
sync_start_height = 1
|
||||
|
||||
# Paramètres de performance
|
||||
# Performance
|
||||
max_parallel_tweak_computations = 4
|
||||
max_parallel_requests = 4
|
||||
|
||||
# Configuration des index
|
||||
# Index
|
||||
tweaks_only = 0
|
||||
tweaks_full_basic = 1
|
||||
tweaks_full_with_dust_filter = 1
|
||||
tweaks_cut_through_with_dust_filter = 1
|
||||
tweaks_cut_through_with_dust_filter = 1
|
||||
|
||||
96
conf/README.md
Normal file
96
conf/README.md
Normal file
@ -0,0 +1,96 @@
|
||||
# Configuration Centralisée - LeCoffre Node
|
||||
|
||||
Ce dossier contient toutes les configurations centralisées pour les services du projet LeCoffre Node.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
conf/
|
||||
├── bitcoin/ # Configuration Bitcoin Signet
|
||||
│ └── bitcoin.conf
|
||||
├── relay/ # Configuration SDK Relay
|
||||
│ └── sdk_relay.conf
|
||||
├── nginx/ # Configurations Nginx (déjà existantes)
|
||||
│ └── ...
|
||||
├── ihm_client/ # Configuration IHM Client
|
||||
│ └── nginx.dev.conf
|
||||
├── lecoffre-front/ # Configuration LeCoffre Frontend
|
||||
├── lecoffre-back/ # Configuration LeCoffre Backend
|
||||
└── miner/ # Configuration du mineur
|
||||
```
|
||||
|
||||
## Scripts de Gestion
|
||||
|
||||
Les configurations et le déploiement sont gérés via des scripts centralisés :
|
||||
|
||||
- `scripts/sync-configs.sh` : Synchronise toutes les configurations
|
||||
- `scripts/startup-sequence.sh` : Script principal avec déploiement complet
|
||||
- `scripts/pre-build.sh` : Prépare l'environnement avant build Docker
|
||||
|
||||
## Avantages
|
||||
|
||||
1. **Centralisation** : Toutes les configurations au même endroit
|
||||
2. **Cohérence** : Gestion uniforme des paramètres
|
||||
3. **Maintenance** : Modifications centralisées
|
||||
4. **Versioning** : Suivi des changements de configuration
|
||||
5. **Backup** : Sauvegarde centralisée
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Synchronisation manuelle
|
||||
```bash
|
||||
# Synchroniser tous les projets
|
||||
./scripts/sync-configs.sh
|
||||
|
||||
# Synchroniser un projet spécifique
|
||||
./scripts/sync-configs.sh ihm_client
|
||||
```
|
||||
|
||||
### Déploiement complet
|
||||
```bash
|
||||
# Déployer tous les projets
|
||||
./scripts/startup-sequence.sh deploy
|
||||
|
||||
# Déployer un projet spécifique
|
||||
./scripts/startup-sequence.sh deploy-project ihm_client
|
||||
|
||||
# Déployer avec push des images Docker
|
||||
PUSH_DOCKER_IMAGES=true ./scripts/startup-sequence.sh deploy
|
||||
```
|
||||
|
||||
### Préparation avant build
|
||||
```bash
|
||||
# Préparer l'environnement avant build Docker
|
||||
./scripts/pre-build.sh
|
||||
```
|
||||
|
||||
### Commandes de maintenance
|
||||
```bash
|
||||
# Mettre à jour toutes les dépendances
|
||||
./scripts/startup-sequence.sh update-deps
|
||||
|
||||
# Vérifier les fichiers ignore
|
||||
./scripts/startup-sequence.sh check-ignore
|
||||
|
||||
# Nettoyer les fichiers non suivis
|
||||
./scripts/startup-sequence.sh clean-untracked
|
||||
|
||||
# Compiler tous les projets
|
||||
./scripts/startup-sequence.sh compile-all
|
||||
|
||||
# Exécuter tous les tests
|
||||
./scripts/startup-sequence.sh test-all
|
||||
```
|
||||
|
||||
### Modification d'une configuration
|
||||
1. Éditer le fichier dans `conf/[service]/`
|
||||
2. Synchroniser avec `./scripts/sync-configs.sh [service]`
|
||||
3. Redémarrer le service concerné
|
||||
|
||||
## Services Concernés
|
||||
|
||||
- **Bitcoin Signet** : Configuration du nœud Bitcoin
|
||||
- **SDK Relay** : Configuration du relais WebSocket
|
||||
- **IHM Client** : Configuration Nginx pour l'interface client
|
||||
- **LeCoffre Front/Back** : Configurations des services web
|
||||
- **Mineur** : Configuration du minage Bitcoin
|
||||
45
conf/bitcoin/bitcoin.conf
Normal file
45
conf/bitcoin/bitcoin.conf
Normal file
@ -0,0 +1,45 @@
|
||||
# Configuration globale
|
||||
signet=1
|
||||
server=1
|
||||
datadir=/home/bitcoin/.bitcoin
|
||||
|
||||
[signet]
|
||||
daemon=0
|
||||
txindex=1
|
||||
upnp=1
|
||||
#debug=1
|
||||
#loglevel=debug
|
||||
logthreadnames=1
|
||||
onion=tor:9050
|
||||
listenonion=1
|
||||
onlynet=onion
|
||||
|
||||
# Paramètres RPC
|
||||
rpcauth=bitcoin:c8ea921c7357bd6a5a8a7c43a12350a7$955e25b17672987b17c5a12f12cd8b9c1d38f0f86201c8cd47fc431f2e1c7956
|
||||
rpcallowip=0.0.0.0/0
|
||||
rpcworkqueue=32
|
||||
rpcthreads=4
|
||||
rpcdoccheck=1
|
||||
|
||||
# Paramètres ZMQ
|
||||
zmqpubhashblock=tcp://0.0.0.0:29000
|
||||
zmqpubrawtx=tcp://0.0.0.0:29001
|
||||
|
||||
listen=1
|
||||
bind=0.0.0.0:38333
|
||||
rpcbind=0.0.0.0:38332
|
||||
rpcport=38332
|
||||
fallbackfee=0.0001
|
||||
blockfilterindex=1
|
||||
datacarriersize=205
|
||||
acceptnonstdtxn=1
|
||||
dustrelayfee=0.00000001
|
||||
minrelaytxfee=0.00000001
|
||||
prune=0
|
||||
signetchallenge=0020341c43803863c252df326e73574a27d7e19322992061017b0dc893e2eab90821
|
||||
wallet=mining
|
||||
wallet=watchonly
|
||||
maxtxfee=1
|
||||
addnode=tlv2yqamflv22vfdzy2hha2nwmt6zrwrhjjzz4lx7qyq7lyc6wfhabyd.onion
|
||||
addnode=6xi33lwwslsx3yi3f7c56wnqtdx4v73vj2up3prrwebpwbz6qisnqbyd.onion
|
||||
addnode=id7e3r3d2epen2v65jebjhmx77aimu7oyhcg45zadafypr4crqsytfid.onion
|
||||
399
conf/grafana/dashboards/bitcoin-miner-detailed.json
Normal file
399
conf/grafana/dashboards/bitcoin-miner-detailed.json
Normal file
@ -0,0 +1,399 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"signet_miner\"} |= \"Block mined\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Blocs Minés par Minute",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"signet_miner\"} |= \"Hashrate\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Hashrate du Mineur",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"signet_miner\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs du Mineur (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 16,
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "right"
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (level) (count_over_time({container=\"signet_miner\"} | json | level != \"\" [1h]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Distribution des Niveaux de Log",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{container=\"signet_miner\"} |= \"Block mined\" | json | line_format \"{{.timestamp}} - Bloc {{.height}} miné - Hash: {{.hash}}\"",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Historique des Blocs Minés",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"bitcoin",
|
||||
"miner",
|
||||
"signet"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Bitcoin Miner - Détails",
|
||||
"uid": "bitcoin-miner-detailed",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
160
conf/grafana/dashboards/bitcoin-miner.json
Normal file
160
conf/grafana/dashboards/bitcoin-miner.json
Normal file
@ -0,0 +1,160 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"showTime": false,
|
||||
"showLabels": false,
|
||||
"showCommonLabels": false,
|
||||
"wrapLogMessage": false,
|
||||
"prettifyLogMessage": false,
|
||||
"enableLogDetails": true,
|
||||
"dedupStrategy": "none",
|
||||
"sortOrder": "Descending"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{job=\"bitcoin\"} |= \"block\" | logfmt",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Bitcoin - Nouveaux Blocs",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"showTime": false,
|
||||
"showLabels": false,
|
||||
"showCommonLabels": false,
|
||||
"wrapLogMessage": false,
|
||||
"prettifyLogMessage": false,
|
||||
"enableLogDetails": true,
|
||||
"dedupStrategy": "none",
|
||||
"sortOrder": "Descending"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{job=\"miner\"} |= \"mined\" | logfmt",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Miner - Blocs Minés",
|
||||
"type": "logs"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"showTime": false,
|
||||
"showLabels": false,
|
||||
"showCommonLabels": false,
|
||||
"wrapLogMessage": false,
|
||||
"prettifyLogMessage": false,
|
||||
"enableLogDetails": true,
|
||||
"dedupStrategy": "none",
|
||||
"sortOrder": "Descending"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{job=~\"bitcoin|miner|blindbit\"} |= \"error\" | logfmt",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Bitcoin/Miner/Blindbit - Erreurs",
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"refresh": "30s",
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": ["bitcoin", "miner", "blockchain"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Bitcoin & Miner Monitoring",
|
||||
"uid": "bitcoin-miner",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
532
conf/grafana/dashboards/bitcoin-services.json
Normal file
532
conf/grafana/dashboards/bitcoin-services.json
Normal file
@ -0,0 +1,532 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"bitcoin-signet\"} |= \"UpdateTip\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Mises à Jour de la Chaîne Bitcoin",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"blindbit-oracle\"} |= \"tweak\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Détection de Tweak (BlindBit)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"bitcoin-signet\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Bitcoin (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"blindbit-oracle\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs BlindBit (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"bitcoin-signet\"} |= \"New block\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Nouveaux Blocs (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"blindbit-oracle\"} |= \"Silent payment\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Silent Payments (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 12
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{container=~\"bitcoin-signet|blindbit-oracle\"} |= \"ERROR\" | line_format \"{{.timestamp}} - {{.container}} - {{.message}}\"",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Bitcoin Services",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"bitcoin",
|
||||
"signet",
|
||||
"blindbit",
|
||||
"oracle"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Bitcoin Services - Monitoring",
|
||||
"uid": "bitcoin-services",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
532
conf/grafana/dashboards/frontend-services.json
Normal file
532
conf/grafana/dashboards/frontend-services.json
Normal file
@ -0,0 +1,532 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=~\"lecoffre-front|ihm_client\"} |= \"GET\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requêtes HTTP par Frontend",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"ihm_client\"} |= \"vite\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Activité Vite (IHM Client)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"lecoffre-front\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs LeCoffre Front (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"ihm_client\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs IHM Client (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(count_over_time({container=~\"lecoffre-front|ihm_client\"} [1h]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Total Logs Frontend (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"ihm_client\"} |= \"Pre-transform error\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Vite (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 12
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{container=~\"lecoffre-front|ihm_client\"} |= \"ERROR\" | line_format \"{{.timestamp}} - {{.container}} - {{.message}}\"",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Récentes Frontend",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"frontend",
|
||||
"lecoffre",
|
||||
"ihm",
|
||||
"client"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Frontend Services - Monitoring",
|
||||
"uid": "frontend-services",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
591
conf/grafana/dashboards/lecoffre-backend.json
Normal file
591
conf/grafana/dashboards/lecoffre-backend.json
Normal file
@ -0,0 +1,591 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"lecoffre-back\"} | json | statusCode != \"\" [5m])) by (statusCode)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requêtes HTTP par Status Code",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"lecoffre-back\"} | json | url != \"\" [5m])) by (url)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Endpoints les Plus Utilisés",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"lecoffre-back\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "avg({container=\"lecoffre-back\"} | json | duration != \"\" | unwrap duration [5m])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Temps de Réponse Moyen (ms)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"lecoffre-back\"} | json | method != \"\" [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requêtes/seconde",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"lecoffre-back\"} | json | statusCode = \"200\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Succès (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 12
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "right"
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (method) (count_over_time({container=\"lecoffre-back\"} | json | method != \"\" [1h]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Distribution des Méthodes HTTP",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 12
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{container=\"lecoffre-back\"} |= \"ERROR\" | json | line_format \"{{.timestamp}} - {{.method}} {{.url}} - {{.error}}\"",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Récentes",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"lecoffre",
|
||||
"backend",
|
||||
"api"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "LeCoffre Backend - Monitoring",
|
||||
"uid": "lecoffre-backend",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
264
conf/grafana/dashboards/lecoffre-overview.json
Normal file
264
conf/grafana/dashboards/lecoffre-overview.json
Normal file
@ -0,0 +1,264 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=~\".*\"} |= \"error\" [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs par Service (5 dernières minutes)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=~\".*\"} [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Volume de Logs par Service (5 dernières minutes)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 12,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"showTime": false,
|
||||
"showLabels": false,
|
||||
"showCommonLabels": false,
|
||||
"wrapLogMessage": false,
|
||||
"prettifyLogMessage": false,
|
||||
"enableLogDetails": true,
|
||||
"dedupStrategy": "none",
|
||||
"sortOrder": "Descending"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{job=~\"bitcoin|blindbit|sdk_relay|sdk_signer|sdk_storage|lecoffre-back|lecoffre-front|ihm_client|miner\"} |= \"error\" | logfmt",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Logs d'Erreur - Tous Services",
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"refresh": "30s",
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": ["lecoffre", "monitoring"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "LeCoffre Node - Vue d'ensemble",
|
||||
"uid": "lecoffre-overview",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
619
conf/grafana/dashboards/sdk-services.json
Normal file
619
conf/grafana/dashboards/sdk-services.json
Normal file
@ -0,0 +1,619 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=~\"sdk_.*\"} |= \"message\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Messages par Service SDK",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 8,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"sdk_relay\"} |= \"transaction\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Transactions Relay",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 8,
|
||||
"x": 16,
|
||||
"y": 0
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(rate({container=\"sdk_signer\"} |= \"signature\" [5m])) by (container)",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Signatures Signer",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"sdk_relay\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Relay (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"sdk_signer\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Signer (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count_over_time({container=\"sdk_storage\"} |= \"ERROR\" [1h])",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Storage (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 8
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(count_over_time({container=~\"sdk_.*\"} [1h]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Total Logs SDK (1h)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 12
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "10.0.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{container=~\"sdk_.*\"} |= \"ERROR\" | line_format \"{{.timestamp}} - {{.container}} - {{.message}}\"",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Erreurs Récentes SDK",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"sdk",
|
||||
"relay",
|
||||
"signer",
|
||||
"storage"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "SDK Services - Monitoring",
|
||||
"uid": "sdk-services",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
442
conf/grafana/dashboards/services-overview.json
Normal file
442
conf/grafana/dashboards/services-overview.json
Normal file
@ -0,0 +1,442 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=\"lecoffre-back\"} [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "LeCoffre Backend - Volume Logs",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=\"lecoffre-front\"} [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "LeCoffre Frontend - Volume Logs",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=\"ihm_client\"} [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "IHM Client - Volume Logs",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"vis": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "never",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom"
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (service) (count_over_time({job=\"sdk_relay\"} [5m]))",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "SDK Relay - Volume Logs",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 12,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"showTime": false,
|
||||
"showLabels": false,
|
||||
"showCommonLabels": false,
|
||||
"wrapLogMessage": false,
|
||||
"prettifyLogMessage": false,
|
||||
"enableLogDetails": true,
|
||||
"dedupStrategy": "none",
|
||||
"sortOrder": "Descending"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "loki",
|
||||
"uid": "loki"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "{job=~\"lecoffre-back|lecoffre-front|ihm_client|sdk_relay|sdk_signer|sdk_storage\"} |= \"error\" | logfmt",
|
||||
"queryType": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Logs d'Erreur - Services Applications",
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"refresh": "30s",
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": ["services", "applications"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Services Applications - Monitoring",
|
||||
"uid": "services-overview",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
57
conf/grafana/grafana.ini
Normal file
57
conf/grafana/grafana.ini
Normal file
@ -0,0 +1,57 @@
|
||||
# Configuration Grafana avancée pour LeCoffre Node
|
||||
|
||||
[server]
|
||||
# URL publique de Grafana
|
||||
root_url = https://dev4.4nkweb.com/grafana/
|
||||
|
||||
# Configuration de sécurité
|
||||
enable_gzip = true
|
||||
cert_file =
|
||||
cert_key =
|
||||
enforce_domain = false
|
||||
|
||||
[security]
|
||||
# Configuration de sécurité
|
||||
admin_user = admin
|
||||
admin_password = admin123
|
||||
secret_key = lecoffre_grafana_secret_key_2025
|
||||
|
||||
# Configuration des sessions
|
||||
cookie_secure = true
|
||||
cookie_samesite = strict
|
||||
|
||||
[users]
|
||||
# Configuration des utilisateurs
|
||||
allow_sign_up = false
|
||||
allow_org_create = false
|
||||
auto_assign_org = true
|
||||
auto_assign_org_id = 1
|
||||
auto_assign_org_role = Viewer
|
||||
|
||||
[auth.anonymous]
|
||||
# Accès anonyme désactivé pour la sécurité
|
||||
enabled = false
|
||||
|
||||
[dashboards]
|
||||
# Configuration des dashboards
|
||||
default_home_dashboard_path = /var/lib/grafana/dashboards/lecoffre-overview.json
|
||||
|
||||
[unified_alerting]
|
||||
# Configuration des alertes unifiées
|
||||
enabled = true
|
||||
|
||||
[log]
|
||||
# Configuration des logs Grafana
|
||||
mode = console
|
||||
level = info
|
||||
format = json
|
||||
|
||||
[metrics]
|
||||
# Métriques Prometheus
|
||||
enabled = true
|
||||
basic_auth_username =
|
||||
basic_auth_password =
|
||||
|
||||
[feature_toggles]
|
||||
# Fonctionnalités activées
|
||||
enable = traceqlEditor
|
||||
12
conf/grafana/provisioning/dashboards/dashboards.yml
Normal file
12
conf/grafana/provisioning/dashboards/dashboards.yml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: 'LeCoffre Node Dashboards'
|
||||
orgId: 1
|
||||
folder: 'LeCoffre Node'
|
||||
type: file
|
||||
disableDeletion: false
|
||||
updateIntervalSeconds: 10
|
||||
allowUiUpdates: true
|
||||
options:
|
||||
path: /var/lib/grafana/dashboards
|
||||
12
conf/grafana/provisioning/datasources/loki.yml
Normal file
12
conf/grafana/provisioning/datasources/loki.yml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
url: http://loki:3100
|
||||
uid: loki
|
||||
isDefault: true
|
||||
editable: true
|
||||
jsonData:
|
||||
maxLines: 1000
|
||||
10
conf/grafana/provisioning/datasources/loki.yml.bak
Normal file
10
conf/grafana/provisioning/datasources/loki.yml.bak
Normal file
@ -0,0 +1,10 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
url: http://loki:3100
|
||||
uid: loki
|
||||
isDefault: true
|
||||
editable: true
|
||||
12
conf/grafana/provisioning/datasources/loki.yml.temp
Normal file
12
conf/grafana/provisioning/datasources/loki.yml.temp
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
url: http://loki:3100
|
||||
uid: loki
|
||||
isDefault: true
|
||||
editable: true
|
||||
jsonData:
|
||||
maxLines: 1000
|
||||
48
conf/ihm_client/nginx.dev.conf
Normal file
48
conf/ihm_client/nginx.dev.conf
Normal file
@ -0,0 +1,48 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Redirection des requêtes HTTP vers Vite
|
||||
location / {
|
||||
proxy_pass http://localhost:3003;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /ws/ {
|
||||
proxy_pass http://dev4.4nkweb.com:8090;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
location /storage/ {
|
||||
rewrite ^/storage(/.*)$ $1 break;
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8091;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS headers
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;
|
||||
add_header Access-Control-Allow-Headers "Authorization,Content-Type,Accept,X-Requested-With" always;
|
||||
}
|
||||
}
|
||||
13
conf/logrotate/bitcoin.conf
Normal file
13
conf/logrotate/bitcoin.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/bitcoin/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart bitcoin 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/blindbit.conf
Normal file
13
conf/logrotate/blindbit.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/blindbit/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart blindbit 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/ihm_client.conf
Normal file
13
conf/logrotate/ihm_client.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/ihm_client/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart ihm_client 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/lecoffre-back.conf
Normal file
13
conf/logrotate/lecoffre-back.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/lecoffre-back/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart lecoffre-back 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/lecoffre-front.conf
Normal file
13
conf/logrotate/lecoffre-front.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/lecoffre-front/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart lecoffre-front 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/miner.conf
Normal file
13
conf/logrotate/miner.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/miner/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart miner 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/nginx.conf
Normal file
13
conf/logrotate/nginx.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/nginx/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart nginx 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/sdk_relay.conf
Normal file
13
conf/logrotate/sdk_relay.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/sdk_relay/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart sdk_relay 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/sdk_signer.conf
Normal file
13
conf/logrotate/sdk_signer.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/sdk_signer/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart sdk_signer 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/sdk_storage.conf
Normal file
13
conf/logrotate/sdk_storage.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/sdk_storage/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart sdk_storage 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
13
conf/logrotate/tor.conf
Normal file
13
conf/logrotate/tor.conf
Normal file
@ -0,0 +1,13 @@
|
||||
logs/tor/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Redémarrer le service si nécessaire
|
||||
docker restart tor 2>/dev/null || true
|
||||
endscript
|
||||
}
|
||||
76
conf/loki/loki-config.yaml
Normal file
76
conf/loki/loki-config.yaml
Normal file
@ -0,0 +1,76 @@
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
grpc_listen_port: 9096
|
||||
http_listen_address: 0.0.0.0
|
||||
grpc_listen_address: 0.0.0.0
|
||||
|
||||
common:
|
||||
instance_addr: 0.0.0.0
|
||||
path_prefix: /loki
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-10-24
|
||||
store: tsdb
|
||||
object_store: filesystem
|
||||
schema: v13
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
ruler:
|
||||
alertmanager_url: http://localhost:9093
|
||||
|
||||
# Configuration de l'ingester - SEULEMENT le paramètre crucial
|
||||
ingester:
|
||||
lifecycler:
|
||||
min_ready_duration: 5s # Réduit le délai de 15s à 5s
|
||||
|
||||
# Configuration des limites
|
||||
limits_config:
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
max_cache_freshness_per_query: 10m
|
||||
split_queries_by_interval: 15m
|
||||
max_query_parallelism: 32
|
||||
max_streams_per_user: 0
|
||||
max_line_size: 256000
|
||||
ingestion_rate_mb: 16
|
||||
ingestion_burst_size_mb: 32
|
||||
per_stream_rate_limit: 3MB
|
||||
per_stream_rate_limit_burst: 15MB
|
||||
max_entries_limit_per_query: 5000
|
||||
max_query_series: 500
|
||||
max_query_length: 721h
|
||||
cardinality_limit: 100000
|
||||
max_streams_matchers_per_query: 1000
|
||||
max_concurrent_tail_requests: 10
|
||||
|
||||
# Configuration du storage
|
||||
storage_config:
|
||||
tsdb_shipper:
|
||||
active_index_directory: /loki/tsdb-index
|
||||
cache_location: /loki/tsdb-cache
|
||||
filesystem:
|
||||
directory: /loki/chunks
|
||||
|
||||
# Configuration du compactor
|
||||
compactor:
|
||||
working_directory: /loki/compactor
|
||||
compaction_interval: 10m
|
||||
retention_enabled: false
|
||||
delete_request_store: filesystem
|
||||
|
||||
# Analytics désactivés
|
||||
analytics:
|
||||
reporting_enabled: false
|
||||
30
conf/monitoring.conf
Normal file
30
conf/monitoring.conf
Normal file
@ -0,0 +1,30 @@
|
||||
# Configuration centralisée du monitoring LeCoffre Node
|
||||
# Généré automatiquement le $(date)
|
||||
|
||||
[monitoring]
|
||||
# Services de monitoring
|
||||
grafana_port=3000
|
||||
loki_port=3100
|
||||
promtail_enabled=true
|
||||
|
||||
[grafana]
|
||||
admin_user=admin
|
||||
admin_password=admin123
|
||||
root_url=https://dev4.4nkweb.com/grafana/
|
||||
dashboard_home=lecoffre-overview
|
||||
|
||||
[logs]
|
||||
# Configuration des logs
|
||||
log_retention_days=30
|
||||
log_rotation=daily
|
||||
log_compression=true
|
||||
|
||||
[services]
|
||||
# Services surveillés
|
||||
services=bitcoin,blindbit,sdk_relay,sdk_signer,sdk_storage,lecoffre-back,lecoffre-front,ihm_client,tor,miner
|
||||
|
||||
[alerts]
|
||||
# Configuration des alertes
|
||||
error_threshold=10
|
||||
warning_threshold=5
|
||||
alert_email=
|
||||
BIN
conf/nginx/assets/favicon.ico
Normal file
BIN
conf/nginx/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 590 B |
15
conf/nginx/dev4.4nkweb.com-http.conf
Normal file
15
conf/nginx/dev4.4nkweb.com-http.conf
Normal file
@ -0,0 +1,15 @@
|
||||
# HTTP server for ACME and redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name dev4.4nkweb.com;
|
||||
|
||||
# ACME HTTP-01 challenges
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/letsencrypt;
|
||||
}
|
||||
|
||||
# Redirection vers HTTPS pour toutes les autres requêtes
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
229
conf/nginx/dev4.4nkweb.com-https.conf
Normal file
229
conf/nginx/dev4.4nkweb.com-https.conf
Normal file
@ -0,0 +1,229 @@
|
||||
# Configuration HTTPS pour dev4.4nkweb.com
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name dev4.4nkweb.com;
|
||||
|
||||
# Certificats SSL
|
||||
ssl_certificate /etc/letsencrypt/live/dev4.4nkweb.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/dev4.4nkweb.com/privkey.pem;
|
||||
|
||||
# Configuration SSL
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Headers de sécurité
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
add_header X-Frame-Options DENY always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Grafana - Interface de monitoring (DOIT être avant location /)
|
||||
location /grafana/ {
|
||||
proxy_pass http://localhost:3005/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Configuration spécifique pour Grafana
|
||||
proxy_set_header X-Grafana-Org-Id 1;
|
||||
|
||||
# Support des WebSockets pour les live updates
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# Loki API - API de logs (DOIT être avant location /)
|
||||
location /loki/ {
|
||||
proxy_pass http://localhost:3100/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour les requêtes depuis Grafana
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# Page de statut des services (DOIT être avant location /)
|
||||
location /status {
|
||||
# Redirection vers /status/
|
||||
return 301 /status/;
|
||||
}
|
||||
|
||||
location /status/ {
|
||||
# Serveur statique pour la page HTML
|
||||
alias /var/www/lecoffre/status/;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /status/index.html;
|
||||
|
||||
# Headers de sécurité
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Cache pour les assets statiques
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# API de statut des services (DOIT être avant location /)
|
||||
location /status/api {
|
||||
proxy_pass http://localhost:3006/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour les requêtes AJAX
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 10s;
|
||||
proxy_read_timeout 10s;
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# API backend - route /back/ vers /api/ du backend
|
||||
location ~* ^/back/(.*)$ {
|
||||
proxy_pass http://localhost:8080/api/$1;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# API direct - route /api/ vers le backend
|
||||
# Autorisations CORS dynamiques pour origines connues
|
||||
set $cors_origin "";
|
||||
if ($http_origin ~* ^(http://local\.4nkweb\.com:3000|https://dev4\.4nkweb\.com)$) {
|
||||
set $cors_origin $http_origin;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
# CORS pour développement local Next.js
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
proxy_hide_header Access-Control-Allow-Headers;
|
||||
proxy_hide_header Access-Control-Allow-Methods;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
return 204;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
|
||||
proxy_pass http://localhost:8080/api/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# WebSocket relay (sdk_relay)
|
||||
location /ws/ {
|
||||
proxy_pass http://localhost:8090/;
|
||||
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
|
||||
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
|
||||
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
|
||||
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# API de transfert de fonds
|
||||
location /api/v1/funds/ {
|
||||
proxy_pass http://localhost:8080/api/v1/funds/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# favicon
|
||||
location = /favicon.ico {
|
||||
root /home/debian/lecoffre_node/conf/nginx/assets;
|
||||
try_files /favicon.ico =404;
|
||||
}
|
||||
|
||||
# blindbit
|
||||
location /blindbit/ {
|
||||
proxy_pass http://localhost:8000/;
|
||||
include /etc/nginx/proxy_params;
|
||||
}
|
||||
|
||||
# signer (sdk_signer) avec support WebSocket
|
||||
location /signer/ {
|
||||
proxy_pass http://localhost:3001/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# lecoffre-front - Application LeCoffre
|
||||
location /lecoffre {
|
||||
proxy_pass http://localhost:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
}
|
||||
|
||||
# ihm_client (root) - DOIT être en dernier
|
||||
location / {
|
||||
proxy_pass http://localhost:3003;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
268
conf/nginx/dev4.4nkweb.com.conf
Normal file
268
conf/nginx/dev4.4nkweb.com.conf
Normal file
@ -0,0 +1,268 @@
|
||||
# HTTP server for ACME and redirect to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name dev4.4nkweb.com;
|
||||
|
||||
# ACME HTTP-01 challenges
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/letsencrypt;
|
||||
}
|
||||
|
||||
# Redirection vers HTTPS pour toutes les autres requêtes
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# API backend - route /back/ vers /api/ du backend
|
||||
location ~* ^/back/(.*)$ {
|
||||
proxy_pass http://localhost:8080/api/$1;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# API direct - route /api/ vers le backend
|
||||
# Autorisations CORS dynamiques pour origines connues
|
||||
set $cors_origin "";
|
||||
if ($http_origin ~* ^(http://local\.4nkweb\.com:3000|https://dev4\.4nkweb\.com)$) {
|
||||
set $cors_origin $http_origin;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
# CORS pour développement local Next.js
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
proxy_hide_header Access-Control-Allow-Headers;
|
||||
proxy_hide_header Access-Control-Allow-Methods;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
return 204;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
|
||||
proxy_pass http://localhost:8080/api/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# Compat: certains clients appellent /apiv1 -> réécriture vers /api/v1
|
||||
location ~* ^/apiv1/(.*)$ {
|
||||
# CORS pour compatibilité
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
proxy_hide_header Access-Control-Allow-Headers;
|
||||
proxy_hide_header Access-Control-Allow-Methods;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
return 204;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
|
||||
proxy_pass http://localhost:8080/api/v1/$1;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# WebSocket relay (sdk_relay)
|
||||
location /ws/ {
|
||||
proxy_pass http://localhost:8090/;
|
||||
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
|
||||
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
|
||||
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
|
||||
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# API de transfert de fonds
|
||||
location /api/v1/funds/ {
|
||||
proxy_pass http://localhost:8080/api/v1/funds/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# Grafana - Interface de monitoring (DOIT être avant location /)
|
||||
location /grafana/ {
|
||||
proxy_pass http://localhost:3005/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Configuration spécifique pour Grafana
|
||||
proxy_set_header X-Grafana-Org-Id 1;
|
||||
|
||||
# Support des WebSockets pour les live updates
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# Loki API - API de logs (DOIT être avant location /)
|
||||
location /loki/ {
|
||||
proxy_pass http://localhost:3100/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour les requêtes depuis Grafana
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# Page de statut des services (DOIT être avant location /)
|
||||
location /status {
|
||||
# Redirection vers /status/
|
||||
return 301 /status/;
|
||||
}
|
||||
|
||||
location /status/ {
|
||||
# Serveur statique pour la page HTML
|
||||
alias /var/www/lecoffre/status/;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /status/index.html;
|
||||
|
||||
# Headers de sécurité
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Cache pour les assets statiques
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# API de statut des services (DOIT être avant location /)
|
||||
location /status/api {
|
||||
proxy_pass http://localhost:3006/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour les requêtes AJAX
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_send_timeout 10s;
|
||||
proxy_read_timeout 10s;
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# ihm_client (root) - DOIT être en dernier
|
||||
location / {
|
||||
proxy_pass http://localhost:3003;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# favicon
|
||||
location = /favicon.ico {
|
||||
root /home/debian/lecoffre_node/conf/nginx/assets;
|
||||
try_files /favicon.ico =404;
|
||||
access_log off;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
# lecoffre frontend
|
||||
location = /lecoffre {
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
}
|
||||
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# Next.js assets
|
||||
location /_next/ {
|
||||
proxy_pass http://127.0.0.2:3004/_next/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
}
|
||||
|
||||
# blindbit
|
||||
location /blindbit/ {
|
||||
proxy_pass http://localhost:8000/;
|
||||
include /etc/nginx/proxy_params;
|
||||
}
|
||||
|
||||
# signer (sdk_signer) avec support WebSocket
|
||||
location /signer/ {
|
||||
proxy_pass http://localhost:3001/;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
}
|
||||
49
conf/nginx/grafana.conf
Normal file
49
conf/nginx/grafana.conf
Normal file
@ -0,0 +1,49 @@
|
||||
# Configuration Nginx pour Grafana
|
||||
server {
|
||||
listen 80;
|
||||
server_name dev4.4nkweb.com;
|
||||
|
||||
# Proxy pour Grafana
|
||||
location /grafana/ {
|
||||
proxy_pass http://127.0.0.1:3005/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Configuration spécifique pour Grafana
|
||||
proxy_set_header X-Grafana-Org-Id 1;
|
||||
|
||||
# Support des WebSockets pour les live updates
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# Buffer settings
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# Proxy pour Loki (API)
|
||||
location /loki/ {
|
||||
proxy_pass http://127.0.0.1:3100/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour les requêtes depuis Grafana
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
conf/nginx/local.4nkweb.com-3000.conf
Normal file
64
conf/nginx/local.4nkweb.com-3000.conf
Normal file
@ -0,0 +1,64 @@
|
||||
server {
|
||||
listen 0.0.0.0:3000;
|
||||
listen [::]:3000;
|
||||
server_name local.4nkweb.com;
|
||||
|
||||
# HTTP pur: pas de HTTPS ni HSTS
|
||||
|
||||
# Favicon
|
||||
location = /favicon.ico {
|
||||
root /home/debian/lecoffre_node/conf/nginx/assets;
|
||||
}
|
||||
|
||||
# Compat: callback ID.not sans basePath (toutes variantes et querystring)
|
||||
location /authorized-client {
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre/authorized-client;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# Entrée sans slash
|
||||
location = /lecoffre {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# BasePath /lecoffre
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# HMR (si utilisé en local)
|
||||
location /lecoffre/_next/webpack-hmr {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre/_next/webpack-hmr;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
# Assets Next.js
|
||||
location ~* ^(/_next/static/|/lecoffre/_next/static/|/.+\.(?:css|js|png|jpg|jpeg|gif|svg|ico|webp|woff2?))$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable" always;
|
||||
proxy_pass http://127.0.0.2:3004$request_uri;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
9
conf/nginx/local.4nkweb.com.conf
Normal file
9
conf/nginx/local.4nkweb.com.conf
Normal file
@ -0,0 +1,9 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name local.4nkweb.com;
|
||||
|
||||
# HTTP only: pas de redirection HTTPS, pas d'HSTS
|
||||
location / {
|
||||
return 302 http://local.4nkweb.com:3000$request_uri;
|
||||
}
|
||||
}
|
||||
55
conf/nginx/local.lecoffreio.4nkweb-3000.conf
Normal file
55
conf/nginx/local.lecoffreio.4nkweb-3000.conf
Normal file
@ -0,0 +1,55 @@
|
||||
server {
|
||||
listen 0.0.0.0:3000;
|
||||
listen [::]:3000;
|
||||
server_name local.lecoffreio.4nkweb;
|
||||
|
||||
# Ne jamais forcer HTTPS ni HSTS sur ce vhost local
|
||||
# Pas de return 301, pas de add_header HSTS
|
||||
|
||||
# Favicon local par défaut
|
||||
location = /favicon.ico {
|
||||
root /home/debian/lecoffre_node/conf/nginx/assets;
|
||||
}
|
||||
|
||||
# Entrée sans slash pour éviter les boucles
|
||||
location = /lecoffre {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# Sous-chemin Next.js (préserve le prefix)
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# HMR en dev (si jamais on l’utilise en local HTTP)
|
||||
location /lecoffre/_next/webpack-hmr {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre/_next/webpack-hmr;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
# Assets Next.js / cache léger côté proxy
|
||||
location ~* ^(/_next/static/|/lecoffre/_next/static/|/.+\.(?:css|js|png|jpg|jpeg|gif|svg|ico|webp|woff2?))$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable" always;
|
||||
proxy_pass http://127.0.0.2:3004$request_uri;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
48
conf/nginx/local.lecoffreio.4nkweb.conf
Normal file
48
conf/nginx/local.lecoffreio.4nkweb.conf
Normal file
@ -0,0 +1,48 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name local.lecoffreio.4nkweb;
|
||||
|
||||
# HTTP pur: pas de redirection vers HTTPS, pas d'HSTS
|
||||
|
||||
location = /favicon.ico {
|
||||
root /home/debian/lecoffre_node/conf/nginx/assets;
|
||||
}
|
||||
|
||||
location = /lecoffre {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://127.0.0.2:3004;
|
||||
include /etc/nginx/proxy_params;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_set_header X-Forwarded-Prefix /lecoffre;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
location /lecoffre/_next/webpack-hmr {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_buffering off;
|
||||
proxy_pass http://127.0.0.2:3004/lecoffre/_next/webpack-hmr;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~* ^(/_next/static/|/lecoffre/_next/static/|/.+\.(?:css|js|png|jpg|jpeg|gif|svg|ico|webp|woff2?))$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable" always;
|
||||
proxy_pass http://127.0.0.2:3004$request_uri;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto http;
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
509
conf/nginx/nginx.conf
Normal file
509
conf/nginx/nginx.conf
Normal file
@ -0,0 +1,509 @@
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
pid /app/nginx.pid;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Configuration de base
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
# MIME types
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /app/logs/nginx/access.log main;
|
||||
error_log /app/logs/nginx/error.log warn;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
|
||||
|
||||
# Upstream servers
|
||||
upstream lecoffre_backend {
|
||||
server localhost:8080;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream lecoffre_frontend {
|
||||
server localhost:3004;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream ihm_client {
|
||||
server localhost:3003;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream grafana {
|
||||
server localhost:3005;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream loki {
|
||||
server localhost:3100;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream status_api {
|
||||
server localhost:3006;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream sdk_relay {
|
||||
server localhost:8090;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream sdk_signer {
|
||||
server localhost:3001;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream blindbit {
|
||||
server localhost:8000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# Serveur principal HTTP (port 80)
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
|
||||
# Redirection automatique vers HTTPS si disponible
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# Serveur HTTPS (port 443)
|
||||
server {
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
server_name _;
|
||||
|
||||
# Certificats SSL (auto-signés pour le développement)
|
||||
ssl_certificate /app/ssl/nginx-selfsigned.crt;
|
||||
ssl_certificate_key /app/ssl/nginx-selfsigned.key;
|
||||
|
||||
# Configuration SSL
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Headers de sécurité
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Page de statut des services
|
||||
location /status/ {
|
||||
alias /var/www/lecoffre/status/;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /status/index.html;
|
||||
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# API de statut des services
|
||||
location /status/api {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://status_api/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# Grafana - Interface de monitoring
|
||||
location /grafana/ {
|
||||
proxy_pass http://grafana/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Grafana-Org-Id 1;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# Loki API - API de logs
|
||||
location /loki/ {
|
||||
limit_req zone=api burst=10 nodelay;
|
||||
proxy_pass http://loki/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS pour Grafana
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# API backend - routes /back/ vers /api/
|
||||
location ~* ^/back/(.*)$ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://lecoffre_backend/api/$1;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# API direct - routes /api/
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
# CORS dynamique
|
||||
set $cors_origin "";
|
||||
if ($http_origin ~* ^(http://localhost:3000|http://local\.4nkweb\.com:3000|https://dev4\.4nkweb\.com)$) {
|
||||
set $cors_origin $http_origin;
|
||||
}
|
||||
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
proxy_hide_header Access-Control-Allow-Headers;
|
||||
proxy_hide_header Access-Control-Allow-Methods;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
return 204;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
|
||||
proxy_pass http://lecoffre_backend/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# WebSocket relay (sdk_relay)
|
||||
location /ws/ {
|
||||
proxy_pass http://sdk_relay/;
|
||||
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
|
||||
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
|
||||
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
|
||||
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# API de transfert de fonds
|
||||
location /api/v1/funds/ {
|
||||
limit_req zone=api burst=5 nodelay;
|
||||
proxy_pass http://lecoffre_backend/api/v1/funds/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# favicon
|
||||
location = /favicon.ico {
|
||||
root /var/www/lecoffre/assets;
|
||||
try_files /favicon.ico =404;
|
||||
}
|
||||
|
||||
# blindbit
|
||||
location /blindbit/ {
|
||||
proxy_pass http://blindbit/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# signer (sdk_signer) avec support WebSocket
|
||||
location /signer/ {
|
||||
proxy_pass http://sdk_signer/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
|
||||
# LeCoffre Front - Application principale
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://lecoffre_frontend/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
|
||||
# Configuration spécifique pour Next.js
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Server $host;
|
||||
}
|
||||
|
||||
# ihm_client (root) - DOIT être en dernier
|
||||
location / {
|
||||
proxy_pass http://ihm_client;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
|
||||
# Serveur pour redirections externes IdNot (port 3000)
|
||||
server {
|
||||
listen 3000 default_server;
|
||||
listen [::]:3000 default_server;
|
||||
server_name local.4nkweb.com;
|
||||
|
||||
# Headers de sécurité
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Page de statut des services
|
||||
location /status/ {
|
||||
alias /var/www/lecoffre/status/;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /status/index.html;
|
||||
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# API de statut des services
|
||||
location /status/api {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://status_api/api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# Grafana - Interface de monitoring
|
||||
location /grafana/ {
|
||||
proxy_pass http://grafana/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Grafana-Org-Id 1;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
# API backend - routes /back/ vers /api/
|
||||
location ~* ^/back/(.*)$ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://lecoffre_backend/api/$1;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# API direct - routes /api/
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
# CORS dynamique pour développement local
|
||||
set $cors_origin "";
|
||||
if ($http_origin ~* ^(http://local\.4nkweb\.com:3000|http://localhost:3000|https://dev4\.4nkweb\.com)$) {
|
||||
set $cors_origin $http_origin;
|
||||
}
|
||||
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
proxy_hide_header Access-Control-Allow-Headers;
|
||||
proxy_hide_header Access-Control-Allow-Methods;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
return 204;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, x-session-id, Authorization" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
|
||||
proxy_pass http://lecoffre_backend/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
}
|
||||
|
||||
# WebSocket relay (sdk_relay)
|
||||
location /ws/ {
|
||||
proxy_pass http://sdk_relay/;
|
||||
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
|
||||
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
|
||||
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
|
||||
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# LeCoffre Front - Application principale
|
||||
location /lecoffre/ {
|
||||
proxy_pass http://lecoffre_frontend/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
|
||||
# Configuration spécifique pour Next.js
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Server $host;
|
||||
}
|
||||
|
||||
# ihm_client (root) - DOIT être en dernier
|
||||
location / {
|
||||
proxy_pass http://ihm_client;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
127
conf/promtail/promtail.yml
Normal file
127
conf/promtail/promtail.yml
Normal file
@ -0,0 +1,127 @@
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://loki:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
# Bitcoin Signet Logs
|
||||
- job_name: bitcoin
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: bitcoin
|
||||
service: bitcoin-signet
|
||||
__path__: /var/log/lecoffre/bitcoin/*.log
|
||||
|
||||
# Blindbit Oracle Logs
|
||||
- job_name: blindbit
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: blindbit
|
||||
service: blindbit-oracle
|
||||
__path__: /var/log/lecoffre/blindbit/*.log
|
||||
|
||||
# SDK Relay Logs
|
||||
- job_name: sdk_relay
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: sdk_relay
|
||||
service: sdk_relay
|
||||
__path__: /var/log/lecoffre/sdk_relay/*.log
|
||||
|
||||
# SDK Signer Logs
|
||||
- job_name: sdk_signer
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: sdk_signer
|
||||
service: sdk_signer
|
||||
__path__: /var/log/lecoffre/sdk_signer/*.log
|
||||
|
||||
# SDK Storage Logs
|
||||
- job_name: sdk_storage
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: sdk_storage
|
||||
service: sdk_storage
|
||||
__path__: /var/log/lecoffre/sdk_storage/*.log
|
||||
|
||||
# LeCoffre Backend Logs
|
||||
- job_name: lecoffre-back
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: lecoffre-back
|
||||
service: lecoffre-back
|
||||
__path__: /var/log/lecoffre/lecoffre-back/*.log
|
||||
|
||||
# LeCoffre Frontend Logs
|
||||
- job_name: lecoffre-front
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: lecoffre-front
|
||||
service: lecoffre-front
|
||||
__path__: /var/log/lecoffre/lecoffre-front/*.log
|
||||
|
||||
# IHM Client Logs
|
||||
- job_name: ihm_client
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: ihm_client
|
||||
service: ihm_client
|
||||
__path__: /var/log/lecoffre/ihm_client/*.log
|
||||
|
||||
# Miner Logs
|
||||
- job_name: miner
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: miner
|
||||
service: signet_miner
|
||||
__path__: /var/log/lecoffre/miner/*.log
|
||||
|
||||
# Tor Logs
|
||||
- job_name: tor
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: tor
|
||||
service: tor-proxy
|
||||
__path__: /var/log/lecoffre/tor/*.log
|
||||
|
||||
# Docker Container Logs
|
||||
- job_name: docker
|
||||
docker_sd_configs:
|
||||
- host: unix:///var/run/docker.sock
|
||||
refresh_interval: 5s
|
||||
filters:
|
||||
- name: label
|
||||
values: ["com.centurylinklabs.watchtower.enable=true"]
|
||||
relabel_configs:
|
||||
- source_labels: ['__meta_docker_container_name']
|
||||
regex: '/?(.*)'
|
||||
target_label: 'container_name'
|
||||
- source_labels: ['__meta_docker_container_log_stream']
|
||||
target_label: 'logstream'
|
||||
- source_labels: ['__meta_docker_container_label_logging_job_name']
|
||||
target_label: 'job'
|
||||
11
conf/relay/sdk_relay.conf
Normal file
11
conf/relay/sdk_relay.conf
Normal file
@ -0,0 +1,11 @@
|
||||
core_url=http://bitcoin:38332
|
||||
ws_url=0.0.0.0:8090
|
||||
wallet_name=default
|
||||
network=signet
|
||||
blindbit_url=http://blindbit-oracle:8000
|
||||
zmq_url=tcp://bitcoin:29000
|
||||
storage=https://dev4.4nkweb.com/storage
|
||||
data_dir=/app/.4nk
|
||||
bitcoin_data_dir=/app/.bitcoin
|
||||
bootstrap_url=
|
||||
bootstrap_faucet=false
|
||||
50
conf/supervisor/supervisord.conf
Normal file
50
conf/supervisor/supervisord.conf
Normal file
@ -0,0 +1,50 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
childlogdir=/var/log/supervisor
|
||||
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///var/run/supervisor.sock
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stderr_logfile=/var/log/supervisor/nginx.err.log
|
||||
stdout_logfile=/var/log/supervisor/nginx.out.log
|
||||
user=root
|
||||
|
||||
[program:docker-compose]
|
||||
command=/app/scripts/startup.sh
|
||||
directory=/app
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stderr_logfile=/var/log/supervisor/docker-compose.err.log
|
||||
stdout_logfile=/var/log/supervisor/docker-compose.out.log
|
||||
user=appuser
|
||||
environment=HOME="/app"
|
||||
|
||||
[program:cron]
|
||||
command=/usr/sbin/cron -f
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stderr_logfile=/var/log/supervisor/cron.err.log
|
||||
stdout_logfile=/var/log/supervisor/cron.out.log
|
||||
user=root
|
||||
|
||||
[program:logrotate]
|
||||
command=/usr/sbin/logrotate /etc/logrotate.d/lecoffre
|
||||
autostart=true
|
||||
autorestart=false
|
||||
startsecs=0
|
||||
exitcodes=0
|
||||
user=root
|
||||
21
conf/tor/torrc
Normal file
21
conf/tor/torrc
Normal file
@ -0,0 +1,21 @@
|
||||
# Configuration Tor pour LeCoffre Node
|
||||
# Écoute sur 127.0.0.1 pour la sécurité
|
||||
|
||||
# Port SOCKS pour les connexions sortantes
|
||||
SOCKSPort 127.0.0.1:9050
|
||||
|
||||
# Port de contrôle (désactivé pour la sécurité)
|
||||
# ControlPort 127.0.0.1:9051
|
||||
|
||||
# Configuration de base
|
||||
Log notice file /var/log/tor/tor.log
|
||||
DataDirectory /var/lib/tor
|
||||
|
||||
# Configuration réseau
|
||||
ClientOnly 1
|
||||
SafeLogging 1
|
||||
WarnUnsafeSocks 1
|
||||
|
||||
# Désactiver les services cachés
|
||||
HiddenServiceDir /var/lib/tor/hidden_service/
|
||||
HiddenServicePort 80 127.0.0.1:80
|
||||
@ -1,74 +1,98 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
tor:
|
||||
image: dperson/torproxy
|
||||
image: btcpayserver/tor:0.4.8.10
|
||||
container_name: tor-proxy
|
||||
volumes:
|
||||
- ./logs/tor:/var/log/tor
|
||||
- ./scripts/healthchecks:/scripts/healthchecks:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- tor
|
||||
ports:
|
||||
- "9052:9050" # Port SOCKS (9052 sur l'hôte, 9050 dans le conteneur)
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "/scripts/healthchecks/tor-progress.sh"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
bitcoin:
|
||||
build: ./bitcoin
|
||||
container_name: bitcoin-signet
|
||||
depends_on:
|
||||
- tor
|
||||
tor:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
- ./bitcoin/bitcoin.conf:/home/bitcoin/.bitcoin/bitcoin.conf
|
||||
ports:
|
||||
- "38333:38333" # signet p2p
|
||||
- "18443:18443" # signet rpc
|
||||
- "29000:29000" # zmq
|
||||
- ./conf/bitcoin/bitcoin.conf:/etc/bitcoin/bitcoin.conf:ro
|
||||
- ./logs/bitcoin:/var/log/bitcoin
|
||||
- ./scripts/healthchecks:/scripts/healthchecks:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- bitcoin
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
mkdir -p /home/bitcoin/.bitcoin/wallets &&
|
||||
bitcoind -conf=/home/bitcoin/.bitcoin/bitcoin.conf -signet -printtoconsole"
|
||||
chown -R bitcoin:bitcoin /home/bitcoin/.bitcoin || echo 'warn: chown partiel (fichiers bind-mount Windows)';
|
||||
exec su-exec bitcoin bitcoind -conf=/etc/bitcoin/bitcoin.conf -signet"
|
||||
healthcheck:
|
||||
test: ["CMD", "bitcoin-cli", "-conf=/home/bitcoin/.bitcoin/bitcoin.conf", "getblockchaininfo"]
|
||||
test: ["CMD", "sh", "/scripts/healthchecks/bitcoin-progress.sh"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
blindbit:
|
||||
build: ./blindbit
|
||||
image: git.4nkweb.com/4nk/blindbit-oracle:dev
|
||||
container_name: blindbit-oracle
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- blindbit_data:/data
|
||||
- ./blindbit/blindbit.toml:/data/blindbit.toml
|
||||
- blindbit_data:/root/.blindbit-oracle
|
||||
- ./blindbit/blindbit.toml:/tmp/blindbit.toml:ro
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
ports:
|
||||
- "8000:8000"
|
||||
- ./logs/blindbit:/var/log/blindbit
|
||||
- ./scripts/healthchecks:/scripts/healthchecks:ro
|
||||
entrypoint: >
|
||||
sh -c "mkdir -p /root/.blindbit-oracle &&
|
||||
if [ ! -f /root/.blindbit-oracle/blindbit.toml ]; then
|
||||
cp /tmp/blindbit.toml /root/.blindbit-oracle/blindbit.toml;
|
||||
fi &&
|
||||
echo 'Waiting for Bitcoin to be ready...' &&
|
||||
while ! nc -z bitcoin 38332; do sleep 2; done &&
|
||||
echo 'Bitcoin is ready, starting BlindBit...' &&
|
||||
exec ./main -datadir /root/.blindbit-oracle"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- blindbit
|
||||
ports:
|
||||
- "0.0.0.0:8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "/scripts/healthchecks/blindbit-progress.sh"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_relay:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: sdk_relay/Dockerfile
|
||||
image: git.4nkweb.com/4nk/sdk_relay:int-dev
|
||||
container_name: sdk_relay
|
||||
depends_on:
|
||||
- blindbit
|
||||
blindbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
- ./bitcoin/bitcoin.conf:/home/bitcoin/.bitcoin/bitcoin.conf
|
||||
- sdk_relay_data:/home/bitcoin/.4nk
|
||||
- ./conf/relay/sdk_relay.conf:/app/.conf:ro
|
||||
- sdk_data:/app/.4nk
|
||||
- bitcoin_data:/app/.bitcoin
|
||||
- ./scripts/funds:/scripts/funds:ro
|
||||
- ./logs/sdk_relay:/var/log/sdk_relay
|
||||
- ./scripts/healthchecks:/scripts/healthchecks:ro
|
||||
ports:
|
||||
- "8090:8090"
|
||||
- "8091:8091"
|
||||
- "0.0.0.0:8090:8090"
|
||||
- "0.0.0.0:8091:8091"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
@ -79,29 +103,214 @@ services:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
environment:
|
||||
- RUST_LOG=debug,bitcoincore_rpc=trace
|
||||
- HOME=/home/bitcoin
|
||||
- BITCOIN_COOKIE_PATH=/home/bitcoin/.bitcoin/signet/.cookie
|
||||
restart: on-failure:3
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
mkdir -p /home/bitcoin/.4nk &&
|
||||
strace -f -e trace=file /usr/local/bin/sdk_relay --config .conf"
|
||||
- HOME=/app
|
||||
- CORE_URL=${SDK_RELAY_CORE_URL}
|
||||
- WS_URL=${SDK_RELAY_WS_URL}
|
||||
- WALLET_NAME=${SDK_RELAY_WALLET_NAME}
|
||||
- NETWORK=${SDK_RELAY_NETWORK}
|
||||
- BLINDBIT_URL=${SDK_RELAY_BLINDBIT_URL}
|
||||
- ZMQ_URL=${SDK_RELAY_ZMQ_URL}
|
||||
- STORAGE=${SDK_RELAY_STORAGE}
|
||||
- DATA_DIR=${SDK_RELAY_DATA_DIR}
|
||||
- BITCOIN_DATA_DIR=${SDK_RELAY_BITCOIN_DATA_DIR}
|
||||
- BOOTSTRAP_URL=${SDK_RELAY_BOOTSTRAP_URL}
|
||||
- BOOTSTRAP_FAUCET=${SDK_RELAY_BOOTSTRAP_FAUCET}
|
||||
- RUST_LOG=INFO
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8091/health"]
|
||||
test: ["CMD", "sh", "/scripts/healthchecks/sdk-relay-progress.sh"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-back:
|
||||
image: git.4nkweb.com/4nk/lecoffre-back-mini:latest
|
||||
image: git.4nkweb.com/4nk/lecoffre-back-mini:int-dev
|
||||
container_name: lecoffre-back
|
||||
environment:
|
||||
- NODE_OPTIONS=${NODE_OPTIONS}
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
- IDNOT_ANNUARY_BASE_URL=${IDNOT_ANNUARY_BASE_URL}
|
||||
- IDNOT_REDIRECT_URI=${IDNOT_REDIRECT_URI}
|
||||
- IDNOT_TOKEN_URL=${IDNOT_TOKEN_URL}
|
||||
- IDNOT_API_BASE_URL=${IDNOT_API_BASE_URL}
|
||||
- APP_HOST=${APP_HOST}
|
||||
- API_BASE_URL=${API_BASE_URL}
|
||||
- DEFAULT_STORAGE=${DEFAULT_STORAGE}
|
||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
||||
- STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY}
|
||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
||||
- MAILCHIMP_API_KEY=${MAILCHIMP_API_KEY}
|
||||
- MAILCHIMP_SERVER_PREFIX=${MAILCHIMP_SERVER_PREFIX}
|
||||
- MAILCHIMP_LIST_ID=${MAILCHIMP_LIST_ID}
|
||||
- OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
|
||||
- OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
|
||||
- OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
|
||||
- OVH_SERVICE_NAME=${OVH_SERVICE_NAME}
|
||||
ports:
|
||||
- "0.0.0.0:8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./logs/lecoffre-back:/var/log/lecoffre-back
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-back
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
user: appuser
|
||||
command: ["node", "dist/server.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:8080/api/v1/health >/dev/null 2>&1; then echo 'LeCoffre Backend ready: API responding'; exit 0; else echo 'LeCoffre Backend starting: API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 60s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-front:
|
||||
image: git.4nkweb.com/4nk/lecoffre-front:int-dev
|
||||
container_name: lecoffre-front
|
||||
working_dir: /leCoffre-front
|
||||
environment:
|
||||
- NODE_OPTIONS=${NODE_OPTIONS}
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
- NEXT_PUBLIC_4NK_URL=${NEXT_PUBLIC_4NK_URL}
|
||||
- NEXT_PUBLIC_FRONT_APP_HOST=${NEXT_PUBLIC_FRONT_APP_HOST}
|
||||
- NEXT_PUBLIC_IDNOT_BASE_URL=${NEXT_PUBLIC_IDNOT_BASE_URL}
|
||||
- NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT=${NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT}
|
||||
- NEXT_PUBLIC_BACK_API_PROTOCOL=${NEXT_PUBLIC_BACK_API_PROTOCOL}
|
||||
- NEXT_PUBLIC_BACK_API_HOST=${NEXT_PUBLIC_BACK_API_HOST}
|
||||
- NEXT_PUBLIC_BACK_API_PORT=${NEXT_PUBLIC_BACK_API_PORT}
|
||||
- NEXT_PUBLIC_BACK_API_ROOT_URL=${NEXT_PUBLIC_BACK_API_ROOT_URL}
|
||||
- NEXT_PUBLIC_BACK_API_VERSION=${NEXT_PUBLIC_BACK_API_VERSION}
|
||||
ports:
|
||||
- "0.0.0.0:3004:3000"
|
||||
volumes:
|
||||
- ./logs/lecoffre-front:/var/log/lecoffre-front
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-front
|
||||
depends_on:
|
||||
lecoffre-back:
|
||||
condition: service_healthy
|
||||
ihm_client:
|
||||
condition: service_healthy
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
sdk_signer:
|
||||
condition: service_healthy
|
||||
user: lecoffreuser
|
||||
command: ["node", "server.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if ps aux | grep -v grep | grep next-server >/dev/null 2>&1; then echo 'LeCoffre Frontend ready: Next.js server running'; exit 0; else echo 'LeCoffre Frontend starting: Next.js server not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
ihm_client:
|
||||
image: git.4nkweb.com/4nk/ihm_client:int-dev
|
||||
container_name: ihm_client
|
||||
environment:
|
||||
- VITE_JWT_SECRET_KEY=${VITE_JWT_SECRET_KEY}
|
||||
- VITE_API_BASE_URL=${VITE_API_BASE_URL}
|
||||
- VITE_WS_URL=${VITE_WS_URL}
|
||||
- VITE_STORAGE_URL=${VITE_STORAGE_URL}
|
||||
- VITE_SIGNER_URL=${VITE_SIGNER_URL}
|
||||
- VITE_BOOTSTRAPURL=wss://dev4.4nkweb.com/ws/
|
||||
ports:
|
||||
- "0.0.0.0:3003:3003"
|
||||
volumes:
|
||||
- ./logs/ihm_client:/var/log/ihm_client
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- ihm_client
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
sdk_signer:
|
||||
condition: service_healthy
|
||||
user: root
|
||||
command: ["npm", "start"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3003/ >/dev/null 2>&1; then echo 'IHM Client ready: Vite dev server responding'; exit 0; else echo 'IHM Client starting: Vite dev server not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_signer:
|
||||
image: git.4nkweb.com/4nk/sdk_signer:int-dev
|
||||
container_name: sdk_signer
|
||||
ports:
|
||||
- "0.0.0.0:3001:9090"
|
||||
volumes:
|
||||
- sdk_signer_data:/app/data
|
||||
- ./logs/sdk_signer:/var/log/sdk_signer
|
||||
- ./scripts/healthchecks:/scripts/healthchecks:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_signer
|
||||
user: appuser
|
||||
depends_on:
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
command: ["node", "/app/dist/index.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "/scripts/healthchecks/sdk-signer-progress.sh"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PORT=${SIGNER_PORT}
|
||||
- API_KEY=${SIGNER_API_KEY}
|
||||
- DATABASE_PATH=${SIGNER_DATABASE_PATH}
|
||||
- RELAY_URLS=${SIGNER_RELAY_URLS}
|
||||
- AUTO_RESTART=${SIGNER_AUTO_RESTART}
|
||||
- MAX_RESTARTS=${SIGNER_MAX_RESTARTS}
|
||||
- LOG_LEVEL=${SIGNER_LOG_LEVEL}
|
||||
- SIGNER_WS_URL=ws://dev3.4nkweb.com:9090
|
||||
- SIGNER_BASE_URL=https://dev3.4nkweb.com
|
||||
|
||||
sdk_storage:
|
||||
image: git.4nkweb.com/4nk/sdk_storage:int-dev
|
||||
container_name: sdk_storage
|
||||
ports:
|
||||
- "0.0.0.0:8081:8080"
|
||||
volumes:
|
||||
- sdk_storage_data:/app/data
|
||||
- ./logs/sdk_storage:/var/log/sdk_storage
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:8080/health >/dev/null 2>&1; then echo 'SDK Storage ready: API responding'; exit 0; else echo 'SDK Storage starting: API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_storage
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
@ -111,12 +320,145 @@ services:
|
||||
command: --interval 30 --label-enable
|
||||
networks:
|
||||
- btcnet
|
||||
restart: unless-stopped
|
||||
|
||||
signet_miner:
|
||||
build:
|
||||
context: ./miner
|
||||
container_name: signet_miner
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./miner/.env
|
||||
volumes:
|
||||
- bitcoin_data:/bitcoin:ro
|
||||
- ./logs/miner:/var/log/miner
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- signet_miner
|
||||
profiles: ["miner"]
|
||||
restart: unless-stopped
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
ports:
|
||||
- "0.0.0.0:3005:3000"
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./conf/grafana/provisioning:/etc/grafana/provisioning
|
||||
- ./conf/grafana/dashboards:/var/lib/grafana/dashboards
|
||||
- ./conf/grafana/grafana.ini:/etc/grafana/grafana.ini:ro
|
||||
- ./logs:/var/log/lecoffre:ro
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=Fuy8ZfxQI2xdSdoB8wsGxNjyU
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_SERVER_ROOT_URL=https://dev4.4nkweb.com/grafana/
|
||||
- GF_PLUGINS_PREINSTALL_SYNC=grafana-clock-panel,grafana-simple-json-datasource
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- grafana
|
||||
depends_on:
|
||||
loki:
|
||||
condition: service_healthy
|
||||
promtail:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3000/api/health >/dev/null 2>&1; then echo 'Grafana ready: Dashboard service responding'; exit 0; else echo 'Grafana starting: Dashboard service not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 60s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
container_name: loki
|
||||
ports:
|
||||
- "0.0.0.0:3100:3100"
|
||||
volumes:
|
||||
- loki_data:/loki
|
||||
- ./conf/loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro
|
||||
command: -config.file=/etc/loki/loki-config.yaml
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- loki
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3100/ready"]
|
||||
interval: 30s
|
||||
timeout: 15s
|
||||
retries: 50
|
||||
start_period: 120s
|
||||
restart: unless-stopped
|
||||
|
||||
promtail:
|
||||
image: promtail-custom:int-dev
|
||||
container_name: promtail
|
||||
volumes:
|
||||
- ./logs:/var/log/lecoffre:ro
|
||||
- ./conf/promtail/promtail.yml:/etc/promtail/config.yml:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: -config.file=/etc/promtail/config.yml
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- promtail
|
||||
depends_on:
|
||||
loki:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if [ -f /tmp/positions.yaml ]; then echo 'Promtail ready: Log collection service responding'; exit 0; else echo 'Promtail starting: Log collection service not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
restart: unless-stopped
|
||||
|
||||
# Service de statut des services
|
||||
status-api:
|
||||
build:
|
||||
context: ./web/status
|
||||
dockerfile: Dockerfile.python
|
||||
container_name: status-api
|
||||
ports:
|
||||
- "0.0.0.0:3006:3006"
|
||||
volumes:
|
||||
- ./web/status/api.py:/app/api.py:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- status-api
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3006/api >/dev/null 2>&1; then echo 'Status API ready: Service monitoring API responding'; exit 0; else echo 'Status API starting: Service monitoring API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
bitcoin_data:
|
||||
name: 4nk_node_bitcoin_data
|
||||
blindbit_data:
|
||||
sdk_relay_data:
|
||||
name: 4nk_node_blindbit_data
|
||||
sdk_data:
|
||||
name: 4nk_node_sdk_data
|
||||
sdk_signer_data:
|
||||
name: 4nk_node_sdk_signer_data
|
||||
sdk_storage_data:
|
||||
name: 4nk_node_sdk_storage_data
|
||||
grafana_data:
|
||||
name: 4nk_node_grafana_data
|
||||
loki_data:
|
||||
name: 4nk_node_loki_data
|
||||
|
||||
networks:
|
||||
btcnet:
|
||||
|
||||
448
docker-compose.yml.backup
Normal file
448
docker-compose.yml.backup
Normal file
@ -0,0 +1,448 @@
|
||||
services:
|
||||
tor:
|
||||
image: btcpayserver/tor:0.4.8.10
|
||||
container_name: tor-proxy
|
||||
volumes:
|
||||
- ./logs/tor:/var/log/tor
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- tor
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if test -f /var/log/tor/tor.log && test -s /var/log/tor/tor.log; then echo 'Tor ready: SOCKS proxy listening on port 9050'; exit 0; else echo 'Tor starting: SOCKS proxy not yet ready'; exit 1; fi"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
bitcoin:
|
||||
image: git.4nkweb.com/4nk/bitcoin:latest
|
||||
container_name: bitcoin-signet
|
||||
depends_on:
|
||||
tor:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
- ./conf/bitcoin/bitcoin.conf:/etc/bitcoin/bitcoin.conf:ro
|
||||
- ./logs/bitcoin:/var/log/bitcoin
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- bitcoin
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
chown -R bitcoin:bitcoin /home/bitcoin/.bitcoin || echo 'warn: chown partiel (fichiers bind-mount Windows)';
|
||||
exec su-exec bitcoin bitcoind -conf=/etc/bitcoin/bitcoin.conf -signet"
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf getblockchaininfo > /dev/null 2>&1; then echo 'Bitcoin ready: RPC responding'; exit 0; else echo 'Bitcoin starting: RPC not ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
blindbit:
|
||||
image: git.4nkweb.com/4nk/blindbit-oracle:dev
|
||||
container_name: blindbit-oracle
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- blindbit_data:/root/.blindbit-oracle
|
||||
- ./blindbit/blindbit.toml:/tmp/blindbit.toml:ro
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
- ./logs/blindbit:/var/log/blindbit
|
||||
entrypoint: >
|
||||
sh -c "cp /tmp/blindbit.toml /root/.blindbit-oracle/blindbit.toml &&
|
||||
./main -datadir /root/.blindbit-oracle"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- blindbit
|
||||
ports:
|
||||
- "0.0.0.0:8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if wget -q --spider http://localhost:8000/tweaks/1; then echo 'BlindBit ready: Oracle service responding'; exit 0; else echo 'BlindBit starting: Oracle service not yet ready'; exit 1; fi"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_relay:
|
||||
image: git.4nkweb.com/4nk/sdk_relay:int-dev
|
||||
container_name: sdk_relay
|
||||
depends_on:
|
||||
blindbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./conf/relay/sdk_relay.conf:/app/.conf:ro
|
||||
- sdk_data:/app/.4nk
|
||||
- bitcoin_data:/app/.bitcoin
|
||||
- ./scripts/funds:/scripts/funds:ro
|
||||
- ./logs/sdk_relay:/var/log/sdk_relay
|
||||
ports:
|
||||
- "0.0.0.0:8090:8090"
|
||||
- "0.0.0.0:8091:8091"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_relay
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
environment:
|
||||
- HOME=/app
|
||||
- CORE_URL=${SDK_RELAY_CORE_URL}
|
||||
- WS_URL=${SDK_RELAY_WS_URL}
|
||||
- WALLET_NAME=${SDK_RELAY_WALLET_NAME}
|
||||
- NETWORK=${SDK_RELAY_NETWORK}
|
||||
- BLINDBIT_URL=${SDK_RELAY_BLINDBIT_URL}
|
||||
- ZMQ_URL=${SDK_RELAY_ZMQ_URL}
|
||||
- STORAGE=${SDK_RELAY_STORAGE}
|
||||
- DATA_DIR=${SDK_RELAY_DATA_DIR}
|
||||
- BITCOIN_DATA_DIR=${SDK_RELAY_BITCOIN_DATA_DIR}
|
||||
- BOOTSTRAP_URL=${SDK_RELAY_BOOTSTRAP_URL}
|
||||
- BOOTSTRAP_FAUCET=${SDK_RELAY_BOOTSTRAP_FAUCET}
|
||||
- RUST_LOG=INFO
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:8091/ >/dev/null 2>&1; then echo 'SDK Relay ready: WebSocket server responding'; exit 0; else echo 'SDK Relay IBD: Waiting for Bitcoin sync to complete'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-back:
|
||||
image: git.4nkweb.com/4nk/lecoffre-back-mini:int-dev
|
||||
container_name: lecoffre-back
|
||||
environment:
|
||||
- NODE_OPTIONS=${NODE_OPTIONS}
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
- IDNOT_ANNUARY_BASE_URL=${IDNOT_ANNUARY_BASE_URL}
|
||||
- IDNOT_REDIRECT_URI=${IDNOT_REDIRECT_URI}
|
||||
- IDNOT_TOKEN_URL=${IDNOT_TOKEN_URL}
|
||||
- IDNOT_API_BASE_URL=${IDNOT_API_BASE_URL}
|
||||
- APP_HOST=${APP_HOST}
|
||||
- API_BASE_URL=${API_BASE_URL}
|
||||
- DEFAULT_STORAGE=${DEFAULT_STORAGE}
|
||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
||||
- STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY}
|
||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
||||
- MAILCHIMP_API_KEY=${MAILCHIMP_API_KEY}
|
||||
- MAILCHIMP_SERVER_PREFIX=${MAILCHIMP_SERVER_PREFIX}
|
||||
- MAILCHIMP_LIST_ID=${MAILCHIMP_LIST_ID}
|
||||
- OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
|
||||
- OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
|
||||
- OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
|
||||
- OVH_SERVICE_NAME=${OVH_SERVICE_NAME}
|
||||
ports:
|
||||
- "0.0.0.0:8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./logs/lecoffre-back:/var/log/lecoffre-back
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-back
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
user: appuser
|
||||
command: ["node", "dist/server.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:8080/api/v1/health >/dev/null 2>&1; then echo 'LeCoffre Backend ready: API responding'; exit 0; else echo 'LeCoffre Backend starting: API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 60s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-front:
|
||||
image: git.4nkweb.com/4nk/lecoffre-front:int-dev
|
||||
container_name: lecoffre-front
|
||||
working_dir: /leCoffre-front
|
||||
environment:
|
||||
- NODE_OPTIONS=${NODE_OPTIONS}
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
- NEXT_PUBLIC_4NK_URL=${NEXT_PUBLIC_4NK_URL}
|
||||
- NEXT_PUBLIC_FRONT_APP_HOST=${NEXT_PUBLIC_FRONT_APP_HOST}
|
||||
- NEXT_PUBLIC_IDNOT_BASE_URL=${NEXT_PUBLIC_IDNOT_BASE_URL}
|
||||
- NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT=${NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT}
|
||||
- NEXT_PUBLIC_BACK_API_PROTOCOL=${NEXT_PUBLIC_BACK_API_PROTOCOL}
|
||||
- NEXT_PUBLIC_BACK_API_HOST=${NEXT_PUBLIC_BACK_API_HOST}
|
||||
- NEXT_PUBLIC_BACK_API_PORT=${NEXT_PUBLIC_BACK_API_PORT}
|
||||
- NEXT_PUBLIC_BACK_API_ROOT_URL=${NEXT_PUBLIC_BACK_API_ROOT_URL}
|
||||
- NEXT_PUBLIC_BACK_API_VERSION=${NEXT_PUBLIC_BACK_API_VERSION}
|
||||
ports:
|
||||
- "0.0.0.0:3004:3000"
|
||||
volumes:
|
||||
- ./logs/lecoffre-front:/var/log/lecoffre-front
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-front
|
||||
depends_on:
|
||||
lecoffre-back:
|
||||
condition: service_healthy
|
||||
ihm_client:
|
||||
condition: service_healthy
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
sdk_signer:
|
||||
condition: service_healthy
|
||||
user: lecoffreuser
|
||||
command: ["node", "server.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if ps aux | grep -v grep | grep next-server >/dev/null 2>&1; then echo 'LeCoffre Frontend ready: Next.js server running'; exit 0; else echo 'LeCoffre Frontend starting: Next.js server not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
ihm_client:
|
||||
image: git.4nkweb.com/4nk/ihm_client:int-dev
|
||||
container_name: ihm_client
|
||||
environment:
|
||||
- VITE_JWT_SECRET_KEY=${VITE_JWT_SECRET_KEY}
|
||||
- VITE_API_BASE_URL=${VITE_API_BASE_URL}
|
||||
- VITE_WS_URL=${VITE_WS_URL}
|
||||
- VITE_STORAGE_URL=${VITE_STORAGE_URL}
|
||||
- VITE_SIGNER_URL=${VITE_SIGNER_URL}
|
||||
- VITE_BOOTSTRAPURL=wss://dev4.4nkweb.com/ws/
|
||||
ports:
|
||||
- "0.0.0.0:3003:3003"
|
||||
volumes:
|
||||
- ./logs/ihm_client:/var/log/ihm_client
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- ihm_client
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
sdk_signer:
|
||||
condition: service_healthy
|
||||
user: root
|
||||
command: ["npm", "start"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3003/ >/dev/null 2>&1; then echo 'IHM Client ready: Vite dev server responding'; exit 0; else echo 'IHM Client starting: Vite dev server not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_signer:
|
||||
image: git.4nkweb.com/4nk/sdk_signer:int-dev
|
||||
container_name: sdk_signer
|
||||
ports:
|
||||
- "0.0.0.0:3001:9090"
|
||||
volumes:
|
||||
- ./logs/sdk_signer:/var/log/sdk_signer
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_signer
|
||||
user: appuser
|
||||
depends_on:
|
||||
sdk_storage:
|
||||
condition: service_healthy
|
||||
command: ["node", "/app/dist/index.js"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:9090/ >/dev/null 2>&1; then echo 'SDK Signer ready: WebSocket server responding'; exit 0; else echo 'SDK Signer starting: WebSocket server not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PORT=${SIGNER_PORT}
|
||||
- API_KEY=${SIGNER_API_KEY}
|
||||
- DATABASE_PATH=${SIGNER_DATABASE_PATH}
|
||||
- RELAY_URLS=${SIGNER_RELAY_URLS}
|
||||
- AUTO_RESTART=${SIGNER_AUTO_RESTART}
|
||||
- MAX_RESTARTS=${SIGNER_MAX_RESTARTS}
|
||||
- LOG_LEVEL=${SIGNER_LOG_LEVEL}
|
||||
- SIGNER_WS_URL=ws://dev3.4nkweb.com:9090
|
||||
- SIGNER_BASE_URL=https://dev3.4nkweb.com
|
||||
|
||||
sdk_storage:
|
||||
image: git.4nkweb.com/4nk/sdk_storage:int-dev
|
||||
container_name: sdk_storage
|
||||
ports:
|
||||
- "0.0.0.0:8081:8080"
|
||||
volumes:
|
||||
- ./logs/sdk_storage:/var/log/sdk_storage
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:8080/health >/dev/null 2>&1; then echo 'SDK Storage ready: API responding'; exit 0; else echo 'SDK Storage starting: API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_storage
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --interval 30 --label-enable
|
||||
networks:
|
||||
- btcnet
|
||||
restart: unless-stopped
|
||||
|
||||
signet_miner:
|
||||
build:
|
||||
context: ./miner
|
||||
container_name: signet_miner
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./miner/.env
|
||||
volumes:
|
||||
- bitcoin_data:/bitcoin:ro
|
||||
- ./logs/miner:/var/log/miner
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- signet_miner
|
||||
profiles: ["miner"]
|
||||
restart: unless-stopped
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
ports:
|
||||
- "0.0.0.0:3005:3000"
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./conf/grafana/provisioning:/etc/grafana/provisioning
|
||||
- ./conf/grafana/dashboards:/var/lib/grafana/dashboards
|
||||
- ./conf/grafana/grafana.ini:/etc/grafana/grafana.ini:ro
|
||||
- ./logs:/var/log/lecoffre:ro
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=Fuy8ZfxQI2xdSdoB8wsGxNjyU
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_SERVER_ROOT_URL=https://dev4.4nkweb.com/grafana/
|
||||
- GF_PLUGINS_PREINSTALL_SYNC=grafana-clock-panel,grafana-simple-json-datasource
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- grafana
|
||||
depends_on:
|
||||
loki:
|
||||
condition: service_healthy
|
||||
promtail:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3000/api/health >/dev/null 2>&1; then echo 'Grafana ready: Dashboard service responding'; exit 0; else echo 'Grafana starting: Dashboard service not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 60s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
container_name: loki
|
||||
ports:
|
||||
- "0.0.0.0:3100:3100"
|
||||
volumes:
|
||||
- loki_data:/loki
|
||||
- ./conf/loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro
|
||||
command: -config.file=/etc/loki/loki-config.yaml
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- loki
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3100/ready"]
|
||||
interval: 30s
|
||||
timeout: 15s
|
||||
retries: 50
|
||||
start_period: 120s
|
||||
restart: unless-stopped
|
||||
|
||||
promtail:
|
||||
image: promtail-custom:int-dev
|
||||
container_name: promtail
|
||||
volumes:
|
||||
- ./logs:/var/log/lecoffre:ro
|
||||
- ./conf/promtail/promtail.yml:/etc/promtail/config.yml:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: -config.file=/etc/promtail/config.yml
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- promtail
|
||||
depends_on:
|
||||
loki:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if [ -f /tmp/positions.yaml ]; then echo 'Promtail ready: Log collection service responding'; exit 0; else echo 'Promtail starting: Log collection service not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
restart: unless-stopped
|
||||
|
||||
# Service de statut des services
|
||||
status-api:
|
||||
build:
|
||||
context: ./web/status
|
||||
dockerfile: Dockerfile.python
|
||||
container_name: status-api
|
||||
ports:
|
||||
- "0.0.0.0:3006:3006"
|
||||
volumes:
|
||||
- ./web/status/api.py:/app/api.py:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- status-api
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "if curl -f http://localhost:3006/api >/dev/null 2>&1; then echo 'Status API ready: Service monitoring API responding'; exit 0; else echo 'Status API starting: Service monitoring API not yet ready'; exit 1; fi"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 50
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
bitcoin_data:
|
||||
name: 4nk_node_bitcoin_data
|
||||
blindbit_data:
|
||||
sdk_data:
|
||||
grafana_data:
|
||||
loki_data:
|
||||
|
||||
networks:
|
||||
btcnet:
|
||||
name: 4nk_node_btcnet
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
62
docker.gpg
Normal file
62
docker.gpg
Normal file
@ -0,0 +1,62 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFit2ioBEADhWpZ8/wvZ6hUTiXOwQHXMAlaFHcPH9hAtr4F1y2+OYdbtMuth
|
||||
lqqwp028AqyY+PRfVMtSYMbjuQuu5byyKR01BbqYhuS3jtqQmljZ/bJvXqnmiVXh
|
||||
38UuLa+z077PxyxQhu5BbqntTPQMfiyqEiU+BKbq2WmANUKQf+1AmZY/IruOXbnq
|
||||
L4C1+gJ8vfmXQt99npCaxEjaNRVYfOS8QcixNzHUYnb6emjlANyEVlZzeqo7XKl7
|
||||
UrwV5inawTSzWNvtjEjj4nJL8NsLwscpLPQUhTQ+7BbQXAwAmeHCUTQIvvWXqw0N
|
||||
cmhh4HgeQscQHYgOJjjDVfoY5MucvglbIgCqfzAHW9jxmRL4qbMZj+b1XoePEtht
|
||||
ku4bIQN1X5P07fNWzlgaRL5Z4POXDDZTlIQ/El58j9kp4bnWRCJW0lya+f8ocodo
|
||||
vZZ+Doi+fy4D5ZGrL4XEcIQP/Lv5uFyf+kQtl/94VFYVJOleAv8W92KdgDkhTcTD
|
||||
G7c0tIkVEKNUq48b3aQ64NOZQW7fVjfoKwEZdOqPE72Pa45jrZzvUFxSpdiNk2tZ
|
||||
XYukHjlxxEgBdC/J3cMMNRE1F4NCA3ApfV1Y7/hTeOnmDuDYwr9/obA8t016Yljj
|
||||
q5rdkywPf4JF8mXUW5eCN1vAFHxeg9ZWemhBtQmGxXnw9M+z6hWwc6ahmwARAQAB
|
||||
tCtEb2NrZXIgUmVsZWFzZSAoQ0UgZGViKSA8ZG9ja2VyQGRvY2tlci5jb20+iQI3
|
||||
BBMBCgAhBQJYrefAAhsvBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEI2BgDwO
|
||||
v82IsskP/iQZo68flDQmNvn8X5XTd6RRaUH33kXYXquT6NkHJciS7E2gTJmqvMqd
|
||||
tI4mNYHCSEYxI5qrcYV5YqX9P6+Ko+vozo4nseUQLPH/ATQ4qL0Zok+1jkag3Lgk
|
||||
jonyUf9bwtWxFp05HC3GMHPhhcUSexCxQLQvnFWXD2sWLKivHp2fT8QbRGeZ+d3m
|
||||
6fqcd5Fu7pxsqm0EUDK5NL+nPIgYhN+auTrhgzhK1CShfGccM/wfRlei9Utz6p9P
|
||||
XRKIlWnXtT4qNGZNTN0tR+NLG/6Bqd8OYBaFAUcue/w1VW6JQ2VGYZHnZu9S8LMc
|
||||
FYBa5Ig9PxwGQOgq6RDKDbV+PqTQT5EFMeR1mrjckk4DQJjbxeMZbiNMG5kGECA8
|
||||
g383P3elhn03WGbEEa4MNc3Z4+7c236QI3xWJfNPdUbXRaAwhy/6rTSFbzwKB0Jm
|
||||
ebwzQfwjQY6f55MiI/RqDCyuPj3r3jyVRkK86pQKBAJwFHyqj9KaKXMZjfVnowLh
|
||||
9svIGfNbGHpucATqREvUHuQbNnqkCx8VVhtYkhDb9fEP2xBu5VvHbR+3nfVhMut5
|
||||
G34Ct5RS7Jt6LIfFdtcn8CaSas/l1HbiGeRgc70X/9aYx/V/CEJv0lIe8gP6uDoW
|
||||
FPIZ7d6vH+Vro6xuWEGiuMaiznap2KhZmpkgfupyFmplh0s6knymuQINBFit2ioB
|
||||
EADneL9S9m4vhU3blaRjVUUyJ7b/qTjcSylvCH5XUE6R2k+ckEZjfAMZPLpO+/tF
|
||||
M2JIJMD4SifKuS3xck9KtZGCufGmcwiLQRzeHF7vJUKrLD5RTkNi23ydvWZgPjtx
|
||||
Q+DTT1Zcn7BrQFY6FgnRoUVIxwtdw1bMY/89rsFgS5wwuMESd3Q2RYgb7EOFOpnu
|
||||
w6da7WakWf4IhnF5nsNYGDVaIHzpiqCl+uTbf1epCjrOlIzkZ3Z3Yk5CM/TiFzPk
|
||||
z2lLz89cpD8U+NtCsfagWWfjd2U3jDapgH+7nQnCEWpROtzaKHG6lA3pXdix5zG8
|
||||
eRc6/0IbUSWvfjKxLLPfNeCS2pCL3IeEI5nothEEYdQH6szpLog79xB9dVnJyKJb
|
||||
VfxXnseoYqVrRz2VVbUI5Blwm6B40E3eGVfUQWiux54DspyVMMk41Mx7QJ3iynIa
|
||||
1N4ZAqVMAEruyXTRTxc9XW0tYhDMA/1GYvz0EmFpm8LzTHA6sFVtPm/ZlNCX6P1X
|
||||
zJwrv7DSQKD6GGlBQUX+OeEJ8tTkkf8QTJSPUdh8P8YxDFS5EOGAvhhpMBYD42kQ
|
||||
pqXjEC+XcycTvGI7impgv9PDY1RCC1zkBjKPa120rNhv/hkVk/YhuGoajoHyy4h7
|
||||
ZQopdcMtpN2dgmhEegny9JCSwxfQmQ0zK0g7m6SHiKMwjwARAQABiQQ+BBgBCAAJ
|
||||
BQJYrdoqAhsCAikJEI2BgDwOv82IwV0gBBkBCAAGBQJYrdoqAAoJEH6gqcPyc/zY
|
||||
1WAP/2wJ+R0gE6qsce3rjaIz58PJmc8goKrir5hnElWhPgbq7cYIsW5qiFyLhkdp
|
||||
YcMmhD9mRiPpQn6Ya2w3e3B8zfIVKipbMBnke/ytZ9M7qHmDCcjoiSmwEXN3wKYI
|
||||
mD9VHONsl/CG1rU9Isw1jtB5g1YxuBA7M/m36XN6x2u+NtNMDB9P56yc4gfsZVES
|
||||
KA9v+yY2/l45L8d/WUkUi0YXomn6hyBGI7JrBLq0CX37GEYP6O9rrKipfz73XfO7
|
||||
JIGzOKZlljb/D9RX/g7nRbCn+3EtH7xnk+TK/50euEKw8SMUg147sJTcpQmv6UzZ
|
||||
cM4JgL0HbHVCojV4C/plELwMddALOFeYQzTif6sMRPf+3DSj8frbInjChC3yOLy0
|
||||
6br92KFom17EIj2CAcoeq7UPhi2oouYBwPxh5ytdehJkoo+sN7RIWua6P2WSmon5
|
||||
U888cSylXC0+ADFdgLX9K2zrDVYUG1vo8CX0vzxFBaHwN6Px26fhIT1/hYUHQR1z
|
||||
VfNDcyQmXqkOnZvvoMfz/Q0s9BhFJ/zU6AgQbIZE/hm1spsfgvtsD1frZfygXJ9f
|
||||
irP+MSAI80xHSf91qSRZOj4Pl3ZJNbq4yYxv0b1pkMqeGdjdCYhLU+LZ4wbQmpCk
|
||||
SVe2prlLureigXtmZfkqevRz7FrIZiu9ky8wnCAPwC7/zmS18rgP/17bOtL4/iIz
|
||||
QhxAAoAMWVrGyJivSkjhSGx1uCojsWfsTAm11P7jsruIL61ZzMUVE2aM3Pmj5G+W
|
||||
9AcZ58Em+1WsVnAXdUR//bMmhyr8wL/G1YO1V3JEJTRdxsSxdYa4deGBBY/Adpsw
|
||||
24jxhOJR+lsJpqIUeb999+R8euDhRHG9eFO7DRu6weatUJ6suupoDTRWtr/4yGqe
|
||||
dKxV3qQhNLSnaAzqW/1nA3iUB4k7kCaKZxhdhDbClf9P37qaRW467BLCVO/coL3y
|
||||
Vm50dwdrNtKpMBh3ZpbB1uJvgi9mXtyBOMJ3v8RZeDzFiG8HdCtg9RvIt/AIFoHR
|
||||
H3S+U79NT6i0KPzLImDfs8T7RlpyuMc4Ufs8ggyg9v3Ae6cN3eQyxcK3w0cbBwsh
|
||||
/nQNfsA6uu+9H7NhbehBMhYnpNZyrHzCmzyXkauwRAqoCbGCNykTRwsur9gS41TQ
|
||||
M8ssD1jFheOJf3hODnkKU+HKjvMROl1DK7zdmLdNzA1cvtZH/nCC9KPj1z8QC47S
|
||||
xx+dTZSx4ONAhwbS/LN3PoKtn8LPjY9NP9uDWI+TWYquS2U+KHDrBDlsgozDbs/O
|
||||
jCxcpDzNmXpWQHEtHU7649OXHP7UeNST1mCUCH5qdank0V1iejF6/CfTFU4MfcrG
|
||||
YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
|
||||
=0YYh
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
9
dockerfiles/Dockerfile.promtail
Normal file
9
dockerfiles/Dockerfile.promtail
Normal file
@ -0,0 +1,9 @@
|
||||
FROM grafana/promtail:latest
|
||||
|
||||
# Installer curl et wget
|
||||
USER root
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
127
installer.nsi
Normal file
127
installer.nsi
Normal file
@ -0,0 +1,127 @@
|
||||
;--------------------------------
|
||||
; Fichier : installer.nsi
|
||||
;--------------------------------
|
||||
|
||||
!define MUI_ICON "kogusico.ico"
|
||||
!define MUI_UNICON "kogusico.ico"
|
||||
!define MUI_UNINST_ICON "kogusico.ico"
|
||||
!define MUI_UNINSTALLER
|
||||
!include "MUI2.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
|
||||
;--------------------------------
|
||||
; Métadonnées produit
|
||||
;--------------------------------
|
||||
!define PRODUCT_NAME "Kogus"
|
||||
!define PRODUCT_VERSION "1.0.0"
|
||||
!define INSTALL_DIR "$PROGRAMFILES\${PRODUCT_NAME}"
|
||||
|
||||
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
|
||||
!define MUI_PRODUCT "${PRODUCT_NAME}"
|
||||
|
||||
; Pages de l’installateur
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "license.txt"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
; Pages de l’uninstaller
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
|
||||
OutFile "Kogus-${PRODUCT_VERSION}.exe"
|
||||
InstallDir "${INSTALL_DIR}"
|
||||
RequestExecutionLevel admin
|
||||
ShowInstDetails show
|
||||
|
||||
Var ExecCode
|
||||
|
||||
;--------------------------------
|
||||
; Section : Installation
|
||||
;--------------------------------
|
||||
Section "Install"
|
||||
|
||||
; 1. Créer le dossier d’installation et copier l’icône
|
||||
SetOutPath "$INSTDIR"
|
||||
File "kogusico.ico"
|
||||
|
||||
; 2. Copier docker-compose, config et script
|
||||
File ".env"
|
||||
File "docker-compose.yml"
|
||||
File "run.ps1"
|
||||
|
||||
; 3. Copier relay
|
||||
CreateDirectory "$INSTDIR\relay"
|
||||
SetOutPath "$INSTDIR\relay"
|
||||
File /r "relay\*.*"
|
||||
|
||||
; 4. Copier bitcoin
|
||||
CreateDirectory "$INSTDIR\bitcoin"
|
||||
SetOutPath "$INSTDIR\bitcoin"
|
||||
File /r "bitcoin\*.*"
|
||||
|
||||
; 5. Copier blindbit
|
||||
CreateDirectory "$INSTDIR\blindbit"
|
||||
SetOutPath "$INSTDIR\blindbit"
|
||||
File /r "blindbit\*.*"
|
||||
|
||||
; 6. Créer dossier de logs
|
||||
CreateDirectory "$INSTDIR\logs"
|
||||
|
||||
; 7. Raccourci Menu Démarrer pour lancer run.ps1
|
||||
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Lancer Kogus.lnk" \
|
||||
"$INSTDIR\run.ps1" "" \
|
||||
"$INSTDIR\kogusico.ico" 0
|
||||
|
||||
; 8. Lancement initial (installe/configure Docker si besoin) + capture code retour
|
||||
ExecWait '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\run.ps1"' $ExecCode
|
||||
|
||||
; 8bis. Si le script signale 3010 => reboot requis (WSL2/VM Platform, etc.)
|
||||
${If} $ExecCode = 3010
|
||||
MessageBox MB_ICONQUESTION|MB_YESNO "Un redémarrage est requis pour terminer l'installation de Kogus. Redémarrer maintenant ?" IDYES +2 IDNO +4
|
||||
SetRebootFlag true
|
||||
Reboot
|
||||
${EndIf}
|
||||
|
||||
; 9. Auto-démarrage Docker Desktop au login utilisateur
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" \
|
||||
"DockerDesktop" \
|
||||
'"$PROGRAMFILES\Docker\Docker\Docker Desktop.exe" --autostart'
|
||||
|
||||
; 10. Raccourci dans le dossier Démarrage pour relancer la stack Kogus
|
||||
CreateDirectory "$SMSTARTUP"
|
||||
CreateShortCut "$SMSTARTUP\Relancer Kogus Stack.lnk" \
|
||||
"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" \
|
||||
'-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\run.ps1"' \
|
||||
"$INSTDIR\kogusico.ico" 0
|
||||
|
||||
; 11. Générer l’uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
; Section : Désinstallation
|
||||
;--------------------------------
|
||||
Section "Uninstall"
|
||||
|
||||
; Arrêter la stack Docker
|
||||
nsExec::ExecToLog '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -Command "docker compose -f `"$INSTDIR\docker-compose.yml`" down"'
|
||||
|
||||
; Supprimer tous les fichiers et dossiers
|
||||
RMDir /r "$INSTDIR"
|
||||
|
||||
; Supprimer le raccourci Menu Démarrer
|
||||
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Lancer Kogus.lnk"
|
||||
RMDir "$SMPROGRAMS\${PRODUCT_NAME}"
|
||||
|
||||
; Supprimer le raccourci de démarrage et l’entrée registre
|
||||
Delete "$SMSTARTUP\Relancer Kogus Stack.lnk"
|
||||
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "DockerDesktop"
|
||||
|
||||
SectionEnd
|
||||
BIN
kogusico.ico
Normal file
BIN
kogusico.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
1
license.txt
Normal file
1
license.txt
Normal file
@ -0,0 +1 @@
|
||||
License Kogus
|
||||
2
logs/bitcoin/bitcoin.log
Executable file
2
logs/bitcoin/bitcoin.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for bitcoin
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service bitcoin started successfully
|
||||
2
logs/blindbit/blindbit.log
Executable file
2
logs/blindbit/blindbit.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for blindbit
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service blindbit started successfully
|
||||
1
logs/docker-compose.log
Executable file
1
logs/docker-compose.log
Executable file
@ -0,0 +1 @@
|
||||
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dlecoffre%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied
|
||||
2
logs/ihm_client/ihm_client.log
Executable file
2
logs/ihm_client/ihm_client.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for ihm_client
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service ihm_client started successfully
|
||||
2
logs/lecoffre-back/lecoffre-back.log
Executable file
2
logs/lecoffre-back/lecoffre-back.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for lecoffre-back
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service lecoffre-back started successfully
|
||||
2
logs/lecoffre-front/lecoffre-front.log
Executable file
2
logs/lecoffre-front/lecoffre-front.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for lecoffre-front
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service lecoffre-front started successfully
|
||||
2
logs/miner/miner.log
Executable file
2
logs/miner/miner.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for miner
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service miner started successfully
|
||||
0
logs/nginx/access.log
Executable file
0
logs/nginx/access.log
Executable file
0
logs/nginx/error.log
Executable file
0
logs/nginx/error.log
Executable file
2
logs/nginx/nginx.log
Executable file
2
logs/nginx/nginx.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for nginx
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service nginx started successfully
|
||||
2
logs/sdk_relay/sdk_relay.log
Executable file
2
logs/sdk_relay/sdk_relay.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for sdk_relay
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service sdk_relay started successfully
|
||||
2
logs/sdk_signer/sdk_signer.log
Executable file
2
logs/sdk_signer/sdk_signer.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for sdk_signer
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service sdk_signer started successfully
|
||||
2
logs/sdk_storage/sdk_storage.log
Executable file
2
logs/sdk_storage/sdk_storage.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for sdk_storage
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service sdk_storage started successfully
|
||||
2
logs/tor/tor.log
Executable file
2
logs/tor/tor.log
Executable file
@ -0,0 +1,2 @@
|
||||
Sun Sep 21 17:19:13 UTC 2025: Test log entry for tor
|
||||
Sun Sep 21 17:19:13 UTC 2025: Service tor started successfully
|
||||
18
miner/.env.backup
Normal file
18
miner/.env.backup
Normal file
@ -0,0 +1,18 @@
|
||||
# Variables d'environnement pour le miner Signet
|
||||
RPC_HOST="bitcoin"
|
||||
RPC_PORT="38332"
|
||||
WATCHONLY_WALLET="watchonly"
|
||||
MINING_WALLET="mining_mnemonic"
|
||||
MINER_TAG="lecoffre"
|
||||
SIGNET_CHALLENGE="0020341c43803863c252df326e73574a27d7e19322992061017b0dc893e2eab90821"
|
||||
SIGNET_MAGIC="b066463d"
|
||||
MINING_FINGERPRINT="86936c07"
|
||||
MINING_PATH_PREFIX="48'/1'/0'/2'"
|
||||
COINBASE_INDEX="0"
|
||||
COINBASE_ADDRESS=tb1q3389vh0k8e9fckjft2pxavnw5qy8xpyvfep8nrhfd07jag3z6pdqpuz82a
|
||||
BITCOIN_CONTAINER="bitcoin-signet"
|
||||
CHALLENGE_ALLPUBS="wsh(sortedmulti(1,[fca68db6/48'/1'/0'/2']tpubDFeV77XRwb9Lob5tBxtPUpZEu9fsj7xS3roiut4BBPzpVvGCT3SShGWksqUYLqKBrt7xeKmmmgSrgbRiffcoS5KPiqyDWk5Kgvxek52XnNV/0/*,[5df7e4b0/48'/1'/0'/2']tpubDF4ix3sjhgzM7iJVfTUVnx3HJ8kvkAvk36sPv5JmsmQcfPPK5KkHxJSgixZAdcYEsGcvHacm1hW4iLksGoTZocJozuaA2BTNp3GEvW432qu/0/*,[ef9d9ce6/48'/1'/0'/2']tpubDFecZkh4Bn5qutowNUC7huYGQeN9VRbNUauhAEN2ofVPat1zZ2yzYg7aULxsdzh79AFz7rBTVQeu2BsBay88XrFLc5diENj4ibizrwPNMbM/0/*,[86936c07/48'/1'/0'/2']tpubDFUys3FLzC4cEqZsTEJHwmSCbeXSTFdPvisp6uD2XhfZPkTJgwHJdVyUXYcfLRrikRxA2MpBaZWE5kZCtHFc15aVtktsHMrTijDjq2dKRGK/0/*,[7f7d263a/48'/1'/0'/2']tpubDEXXuskdCWjFnHuhjHYiWhcCGkz5YGUAj1THU6BRGhvrmwoKohttocoXTCCE9udffumcou7ZYUR5RNqwHW4kw7Jv2UXUUSKeKqJd9xGmSCs/0/*,[154159b3/48'/1'/0'/2']tpubDE3Nt1GGDjm9b2LNXCsszTgXwHDcpmXYCAsZzR9Uy9suicjmA6RqFezD5o8EWHk1vrztkPreHbYXKqGAdupKJNcKWYViKsQNMfr4uW8vcWq/0/*,[46d93da5/48'/1'/0'/2']tpubDF9n9yTw6Ck34SueKLCbv1djAhShkSoTG2m3kATNXKUi5nJwtJ6URJCg4M1je81fyabsX4t6F2itrQinMuu3cYLbpLbVQwWBUwYA8pPyKdZ/0/*,[d3c3bc8f/48'/1'/0'/2']tpubDFGmZ3HuCwoKMhMV7fMWAG2MBz3zWtvupca6oCys9KwAYKiYMB9NHGNq9qvVgPgDgpDLSiCqnp71f7WsV9N1cLkzsjqW9gxJF9VQ9oSZcj9/0/*,[8e236875/48'/1'/0'/2']tpubDFmB8SZte1hp77FdUn8kbHu7doJzWXaRLNoZ2r7V4x5aQY5dL9AaCmrvUNZSPYHJKeqto8roTvUpwWFazfxHEg5DvMq8br266uuD1JKieWj/0/*,[a3a9eb52/48'/1'/0'/2']tpubDE9uNJtEiu5UTMSEkK5egjKH6pXmw2KSAQQ6AbRqVngdHZuPHwxBeiofypHrGmG1WkvAtgjjn7gmPddzaz3ymQj9m3CDFLGEB6Ao4xqripj/0/*,[d03aacca/48'/1'/0'/2']tpubDFQ8YU5mdgP8kJcwhC9HPRQe6W83FNs3BMVTqq5S4ywanEqhdRkpp2cYpro3XRXKJPi8d1d3m4L2JXWdNQFfs31x37S3zfPpd7pwKEwLAm7/0/*,[ce3600ea/48'/1'/0'/2']tpubDFa2XbnHLcVbGM8NAq1soFJmJqtEeePkXAcWxHL71eWasMJujtrKWeQVp7NHQY5euJL2bFuBkVQHk4uoDrVRfCEELLxJhHuNouPquffbmUy/0/*,[fe898c92/48'/1'/0'/2']tpubDDzSj7jfCzXHnZjYNQV6MTK4iuztXr3SeXrQMWNwNiswTGJFdT9QGyjPWMoYcoPY9HCYbLdcMGiDokrWDWWZEhg8HpbgebenhJujvTzMeeN/0/*,[d33c583b/48'/1'/0'/2']tpubDFAeQcDpVPCyjLujPV1Li9LXJwqDvbmESE7wAMEABhesJM4Lhd8pqMgpDVSmf4cpdsfZbDWkhfyxeyG3SaWcB4MqEqhbseQ8mk41PPHb57T/0/*,[facf6b1f/48'/1'/0'/2']tpubDFBTNmh8E5RA9ehaZg9wCHWZvRMKNawQNmmd6V9SQb3NUW9s9y5iupMmDxAbBFFrytzotW9hu8REgqSFg26Q8mcvBjSAaVz9QcNzmCxRJdv/0/*))"
|
||||
RELAY_ADDRESS=tb1pdnczsn2gspwq02mc7j2pe50rn67xd56lz7tahcfhgtgj8gp40utq6w6d03
|
||||
REWARD_SPLIT_RATIO=0.5
|
||||
|
||||
MINING_XPRV="tprv8inwidD6qpNwMNY5ZadhYMn62d1WHvSVMRH2pPAj7RsAZGCY4YTiT1McMQSg5DAyijPBZ4HroX83vZQAevQkJSZUVH8kro9JnVbhTPBSAxL"
|
||||
18
miner/.env.exemple
Normal file
18
miner/.env.exemple
Normal file
@ -0,0 +1,18 @@
|
||||
# Variables d'environnement pour le miner Signet
|
||||
RPC_HOST="bitcoin"
|
||||
RPC_PORT="38332"
|
||||
WATCHONLY_WALLET="watchonly"
|
||||
MINING_WALLET="mining_mnemonic"
|
||||
MINER_TAG="lecoffre"
|
||||
SIGNET_CHALLENGE="0020341c43803863c252df326e73574a27d7e19322992061017b0dc893e2eab90821"
|
||||
SIGNET_MAGIC="b066463d"
|
||||
MINING_FINGERPRINT="86936c07"
|
||||
MINING_PATH_PREFIX="48'/1'/0'/2'"
|
||||
COINBASE_INDEX="0"
|
||||
COINBASE_ADDRESS=tb1q3389vh0k8e9fckjft2pxavnw5qy8xpyvfep8nrhfd07jag3z6pdqpuz82a
|
||||
BITCOIN_CONTAINER="bitcoin-signet"
|
||||
CHALLENGE_ALLPUBS="wsh(sortedmulti(1,[fca68db6/48'/1'/0'/2']tpubDFeV77XRwb9Lob5tBxtPUpZEu9fsj7xS3roiut4BBPzpVvGCT3SShGWksqUYLqKBrt7xeKmmmgSrgbRiffcoS5KPiqyDWk5Kgvxek52XnNV/0/*,[5df7e4b0/48'/1'/0'/2']tpubDF4ix3sjhgzM7iJVfTUVnx3HJ8kvkAvk36sPv5JmsmQcfPPK5KkHxJSgixZAdcYEsGcvHacm1hW4iLksGoTZocJozuaA2BTNp3GEvW432qu/0/*,[ef9d9ce6/48'/1'/0'/2']tpubDFecZkh4Bn5qutowNUC7huYGQeN9VRbNUauhAEN2ofVPat1zZ2yzYg7aULxsdzh79AFz7rBTVQeu2BsBay88XrFLc5diENj4ibizrwPNMbM/0/*,[86936c07/48'/1'/0'/2']tpubDFUys3FLzC4cEqZsTEJHwmSCbeXSTFdPvisp6uD2XhfZPkTJgwHJdVyUXYcfLRrikRxA2MpBaZWE5kZCtHFc15aVtktsHMrTijDjq2dKRGK/0/*,[7f7d263a/48'/1'/0'/2']tpubDEXXuskdCWjFnHuhjHYiWhcCGkz5YGUAj1THU6BRGhvrmwoKohttocoXTCCE9udffumcou7ZYUR5RNqwHW4kw7Jv2UXUUSKeKqJd9xGmSCs/0/*,[154159b3/48'/1'/0'/2']tpubDE3Nt1GGDjm9b2LNXCsszTgXwHDcpmXYCAsZzR9Uy9suicjmA6RqFezD5o8EWHk1vrztkPreHbYXKqGAdupKJNcKWYViKsQNMfr4uW8vcWq/0/*,[46d93da5/48'/1'/0'/2']tpubDF9n9yTw6Ck34SueKLCbv1djAhShkSoTG2m3kATNXKUi5nJwtJ6URJCg4M1je81fyabsX4t6F2itrQinMuu3cYLbpLbVQwWBUwYA8pPyKdZ/0/*,[d3c3bc8f/48'/1'/0'/2']tpubDFGmZ3HuCwoKMhMV7fMWAG2MBz3zWtvupca6oCys9KwAYKiYMB9NHGNq9qvVgPgDgpDLSiCqnp71f7WsV9N1cLkzsjqW9gxJF9VQ9oSZcj9/0/*,[8e236875/48'/1'/0'/2']tpubDFmB8SZte1hp77FdUn8kbHu7doJzWXaRLNoZ2r7V4x5aQY5dL9AaCmrvUNZSPYHJKeqto8roTvUpwWFazfxHEg5DvMq8br266uuD1JKieWj/0/*,[a3a9eb52/48'/1'/0'/2']tpubDE9uNJtEiu5UTMSEkK5egjKH6pXmw2KSAQQ6AbRqVngdHZuPHwxBeiofypHrGmG1WkvAtgjjn7gmPddzaz3ymQj9m3CDFLGEB6Ao4xqripj/0/*,[d03aacca/48'/1'/0'/2']tpubDFQ8YU5mdgP8kJcwhC9HPRQe6W83FNs3BMVTqq5S4ywanEqhdRkpp2cYpro3XRXKJPi8d1d3m4L2JXWdNQFfs31x37S3zfPpd7pwKEwLAm7/0/*,[ce3600ea/48'/1'/0'/2']tpubDFa2XbnHLcVbGM8NAq1soFJmJqtEeePkXAcWxHL71eWasMJujtrKWeQVp7NHQY5euJL2bFuBkVQHk4uoDrVRfCEELLxJhHuNouPquffbmUy/0/*,[fe898c92/48'/1'/0'/2']tpubDDzSj7jfCzXHnZjYNQV6MTK4iuztXr3SeXrQMWNwNiswTGJFdT9QGyjPWMoYcoPY9HCYbLdcMGiDokrWDWWZEhg8HpbgebenhJujvTzMeeN/0/*,[d33c583b/48'/1'/0'/2']tpubDFAeQcDpVPCyjLujPV1Li9LXJwqDvbmESE7wAMEABhesJM4Lhd8pqMgpDVSmf4cpdsfZbDWkhfyxeyG3SaWcB4MqEqhbseQ8mk41PPHb57T/0/*,[facf6b1f/48'/1'/0'/2']tpubDFBTNmh8E5RA9ehaZg9wCHWZvRMKNawQNmmd6V9SQb3NUW9s9y5iupMmDxAbBFFrytzotW9hu8REgqSFg26Q8mcvBjSAaVz9QcNzmCxRJdv/0/*))"
|
||||
RELAY_ADDRESS=tsp1qqfzxxz9fht9w8pg9q8z0zseynt2prapktyx4eylm4jlwg5mukqg95qnmm2va956rhggul4vspjda368nlzvufahx70n67z66a2vgs5lspytmuvty
|
||||
REWARD_SPLIT_RATIO=0.5
|
||||
|
||||
MINING_XPRV=
|
||||
49
miner/Dockerfile
Normal file
49
miner/Dockerfile
Normal file
@ -0,0 +1,49 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Installation des dépendances de base
|
||||
RUN apt-get update && apt-get upgrade -y && \
|
||||
apt-get install -y --fix-missing \
|
||||
ca-certificates curl jq git python3 python3-pip && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Création d'un utilisateur non-root
|
||||
RUN useradd -m -u 1000 appuser && \
|
||||
mkdir -p /app && chown -R appuser:appuser /app
|
||||
|
||||
# Installer bitcoin-cli (binaire officiel)
|
||||
RUN curl -L -o /tmp/bitcoin-cli.tar.gz https://bitcoincore.org/bin/bitcoin-core-26.2/bitcoin-26.2-x86_64-linux-gnu.tar.gz \
|
||||
&& mkdir -p /tmp/bitcoin-cli \
|
||||
&& tar -xzf /tmp/bitcoin-cli.tar.gz -C /tmp/bitcoin-cli --strip-components=2 bitcoin-26.2/bin/bitcoin-cli \
|
||||
&& mv /tmp/bitcoin-cli/bitcoin-cli /usr/local/bin/bitcoin-cli \
|
||||
&& chmod +x /usr/local/bin/bitcoin-cli \
|
||||
&& rm -rf /tmp/bitcoin-cli /tmp/bitcoin-cli.tar.gz
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Vendoriser test_framework depuis Bitcoin Core (pour le script signet/miner)
|
||||
RUN curl -L -o /tmp/bitcoin-core.tar.gz https://github.com/bitcoin/bitcoin/archive/refs/tags/v26.2.tar.gz \
|
||||
&& mkdir -p /tmp/bitcoin-core \
|
||||
&& tar -xzf /tmp/bitcoin-core.tar.gz -C /tmp/bitcoin-core --strip-components=1 \
|
||||
&& mkdir -p /app/test/functional \
|
||||
&& cp -r /tmp/bitcoin-core/test/functional/test_framework /app/test/functional/test_framework \
|
||||
&& rm -rf /tmp/bitcoin-core /tmp/bitcoin-core.tar.gz
|
||||
|
||||
COPY entrypoint.sh ./
|
||||
COPY signet_miner.py ./
|
||||
COPY signet/ ./signet/
|
||||
|
||||
RUN chmod +x /app/entrypoint.sh && \
|
||||
chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
VOLUME ["/bitcoin"]
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
56
miner/entrypoint.sh
Executable file
56
miner/entrypoint.sh
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BITCOIN_DIR=${BITCOIN_DIR:-/bitcoin}
|
||||
COOKIE_FILE=${COOKIE_FILE:-$BITCOIN_DIR/signet/.cookie}
|
||||
RPC_HOST=${RPC_HOST:-bitcoin}
|
||||
RPC_PORT=${RPC_PORT:-38332}
|
||||
POLL_INTERVAL=${POLL_INTERVAL:-5}
|
||||
WATCHONLY_WALLET=${WATCHONLY_WALLET:-watchonly}
|
||||
MINING_WALLET=${MINING_WALLET:-mining_mnemonic}
|
||||
MINER_TAG=${MINER_TAG:-lecoffre}
|
||||
|
||||
# Ajouter test_framework au PYTHONPATH
|
||||
export PYTHONPATH="/app/test/functional:${PYTHONPATH:-}"
|
||||
|
||||
if [ ! -f "$COOKIE_FILE" ]; then
|
||||
echo "Cookie introuvable: $COOKIE_FILE" >&2
|
||||
ls -la "$BITCOIN_DIR" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Variables attendues via miner/.env
|
||||
# COINBASE_ADDRESS est optionnel - si non défini, une adresse sera générée automatiquement
|
||||
|
||||
# Adresse du relay pour partager les rewards (optionnel)
|
||||
RELAY_ADDRESS="${RELAY_ADDRESS:-}"
|
||||
REWARD_SPLIT_RATIO="${REWARD_SPLIT_RATIO:-0.5}"
|
||||
|
||||
# Lancer le miner (les options globales doivent précéder la sous-commande)
|
||||
MINER_CMD=(
|
||||
python /app/signet/miner \
|
||||
--cli "bitcoin-cli -datadir=$BITCOIN_DIR -rpcconnect=$RPC_HOST -rpcport=$RPC_PORT -rpccookiefile=$COOKIE_FILE" \
|
||||
generate \
|
||||
--ongoing \
|
||||
--min-nbits \
|
||||
--WATCHONLY_WALLET "$WATCHONLY_WALLET" \
|
||||
--MINING_WALLET "$MINING_WALLET" \
|
||||
--MINER_TAG "$MINER_TAG"
|
||||
)
|
||||
|
||||
if [ -n "${COINBASE_ADDRESS:-}" ]; then
|
||||
MINER_CMD+=( --address "$COINBASE_ADDRESS" )
|
||||
elif [ -n "${COINBASE_DESCRIPTOR:-}" ]; then
|
||||
MINER_CMD+=( --descriptor "$COINBASE_DESCRIPTOR" )
|
||||
else
|
||||
# Générer automatiquement une adresse
|
||||
MINER_CMD+=( --address "auto" )
|
||||
fi
|
||||
|
||||
if [ -n "${RELAY_ADDRESS:-}" ]; then
|
||||
MINER_CMD+=( --relay-address "$RELAY_ADDRESS" )
|
||||
fi
|
||||
|
||||
MINER_CMD+=( --reward-split-ratio "$REWARD_SPLIT_RATIO" )
|
||||
|
||||
exec "${MINER_CMD[@]}"
|
||||
4
miner/miner.env
Normal file
4
miner/miner.env
Normal file
@ -0,0 +1,4 @@
|
||||
# Configuration du miner signet
|
||||
# COINBASE_ADDRESS= # Générer automatiquement
|
||||
RELAY_ADDRESS=tsp1qqd8k3twmuq3awxjmfukhma36j4la8gzsa8t0dgfms3cfglt2gkz6wqsqpd3d2q4quq59agtyfsr7gj9t07qt0nlrlrzgmhvpn5enfm76fud6sm0y
|
||||
REWARD_SPLIT_RATIO=0.5
|
||||
3
miner/requirements.txt
Normal file
3
miner/requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
requests==2.32.3
|
||||
python-bitcointx==1.1.2
|
||||
websockets==12.0
|
||||
83
miner/signet/README.md
Normal file
83
miner/signet/README.md
Normal file
@ -0,0 +1,83 @@
|
||||
Contents
|
||||
========
|
||||
This directory contains tools related to Signet, both for running a Signet yourself and for using one.
|
||||
|
||||
getcoins.py
|
||||
===========
|
||||
|
||||
A script to call a faucet to get Signet coins.
|
||||
|
||||
Syntax: `getcoins.py [-h|--help] [-c|--cmd=<bitcoin-cli path>] [-f|--faucet=<faucet URL>] [-a|--addr=<signet bech32 address>] [-p|--password=<faucet password>] [--] [<bitcoin-cli args>]`
|
||||
|
||||
* `--cmd` lets you customize the bitcoin-cli path. By default it will look for it in the PATH
|
||||
* `--faucet` lets you specify which faucet to use; the faucet is assumed to be compatible with https://github.com/kallewoof/bitcoin-faucet
|
||||
* `--addr` lets you specify a Signet address; by default, the address must be a bech32 address. This and `--cmd` above complement each other (i.e. you do not need `bitcoin-cli` if you use `--addr`)
|
||||
* `--password` lets you specify a faucet password; this is handy if you are in a classroom and set up your own faucet for your students; (above faucet does not limit by IP when password is enabled)
|
||||
|
||||
If using the default network, invoking the script with no arguments should be sufficient under normal
|
||||
circumstances, but if multiple people are behind the same IP address, the faucet will by default only
|
||||
accept one claim per day. See `--password` above.
|
||||
|
||||
miner
|
||||
=====
|
||||
|
||||
You will first need to pick a difficulty target. Since signet chains are primarily protected by a signature rather than proof of work, there is no need to spend as much energy as possible mining, however you may wish to choose to spend more time than the absolute minimum. The calibrate subcommand can be used to pick a target appropriate for your hardware, eg:
|
||||
|
||||
cd src/
|
||||
MINER="../contrib/signet/miner"
|
||||
GRIND="./bitcoin-util grind"
|
||||
$MINER calibrate --grind-cmd="$GRIND"
|
||||
nbits=1e00f403 for 25s average mining time
|
||||
|
||||
It defaults to estimating an nbits value resulting in 25s average time to find a block, but the --seconds parameter can be used to pick a different target, or the --nbits parameter can be used to estimate how long it will take for a given difficulty.
|
||||
|
||||
To mine the first block in your custom chain, you can run:
|
||||
|
||||
CLI="./bitcoin-cli -conf=mysignet.conf"
|
||||
ADDR=$($CLI -signet getnewaddress)
|
||||
NBITS=1e00f403
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS
|
||||
|
||||
This will mine a single block with a backdated timestamp designed to allow 100 blocks to be mined as quickly as possible, so that it is possible to do transactions.
|
||||
|
||||
Adding the --ongoing parameter will then cause the signet miner to create blocks indefinitely. It will pick the time between blocks so that difficulty is adjusted to match the provided --nbits value.
|
||||
|
||||
$MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=$NBITS --ongoing
|
||||
|
||||
Other options
|
||||
-------------
|
||||
|
||||
The --debug and --quiet options are available to control how noisy the signet miner's output is. Note that the --debug, --quiet and --cli parameters must all appear before the subcommand (generate, calibrate, etc) if used.
|
||||
|
||||
Instead of specifying --ongoing, you can specify --max-blocks=N to mine N blocks and stop.
|
||||
|
||||
The --set-block-time option is available to manually move timestamps forward or backward (subject to the rules that blocktime must be greater than mediantime, and dates can't be more than two hours in the future). It can only be used when mining a single block (ie, not when using --ongoing or --max-blocks greater than 1).
|
||||
|
||||
Instead of using a single address, a ranged descriptor may be provided via the --descriptor parameter, with the reward for the block at height H being sent to the H'th address generated from the descriptor.
|
||||
|
||||
Instead of calculating a specific nbits value, --min-nbits can be specified instead, in which case the minimum signet difficulty will be targeted. Signet's minimum difficulty corresponds to --nbits=1e0377ae.
|
||||
|
||||
By default, the signet miner mines blocks at fixed intervals with minimal variation. If you want blocks to appear more randomly, as they do in mainnet, specify the --poisson option.
|
||||
|
||||
Using the --multiminer parameter allows mining to be distributed amongst multiple miners. For example, if you have 3 miners and want to share blocks between them, specify --multiminer=1/3 on one, --multiminer=2/3 on another, and --multiminer=3/3 on the last one. If you want one to do 10% of blocks and two others to do 45% each, --multiminer=1-10/100 on the first, and --multiminer=11-55 and --multiminer=56-100 on the others. Note that which miner mines which block is determined by the previous block hash, so occasional runs of one miner doing many blocks in a row is to be expected.
|
||||
|
||||
When --multiminer is used, if a miner is down and does not mine a block within five minutes of when it is due, the other miners will automatically act as redundant backups ensuring the chain does not halt. The --backup-delay parameter can be used to change how long a given miner waits, allowing one to be the primary backup (after five minutes) and another to be the secondary backup (after six minutes, eg).
|
||||
|
||||
The --standby-delay parameter can be used to make a backup miner that only mines if a block doesn't arrive on time. This can be combined with --multiminer if desired. Setting --standby-delay also prevents the first block from being mined immediately.
|
||||
|
||||
Advanced usage
|
||||
--------------
|
||||
|
||||
The process generate follows internally is to get a block template, convert that into a PSBT, sign the PSBT, move the signature from the signed PSBT into the block template's coinbase, grind proof of work for the block, and then submit the block to the network.
|
||||
|
||||
These steps can instead be done explicitly:
|
||||
|
||||
$CLI -signet getblocktemplate '{"rules": ["signet","segwit"]}' |
|
||||
$MINER --cli="$CLI" genpsbt --address="$ADDR" |
|
||||
$CLI -signet -stdin walletprocesspsbt |
|
||||
jq -r .psbt |
|
||||
$MINER --cli="$CLI" solvepsbt --grind-cmd="$GRIND" |
|
||||
$CLI -signet -stdin submitblock
|
||||
|
||||
This is intended to allow you to replace part of the pipeline for further experimentation (eg, to sign the block with a hardware wallet).
|
||||
|
||||
158
miner/signet/getcoins.py
Normal file
158
miner/signet/getcoins.py
Normal file
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2020-2021 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import requests
|
||||
import subprocess
|
||||
import sys
|
||||
import xml.etree.ElementTree
|
||||
|
||||
DEFAULT_GLOBAL_FAUCET = 'https://signetfaucet.com/claim'
|
||||
DEFAULT_GLOBAL_CAPTCHA = 'https://signetfaucet.com/captcha'
|
||||
GLOBAL_FIRST_BLOCK_HASH = '00000086d6b2636cb2a392d45edc4ec544a10024d30141c9adf4bfd9de533b53'
|
||||
|
||||
# braille unicode block
|
||||
BASE = 0x2800
|
||||
BIT_PER_PIXEL = [
|
||||
[0x01, 0x08],
|
||||
[0x02, 0x10],
|
||||
[0x04, 0x20],
|
||||
[0x40, 0x80],
|
||||
]
|
||||
BW = 2
|
||||
BH = 4
|
||||
|
||||
# imagemagick or compatible fork (used for converting SVG)
|
||||
CONVERT = 'convert'
|
||||
|
||||
class PPMImage:
|
||||
'''
|
||||
Load a PPM image (Pillow-ish API).
|
||||
'''
|
||||
def __init__(self, f):
|
||||
if f.readline() != b'P6\n':
|
||||
raise ValueError('Invalid ppm format: header')
|
||||
line = f.readline()
|
||||
(width, height) = (int(x) for x in line.rstrip().split(b' '))
|
||||
if f.readline() != b'255\n':
|
||||
raise ValueError('Invalid ppm format: color depth')
|
||||
data = f.read(width * height * 3)
|
||||
stride = width * 3
|
||||
self.size = (width, height)
|
||||
self._grid = [[tuple(data[stride * y + 3 * x:stride * y + 3 * (x + 1)]) for x in range(width)] for y in range(height)]
|
||||
|
||||
def getpixel(self, pos):
|
||||
return self._grid[pos[1]][pos[0]]
|
||||
|
||||
def print_image(img, threshold=128):
|
||||
'''Print black-and-white image to terminal in braille unicode characters.'''
|
||||
x_blocks = (img.size[0] + BW - 1) // BW
|
||||
y_blocks = (img.size[1] + BH - 1) // BH
|
||||
|
||||
for yb in range(y_blocks):
|
||||
line = []
|
||||
for xb in range(x_blocks):
|
||||
ch = BASE
|
||||
for y in range(BH):
|
||||
for x in range(BW):
|
||||
try:
|
||||
val = img.getpixel((xb * BW + x, yb * BH + y))
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if val[0] < threshold:
|
||||
ch |= BIT_PER_PIXEL[y][x]
|
||||
line.append(chr(ch))
|
||||
print(''.join(line))
|
||||
|
||||
parser = argparse.ArgumentParser(description='Script to get coins from a faucet.', epilog='You may need to start with double-dash (--) when providing bitcoin-cli arguments.')
|
||||
parser.add_argument('-c', '--cmd', dest='cmd', default='bitcoin-cli', help='bitcoin-cli command to use')
|
||||
parser.add_argument('-f', '--faucet', dest='faucet', default=DEFAULT_GLOBAL_FAUCET, help='URL of the faucet')
|
||||
parser.add_argument('-g', '--captcha', dest='captcha', default=DEFAULT_GLOBAL_CAPTCHA, help='URL of the faucet captcha, or empty if no captcha is needed')
|
||||
parser.add_argument('-a', '--addr', dest='addr', default='', help='Bitcoin address to which the faucet should send')
|
||||
parser.add_argument('-p', '--password', dest='password', default='', help='Faucet password, if any')
|
||||
parser.add_argument('-n', '--amount', dest='amount', default='0.001', help='Amount to request (0.001-0.1, default is 0.001)')
|
||||
parser.add_argument('-i', '--imagemagick', dest='imagemagick', default=CONVERT, help='Path to imagemagick convert utility')
|
||||
parser.add_argument('bitcoin_cli_args', nargs='*', help='Arguments to pass on to bitcoin-cli (default: -signet)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.bitcoin_cli_args == []:
|
||||
args.bitcoin_cli_args = ['-signet']
|
||||
|
||||
|
||||
def bitcoin_cli(rpc_command_and_params):
|
||||
argv = [args.cmd] + args.bitcoin_cli_args + rpc_command_and_params
|
||||
try:
|
||||
return subprocess.check_output(argv).strip().decode()
|
||||
except FileNotFoundError:
|
||||
raise SystemExit(f"The binary {args.cmd} could not be found")
|
||||
except subprocess.CalledProcessError:
|
||||
cmdline = ' '.join(argv)
|
||||
raise SystemExit(f"-----\nError while calling {cmdline} (see output above).")
|
||||
|
||||
|
||||
if args.faucet.lower() == DEFAULT_GLOBAL_FAUCET:
|
||||
# Get the hash of the block at height 1 of the currently active signet chain
|
||||
curr_signet_hash = bitcoin_cli(['getblockhash', '1'])
|
||||
if curr_signet_hash != GLOBAL_FIRST_BLOCK_HASH:
|
||||
raise SystemExit('The global faucet cannot be used with a custom Signet network. Please use the global signet or setup your custom faucet to use this functionality.\n')
|
||||
else:
|
||||
# For custom faucets, don't request captcha by default.
|
||||
if args.captcha == DEFAULT_GLOBAL_CAPTCHA:
|
||||
args.captcha = ''
|
||||
|
||||
if args.addr == '':
|
||||
# get address for receiving coins
|
||||
args.addr = bitcoin_cli(['getnewaddress', 'faucet', 'bech32'])
|
||||
|
||||
data = {'address': args.addr, 'password': args.password, 'amount': args.amount}
|
||||
|
||||
# Store cookies
|
||||
# for debugging: print(session.cookies.get_dict())
|
||||
session = requests.Session()
|
||||
|
||||
if args.captcha != '': # Retrieve a captcha
|
||||
try:
|
||||
res = session.get(args.captcha)
|
||||
res.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise SystemExit(f"Unexpected error when contacting faucet: {e}")
|
||||
|
||||
# Size limitation
|
||||
svg = xml.etree.ElementTree.fromstring(res.content)
|
||||
if svg.attrib.get('width') != '150' or svg.attrib.get('height') != '50':
|
||||
raise SystemExit("Captcha size doesn't match expected dimensions 150x50")
|
||||
|
||||
# Convert SVG image to PPM, and load it
|
||||
try:
|
||||
rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except FileNotFoundError:
|
||||
raise SystemExit(f"The binary {args.imagemagick} could not be found. Please make sure ImageMagick (or a compatible fork) is installed and that the correct path is specified.")
|
||||
|
||||
img = PPMImage(io.BytesIO(rv.stdout))
|
||||
|
||||
# Terminal interaction
|
||||
print_image(img)
|
||||
print(f"Captcha from URL {args.captcha}")
|
||||
data['captcha'] = input('Enter captcha: ')
|
||||
|
||||
try:
|
||||
res = session.post(args.faucet, data=data)
|
||||
except:
|
||||
raise SystemExit(f"Unexpected error when contacting faucet: {sys.exc_info()[0]}")
|
||||
|
||||
# Display the output as per the returned status code
|
||||
if res:
|
||||
# When the return code is in between 200 and 400 i.e. successful
|
||||
print(res.text)
|
||||
elif res.status_code == 404:
|
||||
print('The specified faucet URL does not exist. Please check for any server issues/typo.')
|
||||
elif res.status_code == 429:
|
||||
print('The script does not allow for repeated transactions as the global faucet is rate-limitied to 1 request/IP/day. You can access the faucet website to get more coins manually')
|
||||
else:
|
||||
print(f'Returned Error Code {res.status_code}\n{res.text}\n')
|
||||
print('Please check the provided arguments for their validity and/or any possible typo.')
|
||||
989
miner/signet/miner
Normal file
989
miner/signet/miner
Normal file
@ -0,0 +1,989 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2020 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
import subprocess
|
||||
import asyncio, websockets
|
||||
from hashlib import sha256
|
||||
|
||||
from io import BytesIO
|
||||
from random import uniform
|
||||
from decimal import Decimal
|
||||
|
||||
PATH_BASE_CONTRIB_SIGNET = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
|
||||
PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNET, "..", "..", "test", "functional"))
|
||||
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
|
||||
|
||||
|
||||
from test_framework.blocktools import WITNESS_COMMITMENT_HEADER, script_BIP34_coinbase_height # noqa: E402
|
||||
from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_hex, deser_string, hash256, ser_compact_size, ser_string, ser_uint256, tx_from_hex, uint256_from_str # noqa: E402
|
||||
from test_framework.script import CScript, CScriptOp # noqa: E402
|
||||
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s %(levelname)s %(message)s',
|
||||
level=logging.INFO,
|
||||
datefmt='%Y-%m-%d %H:%M:%S')
|
||||
|
||||
SIGNET_HEADER = b"\xec\xc7\xda\xa2"
|
||||
PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
|
||||
RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
|
||||
CC_URL = 'ws://localhost:9823/websocket'
|
||||
|
||||
|
||||
def json_dumps(obj, **k):
|
||||
def hook(dd):
|
||||
if isinstance(dd, Decimal):
|
||||
return float(dd)
|
||||
if hasattr(dd, 'strftime'):
|
||||
return str(dd) # isoformat
|
||||
logging.error("Unhandled JSON type: %r" % dd)
|
||||
raise TypeError
|
||||
|
||||
k['default'] = hook
|
||||
|
||||
return json.dumps(obj, **k)
|
||||
|
||||
def message(action, *args):
|
||||
return json_dumps(dict(action=action, args=args))
|
||||
|
||||
POLICY = {
|
||||
'never_log': False,
|
||||
'must_log': False,
|
||||
'priv_over_ux': True,
|
||||
'boot_to_hsm': "123456",
|
||||
'period': None,
|
||||
'set_sl': None,
|
||||
'allow_sl': None,
|
||||
'rules': [
|
||||
{
|
||||
"whitelist": "",
|
||||
"per_period": None,
|
||||
"max_amount": None,
|
||||
"users": "",
|
||||
"min_users": "all",
|
||||
"local_conf": False,
|
||||
"wallet": None
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# #### some helpers that could go into test_framework
|
||||
|
||||
# like from_hex, but without the hex part
|
||||
def FromBinary(cls, stream):
|
||||
"""deserialize a binary stream (or bytes object) into an object"""
|
||||
# handle bytes object by turning it into a stream
|
||||
was_bytes = isinstance(stream, bytes)
|
||||
if was_bytes:
|
||||
stream = BytesIO(stream)
|
||||
obj = cls()
|
||||
obj.deserialize(stream)
|
||||
if was_bytes:
|
||||
assert len(stream.read()) == 0
|
||||
return obj
|
||||
|
||||
class PSBTMap:
|
||||
"""Class for serializing and deserializing PSBT maps"""
|
||||
|
||||
def __init__(self, map=None):
|
||||
self.map = map if map is not None else {}
|
||||
|
||||
def deserialize(self, f):
|
||||
m = {}
|
||||
while True:
|
||||
k = deser_string(f)
|
||||
if len(k) == 0:
|
||||
break
|
||||
v = deser_string(f)
|
||||
if len(k) == 1:
|
||||
k = k[0]
|
||||
assert k not in m
|
||||
m[k] = v
|
||||
self.map = m
|
||||
|
||||
def serialize(self):
|
||||
m = b""
|
||||
for k,v in self.map.items():
|
||||
if isinstance(k, int) and 0 <= k and k <= 255:
|
||||
k = bytes([k])
|
||||
m += ser_compact_size(len(k)) + k
|
||||
m += ser_compact_size(len(v)) + v
|
||||
m += b"\x00"
|
||||
return m
|
||||
|
||||
class PSBT:
|
||||
"""Class for serializing and deserializing PSBTs"""
|
||||
|
||||
def __init__(self):
|
||||
self.g = PSBTMap()
|
||||
self.i = []
|
||||
self.o = []
|
||||
self.tx = None
|
||||
|
||||
def deserialize(self, f):
|
||||
assert f.read(5) == b"psbt\xff"
|
||||
self.g = FromBinary(PSBTMap, f)
|
||||
assert 0 in self.g.map
|
||||
self.tx = FromBinary(CTransaction, self.g.map[0])
|
||||
self.i = [FromBinary(PSBTMap, f) for _ in self.tx.vin]
|
||||
self.o = [FromBinary(PSBTMap, f) for _ in self.tx.vout]
|
||||
return self
|
||||
|
||||
def serialize(self):
|
||||
assert isinstance(self.g, PSBTMap)
|
||||
assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
|
||||
assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
|
||||
assert 0 in self.g.map
|
||||
tx = FromBinary(CTransaction, self.g.map[0])
|
||||
assert len(tx.vin) == len(self.i)
|
||||
assert len(tx.vout) == len(self.o)
|
||||
|
||||
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
|
||||
return b"psbt\xff" + b"".join(psbt)
|
||||
|
||||
def to_base64(self):
|
||||
return base64.b64encode(self.serialize()).decode("utf8")
|
||||
|
||||
@classmethod
|
||||
def from_base64(cls, b64psbt):
|
||||
return FromBinary(cls, base64.b64decode(b64psbt))
|
||||
|
||||
# #####
|
||||
|
||||
def create_coinbase(height, value, spk, miner_tag=''):
|
||||
cb = CTransaction()
|
||||
scriptsig = bytes(script_BIP34_coinbase_height(height))
|
||||
if miner_tag is not None:
|
||||
scriptsig = CScript(scriptsig + CScriptOp.encode_op_pushdata(miner_tag.encode()))
|
||||
else:
|
||||
scriptsig = CScript(scriptsig)
|
||||
cb.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptsig, 0xffffffff)]
|
||||
|
||||
# Utiliser une seule sortie pour le miner (le relay recevra des fonds via une transaction normale)
|
||||
cb.vout = [CTxOut(value, spk)]
|
||||
logging.info(f"Coinbase reward: {value} sat to miner")
|
||||
|
||||
return cb
|
||||
|
||||
def get_witness_script(witness_root, witness_nonce):
|
||||
commitment = uint256_from_str(hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce)))
|
||||
return b"\x6a" + CScriptOp.encode_op_pushdata(WITNESS_COMMITMENT_HEADER + ser_uint256(commitment))
|
||||
|
||||
def signet_txs(block, challenge):
|
||||
# assumes signet solution has not been added yet so does not need
|
||||
# to be removed
|
||||
|
||||
txs = block.vtx[:]
|
||||
txs[0] = CTransaction(txs[0])
|
||||
txs[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER)
|
||||
hashes = []
|
||||
for tx in txs:
|
||||
tx.rehash()
|
||||
hashes.append(ser_uint256(tx.sha256))
|
||||
mroot = block.get_merkle_root(hashes)
|
||||
|
||||
sd = b""
|
||||
sd += struct.pack("<i", block.nVersion)
|
||||
sd += ser_uint256(block.hashPrevBlock)
|
||||
sd += ser_uint256(mroot)
|
||||
sd += struct.pack("<I", block.nTime)
|
||||
|
||||
to_spend = CTransaction()
|
||||
to_spend.nVersion = 0
|
||||
to_spend.nLockTime = 0
|
||||
to_spend.vin = [CTxIn(COutPoint(0, 0xFFFFFFFF), b"\x00" + CScriptOp.encode_op_pushdata(sd), 0)]
|
||||
to_spend.vout = [CTxOut(0, challenge)]
|
||||
to_spend.rehash()
|
||||
|
||||
spend = CTransaction()
|
||||
spend.nVersion = 0
|
||||
spend.nLockTime = 0
|
||||
spend.vin = [CTxIn(COutPoint(to_spend.sha256, 0), b"", 0)]
|
||||
spend.vout = [CTxOut(0, b"\x6a")]
|
||||
|
||||
return spend, to_spend
|
||||
|
||||
def do_createpsbt(block, signme, spendme):
|
||||
psbt = PSBT()
|
||||
psbt.g = PSBTMap( {0: signme.serialize(),
|
||||
PSBT_SIGNET_BLOCK: block.serialize()
|
||||
} )
|
||||
psbt.i = [ PSBTMap( {0: spendme.serialize(),
|
||||
3: bytes([1,0,0,0])})
|
||||
]
|
||||
psbt.o = [ PSBTMap() ]
|
||||
return psbt.to_base64()
|
||||
|
||||
def do_decode_psbt(b64psbt):
|
||||
psbt = PSBT.from_base64(b64psbt)
|
||||
|
||||
assert len(psbt.tx.vin) == 1
|
||||
assert len(psbt.tx.vout) == 1
|
||||
assert PSBT_SIGNET_BLOCK in psbt.g.map
|
||||
|
||||
scriptSig = psbt.i[0].map.get(7, b"")
|
||||
scriptWitness = psbt.i[0].map.get(8, b"\x00")
|
||||
|
||||
return FromBinary(CBlock, psbt.g.map[PSBT_SIGNET_BLOCK]), ser_string(scriptSig) + scriptWitness
|
||||
|
||||
def finish_block(block, signet_solution, grind_cmd):
|
||||
block.vtx[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER + signet_solution)
|
||||
block.vtx[0].rehash()
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
if grind_cmd is None:
|
||||
block.solve()
|
||||
else:
|
||||
headhex = CBlockHeader.serialize(block).hex()
|
||||
cmd = grind_cmd.split(" ") + [headhex]
|
||||
newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
|
||||
newhead = from_hex(CBlockHeader(), newheadhex.decode('utf8'))
|
||||
block.nNonce = newhead.nNonce
|
||||
block.rehash()
|
||||
return block
|
||||
|
||||
def generate_psbt(tmpl, reward_spk, *, blocktime=None, miner_tag='', relay_spk=None, reward_split_ratio=0.5):
|
||||
signet_spk = tmpl["signet_challenge"]
|
||||
signet_spk_bin = bytes.fromhex(signet_spk)
|
||||
|
||||
cbtx = create_coinbase(height=tmpl["height"], value=tmpl["coinbasevalue"], spk=reward_spk, miner_tag=miner_tag)
|
||||
cbtx.vin[0].nSequence = 2**32-2
|
||||
cbtx.rehash()
|
||||
|
||||
block = CBlock()
|
||||
block.nVersion = tmpl["version"]
|
||||
block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
|
||||
block.nTime = tmpl["curtime"] if blocktime is None else blocktime
|
||||
if block.nTime < tmpl["mintime"]:
|
||||
block.nTime = tmpl["mintime"]
|
||||
block.nBits = int(tmpl["bits"], 16)
|
||||
block.nNonce = 0
|
||||
block.vtx = [cbtx] + [tx_from_hex(t["data"]) for t in tmpl["transactions"]]
|
||||
|
||||
witnonce = 0
|
||||
witroot = block.calc_witness_merkle_root()
|
||||
cbwit = CTxInWitness()
|
||||
cbwit.scriptWitness.stack = [ser_uint256(witnonce)]
|
||||
block.vtx[0].wit.vtxinwit = [cbwit]
|
||||
block.vtx[0].vout.append(CTxOut(0, get_witness_script(witroot, witnonce)))
|
||||
|
||||
signme, spendme = signet_txs(block, signet_spk_bin)
|
||||
|
||||
return do_createpsbt(block, signme, spendme)
|
||||
|
||||
def get_reward_address(args, height):
|
||||
if args.address is not None:
|
||||
if args.address == "auto":
|
||||
# Générer automatiquement une adresse
|
||||
try:
|
||||
addr = json.loads(args.bcli(f"-rpcwallet={args.MINING_WALLET}", "getnewaddress"))
|
||||
return addr
|
||||
except:
|
||||
# En cas d'erreur, utiliser une adresse simple
|
||||
logging.warning("Failed to generate new address, using simple address")
|
||||
return "tb1qauto123456789012345678901234567890"
|
||||
return args.address
|
||||
|
||||
if args.descriptor is None:
|
||||
try:
|
||||
addr = json.loads(args.bcli(f"-rpcwallet={args.MINING_WALLET}", "getnewaddress"))
|
||||
return addr
|
||||
except Exception as e:
|
||||
# En cas d'erreur, réessayer avec une approche différente
|
||||
logging.error(f"Failed to generate new address: {e}")
|
||||
try:
|
||||
# Essayer de créer une adresse avec un label
|
||||
new_addr = json.loads(args.bcli(f"-rpcwallet={args.MINING_WALLET}", "getnewaddress", "miner"))
|
||||
logging.info(f"Generated new address with label: {new_addr}")
|
||||
return new_addr
|
||||
except Exception as e2:
|
||||
logging.error(f"Failed to generate address with label: {e2}")
|
||||
# En dernier recours, utiliser une adresse simple
|
||||
return "tb1qauto123456789012345678901234567890"
|
||||
|
||||
if '*' not in args.descriptor:
|
||||
addr = json.loads(args.bcli("deriveaddresses", args.descriptor))[0]
|
||||
args.address = addr
|
||||
return addr
|
||||
|
||||
remove = [k for k in args.derived_addresses.keys() if k+20 <= height]
|
||||
for k in remove:
|
||||
del args.derived_addresses[k]
|
||||
|
||||
addr = args.derived_addresses.get(height, None)
|
||||
if addr is None:
|
||||
addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20)))
|
||||
addr = addrs[0]
|
||||
for k, a in enumerate(addrs):
|
||||
args.derived_addresses[height+k] = a
|
||||
|
||||
return addr
|
||||
|
||||
def get_reward_addr_spk(args, height):
|
||||
#assert args.address is not None or args.descriptor is not None
|
||||
|
||||
if hasattr(args, "reward_spk"):
|
||||
return args.address, args.reward_spk
|
||||
|
||||
reward_addr = get_reward_address(args, height)
|
||||
if args.signer != None:
|
||||
wallet = args.WATCHONLY_WALLET
|
||||
else:
|
||||
wallet = args.MINING_WALLET
|
||||
print("%s", reward_addr)
|
||||
|
||||
try:
|
||||
reward_spk = bytes.fromhex(json.loads(args.bcli(f"-rpcwallet={wallet}", "getaddressinfo", reward_addr))["scriptPubKey"])
|
||||
except:
|
||||
# Si l'adresse n'est pas dans le wallet, générer une nouvelle adresse
|
||||
logging.warning(f"Address {reward_addr} not in wallet, generating new address")
|
||||
try:
|
||||
new_addr = json.loads(args.bcli(f"-rpcwallet={wallet}", "getnewaddress"))
|
||||
reward_spk = bytes.fromhex(json.loads(args.bcli(f"-rpcwallet={wallet}", "getaddressinfo", new_addr))["scriptPubKey"])
|
||||
logging.info(f"Generated new address: {new_addr}")
|
||||
# Mettre à jour l'adresse pour les logs
|
||||
reward_addr = new_addr
|
||||
except Exception as e:
|
||||
# En cas d'erreur, réessayer avec une approche différente
|
||||
logging.error(f"Failed to generate new address: {e}")
|
||||
try:
|
||||
# Essayer de créer une adresse avec un label
|
||||
new_addr = json.loads(args.bcli(f"-rpcwallet={wallet}", "getnewaddress", "miner"))
|
||||
reward_spk = bytes.fromhex(json.loads(args.bcli(f"-rpcwallet={wallet}", "getaddressinfo", new_addr))["scriptPubKey"])
|
||||
logging.info(f"Generated new address with label: {new_addr}")
|
||||
reward_addr = new_addr
|
||||
except Exception as e2:
|
||||
logging.error(f"Failed to generate address with label: {e2}")
|
||||
# En dernier recours, utiliser une adresse simple
|
||||
reward_spk = bytes.fromhex("0014" + "0" * 40)
|
||||
|
||||
if args.address is not None:
|
||||
# will always be the same, so cache
|
||||
args.reward_spk = reward_spk
|
||||
|
||||
return reward_addr, reward_spk
|
||||
|
||||
def do_genpsbt(args):
|
||||
tmpl = json.load(sys.stdin)
|
||||
_, reward_spk = get_reward_addr_spk(args, tmpl["height"])
|
||||
|
||||
# Obtenir l'adresse et le scriptPubKey du relay
|
||||
relay_spk = None
|
||||
if hasattr(args, 'relay_address') and args.relay_address:
|
||||
try:
|
||||
relay_spk = bytes.fromhex(json.loads(args.bcli(f"-rpcwallet={args.WATCHONLY_WALLET}", "getaddressinfo", args.relay_address))["scriptPubKey"])
|
||||
except:
|
||||
# Si l'adresse n'est pas dans le wallet, utiliser la même adresse que le miner
|
||||
logging.warning(f"Relay address {args.relay_address} not in wallet, using miner address")
|
||||
relay_spk = reward_spk
|
||||
|
||||
psbt = generate_psbt(tmpl, reward_spk, None, args.MINER_TAG, relay_spk, getattr(args, 'reward_split_ratio', 0.5))
|
||||
print(psbt)
|
||||
|
||||
def do_solvepsbt(args):
|
||||
block, signet_solution = do_decode_psbt(sys.stdin.read())
|
||||
block = finish_block(block, signet_solution, args.grind_cmd)
|
||||
print(block.serialize().hex())
|
||||
|
||||
def nbits_to_target(nbits):
|
||||
shift = (nbits >> 24) & 0xff
|
||||
return (nbits & 0x00ffffff) * 2**(8*(shift - 3))
|
||||
|
||||
def target_to_nbits(target):
|
||||
tstr = "{0:x}".format(target)
|
||||
if len(tstr) < 6:
|
||||
tstr = ("000000"+tstr)[-6:]
|
||||
if len(tstr) % 2 != 0:
|
||||
tstr = "0" + tstr
|
||||
if int(tstr[0],16) >= 0x8:
|
||||
# avoid "negative"
|
||||
tstr = "00" + tstr
|
||||
fix = int(tstr[:6], 16)
|
||||
sz = len(tstr)//2
|
||||
if tstr[6:] != "0"*(sz*2-6):
|
||||
fix += 1
|
||||
|
||||
return int("%02x%06x" % (sz,fix), 16)
|
||||
|
||||
def seconds_to_hms(s):
|
||||
if s == 0:
|
||||
return "0s"
|
||||
neg = (s < 0)
|
||||
if neg:
|
||||
s = -s
|
||||
out = ""
|
||||
if s % 60 > 0:
|
||||
out = "%ds" % (s % 60)
|
||||
s //= 60
|
||||
if s % 60 > 0:
|
||||
out = "%dm%s" % (s % 60, out)
|
||||
s //= 60
|
||||
if s > 0:
|
||||
out = "%dh%s" % (s, out)
|
||||
if neg:
|
||||
out = "-" + out
|
||||
return out
|
||||
|
||||
def send_to_relay(args, miner_addr, height):
|
||||
"""Envoie des fonds au relay après avoir miné un bloc"""
|
||||
if not hasattr(args, 'relay_address') or not args.relay_address:
|
||||
return
|
||||
|
||||
relay_addr = args.relay_address
|
||||
split_ratio = getattr(args, 'reward_split_ratio', 0.5)
|
||||
|
||||
# Attendre que le bloc soit confirmé
|
||||
time.sleep(5)
|
||||
|
||||
try:
|
||||
# Vérifier le solde du wallet
|
||||
balance = json.loads(args.bcli(f"-rpcwallet={args.MINING_WALLET}", "getbalance"))
|
||||
if balance < 0.001: # Minimum 0.001 BTC
|
||||
logging.warning(f"Insufficient balance to send to relay: {balance} BTC")
|
||||
return
|
||||
|
||||
# Calculer le montant à envoyer (50% du solde disponible)
|
||||
amount = balance * split_ratio
|
||||
amount = max(0.001, min(amount, 0.1)) # Entre 0.001 et 0.1 BTC
|
||||
|
||||
# Envoyer les fonds au relay
|
||||
txid = json.loads(args.bcli(f"-rpcwallet={args.MINING_WALLET}", "sendtoaddress", relay_addr, str(amount)))
|
||||
logging.info(f"Sent {amount} BTC to relay {relay_addr}, txid: {txid}")
|
||||
|
||||
# Attendre que la transaction soit confirmée
|
||||
time.sleep(2)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to send funds to relay: {e}")
|
||||
|
||||
def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson):
|
||||
# strategy:
|
||||
# 1) work out how far off our desired target we are
|
||||
# 2) cap it to a factor of 4 since that's the best we can do in a single retarget period
|
||||
# 3) use that to work out the desired average interval in this retarget period
|
||||
# 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by
|
||||
# 5) cap the resulting interval between 1 second and 1 hour to avoid extremes
|
||||
|
||||
INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug
|
||||
|
||||
current_target = nbits_to_target(last_nbits)
|
||||
retarget_factor = ultimate_target / current_target
|
||||
retarget_factor = max(0.25, min(retarget_factor, 4.0))
|
||||
|
||||
avg_interval = INTERVAL * retarget_factor
|
||||
|
||||
if do_poisson:
|
||||
det_rand = int(last_hash[-8:], 16) * 2**-32
|
||||
this_interval_variance = -math.log1p(-det_rand)
|
||||
else:
|
||||
this_interval_variance = uniform(0.95,1.05)
|
||||
|
||||
this_interval = avg_interval * this_interval_variance
|
||||
this_interval = max(1, min(this_interval, 3600))
|
||||
|
||||
return this_interval
|
||||
|
||||
def next_block_is_mine(last_hash, my_blocks):
|
||||
det_rand = int(last_hash[-16:-8], 16)
|
||||
return my_blocks[0] <= (det_rand % my_blocks[2]) < my_blocks[1]
|
||||
|
||||
def do_generate(args):
|
||||
if args.max_blocks is not None:
|
||||
if args.ongoing:
|
||||
logging.error("Cannot specify both --ongoing and --max-blocks")
|
||||
return 1
|
||||
if args.max_blocks < 1:
|
||||
logging.error("N must be a positive integer")
|
||||
return 1
|
||||
max_blocks = args.max_blocks
|
||||
elif args.ongoing:
|
||||
max_blocks = None
|
||||
else:
|
||||
max_blocks = 1
|
||||
|
||||
if args.set_block_time is not None and max_blocks != 1:
|
||||
logging.error("Cannot specify --ongoing or --max-blocks > 1 when using --set-block-time")
|
||||
return 1
|
||||
if args.set_block_time is not None and args.set_block_time < 0:
|
||||
args.set_block_time = time.time()
|
||||
logging.info("Treating negative block time as current time (%d)" % (args.set_block_time))
|
||||
|
||||
if args.min_nbits:
|
||||
if args.nbits is not None:
|
||||
logging.error("Cannot specify --nbits and --min-nbits")
|
||||
return 1
|
||||
args.nbits = "1e0377ae"
|
||||
logging.info("Using nbits=%s" % (args.nbits))
|
||||
|
||||
if args.set_block_time is None:
|
||||
if args.nbits is None or len(args.nbits) != 8:
|
||||
logging.error("Must specify --nbits (use calibrate command to determine value)")
|
||||
return 1
|
||||
|
||||
if args.multiminer is None:
|
||||
my_blocks = (0,1,1)
|
||||
else:
|
||||
if not args.ongoing:
|
||||
logging.error("Cannot specify --multiminer without --ongoing")
|
||||
return 1
|
||||
m = RE_MULTIMINER.match(args.multiminer)
|
||||
if m is None:
|
||||
logging.error("--multiminer argument must be k/m or j-k/m")
|
||||
return 1
|
||||
start,_,stop,total = m.groups()
|
||||
if stop is None:
|
||||
stop = start
|
||||
start, stop, total = map(int, (start, stop, total))
|
||||
if stop < start or start <= 0 or total < stop or total == 0:
|
||||
logging.error("Inconsistent values for --multiminer")
|
||||
return 1
|
||||
my_blocks = (start-1, stop, total)
|
||||
|
||||
if args.MINER_TAG is not None:
|
||||
args.MINER_TAG = args.MINER_TAG.encode('utf-8')
|
||||
else:
|
||||
args.MINER_TAG = "default".encode('utf-8')
|
||||
|
||||
ultimate_target = nbits_to_target(int(args.nbits,16))
|
||||
|
||||
mined_blocks = 0
|
||||
bestheader = {"hash": None}
|
||||
lastheader = None
|
||||
while max_blocks is None or mined_blocks < max_blocks:
|
||||
|
||||
# current status?
|
||||
bci = json.loads(args.bcli("getblockchaininfo"))
|
||||
|
||||
if bestheader["hash"] != bci["bestblockhash"]:
|
||||
bestheader = json.loads(args.bcli("getblockheader", bci["bestblockhash"]))
|
||||
|
||||
if lastheader is None:
|
||||
lastheader = bestheader["hash"]
|
||||
elif bestheader["hash"] != lastheader:
|
||||
next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson)
|
||||
next_delta += bestheader["time"] - time.time()
|
||||
next_is_mine = next_block_is_mine(bestheader["hash"], my_blocks)
|
||||
logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup"))
|
||||
lastheader = bestheader["hash"]
|
||||
|
||||
# when is the next block due to be mined?
|
||||
now = time.time()
|
||||
if args.set_block_time is not None:
|
||||
logging.debug("Setting start time to %d", args.set_block_time)
|
||||
mine_time = args.set_block_time
|
||||
action_time = now
|
||||
is_mine = True
|
||||
elif bestheader["height"] == 0:
|
||||
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
|
||||
time_delta *= 100 # 100 blocks
|
||||
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
|
||||
mine_time = now - time_delta
|
||||
action_time = now
|
||||
is_mine = True
|
||||
else:
|
||||
time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
|
||||
mine_time = bestheader["time"] + time_delta
|
||||
|
||||
is_mine = next_block_is_mine(bci["bestblockhash"], my_blocks)
|
||||
|
||||
action_time = mine_time
|
||||
if not is_mine:
|
||||
action_time += args.backup_delay
|
||||
|
||||
if args.standby_delay > 0:
|
||||
action_time += args.standby_delay
|
||||
elif mined_blocks == 0:
|
||||
# for non-standby, always mine immediately on startup,
|
||||
# even if the next block shouldn't be ours
|
||||
action_time = now
|
||||
|
||||
# don't want fractional times so round down
|
||||
mine_time = int(mine_time)
|
||||
action_time = int(action_time)
|
||||
|
||||
# can't mine a block 2h in the future; 1h55m for some safety
|
||||
action_time = max(action_time, mine_time - 6900)
|
||||
|
||||
# ready to go? otherwise sleep and check for new block
|
||||
if now < action_time:
|
||||
sleep_for = min(action_time - now, 60)
|
||||
if mine_time < now:
|
||||
# someone else might have mined the block,
|
||||
# so check frequently, so we don't end up late
|
||||
# mining the next block if it's ours
|
||||
sleep_for = min(20, sleep_for)
|
||||
minestr = "mine" if is_mine else "backup"
|
||||
logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(mine_time - now), minestr))
|
||||
time.sleep(sleep_for)
|
||||
continue
|
||||
|
||||
# gbt
|
||||
tmpl = json.loads(args.bcli("getblocktemplate", '{"rules":["signet","segwit"]}'))
|
||||
if tmpl["previousblockhash"] != bci["bestblockhash"]:
|
||||
logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"])
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
logging.debug("GBT template: %s", tmpl)
|
||||
|
||||
if tmpl["mintime"] > mine_time:
|
||||
logging.info("Updating block time from %d to %d", mine_time, tmpl["mintime"])
|
||||
mine_time = tmpl["mintime"]
|
||||
if mine_time > now:
|
||||
logging.error("GBT mintime is in the future: %d is %d seconds later than %d", mine_time, (mine_time-now), now)
|
||||
return 1
|
||||
|
||||
# address for reward
|
||||
reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"])
|
||||
|
||||
# Obtenir l'adresse et le scriptPubKey du relay
|
||||
relay_spk = None
|
||||
if hasattr(args, 'relay_address') and args.relay_address:
|
||||
try:
|
||||
relay_spk = bytes.fromhex(json.loads(args.bcli(f"-rpcwallet={args.WATCHONLY_WALLET}", "getaddressinfo", args.relay_address))["scriptPubKey"])
|
||||
except:
|
||||
# Si l'adresse n'est pas dans le wallet, créer une adresse simple
|
||||
logging.warning(f"Relay address {args.relay_address} not in wallet, using simple address")
|
||||
# Pour l'instant, on utilise la même adresse que le miner
|
||||
relay_spk = reward_spk
|
||||
|
||||
# mine block
|
||||
logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(mine_time-bestheader["time"]), mine_time, is_mine)
|
||||
mined_blocks += 1
|
||||
psbt = generate_psbt(tmpl, reward_spk, blocktime=mine_time, relay_spk=relay_spk, reward_split_ratio=getattr(args, 'reward_split_ratio', 0.5))
|
||||
logging.info(f"psbt pre-processing: {psbt}")
|
||||
input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8')
|
||||
if args.signer == "coldcard":
|
||||
psbt = json.loads(args.bcli("-stdin", f"-rpcwallet={args.WATCHONLY_WALLET}", "walletprocesspsbt", input=input_stream))['psbt']
|
||||
try:
|
||||
psbt_hash = asyncio.get_event_loop().run_until_complete(coldcard_upload_psbt(psbt))
|
||||
except Exception as e:
|
||||
logging.error("Waiting 5s before trying again.")
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
try:
|
||||
psbt_signed = asyncio.get_event_loop().run_until_complete(coldcard_sign_psbt(psbt_hash))
|
||||
except Exception as e:
|
||||
logging.error("Please check your keys.")
|
||||
return 1
|
||||
|
||||
try:
|
||||
assert('local_download' in psbt_signed)
|
||||
except AssertionError as e:
|
||||
logging.error("Didn't receive signed psbt")
|
||||
logging.error(f"Received: {psbt_signed}")
|
||||
logging.error("Waiting 5s before trying again.")
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
input_stream = os.linesep.join([psbt_signed['local_download']['data'], "false"]).encode('utf8')
|
||||
try:
|
||||
final_psbt = json.loads(args.bcli("-stdin", "finalizepsbt", input=input_stream))
|
||||
except Exception as e:
|
||||
logging.error(f"Core can't finalize psbt: {e}")
|
||||
return 1
|
||||
if not final_psbt.get("complete",False):
|
||||
logging.error("finalizepsbt return: %s" % (final_psbt,))
|
||||
sys.stderr.write("PSBT finalization failed\n")
|
||||
return 1
|
||||
|
||||
final_psbt = final_psbt["psbt"]
|
||||
else:
|
||||
psbt_signed = json.loads(args.bcli("-stdin", f"-rpcwallet={args.MINING_WALLET}", "walletprocesspsbt", input=input_stream))
|
||||
if not psbt_signed.get("complete",False):
|
||||
logging.debug("Generated PSBT: %s" % (psbt,))
|
||||
sys.stderr.write("PSBT signing failed\n")
|
||||
return 1
|
||||
final_psbt = psbt_signed["psbt"]
|
||||
block, signet_solution = do_decode_psbt(final_psbt)
|
||||
block = finish_block(block, signet_solution, args.grind_cmd)
|
||||
|
||||
# submit block
|
||||
r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8'))
|
||||
|
||||
# report
|
||||
bstr = "block" if is_mine else "backup block"
|
||||
|
||||
next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson)
|
||||
next_delta += block.nTime - time.time()
|
||||
next_is_mine = next_block_is_mine(block.hash, my_blocks)
|
||||
|
||||
logging.debug("Block hash %s payout to %s", block.hash, reward_addr)
|
||||
logging.info("Mined %s at height %d; next in %s (%s)", bstr, tmpl["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup"))
|
||||
if r != "":
|
||||
logging.warning("submitblock returned %s for height %d hash %s", r, tmpl["height"], block.hash)
|
||||
|
||||
# Envoyer des fonds au relay si configuré
|
||||
if hasattr(args, 'relay_address') and args.relay_address and getattr(args, 'reward_split_ratio', 0) > 0:
|
||||
try:
|
||||
send_to_relay(args, reward_addr, tmpl["height"])
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to send funds to relay: {e}")
|
||||
|
||||
lastheader = block.hash
|
||||
|
||||
async def coldcard_upload_psbt(psbt):
|
||||
async with websockets.connect(CC_URL) as ws:
|
||||
psbt_bin = base64.b64decode(psbt)
|
||||
psbt_hash = sha256(psbt_bin).digest()
|
||||
payload = message("upload_psbt", len(psbt_bin), psbt_hash.hex(), psbt)
|
||||
await ws.send(payload)
|
||||
async for msg in ws:
|
||||
try:
|
||||
r = json.loads(msg)
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(f"{e}: {msg} is not valid json")
|
||||
continue
|
||||
|
||||
if 'update_status' in r:
|
||||
logging.info(f"Received update: {r['update_status']}")
|
||||
elif 'success' in r:
|
||||
break
|
||||
|
||||
return psbt_hash.hex()
|
||||
|
||||
async def coldcard_sign_psbt(psbt_hash):
|
||||
async with websockets.connect(CC_URL) as ws:
|
||||
payload = message("submit_psbt", psbt_hash, False, False, True)
|
||||
await ws.send(payload)
|
||||
|
||||
async for msg in ws:
|
||||
try:
|
||||
r = json.loads(msg)
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(f"{e}: {msg} is not valid json")
|
||||
continue
|
||||
|
||||
if "update_status" in r:
|
||||
continue
|
||||
elif 'local_download' in r:
|
||||
break
|
||||
|
||||
return r
|
||||
|
||||
def do_calibrate(args):
|
||||
if args.nbits is not None and args.seconds is not None:
|
||||
sys.stderr.write("Can only specify one of --nbits or --seconds\n")
|
||||
return 1
|
||||
if args.nbits is not None and len(args.nbits) != 8:
|
||||
sys.stderr.write("Must specify 8 hex digits for --nbits\n")
|
||||
return 1
|
||||
|
||||
TRIALS = 600 # gets variance down pretty low
|
||||
TRIAL_BITS = 0x1e3ea75f # takes about 5m to do 600 trials
|
||||
|
||||
header = CBlockHeader()
|
||||
header.nBits = TRIAL_BITS
|
||||
targ = nbits_to_target(header.nBits)
|
||||
|
||||
start = time.time()
|
||||
count = 0
|
||||
for i in range(TRIALS):
|
||||
header.nTime = i
|
||||
header.nNonce = 0
|
||||
headhex = header.serialize().hex()
|
||||
cmd = args.grind_cmd.split(" ") + [headhex]
|
||||
newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
|
||||
|
||||
avg = (time.time() - start) * 1.0 / TRIALS
|
||||
|
||||
if args.nbits is not None:
|
||||
want_targ = nbits_to_target(int(args.nbits,16))
|
||||
want_time = avg*targ/want_targ
|
||||
else:
|
||||
want_time = args.seconds if args.seconds is not None else 25
|
||||
want_targ = int(targ*(avg/want_time))
|
||||
|
||||
print("nbits=%08x for %ds average mining time" % (target_to_nbits(want_targ), want_time))
|
||||
return 0
|
||||
|
||||
def do_setup(args):
|
||||
if args.signer == "coldcard":
|
||||
sys.exit(asyncio.get_event_loop().run_until_complete(coldcard_setup()))
|
||||
else:
|
||||
logging.error("Unknown option")
|
||||
sys.exit(1)
|
||||
|
||||
async def coldcard_status() -> dict:
|
||||
logging.info("Checking that server is up and connected to Coldcard")
|
||||
status = {}
|
||||
while 1:
|
||||
try:
|
||||
async with websockets.connect(CC_URL) as ws:
|
||||
payload = message("get_info")
|
||||
await ws.send(payload)
|
||||
|
||||
async for msg in ws:
|
||||
try:
|
||||
r = json.loads(msg)
|
||||
except json.JSONDecodeError:
|
||||
logging.info(f"{msg} is not valid json")
|
||||
return 1
|
||||
|
||||
try:
|
||||
if 'status' in r:
|
||||
logging.info("Got status")
|
||||
logging.info(f"{r}")
|
||||
status = r['status']
|
||||
break
|
||||
elif 'update_status' in r:
|
||||
# we ignore this as there's not all the details there
|
||||
logging.info("Received update_status, ignoring")
|
||||
continue
|
||||
elif 'error' in r:
|
||||
logging.error(f"{r['error']}")
|
||||
return 1
|
||||
else:
|
||||
logging.info(f"{r}")
|
||||
logging.info("Still waiting for Coldcard connection")
|
||||
continue
|
||||
except Exception as e:
|
||||
logging.error(f"{e}")
|
||||
return 1
|
||||
except ConnectionError as e:
|
||||
logging.error("Server seems to be offline. Trying again.")
|
||||
await asyncio.sleep(10)
|
||||
continue
|
||||
|
||||
logging.info(f"{status}")
|
||||
|
||||
return status
|
||||
|
||||
|
||||
async def coldcard_setup():
|
||||
status = await coldcard_status()
|
||||
|
||||
logging.info(f"{status}")
|
||||
if not status['hsm']['active']:
|
||||
logging.info("Entering Coldcard HSM setup")
|
||||
logging.info("Please follow the instructions on the coldcard")
|
||||
async with websockets.connect(CC_URL) as ws:
|
||||
payload = message("submit_policy", json_dumps(POLICY), False)
|
||||
await ws.send(payload)
|
||||
|
||||
async for msg in ws:
|
||||
try:
|
||||
r = json.loads(msg)
|
||||
except json.JSONDecodeError:
|
||||
logging.info(f"{msg} is not valid json")
|
||||
return 1
|
||||
|
||||
try:
|
||||
if 'update_status' in r:
|
||||
if r['update_status']['hsm']['active']:
|
||||
logging.info("HSM is now activated. Proceeding.")
|
||||
break
|
||||
else:
|
||||
logging.info(f"Received update: {r['update_status']['hsm']}")
|
||||
except KeyError:
|
||||
logging.error(f"Received unexpected message: {r}")
|
||||
continue
|
||||
except Exception as e:
|
||||
logging.error(f"{e}")
|
||||
return 1
|
||||
elif not status['sl_loaded']:
|
||||
while 1:
|
||||
status = await coldcard_status()
|
||||
if status['sl_loaded']:
|
||||
logging.info("Coldcard in HSM mode. Proceeding...")
|
||||
break
|
||||
await asyncio.sleep(10)
|
||||
else:
|
||||
logging.info("Coldcard already in HSM mode. Proceeding...")
|
||||
|
||||
return 0
|
||||
|
||||
def bitcoin_cli(basecmd, args, **kwargs):
|
||||
cmd = basecmd + ["-signet"] + args
|
||||
logging.debug("Calling bitcoin-cli: %r", cmd)
|
||||
out = subprocess.run(cmd, stdout=subprocess.PIPE, **kwargs, check=True).stdout
|
||||
if isinstance(out, bytes):
|
||||
out = out.decode('utf8')
|
||||
return out.strip()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--cli", default="bitcoin-cli", type=str, help="bitcoin-cli command")
|
||||
parser.add_argument("--debug", action="store_true", help="Print debugging info")
|
||||
parser.add_argument("--quiet", action="store_true", help="Only print warnings/errors")
|
||||
|
||||
cmds = parser.add_subparsers(help="sub-commands")
|
||||
genpsbt = cmds.add_parser("genpsbt", help="Generate a block PSBT for signing")
|
||||
genpsbt.set_defaults(fn=do_genpsbt)
|
||||
genpsbt.add_argument('--MINER_TAG', required=True, help='Miner tag')
|
||||
|
||||
solvepsbt = cmds.add_parser("solvepsbt", help="Solve a signed block PSBT")
|
||||
solvepsbt.set_defaults(fn=do_solvepsbt)
|
||||
|
||||
setup = cmds.add_parser("setup", help="Setup HSM for coldcard")
|
||||
setup.set_defaults(fn=do_setup)
|
||||
setup.add_argument("--signer", default=None, type=str, help="Who's signing blocks (default: Bitcoin Core)")
|
||||
|
||||
generate = cmds.add_parser("generate", help="Mine blocks")
|
||||
generate.set_defaults(fn=do_generate)
|
||||
generate.add_argument("--ongoing", action="store_true", help="Keep mining blocks")
|
||||
generate.add_argument("--max-blocks", default=None, type=int, help="Max blocks to mine (default=1)")
|
||||
generate.add_argument("--set-block-time", default=None, type=int, help="Set block time (unix timestamp)")
|
||||
generate.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)")
|
||||
generate.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)")
|
||||
generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times")
|
||||
generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)")
|
||||
generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)")
|
||||
generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)")
|
||||
generate.add_argument("--signer", default=None, type=str, help="Who's signing blocks (default: Bitcoin Core)")
|
||||
generate.add_argument('--WATCHONLY_WALLET', required=True, help='Watch-only wallet')
|
||||
generate.add_argument('--MINING_WALLET', required=True, help='Mining wallet')
|
||||
generate.add_argument('--MINER_TAG', required=True, help='Miner tag')
|
||||
|
||||
calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty")
|
||||
calibrate.set_defaults(fn=do_calibrate)
|
||||
calibrate.add_argument("--nbits", type=str, default=None)
|
||||
calibrate.add_argument("--seconds", type=int, default=None)
|
||||
|
||||
for sp in [genpsbt, generate]:
|
||||
sp.add_argument("--address", default=None, type=str, help="Address for block reward payment")
|
||||
sp.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment")
|
||||
sp.add_argument("--relay-address", default=None, type=str, help="Address for relay reward payment (50% of block reward)")
|
||||
sp.add_argument("--reward-split-ratio", default=0.5, type=float, help="Ratio of block reward to send to relay (default: 0.5)")
|
||||
|
||||
for sp in [solvepsbt, generate, calibrate]:
|
||||
sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work")
|
||||
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
args.bcli = lambda *a, input=b"", **kwargs: bitcoin_cli(args.cli.split(" "), list(a), input=input, **kwargs)
|
||||
|
||||
if hasattr(args, "address") and hasattr(args, "descriptor"):
|
||||
if args.address is None and args.descriptor is None:
|
||||
sys.stderr.write("Must specify --address or --descriptor\n")
|
||||
return 1
|
||||
elif args.address is not None and args.descriptor is not None:
|
||||
sys.stderr.write("Only specify one of --address or --descriptor\n")
|
||||
return 1
|
||||
args.derived_addresses = {}
|
||||
|
||||
if args.debug:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
elif args.quiet:
|
||||
logging.getLogger().setLevel(logging.WARNING)
|
||||
else:
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
if hasattr(args, "fn"):
|
||||
return args.fn(args)
|
||||
else:
|
||||
logging.error("Must specify command")
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
78
miner/signet_miner.py
Normal file
78
miner/signet_miner.py
Normal file
@ -0,0 +1,78 @@
|
||||
import argparse
|
||||
import base64
|
||||
import http.client
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
def rpc_call(host: str, port: int, cookie_path: str, method: str, params):
|
||||
with open(cookie_path, 'r', encoding='utf-8') as f:
|
||||
cookie = f.read().strip()
|
||||
auth = base64.b64encode(cookie.encode()).decode()
|
||||
|
||||
conn = http.client.HTTPConnection(host, port, timeout=30)
|
||||
payload = json.dumps({"jsonrpc": "1.0", "id": "miner", "method": method, "params": params})
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Basic {auth}"}
|
||||
conn.request("POST", "/", payload, headers)
|
||||
resp = conn.getresponse()
|
||||
body = resp.read()
|
||||
if resp.status != 200:
|
||||
raise RuntimeError(f"RPC HTTP {resp.status}: {body.decode(errors='ignore')}")
|
||||
data = json.loads(body)
|
||||
if data.get("error"):
|
||||
raise RuntimeError(str(data["error"]))
|
||||
return data["result"]
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument('--cookie', required=True)
|
||||
p.add_argument('--rpc-host', default='bitcoin')
|
||||
p.add_argument('--rpc-port', type=int, default=38332)
|
||||
p.add_argument('--poll-interval', type=int, default=5)
|
||||
args = p.parse_args()
|
||||
|
||||
# Paramètres via env
|
||||
challenge = os.environ.get('SIGNET_CHALLENGE', '')
|
||||
xprv = os.environ.get('SIGNET_MINER_XPRV', '')
|
||||
derivation = os.environ.get('DERIVATION_PATH', "48'/1'/0'/2'/0/0")
|
||||
coinbase_addr = os.environ.get('COINBASE_ADDRESS', '')
|
||||
|
||||
if not challenge:
|
||||
raise SystemExit('SIGNET_CHALLENGE non défini')
|
||||
if not xprv:
|
||||
print('Avertissement: SIGNET_MINER_XPRV non défini (mode lecture gbt uniquement)')
|
||||
if not coinbase_addr:
|
||||
raise SystemExit('COINBASE_ADDRESS non défini')
|
||||
|
||||
print('Miner signet: host=%s port=%d' % (args.rpc_host, args.rpc_port), flush=True)
|
||||
print('Challenge:', challenge, flush=True)
|
||||
print('Derivation:', derivation, flush=True)
|
||||
print('Coinbase address:', coinbase_addr, flush=True)
|
||||
|
||||
try:
|
||||
bh = rpc_call(args.rpc_host, args.rpc_port, args.cookie, 'getblockcount', [])
|
||||
print('Hauteur actuelle:', bh, flush=True)
|
||||
except Exception as e:
|
||||
print('Erreur RPC initiale:', e, flush=True)
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Inclure la règle signet comme demandé par bitcoind en signet
|
||||
tmpl = rpc_call(
|
||||
args.rpc_host,
|
||||
args.rpc_port,
|
||||
args.cookie,
|
||||
'getblocktemplate',
|
||||
[{"rules": ["segwit", "signet"]}]
|
||||
)
|
||||
print('Template: height=%s nTx=%s' % (tmpl.get('height'), len(tmpl.get('transactions', []))), flush=True)
|
||||
# TODO: construire coinbase (coinbase_addr), header, signer selon le challenge signet puis submitblock
|
||||
except Exception as e:
|
||||
print('Erreur getblocktemplate:', e, flush=True)
|
||||
time.sleep(args.poll_interval)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
78
miner/tools/import_signet_descriptors.sh
Executable file
78
miner/tools/import_signet_descriptors.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Fichier d'env introuvable: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
|
||||
cli() {
|
||||
docker exec "$BITCOIN_CONTAINER" sh -lc "bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf -signet $*"
|
||||
}
|
||||
|
||||
cli_stdin() {
|
||||
local subcmd="$1"; shift || true
|
||||
docker exec -i "$BITCOIN_CONTAINER" sh -lc "bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf -signet -stdin $subcmd"
|
||||
}
|
||||
|
||||
extract_checksum() {
|
||||
sed -n 's/.*"checksum"[[:space:]]*:[[:space:]]*"\([a-z0-9]\{8\}\)".*/\1/p' | tr -d '\n'
|
||||
}
|
||||
|
||||
wallet_is_descriptors() {
|
||||
cli -rpcwallet="$MINING_WALLET" getwalletinfo 2>/dev/null | grep -q '"descriptors"[[:space:]]*:[[:space:]]*true'
|
||||
}
|
||||
|
||||
wallet_exists() {
|
||||
cli -rpcwallet="$MINING_WALLET" getwalletinfo >/dev/null 2>&1
|
||||
}
|
||||
|
||||
ensure_descriptors_wallet() {
|
||||
local wallet_path="/home/bitcoin/.bitcoin/signet/wallets/$MINING_WALLET"
|
||||
if wallet_exists && wallet_is_descriptors; then
|
||||
return 0
|
||||
fi
|
||||
cli -rpcwallet="$MINING_WALLET" unloadwallet "$MINING_WALLET" >/dev/null 2>&1 || true
|
||||
docker exec "$BITCOIN_CONTAINER" sh -lc "if [ -d '$wallet_path' ]; then rm -rf '$wallet_path'; fi"
|
||||
cli createwallet "$MINING_WALLET" false true "" true true true false >/dev/null
|
||||
}
|
||||
|
||||
ensure_descriptors_wallet
|
||||
|
||||
DESC_EXT_ORIG="wsh(multi(1,[$MINING_FINGERPRINT/$MINING_PATH_PREFIX]$MINING_XPRV/0/*))"
|
||||
DESC_INT_ORIG="wsh(multi(1,[$MINING_FINGERPRINT/$MINING_PATH_PREFIX]$MINING_XPRV/1/*))"
|
||||
|
||||
CS_EXT=$(printf '%s' "$DESC_EXT_ORIG" | cli_stdin getdescriptorinfo | extract_checksum)
|
||||
CS_INT=$(printf '%s' "$DESC_INT_ORIG" | cli_stdin getdescriptorinfo | extract_checksum)
|
||||
DESC_EXT="$DESC_EXT_ORIG#$CS_EXT"
|
||||
DESC_INT="$DESC_INT_ORIG#$CS_INT"
|
||||
|
||||
PAYLOAD_MINER=$(printf '[{"desc":"%s","timestamp":"now","active":true,"range":[0,1000]},{"desc":"%s","timestamp":"now","active":true,"internal":true,"range":[0,1000]}]' "$DESC_EXT" "$DESC_INT")
|
||||
printf '%s\n' "$PAYLOAD_MINER" | cli_stdin importdescriptors | cat
|
||||
|
||||
# Adresse coinbase: si vide, utiliser getnewaddress du wallet (garanti p2wsh multisig)
|
||||
if [ -z "${COINBASE_ADDRESS:-}" ]; then
|
||||
ADDR=$(cli -rpcwallet="$MINING_WALLET" getnewaddress coinbase bech32)
|
||||
tmpfile=$(mktemp)
|
||||
awk -v addr="$ADDR" 'BEGIN{updated=0} /^COINBASE_ADDRESS=/{print "COINBASE_ADDRESS=" addr; updated=1; next} {print} END{if(updated==0) print "COINBASE_ADDRESS=" addr}' "$ENV_FILE" > "$tmpfile"
|
||||
mv "$tmpfile" "$ENV_FILE"
|
||||
echo "COINBASE_ADDRESS=$ADDR"
|
||||
else
|
||||
echo "COINBASE_ADDRESS=$COINBASE_ADDRESS"
|
||||
fi
|
||||
|
||||
if [ -n "${CHALLENGE_ALLPUBS:-}" ]; then
|
||||
CHALL_PRIV_ORIG=$(printf '%s' "$CHALLENGE_ALLPUBS" | sed -E "s#\[$MINING_FINGERPRINT/$MINING_PATH_PREFIX\]tpub[[:alnum:]]+#[$MINING_FINGERPRINT/$MINING_PATH_PREFIX]$MINING_XPRV#g")
|
||||
CS_CHALL=$(printf '%s' "$CHALL_PRIV_ORIG" | cli_stdin getdescriptorinfo | extract_checksum)
|
||||
CHALL_PRIV="$CHALL_PRIV_ORIG#$CS_CHALL"
|
||||
PAYLOAD_CHAL=$(printf '[{"desc":"%s","timestamp":"now","active":false,"range":[0,1000]}]' "$CHALL_PRIV")
|
||||
printf '%s\n' "$PAYLOAD_CHAL" | cli_stdin importdescriptors | cat
|
||||
fi
|
||||
|
||||
echo "Import terminé."
|
||||
75
miner/tools/priv_key.json
Normal file
75
miner/tools/priv_key.json
Normal file
@ -0,0 +1,75 @@
|
||||
[
|
||||
{
|
||||
"Mnemonic": "tower keen enrich problem essence east plastic lounge merge sand increase company",
|
||||
"xprv": "tprv8inwidD6qpNwMNY5ZadhYMn62d1WHvSVMRH2pPAj7RsAZGCY4YTiT1McMQSg5DAyijPBZ4HroX83vZQAevQkJSZUVH8kro9JnVbhTPBSAxL",
|
||||
"wallet descriptor": "wsh(multi(1,[86936c07/48'/1'/0'/2']tpubDFUys3FLzC4cEqZsTEJHwmSCbeXSTFdPvisp6uD2XhfZPkTJgwHJdVyUXYcfLRrikRxA2MpBaZWE5kZCtHFc15aVtktsHMrTijDjq2dKRGK/0/*))#pslna7dm",
|
||||
},
|
||||
{
|
||||
"Mnemonic": "deer trust ceiling youth brass rapid scout cradle better clap spike morning",
|
||||
"xprv": "tprv8iNgodqVZKJgEFGhmoouPYPAj7EzaqjqToGcdZGUTVcDpu8YSvvhmoppYp7vWG2LR2SrF93AVYZGgG9bCzuQs1xqwJ2QW8hRwtEVdyUofuH",
|
||||
"wallet descriptor": "wsh(multi(1,[5df7e4b0/48'/1'/0'/2']tpubDF4ix3sjhgzM7iJVfTUVnx3HJ8kvkAvk36sPv5JmsmQcfPPK5KkHxJSgixZAdcYEsGcvHacm1hW4iLksGoTZocJozuaA2BTNp3GEvW432qu/0/*))#4ma3uvl0"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "control load guard error caution hundred main adjust happy infant safe brother",
|
||||
"xprv": "tprv8hTsDtqzaXPoZtQSrfR4HKfAXo1qmh8Xb6oJt5PY5WtET5ecfZ8bUEBoofVrH6s8STU586QHhYSppmQ3n1nvsZ6p5VaKu4MHxsvzUf1gg2D",
|
||||
"wallet descriptor": "wsh(multi(1,[a3a9eb52/48'/1'/0'/2']tpubDE9uNJtEiu5UTMSEkK5egjKH6pXmw2KSAQQ6AbRqVngdHZuPHwxBeiofypHrGmG1WkvAtgjjn7gmPddzaz3ymQj9m3CDFLGEB6Ao4xqripj/0/*))#ju6z6s7v"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "venture ice crash venture tourist tail naive curtain pilot engage code celery",
|
||||
"xprv": "tprv8iTk1ZRgwq4NAysrRgY1Wbycbfvmb7cYgjAGTeR573gKFJ4BFuGtEoaotCS6wdGiUfC2BTHg79tiX7i6NuFiTfjiaM8LXfNzL77YuBGY3K7",
|
||||
"wallet descriptor": "wsh(multi(1,[46d93da5/48'/1'/0'/2']tpubDF9n9yTw6Ck34SueKLCbv1djAhShkSoTG2m3kATNXKUi5nJwtJ6URJCg4M1je81fyabsX4t6F2itrQinMuu3cYLbpLbVQwWBUwYA8pPyKdZ/0/*))#8q8j9sft"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "sheriff zone betray cactus error enable code flat coyote worry guitar equal",
|
||||
"xprv": "tprv8iajQdFf4a7eUEKhE1gukrNEcxY4MZk1FJyKWgwZj48mhqTminKn6mkxyfyn1QwJ2XUke2aiXfXNQ2XqpGBbwXSSRK8hvqHQJuHWHs68YTh",
|
||||
"wallet descriptor": "wsh(multi(1,[d3c3bc8f/48'/1'/0'/2']tpubDFGmZ3HuCwoKMhMV7fMWAG2MBz3zWtvupca6oCys9KwAYKiYMB9NHGNq9qvVgPgDgpDLSiCqnp71f7WsV9N1cLkzsjqW9gxJF9VQ9oSZcj9/0/*))#7r3f3xys"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "bottom sight mistake next reveal modify rather bulk mountain arrow useful buzz",
|
||||
"xprv": "tprv8hqVmTiP493atpsuqdt87Hx5hjU9NwHG9hrWBa97rS8TwTYZBK5Jd8BfH4Jv154oP9YRWy7kU9p7xnqTwXCAnKZuEpACt2uzTx83HrTjqen",
|
||||
"wallet descriptor": "wsh(multi(1,[7f7d263a/48'/1'/0'/2']tpubDEXXuskdCWjFnHuhjHYiWhcCGkz5YGUAj1THU6BRGhvrmwoKohttocoXTCCE9udffumcou7ZYUR5RNqwHW4kw7Jv2UXUUSKeKqJd9xGmSCs/0/*))#zc5ruh7c"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "payment ill whisper noble casual shallow clown pipe keen pencil fluid term""xprv": "tprv8hMLjbE25N5UhZJadZDHb42RNFhgfSLdcsGnhu7BYt5Wt8UzXhcF5ANLuezsgJUNyCC4TJtekes9gssUCm6UKASnqMTPwm6KcePSw4npybF""wallet descriptor": "wsh(multi(1,[154159b3/48'/1'/0'/2']tpubDE3Nt1GGDjm9b2LNXCsszTgXwHDcpmXYCAsZzR9Uy9suicjmA6RqFezD5o8EWHk1vrztkPreHbYXKqGAdupKJNcKWYViKsQNMfr4uW8vcWq/0/*))#5k6w6h6g"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "lesson trumpet royal bright three oval vague organ atom joke favorite april",
|
||||
"xprv": "tprv8ixSxhVBoDTfv846JKDo5Qu8L89wZnmXUZCwdN1sm8CRfS1RpecrWmtthiTqepjnBroRit3Zygn53z3v8QWp3bqQYjev2Mn92g9jGkzaGya",
|
||||
"wallet descriptor": "wsh(multi(1,[fca68db6/48'/1'/0'/2']tpubDFeV77XRwb9Lob5tBxtPUpZEu9fsj7xS3roiut4BBPzpVvGCT3SShGWksqUYLqKBrt7xeKmmmgSrgbRiffcoS5KPiqyDWk5Kgvxek52XnNV/0/*))#j6sm3ntm"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "lyrics undo baby chicken possible vicious capital fun order salon maple source",
|
||||
"xprv": "tprv8ixaRLep3QQB2Rn9UpXXJVt9qcrDL6QTuHJusiKjPPgzkPmDveAQNBViJBrJakLKaoc3w7JzNUXAkSaeQHJAzGsMnrJQggWNkMn1e9rihgP",
|
||||
"wallet descriptor": "wsh(multi(1,[ef9d9ce6/48'/1'/0'/2']tpubDFecZkh4Bn5qutowNUC7huYGQeN9VRbNUauhAEN2ofVPat1zZ2yzYg7aULxsdzh79AFz7rBTVQeu2BsBay88XrFLc5diENj4ibizrwPNMbM/0/*))#zyhj4kj3"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "canoe coral egg public boss stable mercy side tennis behind dance shy",
|
||||
"xprv": "tprv8j58z2XeVe29DeDqb8UABtF14mo4MCPWm5CmkL5BegHBa3prhkLz2HF4JFwU5Z6ypnA7qCVcwdyPGj5yqXPoXiaE2Rcosmx9Ntiav39vRfp",
|
||||
"wallet descriptor": "wsh(multi(1,[8e236875/48'/1'/0'/2']tpubDFmB8SZte1hp77FdUn8kbHu7doJzWXaRLNoZ2r7V4x5aQY5dL9AaCmrvUNZSPYHJKeqto8roTvUpwWFazfxHEg5DvMq8br266uuD1JKieWj/0/*))#8xxkeruq"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "expire document depend hamster spy become blossom midnight ecology salon all earth",
|
||||
"xprv": "tprv8ii6Q43XVJhTrqb9oYUgz1kXXUc763g8c3tgZK38ei9Bwkaw12wEdXzgemB6fmF4jgDBAdavNg4YXyRe1XSx3jxjZ8i2fHruuyn6bP4r7uq",
|
||||
"wallet descriptor": "wsh(multi(1,[d03aacca/48'/1'/0'/2']tpubDFQ8YU5mdgP8kJcwhC9HPRQe6W83FNs3BMVTqq5S4ywanEqhdRkpp2cYpro3XRXKJPi8d1d3m4L2JXWdNQFfs31x37S3zfPpd7pwKEwLAm7/0/*))#phcw966k"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "movie west unit carbon adapt liberty crack easily raise toward brother quality",
|
||||
"xprv": "tprv8iszPBk3CEovNt6aHBMHPqeejpNJVKCqws1jfmHobNiC2s497W2jL9nde2FmTBWKMpkuKXDuFKPrBqKcEpsjgYeLsoQVT3MgsHoTjTL64qB",
|
||||
"wallet descriptor": "wsh(multi(1,[ce3600ea/48'/1'/0'/2']tpubDFa2XbnHLcVbGM8NAq1soFJmJqtEeePkXAcWxHL71eWasMJujtrKWeQVp7NHQY5euJL2bFuBkVQHk4uoDrVRfCEELLxJhHuNouPquffbmUy/0/*))#lwv5ura2"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "tip mixture supreme govern faculty panel judge motion aim write soon arrive",
|
||||
"xprv": "tprv8hJQahhR4cqcu6hkUkpVx3ex9tUxNWrY5EFd4zLdxT5Ycn3V14Kp6V7XLEtJ2N5p5dpVeP9mhMqNwTBBeJaavMDquLh8SRFfdDejAy8yygX",
|
||||
"wallet descriptor": "wsh(multi(1,[fe898c92/48'/1'/0'/2']tpubDDzSj7jfCzXHnZjYNQV6MTK4iuztXr3SeXrQMWNwNiswTGJFdT9QGyjPWMoYcoPY9HCYbLdcMGiDokrWDWWZEhg8HpbgebenhJujvTzMeeN/0/*))#675457w4"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "identify devote dice young air turkey angle code observe innocent fragile bench",
|
||||
"xprv": "tprv8iUcGCBaM1XJqsswVqLkJjgQjvKHmGaKrvX9sqBrmRrUTroa5EKEes4x3L7AFE7tLDW4mUCWLmpAhFrjQvZ1uUzuAaziFvLwrtq253g9yzp",
|
||||
"wallet descriptor": "wsh(multi(1,[d33c583b/48'/1'/0'/2']tpubDFAeQcDpVPCyjLujPV1Li9LXJwqDvbmESE7wAMEABhesJM4Lhd8pqMgpDVSmf4cpdsfZbDWkhfyxeyG3SaWcB4MqEqhbseQ8mk41PPHb57T/0/*))#u9xx2lkz"
|
||||
},
|
||||
{
|
||||
"Mnemonic": "slide hollow decade federal pair brief furnace fit pelican heart better place",
|
||||
"xprv": "tprv8iVREMet5hjVGBfng2VLnsrTMPqPDFkVoUAqoy78zKEye1u6XaG8jKju3nsf6GN1UTMbkFWoD6TiTTvnP2ez4NvXyX9c1UMfQ932CmZjuLg",
|
||||
"wallet descriptor": "wsh(multi(1,[facf6b1f/48'/1'/0'/2']tpubDFBTNmh8E5RA9ehaZg9wCHWZvRMKNawQNmmd6V9SQb3NUW9s9y5iupMmDxAbBFFrytzotW9hu8REgqSFg26Q8mcvBjSAaVz9QcNzmCxRJdv/0/*))#3407up02"
|
||||
}
|
||||
]
|
||||
25
miner/tools/pubkeys.json
Normal file
25
miner/tools/pubkeys.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "wsh",
|
||||
"multi": "sortedmulti",
|
||||
"min": "1",
|
||||
"pubkeys": [
|
||||
"[fca68db6/48'/1'/0'/2']tpubDFeV77XRwb9Lob5tBxtPUpZEu9fsj7xS3roiut4BBPzpVvGCT3SShGWksqUYLqKBrt7xeKmmmgSrgbRiffcoS5KPiqyDWk5Kgvxek52XnNV/0/*",
|
||||
"[5df7e4b0/48'/1'/0'/2']tpubDF4ix3sjhgzM7iJVfTUVnx3HJ8kvkAvk36sPv5JmsmQcfPPK5KkHxJSgixZAdcYEsGcvHacm1hW4iLksGoTZocJozuaA2BTNp3GEvW432qu/0/*",
|
||||
"[ef9d9ce6/48'/1'/0'/2']tpubDFecZkh4Bn5qutowNUC7huYGQeN9VRbNUauhAEN2ofVPat1zZ2yzYg7aULxsdzh79AFz7rBTVQeu2BsBay88XrFLc5diENj4ibizrwPNMbM/0/*",
|
||||
"[86936c07/48'/1'/0'/2']tpubDFUys3FLzC4cEqZsTEJHwmSCbeXSTFdPvisp6uD2XhfZPkTJgwHJdVyUXYcfLRrikRxA2MpBaZWE5kZCtHFc15aVtktsHMrTijDjq2dKRGK/0/*",
|
||||
"[7f7d263a/48'/1'/0'/2']tpubDEXXuskdCWjFnHuhjHYiWhcCGkz5YGUAj1THU6BRGhvrmwoKohttocoXTCCE9udffumcou7ZYUR5RNqwHW4kw7Jv2UXUUSKeKqJd9xGmSCs/0/*",
|
||||
"[154159b3/48'/1'/0'/2']tpubDE3Nt1GGDjm9b2LNXCsszTgXwHDcpmXYCAsZzR9Uy9suicjmA6RqFezD5o8EWHk1vrztkPreHbYXKqGAdupKJNcKWYViKsQNMfr4uW8vcWq/0/*",
|
||||
"[46d93da5/48'/1'/0'/2']tpubDF9n9yTw6Ck34SueKLCbv1djAhShkSoTG2m3kATNXKUi5nJwtJ6URJCg4M1je81fyabsX4t6F2itrQinMuu3cYLbpLbVQwWBUwYA8pPyKdZ/0/*",
|
||||
"[d3c3bc8f/48'/1'/0'/2']tpubDFGmZ3HuCwoKMhMV7fMWAG2MBz3zWtvupca6oCys9KwAYKiYMB9NHGNq9qvVgPgDgpDLSiCqnp71f7WsV9N1cLkzsjqW9gxJF9VQ9oSZcj9/0/*",
|
||||
"[8e236875/48'/1'/0'/2']tpubDFmB8SZte1hp77FdUn8kbHu7doJzWXaRLNoZ2r7V4x5aQY5dL9AaCmrvUNZSPYHJKeqto8roTvUpwWFazfxHEg5DvMq8br266uuD1JKieWj/0/*",
|
||||
"[a3a9eb52/48'/1'/0'/2']tpubDE9uNJtEiu5UTMSEkK5egjKH6pXmw2KSAQQ6AbRqVngdHZuPHwxBeiofypHrGmG1WkvAtgjjn7gmPddzaz3ymQj9m3CDFLGEB6Ao4xqripj/0/*",
|
||||
"[d03aacca/48'/1'/0'/2']tpubDFQ8YU5mdgP8kJcwhC9HPRQe6W83FNs3BMVTqq5S4ywanEqhdRkpp2cYpro3XRXKJPi8d1d3m4L2JXWdNQFfs31x37S3zfPpd7pwKEwLAm7/0/*",
|
||||
"[ce3600ea/48'/1'/0'/2']tpubDFa2XbnHLcVbGM8NAq1soFJmJqtEeePkXAcWxHL71eWasMJujtrKWeQVp7NHQY5euJL2bFuBkVQHk4uoDrVRfCEELLxJhHuNouPquffbmUy/0/*",
|
||||
"[fe898c92/48'/1'/0'/2']tpubDDzSj7jfCzXHnZjYNQV6MTK4iuztXr3SeXrQMWNwNiswTGJFdT9QGyjPWMoYcoPY9HCYbLdcMGiDokrWDWWZEhg8HpbgebenhJujvTzMeeN/0/*",
|
||||
"[d33c583b/48'/1'/0'/2']tpubDFAeQcDpVPCyjLujPV1Li9LXJwqDvbmESE7wAMEABhesJM4Lhd8pqMgpDVSmf4cpdsfZbDWkhfyxeyG3SaWcB4MqEqhbseQ8mk41PPHb57T/0/*",
|
||||
"[facf6b1f/48'/1'/0'/2']tpubDFBTNmh8E5RA9ehaZg9wCHWZvRMKNawQNmmd6V9SQb3NUW9s9y5iupMmDxAbBFFrytzotW9hu8REgqSFg26Q8mcvBjSAaVz9QcNzmCxRJdv/0/*"
|
||||
],
|
||||
"checksum": "#jmqku76u",
|
||||
"signet_challenge": "0020341c43803863c252df326e73574a27d7e19322992061017b0dc893e2eab90821",
|
||||
"magic": "b066463d"
|
||||
}
|
||||
113
nodesource_setup.sh
Normal file
113
nodesource_setup.sh
Normal file
@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Logger Function
|
||||
log() {
|
||||
local message="$1"
|
||||
local type="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local color
|
||||
local endcolor="\033[0m"
|
||||
|
||||
case "$type" in
|
||||
"info") color="\033[38;5;79m" ;;
|
||||
"success") color="\033[1;32m" ;;
|
||||
"error") color="\033[1;31m" ;;
|
||||
*) color="\033[1;34m" ;;
|
||||
esac
|
||||
|
||||
echo -e "${color}${timestamp} - ${message}${endcolor}"
|
||||
}
|
||||
|
||||
# Error handler function
|
||||
handle_error() {
|
||||
local exit_code=$1
|
||||
local error_message="$2"
|
||||
log "Error: $error_message (Exit Code: $exit_code)" "error"
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Function to check for command availability
|
||||
command_exists() {
|
||||
command -v "$1" &> /dev/null
|
||||
}
|
||||
|
||||
check_os() {
|
||||
if ! [ -f "/etc/debian_version" ]; then
|
||||
echo "Error: This script is only supported on Debian-based systems."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to Install the script pre-requisites
|
||||
install_pre_reqs() {
|
||||
log "Installing pre-requisites" "info"
|
||||
|
||||
# Run 'apt-get update'
|
||||
if ! apt-get update -y; then
|
||||
handle_error "$?" "Failed to run 'apt-get update'"
|
||||
fi
|
||||
|
||||
# Run 'apt-get install'
|
||||
if ! apt-get install -y apt-transport-https ca-certificates curl gnupg; then
|
||||
handle_error "$?" "Failed to install packages"
|
||||
fi
|
||||
|
||||
if ! mkdir -p /usr/share/keyrings; then
|
||||
handle_error "$?" "Makes sure the path /usr/share/keyrings exist or run ' mkdir -p /usr/share/keyrings' with sudo"
|
||||
fi
|
||||
|
||||
rm -f /usr/share/keyrings/nodesource.gpg || true
|
||||
rm -f /etc/apt/sources.list.d/nodesource.list || true
|
||||
|
||||
# Run 'curl' and 'gpg' to download and import the NodeSource signing key
|
||||
if ! curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource.gpg; then
|
||||
handle_error "$?" "Failed to download and import the NodeSource signing key"
|
||||
fi
|
||||
|
||||
# Explicitly set the permissions to ensure the file is readable by all
|
||||
if ! chmod 644 /usr/share/keyrings/nodesource.gpg; then
|
||||
handle_error "$?" "Failed to set correct permissions on /usr/share/keyrings/nodesource.gpg"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to configure the Repo
|
||||
configure_repo() {
|
||||
local node_version=$1
|
||||
|
||||
arch=$(dpkg --print-architecture)
|
||||
if [ "$arch" != "amd64" ] && [ "$arch" != "arm64" ] && [ "$arch" != "armhf" ]; then
|
||||
handle_error "1" "Unsupported architecture: $arch. Only amd64, arm64, and armhf are supported."
|
||||
fi
|
||||
|
||||
echo "deb [arch=$arch signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$node_version nodistro main" | tee /etc/apt/sources.list.d/nodesource.list > /dev/null
|
||||
|
||||
# N|solid Config
|
||||
echo "Package: nsolid" | tee /etc/apt/preferences.d/nsolid > /dev/null
|
||||
echo "Pin: origin deb.nodesource.com" | tee -a /etc/apt/preferences.d/nsolid > /dev/null
|
||||
echo "Pin-Priority: 600" | tee -a /etc/apt/preferences.d/nsolid > /dev/null
|
||||
|
||||
# Nodejs Config
|
||||
echo "Package: nodejs" | tee /etc/apt/preferences.d/nodejs > /dev/null
|
||||
echo "Pin: origin deb.nodesource.com" | tee -a /etc/apt/preferences.d/nodejs > /dev/null
|
||||
echo "Pin-Priority: 600" | tee -a /etc/apt/preferences.d/nodejs > /dev/null
|
||||
|
||||
# Run 'apt-get update'
|
||||
if ! apt-get update -y; then
|
||||
handle_error "$?" "Failed to run 'apt-get update'"
|
||||
else
|
||||
log "Repository configured successfully."
|
||||
log "To install Node.js, run: apt-get install nodejs -y" "info"
|
||||
log "You can use N|solid Runtime as a node.js alternative" "info"
|
||||
log "To install N|solid Runtime, run: apt-get install nsolid -y \n" "success"
|
||||
fi
|
||||
}
|
||||
|
||||
# Define Node.js version
|
||||
NODE_VERSION="22.x"
|
||||
|
||||
# Check OS
|
||||
check_os
|
||||
|
||||
# Main execution
|
||||
install_pre_reqs || handle_error $? "Failed installing pre-requisites"
|
||||
configure_repo "$NODE_VERSION" || handle_error $? "Failed configuring repository"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user