Server Monitoring

Web App -

Présentation

Il y a quelques années, je me suis installé un serveur Linux qui me permettait, en autre, d’avoir un serveur multimédia, un serveur git, ou encore d’héberger mes projets web. Ce serveur a donc de nombreuses utilités.

Lors de la toute première installation, j’ai décidé de me créer un petit site web qui écouterait sur le port 80 et qui me permettrait d’avoir accès à toutes les infos du serveur. Je voulais pouvoir accéder à tous les projets hébergés, en un clic, je voulais pouvoir avoir accès à l’utilisation des disques durs, etc …

La première version de ce site était faite en PHP sur un seul fichier. Je devais modifier directement le fichier source pour afficher ou changer les éléments de la page. Quelques mois plus tard, après avoir découvert l’ASP Core, j’ai décidé de tout refaire avec le langage C# et d’utiliser une base de données pour stocker les informations. Ce projet a plutôt bien tourné et m’a permis d’ajouter des nouvelles fonctionnalités comme les backups et l’affichage des applications installées (Emby, Gitea, PhpMyAdmin, …).

servermonitoring-old

Ancienne version

Ce projet était relativement basique et ne permettait pas de modifier et de configurer simplement les éléments affichés. Je devais aller directement en base de données pour faire les modifications. La partie authentification était aussi très bancale. Une clé d’API devait être manuellement renseignée pour avoir accès aux fonctionnalités.

Le projet précédent répondait globalement à mes attentes, mais après avoir découvert un nouveau framework, je me suis motivé à refaire proprement ce projet avec le nouveau framework afin de m’améliorer sur celui-ci. J’ai donc décidé de repartir de zéro et d’avoir les toutes les fonctionnalités de base complète.

Objectifs

Les objectifs de la nouvelle version étaient donc :

  • Pouvoir accéder aux tailles des disques durs et à leurs utilisations
    • Pouvoir les renommer
    • Avoir un pourcentage de la taille utilisée
  • Pouvoir gérer les applications disponibles sur le serveur
    • Créer, modifier et supprimer une application
    • Afficher le statut de l’application
    • Pourvoir démarrer, redémarrer et arrêter une application

Ces fonctionnalités étaient donc simples et faciles à implémenter et répondaient au besoin que j’avais.

Pendant la phase de développement, j’ai décidé de rajouter la gestion des tous les appareils du “parc informatique” de la maison.

Une nouvelle fonctionnalité c’est donc greffé au projet :

  • Pouvoir gérer les appareils :
    • Créer, modifier et supprimer un appareil
    • Avoir accès à ces heures de connexion
    • Avoir accès à l’usage des disques durs et avoir un graph évolutif dans le temps

Technologies

Back-end

Le framework que j’ai découvert et que je souhaitais apprendre était AdonisJS. Celui-ci reprend globalement le concept et les idées de Laravel, mais sous NodeJS. J’avais auparavant fait quelques projets sous expressJs et je trouvais intéressant le fait d’utiliser un Framework beaucoup plus complet.

Au moment où je démarrais le projet, la version 5 venait de sortir. Celle-ci apportait la gestion et l’utilisation complète du TypeScript.

Front-end

Le framewok que j’ai choisi pour le front était Vue 3. Celui-ci avait aussi été mis à jour récemment vers la version 3 qui apporte une meilleure gestion du TypeScript et notamment la partie Composition API qui intégrait une partie plus developper-friendly.

Pour faire le lien entre le back et le front-end, j’avais décidé de faire une API pour envoyer les données vers le front. Mais après quelques recherches, j’ai découvert une librairie nommée InertiaJS. Celle-ci permet d’avoir un framework One Page Application (type Vue, React ou encore Svelte) tout en utilisant le routage classique des frameworks backend. Il n’y avait même pas de version 1, mais l’idée semblait prometteuse. J’ai donc fait le choix de partir sur cette technologie.

Pour le CSS, j’ai décidé d’utiliser Tailwind. Énormément de composants sont disponibles sur internet, ce qui facilite la partie “design”, qui est quelque chose que je maîtrise très peu.

Développement

