Netwatch Dashboard est une application de surveillance d’URL auto-hébergée. Elle permet de suivre la disponibilité de services HTTP, leur temps de réponse, leur dernier code HTTP et la date de leur dernière vérification depuis une interface inspirée des consoles netrunner.
La consultation du dashboard est publique. Les actions de gestion sont protégées par un mot de passe partagé et une session persistée dans MySQL.
- ajout, modification et suppression d’un service à surveiller ;
- vérification immédiate lors de l’ajout d’un service depuis l’interface ;
- vérification manuelle d’un service ou de l’ensemble des services ;
- vérification automatique toutes les cinq minutes ;
- actualisation automatique du dashboard toutes les trente secondes ;
- statuts
ONLINE,OFFLINEetUNKNOWN; - mesure du temps de réponse et conservation du dernier code HTTP ;
- affichage de la dernière erreur rencontrée ;
- statistiques globales : nombre de services, disponibilité et latence moyenne ;
- interface publique en lecture seule ;
- espace d’administration protégé par une session MySQL ;
- frontend React compilé et servi directement par NestJS ;
- image Docker multi-stage et script de déploiement sur un réseau MariaDB existant.
- Node.js 22 ;
- NestJS 11 ;
- TypeORM ;
- MySQL ou MariaDB ;
- Axios pour les vérifications HTTP ;
@nestjs/schedulepour les vérifications périodiques ;express-sessionetexpress-mysql-sessionpour l’authentification.
- React 19 ;
- TypeScript ;
- Vite ;
- React Router ;
- TanStack Query ;
- Axios ;
- Tailwind CSS et CSS personnalisé.
Chaque vérification envoie une requête HTTP avec un délai maximal de cinq secondes et autorise jusqu’à trois redirections.
| Résultat | Statut enregistré |
|---|---|
Réponse HTTP de 200 à 499 |
ONLINE |
Réponse HTTP 500 ou supérieure |
OFFLINE |
| Timeout, erreur DNS ou connexion impossible | OFFLINE |
| Service pas encore vérifié | UNKNOWN |
Le dashboard conserve uniquement le dernier résultat de chaque service. Il ne stocke pas encore d’historique de disponibilité.
.
├── client/ # Application React/Vite
│ └── src/
│ ├── components/ # Cartes, formulaires, badges et modale
│ ├── pages/ # Dashboard, connexion, ajout et modification
│ ├── services/ # Client Axios et appels à l’API
│ └── types/ # Types du frontend
├── src/
│ ├── auth/ # Connexion, déconnexion, session et guard
│ ├── monitors/ # API, service TypeORM et entité Monitor
│ ├── app.module.ts # Configuration NestJS et MySQL
│ └── main.ts # Sessions, CORS, validation et démarrage
├── database/schema.sql # Création de la base et de la table monitors
├── Dockerfile # Build frontend, backend et image d’exécution
├── build.sh # Déploiement sur un réseau MariaDB existant
└── .env.example # Variables d’environnement attendues
- Node.js
22.22.0ou supérieur ; - npm ;
- MySQL 8 ou une version compatible de MariaDB ;
- Docker avec BuildKit pour le déploiement conteneurisé.
À la racine du projet :
npm ci
npm --prefix client ciCREATE DATABASE monitoring
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Créer ensuite la table utilisée par TypeORM :
USE monitoring;
CREATE TABLE IF NOT EXISTS monitors (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
url VARCHAR(2048) NOT NULL,
status ENUM('UNKNOWN', 'ONLINE', 'OFFLINE') NOT NULL DEFAULT 'UNKNOWN',
responseTime INT NULL,
statusCode SMALLINT NULL,
lastError VARCHAR(255) NULL,
lastCheckedAt DATETIME NULL,
createdAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updatedAt DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)
ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
UNIQUE KEY UQ_monitors_url (url) USING HASH
) ENGINE=InnoDB
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Le script complet peut être importé directement :
mysql -u root -p < database/schema.sqlL’utilisateur défini dans .env doit pouvoir lire et modifier les données de cette base. Il doit également pouvoir créer la table sessions, générée automatiquement par express-mysql-session au premier démarrage.
En développement, cette importation reste facultative : TypeORM crée ou met à jour automatiquement la table monitors lorsque NODE_ENV n’est pas égal à production.
Copier le fichier d’exemple :
cp .env.example .envSous PowerShell :
Copy-Item .env.example .envPuis adapter les valeurs à la base locale.
npm run start:devL’API écoute par défaut sur http://localhost:3000.
Dans un second terminal :
npm --prefix client run devLe dashboard est disponible sur http://localhost:5173. Vite transmet automatiquement les appels /api au backend local.
PORT=3000
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=
DB_DATABASE=monitoring
FRONTEND_URL=http://localhost:5173
NODE_ENV=development
DASHBOARD_PASSWORD=test
SESSION_SECRET=replace-with-a-long-random-secret| Variable | Description | Exemple local |
|---|---|---|
PORT |
Port d’écoute de NestJS | 3000 |
DB_HOST |
Hôte MySQL. Dans Docker, utiliser le nom du conteneur ou son alias réseau | localhost |
DB_PORT |
Port interne de MySQL | 3306 |
DB_USERNAME |
Utilisateur MySQL | root |
DB_PASSWORD |
Mot de passe MySQL | chaîne vide en local si autorisé |
DB_DATABASE |
Base utilisée pour les monitors et les sessions | monitoring |
FRONTEND_URL |
Origine frontend autorisée par CORS | http://localhost:5173 |
NODE_ENV |
Active les réglages de production avec la valeur production |
development |
DASHBOARD_PASSWORD |
Mot de passe partagé de l’administration | test uniquement en développement |
SESSION_SECRET |
Secret utilisé pour signer le cookie de session | une longue valeur aléatoire |
Le fichier .env est exclu de Git et du contexte Docker. Il ne doit jamais être ajouté à l’image.
Le dashboard reste consultable sans connexion. Une session authentifiée est obligatoire pour :
- ajouter ou modifier un service ;
- supprimer un service ;
- vérifier un service ;
- déclencher la vérification globale.
Après une connexion réussie, l’identifiant de session est enregistré dans le cookie dashboard.sid. Le cookie est HTTP-only, utilise SameSite=Lax et expire après 24 heures. Les données de session sont stockées dans MySQL et les sessions expirées sont régulièrement supprimées.
En production, le cookie devient sécurisé et nécessite donc HTTPS.
Toutes les routes sont préfixées par /api.
| Méthode | Route | Accès | Description |
|---|---|---|---|
GET |
/api/auth/session |
Public | Retourne l’état de la session |
POST |
/api/auth/login |
Public | Ouvre une session avec le mot de passe du dashboard |
POST |
/api/auth/logout |
Public | Détruit la session courante |
Corps de la requête de connexion :
{
"password": "test"
}| Méthode | Route | Accès | Description |
|---|---|---|---|
GET |
/api/monitors |
Public | Liste les services |
GET |
/api/monitors/:id |
Public | Retourne un service |
POST |
/api/monitors |
Session | Ajoute un service |
PATCH |
/api/monitors/:id |
Session | Modifie un service |
DELETE |
/api/monitors/:id |
Session | Supprime un service |
POST |
/api/monitors/:id/check |
Session | Vérifie un service |
POST |
/api/monitors/check-all |
Session | Vérifie tous les services |
Exemple de service :
{
"id": 1,
"name": "Portfolio",
"url": "https://example.com",
"status": "ONLINE",
"responseTime": 184,
"statusCode": 200,
"lastError": null,
"lastCheckedAt": "2026-08-05T10:30:00.000Z",
"createdAt": "2026-08-05T10:00:00.000Z",
"updatedAt": "2026-08-05T10:30:00.000Z"
}Compiler séparément le frontend et le backend :
npm --prefix client run build
npm run buildNestJS sert ensuite les fichiers générés dans client/dist :
npm run start:prodPour un lancement avec NODE_ENV=production, la base doit avoir été préparée avec des migrations et l’application doit être exposée derrière HTTPS.
Le Dockerfile utilise trois étapes :
- compilation du frontend React ;
- compilation du backend NestJS ;
- création d’une image d’exécution contenant uniquement les dépendances de production et les deux builds.
Le processus Node s’exécute avec l’utilisateur non privilégié node.
Le script build.sh suppose que MySQL ou MariaDB fonctionne déjà dans un autre conteneur, connecté au réseau Docker mariadb-network.
Créer le réseau s’il n’existe pas :
docker network create mariadb-networkLe conteneur de base de données doit rejoindre ce même réseau. Dans le .env du serveur, DB_HOST doit contenir son nom ou son alias Docker, jamais localhost :
DB_HOST=mariadb
DB_PORT=3306Lancer ensuite le déploiement :
chmod +x build.sh
./build.shLe dashboard écoute par défaut sur 127.0.0.1:3334. Le script construit l’image, remplace l’ancien conteneur, injecte le .env, rejoint le réseau MariaDB et affiche les derniers logs.
Les valeurs suivantes peuvent être surchargées au lancement :
| Variable | Valeur par défaut | Rôle |
|---|---|---|
IMAGE_NAME |
dashboard-image |
Nom de l’image Docker |
CONTAINER_NAME |
dashboard |
Nom du conteneur |
HOST_PORT |
3334 |
Port exposé sur l’hôte |
CONTAINER_PORT |
valeur PORT du .env |
Port écouté dans le conteneur |
NETWORK_NAME |
mariadb-network |
Réseau de la base de données |
ENV_FILE |
.env à la racine |
Fichier injecté dans le conteneur |
DB_HOST_DOCKER |
valeur DB_HOST du .env |
Surcharge ponctuelle de l’hôte MySQL |
Exemple :
HOST_PORT=3500 DB_HOST_DOCKER=mariadb ./build.shnpm run start:dev # serveur avec rechargement automatique
npm run build # compilation NestJS
npm run start:prod # lancement du build
npm run lint # lint et corrections automatiques
npm run format # formatage Prettier du backendnpm --prefix client run dev
npm --prefix client run build
npm --prefix client run lint
npm --prefix client run previewCe projet fournit une authentification légère adaptée à un dashboard personnel. Avant une exposition publique, il faut notamment :
- remplacer
DASHBOARD_PASSWORDetSESSION_SECRETpar des valeurs fortes ; - utiliser HTTPS et conserver
NODE_ENV=production; - ajouter une limitation des tentatives de connexion ;
- ajouter une protection CSRF pour les mutations ;
- stocker un hash du mot de passe au lieu du mot de passe brut ;
- gérer le schéma de production avec des migrations TypeORM ;
- protéger les vérifications contre les attaques SSRF en bloquant localhost, les réseaux privés, les métadonnées cloud et les redirections dangereuses ;
- limiter la taille des réponses téléchargées pendant une vérification ;
- ajouter un historique, des alertes et des tests automatisés si le projet devient un outil de production.
Avec NODE_ENV=production, synchronize est désactivé. C’est volontaire : TypeORM ne doit pas modifier automatiquement un schéma de production.
Ce projet est distribué sous licence MIT. Voir le fichier LICENSE.