Portfolio personnel — BTS SIO SLAM

keryan.net — Portfolio actuel

Portfolio personnel self-hosted sur VPS, accessible publiquement. Présente l'ensemble du parcours BTS SIO, les réalisations professionnelles, et sert de support numérique pour l'épreuve E5.

Voir le portfolio
HTML/CSS JavaScript Nginx VPS HTTPS / Let's Encrypt Authelia SSO Self-hosting
Trame de présentation — 15 minutes

Structure recommandée pour l'épreuve E5 : 10 min présentation du parcours de professionnalisation + 5 min transition vers l'échange jury (30 min). Utilise le portfolio comme fil conducteur.

0–2 min

Introduction — Parcours et contexte

« Je m'appelle Keryan, je suis en BTS SIO option SLAM en alternance chez [entreprise]. Mon parcours couvre à la fois le développement applicatif en entreprise et des projets personnels de formation. Je vais vous présenter mes réalisations professionnelles à travers mon portfolio disponible en ligne sur keryan.net. »

Mots-clés jury : parcours de professionnalisation · alternance · portfolio numérique accessible
2–4 min

WAChangeLogUrgence — Réalisation principale (alternance)

« En alternance, j'ai développé WAChangeLogUrgence, une application web de gestion des notes de mise à jour des logiciels internes. »

  • Architecture découplée : API REST ASP.NET Core 8 (C#) + SPA Angular 17
  • Authentification stateless par JWT (access token 15 min + refresh token 7 jours)
  • Entity Framework Core comme ORM, base MySQL, migrations versionnées
  • Pattern MVC côté API : Controller renvoie du JSON, la View est Angular
Compétences Annexe 8-3 : Mettre à disposition un service informatique · Travailler en mode projet · Contribution personnelle
4–5 min

Modifications WinDev — Maintenance applicative (alternance)

« Parallèlement, j'ai assuré la maintenance corrective et évolutive des logiciels Urgence et Akosone développés en WinDev 27. »

  • Analyse des rapports de bugs, reproduction, correction, tests, livraison
  • Évolutions fonctionnelles à la demande des utilisateurs métier
Compétences Annexe 8-3 : Répondre aux incidents et demandes d'évolution · Mettre à disposition un service informatique
5–7 min

GSB — Projet formation fil rouge BTS SIO

« En formation, j'ai réalisé GSB, l'application de gestion des frais des visiteurs médicaux du Laboratoire Galaxy Swiss Bourdin. »

  • Architecture MVC en PHP 8, accès BDD via PDO (requêtes préparées, protection injection SQL)
  • Authentification par sessions PHP, mots de passe hashés en SHA-256
  • Gestion des états de fiche (CR → VA → RB), génération PDF avec cache via TCPDF
  • Tests unitaires PHPUnit, documentation auto phpDocumentor
Compétences Annexe 8-3 : Développer la présence en ligne · Gérer le patrimoine informatique · Travailler en mode projet
7–8 min

Nolark & Ancien portfolio — Projets de formation front-end

« En début de formation, j'ai réalisé deux projets front-end statiques pour acquérir les fondamentaux. »

  • Nolark : site vitrine HTML5 sémantique, CSS3 Flexbox, responsive design avec media queries
  • Ancien portfolio : portfolio sur GitHub Pages, Bootstrap, formulaire de contact
  • Ces projets posent les bases qui me permettent aujourd'hui de lire et comprendre le HTML/CSS généré par Angular
Compétences Annexe 8-3 : Développer la présence en ligne · Organiser son développement professionnel
8–10 min

Portfolio actuel keryan.net — Infrastructure et self-hosting

« Pour héberger et présenter l'ensemble de ces réalisations, j'ai déployé ce portfolio sur un VPS self-managed. »

  • Serveur web Nginx en reverse proxy, certificat HTTPS Let's Encrypt
  • Authentification centralisée Authelia SSO (2FA TOTP) sur les zones privées
  • Démos live des projets accessibles derrière Authelia : /wachangelog-demo/, /gsb/, /nolark/
  • Site statique HTML/CSS/JS pur, sans framework — CSS variables, mode jour/nuit, slider d'images
  • Favicon SVG, CSP headers, HSTS, balises Open Graph
Compétences Annexe 8-3 : Gérer le patrimoine informatique · Développer la présence en ligne · Mettre à disposition un service informatique · Organiser son développement professionnel
10–12 min

Progression et fil conducteur

« Ce qui relie tous ces projets, c'est une progression logique des compétences : »

  • HTML/CSS statique (Nolark, ancien portfolio) → bases front-end
  • PHP/MySQL/MVC (GSB) → introduction au back-end, sessions, ORM
  • WinDev (alternance) → maintenance d'un existant, relation client interne
  • ASP.NET Core + Angular + JWT (WAChangeLogUrgence) → architecture professionnelle découplée
  • Nginx + Authelia + VPS (portfolio) → infrastructure, sécurité, self-hosting
Argument fort pour le jury : chaque projet a enrichi les compétences du suivant — montée en compétence structurée et documentée.
12–15 min

Conclusion + ouverture vers l'échange

« L'ensemble de ces réalisations est consultable en ligne sur keryan.net/projet/. Chaque fiche projet détaille les compétences mobilisées, les choix techniques et les alternatives envisagées. Je suis prêt à approfondir n'importe lequel de ces points. »

  • Proposer au jury d'accéder au portfolio en direct si possible
  • Avoir les démos prêtes : WAChangeLog (keryan / Test1234!), GSB (p.ayot / xiej3uuY0)
  • Tableau de synthèse prêt (annexe 8-1)
⚠ Rappel pénalités E5 : portfolio inaccessible −10 pts · tableau de synthèse absent −2 pts · Note sur 20.
Pourquoi ces choix techniques ?
Hébergement

VPS plutôt que GitHub Pages

GitHub Pages héberge uniquement du statique. Le VPS permet d'exécuter PHP, .NET, des conteneurs Docker — nécessaire pour les démos live des projets. Coût : ~5€/mois, compétence infra en prime.

Reverse proxy

Nginx plutôt qu'Apache

Nginx consomme moins de mémoire en charge, gère mieux les connexions concurrentes, et sa syntaxe de configuration est plus lisible pour les proxys. Choix standard en production moderne.

Sécurité

Authelia plutôt qu'un simple .htpasswd

Authelia apporte le SSO (une seule authentification pour tous les services), le 2FA TOTP, et des règles d'accès par chemin URL. .htpasswd ne gère qu'un mot de passe basique sans 2FA.

Frontend

CSS pur plutôt que Bootstrap

CSS variables natives (var(--bg)), Grid et Flexbox couvrent tous les besoins sans dépendance externe. Bootstrap aurait ajouté ~150 Ko inutiles. Résultat : site plus rapide et CSS entièrement maîtrisé.

Compétences BTS SIO — Annexe 8-3
Bloc de compétenceApplication dans le portfolio
Développer la présence en ligne de l'organisation Portfolio public HTTPS sur keryan.net. Balises Open Graph, canonical, robots.txt, favicon SVG. Mise en valeur du parcours professionnel et des réalisations accessibles en ligne.
Gérer le patrimoine informatique Configuration Nginx avec règles d'accès par chemin, headers de sécurité (CSP, HSTS, X-Frame-Options). Gestion des services auto-hébergés via Authelia. Certificat SSL Let's Encrypt avec renouvellement automatique.
Mettre à disposition un service informatique Déploiement des démos projets sur le même VPS (WAChangeLog, GSB, Nolark). Tests de bon fonctionnement. Documentation d'accès (identifiants démo) disponible sur chaque fiche projet.
Organiser son développement professionnel Identité professionnelle visible publiquement (GitHub, LinkedIn, email). Portfolio évolutif qui documente la progression des compétences. Veille active sur les pratiques web modernes (CSS variables, SVG, sécurité HTTP).
Travailler en mode projet Conception et réalisation du portfolio itérativement : version statique simple → ajout des sliders d'images → mode théâtre → fiches projet E5 → self-hosting avec Authelia.
Nginx, reverse proxy & Authelia — fonctionnement concret

1. Qu'est-ce qu'un reverse proxy ?

Un proxy classique se place entre le client et internet (ex : proxy d'entreprise qui filtre les sites). Un reverse proxy se place entre internet et les serveurs internes. Le client ne parle qu'au reverse proxy — il ne sait pas qu'il y a plusieurs applications derrière.

Navigateurhttps://keryan.net/gsb/ ↓ (port 443 HTTPS) Nginx (reverse proxy) ├─ /gsb/ → PHP-FPM socket → /var/www/gsb/public/index.php ├─ /wachangelog-api/ → http://127.0.0.1:5285 (ASP.NET Kestrel) ├─ /nolark/ → /var/www/nolark/ (fichiers statiques) └─ /authelia/ → http://127.0.0.1:9092 (Authelia)

Avantages : un seul port 443 exposé, HTTPS centralisé sur Nginx (les apps internes tournent en HTTP simple), routing par chemin URL, headers de sécurité ajoutés en un seul endroit.

2. Configuration Nginx — comment ça marche vraiment

Nginx lit les blocs location selon un ordre de priorité strict : exact match = > préfixe prioritaire ^~ > regex ~ > préfixe simple.

# Fichier : /etc/nginx/sites-enabled/default # Bloc pour GSB (PHP) — protégé par Authelia location /gsb/ { include /etc/nginx/snippets/authelia-authrequest.conf; # ← vérification auth alias /var/www/gsb/public/; # répertoire physique index index.php; try_files $uri $uri/ @gsb_fallback; location ~ \.php$ { # fichiers .php → PHP-FPM fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $request_filename; } } location @gsb_fallback { rewrite ^/gsb/(.*)$ /gsb/index.php?$query_string last; } # Bloc pour WAChangeLog API (ASP.NET Kestrel) location /wachangelog-api/ { proxy_pass http://127.0.0.1:5285/; # redirige vers Kestrel proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; }

alias vs root : avec root /var/www/gsb/public, Nginx cherche /var/www/gsb/public/gsb/index.php (chemin doublé). Avec alias /var/www/gsb/public/, il remplace le préfixe /gsb/ par le chemin physique → correct.

3. HTTPS avec Let's Encrypt

Let's Encrypt est une autorité de certification gratuite. L'outil certbot génère un certificat TLS valide 90 jours et le renouvelle automatiquement via un cron.

# Génération initiale certbot --nginx -d keryan.net -d www.keryan.net # Résultat dans nginx : ssl_certificate /etc/letsencrypt/live/keryan.net/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/keryan.net/privkey.pem; # HSTS : force HTTPS même si le navigateur tape http:// add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Comment ça fonctionne : lors du handshake TLS, le navigateur vérifie que le certificat est signé par une autorité reconnue (Let's Encrypt → ISRG Root X1). Le contenu est ensuite chiffré via AES. Sans HTTPS, n'importe qui sur le réseau pourrait lire les tokens JWT ou les mots de passe en transit.

4. Authelia — SSO et 2FA, comment ça s'intègre à Nginx

Authelia est un serveur d'authentification. Il ne sert pas les pages lui-même — il répond uniquement à une question : « cet utilisateur est-il connecté et autorisé à accéder à cette URL ? ». C'est Nginx qui l'interroge via la directive auth_request.

Flux complet — accès à /gsb/ sans être connecté :

1. Navigateur → GET https://keryan.net/gsb/ 2. Nginx reçoit la requête → lit auth_request /authelia/api/verify └─ Nginx fait une sous-requête interne vers Authelia 3. Authelia /api/verify vérifie le cookie de session └─ Pas de session valide → répond 401 Unauthorized 4. Nginx reçoit le 401 → applique la règle : error_page 401 =302 https://keryan.net/authelia/?rd=https://keryan.net/gsb/ 5. Navigateur redirigé vers le portail Authelia └─ L'utilisateur saisit login + mot de passe + code TOTP (2FA) 6. Authelia valide → pose un cookie de session chiffré └─ Redirige vers l'URL originale (/gsb/) 7. Nginx reçoit la nouvelle requête → auth_request à nouveau └─ Cette fois Authelia répond 200 OK 8. Nginx laisse passer → PHP-FPM génère la page GSB → 200 OK au navigateur

Le snippet nginx qui déclenche tout ça (/etc/nginx/snippets/authelia-authrequest.conf) :

# Sous-requête interne vers Authelia pour vérifier l'auth auth_request /authelia/api/verify; # Récupère les infos utilisateur depuis la réponse Authelia auth_request_set $target_url $scheme://$http_host$request_uri; auth_request_set $user $upstream_http_remote_user; auth_request_set $groups $upstream_http_remote_groups; # Transmet l'identité à l'application en aval proxy_set_header Remote-User $user; proxy_set_header Remote-Groups $groups; # Si Authelia renvoie 401 → redirection vers le portail de login error_page 401 =302 https://$http_host/authelia/?rd=$target_url;

L'endpoint de vérification interne (location /authelia/api/verify, marqué internal = inaccessible depuis le navigateur) :

location /authelia/api/verify { internal; # ← impossible d'appeler cette URL depuis un navigateur proxy_pass http://127.0.0.1:9092/authelia/api/verify; proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Forwarded-Method $request_method; proxy_pass_request_body off; # Authelia n'a pas besoin du corps de la requête proxy_set_header Content-Length ""; }

5. Headers de sécurité HTTP

# Content Security Policy : interdit le chargement de ressources non autorisées add_header Content-Security-Policy "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self'"; # Empêche le navigateur de "deviner" le type MIME (protection contre certaines injections) add_header X-Content-Type-Options "nosniff"; # Interdit à d'autres sites d'inclure la page dans une iframe (clickjacking) add_header X-Frame-Options "SAMEORIGIN";

6. Problèmes rencontrés et solutions

🔴 Problème — La favicon était interceptée par le proxy Authelia

La règle Nginx location ~ ^/(favicon) capturait /favicon.svg et la renvoyait vers le proxy de la homepage (port 7575), qui répondait avec une redirection 302 vers Authelia. La favicon n'apparaissait jamais.

✅ Solution — Exact match prioritaire

Ajout d'une règle location = /favicon.svg (exact match =) avant la regex. En Nginx, = a priorité absolue sur ~, donc le fichier statique est servi directement sans passer par Authelia.

🔴 Problème — alias + PHP-FPM : chemin SCRIPT_FILENAME incorrect

Avec root /var/www/gsb/public et l'URL /gsb/index.php, Nginx construisait le chemin /var/www/gsb/public/gsb/index.php qui n'existe pas. PHP-FPM retournait une 404.

✅ Solution — Utiliser alias + $request_filename

Avec alias /var/www/gsb/public/, Nginx remplace le préfixe /gsb/ par le chemin physique. fastcgi_param SCRIPT_FILENAME $request_filename récupère alors le bon chemin résolu.

🔴 Problème — Le JavaScript du slider Nolark ne s'exécutait pas

Le bloc (function() { makeSlider(...) })() était inséré dans le HTML sans balises <script></script>. Le navigateur l'ignorait complètement, les flèches et le bouton expand ne répondaient pas.

✅ Solution — Balises script manquantes

Ajout de <script> avant l'IIFE et </script> après. Diagnostic : inspection du DOM avec les DevTools du navigateur → onglet Sources → le code JS n'apparaissait pas dans les scripts chargés.

🔴 Problème — auth_request renvoyait 500 sur certaines routes

Lorsqu'Authelia n'était pas encore démarré ou que son socket était inaccessible, Nginx renvoyait une erreur 500 au lieu d'une redirection propre vers le portail de login.

✅ Solution — Vérifier l'ordre de démarrage des services

Authelia doit être démarré avant Nginx. Dans systemd, configurer After=authelia.service dans l'unité Nginx. Vérifier avec systemctl status authelia que le service est active (running) avant de recharger Nginx.