La phase de développement à durée environ 2 semaines.

Les ajouts de fonctionnalités comme ‘Device’, on permit d’ajouter plus de complexité dans le projet.

Gestion de projet

La partie gestion de projet a été plutôt soft. J’ai simplement mis en place un Trello qui me servait à regrouper toutes les idées et à me rendre compte des tâches qu’il me restait à effectuer.

servermonitoring-trello

Trello

Routes

Front-end

Comme expliqué en introduction, j’ai fait le choix d’utiliser InertiaJS. Une librairie tierce a été créée pour faire le lien entre Adonis et Inertia. Cette libraire s’utilise classiquement, il faut utiliser l’attribut inertia et lui fournir le nom de la page et les données qui doivent être affichées sur la page.

export default class DrivesController {
    public async index({ inertia }: HttpContextContract) {
        const drivesData = await Drive.all();
        const drives = await getDrivesInfo(drivesData);
        return inertia.render("Drives/Index", { drives });
    }
}

Exemple pour la page d’accueil de ‘Drive’

Toute la partie front a donc été gérée avec Inertia. Un intergiciel (Middleware) d’authentification est utilisé sur chacune des pages afin de vérifier que l’utilisateur est connecté.

API

Une petite partie API a été ajoutée afin de gérer la partie Service Worker. L’API ne traite que les données provenant de l’extérieur. À l’heure actuelle, un seul controller gère toute la partie Device. La partie sécurité est détaillée juste en dessous.

Sécurité

Front-end

La partie authentification a été ajoutée à la toute fin du projet. La sécurité est plutôt simple, lorsque l’on arrive sur le site, si l’utilisateur n’est pas connecté, il est directement redirigé vers la page de connexion.

Service Worker

Identification

Pour le worker, l’authentification se base au niveau de l’identifiant générer. Pour connaître un appareil, j’utilise les informations qui sont fournies par Windows ou Linux. Par exemple pour Linux, j’utilise le nom de la machine, la version de l’os, le numéro de série de la carte mère, etc. L’agrégation de toutes ces données forme un identifiant qui est relativement unique et qui permet de “reconnaître” les machines. Pour ce faire, j’utilise la librairie DeviceId

string deviceId = new DeviceIdBuilder()
	.AddMachineName()
	.AddOSVersion()
	.AddMotherboardSerialNumber()
	.AddSystemDriveSerialNumber()
	.ToString();

Exemple de génération d’identifiant pour Linux

API

Pour empêcher les possibles attaques, 2 paramètres ont été ajoutés au niveau du serveur web afin de le protéger.

La première est APP_AUTO_CREATE_DEVICE. Celle-ci empêche l’enregistrement de données si l’identifiant de l’appareil n’est pas connu (donc non sauvegardé en base de données). Tous les appareils doivent donc être créés par un administrateur au préalable.

La deuxième est *APP_DEVICE_USE_KEY. Celle-ci a pour but de forcer l’ajout d’une clé d’API dans les requêtes HTTPs. Lorsqu’une nouvelle machine est créée, une clé d’API est automatiquement générée (sous forme d’*UUID* : 123e4567-e89b-12d3-a456-426614174000). Si l’option est active, sur chaque requête, le serveur va vérifier si l’en-tête Authorization contient la clé d’API.

La clé d’API doit être enregistrée manuellement dans les fichiers de configuration du worker.

L’interface web permet de regénérer la clé si besoin.

servermonitoring-device-regenerate-key

Exemple rendu

Design

Comme dit plus haut pour la partie design et donc CSS, j’ai choisi Tailwind. Tailwind est un outil plutôt performant qui permet de casi tout faire via les classes CSS. Il permet aussi de créer ses propres composants via des helpers.

La plupart des éléments utilisés ont été trouvés sur Internet.

servermonitoring-drives-white

Exemple avec la page ‘Drive’

Dark Mode

Tailwind apporte la possibilité d’ajouter très simplement un mode sombre aux classes CSS. J’ai donc intégré ce mode sombre qui est modifiable en haut à droite.

servermonitoring-drives-dark

Exemple avec la page ‘Drive’

Responsive

Tailwind contient aussi beaucoup de classes qui permettent de gérer le responsive. Il reste encore quelques problèmes à ce niveau-là. Mais la plupart des pages sont fonctionnelles.

servermonitoring-drives-info-mobile

Page info sur un mobile

Docker

À la fin du projet, j’ai “conteneurisé” mon application afin qu’elle puisse tourner dans des conteneurs Docker.

Le conteneur est totalement fonctionnel, mais l’application n’est pas forcément prévue pour tourner dans un environnement virtualisé. Un effet, pour récupérer la taille des disques durs, j’utilise la commande df. Mais, si cette commande est lancée dans un conteneur, elle va forcément renvoyer les infos de docker et non de la machine. Les pages concernant les disques durs ne sont donc pas utilisables lorsque l’application est hébergée avec Docker.

Fonctionnalités

Drives

Cette partie est la plus simple. Le système se charge de récupérer tous les disques durs et d’afficher le pourcentage d’utilisation du disque. La progress bar vire au rouge lorsque le disque est trop rempli.

La majeure partie de cette fonctionnalité est donc l’affichage des données. Il est quand même possible de renommer un disque si besoin.

servermonitoring-devices-index

Exemple page des disques durs

servermonitoring-drives-edit

Exemple page de modification d’un disque

Applications

Sur ces pages, j’affiche les applications enregistrées. Lors de la création, quelques informations optionnelles sont demandées comme le nom du service (le service dans systemctl). Cette information permet de savoir si l’application est active ou non.

servermonitoring-applications-index

Exemple page des applications

servermonitoring-home-applications

Exemple page d’accueil

On a donc la possibilité d’afficher, d’ouvrir, de créer, modifier et de supprimer une application.

sevrermonitoring-applications-edit

Exemple page de modification d’une application

Devices

Cette partie est donc la plus avancée. Elle a pour but de récupérer et d’afficher toutes les informations concernant les appareils disponibles en local sur le réseau.

servermonitoring-devices

Exemple page des appareils

Un Service Worker a été mis en place. Celui-ci a pour but d’envoyer des informations au serveur à intervalle régulier concernant des thématiques spécifiques.

Le service :

  • Envoi son état (lorsque l’appareil s’allume ou s’éteint)
  • Envoi des informations pour prévenir qu’il est toujours actif (toutes les 3mn30).
  • Envoi des informations sur les tous les disques présents sur le système (au démarrage, à la fermeture et toutes les 4 heures)

Quelques pages de récapitulatif ont été mises en place afin de traiter toutes ces informations.

servermonitoring-devices-utime

Exemple uptime

servermonitoring-devices-drives

Exemple des disques durs

Conclusion

Atouts

Le projet est relativement basique, mais il est très facile d’y rajouter des nouvelles fonctionnalités.

L’application étant OnePage, la navigation est très fluide et réactive.

L’ajout des paramètres permet de configurer le serveur.

Le projet est capable de tourner sous docker, malgré, comme dit plus haut, des problèmes liés aux disques.

Améliorations / Extensions

  • Gérer les backups
    • Avoir une partie permettant de sauvegarder des chemins, avec conservation de x dossiers, enregistrement en base de données des temps d’exécution, de chaque backup etc…
    • Enregistrement des data généré par les conteneurs docker
  • Gérer les users
    • À l’heure actuelle, les utilisateurs ayant accès au système doivent être créés “à la main”
  • Gérer le système
    • Permettre d’éteindre, redémarrer ou planifier des arrêts du serveur
  • Gérer les conteneurs docker
    • Le projet permet de gérer les services Linux. Il serait intéressant de pouvoir gérer, de façon basique, les conteneurs docker (arrêt, redémarrage, etc)

Retour d’expérience

Projet hyper intéressant ou j’ai pu découvrir de nouveau Framework JS. Adonis ressemble fortement à Laravel. Il a entièrement été réécrit en TypeScript.

J’ai aussi pu découvrir les services worker. Cette partie est la plus simple, ça m’a permis découvrir les services Windows, avec sc.exe, et côté Linux, avec systemctl.

Repositories