New article
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
nemunaire 2026-03-05 23:09:20 +07:00
commit 925f5e47d5
2 changed files with 379 additions and 0 deletions

View file

@ -0,0 +1,181 @@
---
title: The pragmatic architecture of my production projects
date: !!timestamp '2026-03-05 15:00:00'
tags:
- architecture
- web
- infrastructure
---
Reading some discussions between developers or software architects, one might
think that the smallest web application today requires a distributed
infrastructure, a Kubernetes cluster, and several specialized cloud services.
Yet many web services (including those that receive several thousand visitors
per day) can work perfectly well with a much simpler architecture.
Here is a hands-on account of the infrastructure I use for my production
projects, some of which exceed 2,000 daily visitors, and which I also applied
for years during a cybersecurity competition with more than 250 on-site
participants.
<!-- more -->
# Context
For a long time, I hosted all my projects from home. My websites, services, Git
forge, and even my continuous integration infrastructure ran on small ARM
machines (mainly Pine64 boards).
Contrary to what I hear everywhere, it worked very well.
The main reason I stopped is not a problem of computing power or reliability,
but simply my shift to a more nomadic lifestyle. A stable, permanent residential
connection becomes hard to guarantee when you travel often.
I therefore moved the public-facing part of my services to OVH, trying to keep
the same philosophy: simplicity and pragmatism.
# A simple observation
In many modern web projects, the architecture looks something like this:
```
user → CDN → frontend → API → database
```
Every request triggers server-side computation, even when the content changes
very rarely.
In my case, several of my sites share an important characteristic: **the main
content changes once a day.**
Take the [daily game Yakazu](https://yakazu-gratuit.fr/) as an example: for the
vast majority of visitors, the only thing that matters is **the grid of the
day**, which changes just once a day.
Under these conditions, generating the page dynamically on every request does
not make much sense.
# Chosen architecture
The solution is therefore very simple: the site is entirely static.
Every day, a scheduled event triggers the CI pipeline which:
1. generates the new grid;
2. rebuilds the site;
3. publishes the static files.
These files are then served directly by the static hosting included with the
domain name at OVH.
Yes, the free 100 MB plan.
This gives a very simple architecture:
```
CI → site generation → static files → OVH
```
All traffic is absorbed by the hosting provider's infrastructure, which is
exactly what it is designed for.
# Frontend
The site is built with SvelteKit.
This choice might seem surprising since I don't use the server-side capabilities
of this framework at all. But it allows:
- easily generating a static site (`@sveltejs/adapter-static`);
- clean routing;
- well-structured code;
- building Progressive Web Apps.
In other words: a modern framework, but without depending on a permanent
backend.
# And when a backend is needed?
Some features still require a bit of server-side logic.
For instance, regularly held championships need to verify participations and
record results and times.
In that case, I spin up a small separate backend server, which only receives a
very limited number of requests.
The architecture then becomes:
```
static site → CORS → small backend
```
This backend is deliberately minimal and only handles actions that cannot be
performed on the client side.
The key point is that **the vast majority of traffic never touches it**.
# Results
With this architecture:
- almost all traffic is served as static files;
- there is virtually no server-side computation;
- the failure surface is very small.
The issues I encounter are almost always related to the generation pipeline:
- an outdated Docker image;
- a CI trigger that fails;
- something missing in the data generation (the absence of a game grid, for example).
But these problems are easy to detect and usually fixed within minutes.
# Why keep it simple?
Looking back, I realize this approach follows a few simple principles:
1. **pre-compute what can be pre-computed**;
2. **serve files rather than computation**;
3. **reserve the backend for cases that truly need it**.
These principles often make it possible to handle significant load with very
modest resources.
For more than ten years, I organized a cybersecurity challenge that eventually
hosted around 300 simultaneous participants, with very basic machines.
The secret was not the hardware's power, but the system's design. I invite you
to watch my [presentation of this
infrastructure](https://youtube.com/watch?v=naFxBW5yoUA), with the trial and
error, the mistakes, and the constraints that shaped it.
# What about user accounts and payments?
A "login" to a user account does not necessarily require systematic validation
by a backend (and the notion of a user account is not always meaningful anyway).
A single API request can handle authentication (whether verifying a payment or
an email address, ...) and then you store that response in the browser to use in
the interface: right away... or even later. That way, there is no need to make
another API request for information you already have.
Not only does this reduce server load, it also speeds up page loading for the
user, who sees their data without a network call — and therefore even offline.
Everyone wins.
# Conclusion
Modern infrastructure offers many very powerful tools. But it is sometimes worth
remembering that many problems can be solved in a much simpler way.
Before adding a new technological layer, it is often worth asking a very simple
question:
**does this content really need to be generated on every request?**
In many cases, the answer is no.

View file

@ -0,0 +1,198 @@
---
title: L'architecture pragmatique de mes projets en production
date: !!timestamp '2026-03-05 15:00:00'
tags:
- architecture
- web
- infrastructure
---
Lorsqu'on lit certaines discussions entre développeurs ou architectes
logiciels, on pourrait croire que la moindre application web nécessite
aujourd'hui une infrastructure distribuée, un cluster Kubernetes et
plusieurs services cloud spécialisés.
Pourtant, de nombreux services web (y compris ceux qui accueillent
plusieurs milliers de visiteurs par jour) peuvent fonctionner
parfaitement avec une architecture beaucoup plus simple.
Voici un retour d'expérience sur l'infrastructure que j'utilise pour
mes projets en production, dont certains dépassent les 2000 visiteurs
quotidiens, et que j'ai également appliqué pendant des années lors
d'une compétition de sécurité informatique avec plus de 250
participants en présentiel.
<!-- more -->
# Contexte
Pendant longtemps, j'ai hébergé l'ensemble de mes projets directement
chez moi. Mes sites web, mes services, ma forge Git et même mon
infrastructure d'intégration continue tournaient sur de petites
machines ARM (principalement des Pine64).
Contrairement à ce que j'entends partout, cela fonctionnait très bien.
La principale raison pour laquelle j'ai arrêté n'est pas un problème
de puissance de calcul ou de fiabilité, mais simplement mon passage à
un mode de vie plus nomade. Une connexion résidentielle stable et
permanente devient difficile à garantir lorsque l'on se déplace
souvent.
J'ai donc déplacé la partie publique de mes services chez OVH, en
essayant de conserver la même philosophie : simplicité et pragmatisme.
# Une observation simple
Dans beaucoup de projets web modernes, l'architecture ressemble à
quelque chose comme ceci :
```
utilisateur → CDN → frontend → API → base de données
```
Chaque requête déclenche du calcul côté serveur, même lorsque le
contenu change très rarement.
Dans mon cas, plusieurs de mes sites ont une caractéristique
importante : **le contenu principal change une fois par jour.**
Prenons par exemple le [jeu quotidien
Yakazu](https://yakazu-gratuit.fr/) : pour la majorité des visiteurs,
la seule chose qui compte est **la grille du jour**, qui ne change
qu'une fois par jour.
Dans ces conditions, générer la page dynamiquement à chaque requête
n'a pas beaucoup de sens.
# Architecture retenue
La solution est donc très simple : le site est entièrement statique.
Chaque jour, un événement déclenche la CI qui :
1. génère la nouvelle grille ;
2. reconstruit le site ;
3. publie les fichiers statiques.
Ces fichiers sont ensuite servis directement par l'hébergement
statique fourni avec le nom de domaine chez OVH.
Oui, l'offre gratuite de 100 MB.
Cela donne donc une architecture très simple :
```
CI → génération du site → fichiers statiques → OVH
```
Tout le trafic est absorbé par l'infrastructure de l'hébergeur, ce
qui est exactement ce pour quoi elle est conçue.
# Frontend
Le site est construit avec SvelteKit.
Ce choix peut surprendre puisque je n'utilise pas du tout les
capacités serveur de ce framework. Mais il permet :
- de générer facilement un site statique (`@sveltejs/adapter-static`) ;
- d'avoir un routage propre ;
- de structurer le code proprement ;
- de construire des Progressive Web Apps.
Autrement dit : un framework moderne, mais sans dépendre d'un backend
permanent.
# Et quand il faut un backend ?
Certaines fonctionnalités nécessitent malgré tout un peu de logique
serveur.
Par exemple, les championnats organisés régulièrement doivent vérifier les
participations et enregistrer les résultats et les chronos.
Dans ce cas, je démarre un petit serveur backend séparé, qui ne reçoit
qu'un nombre très limité de requêtes.
L'architecture devient alors :
```
site statique → CORS → petit backend
```
Ce backend est volontairement minimal et ne traite que les actions
qui ne peuvent pas être réalisées côté client.
Le point important est que **la majorité du trafic ne le touche
jamais**.
# Résultat
Avec cette architecture :
- la quasi-totalité du trafic est servie sous forme de fichiers ;
- il n'y a quasiment pas de calcul côté serveur ;
- la surface de panne est très réduite.
Les problèmes que je rencontre sont presque toujours liés au pipeline
de génération :
- une image Docker qui n'est plus à jour ;
- un déclenchement CI qui échoue ;
- un oubli dans la génération des données (l'absence de grille de jeu par exemple).
Mais ces problèmes sont faciles à détecter et se corrigent
généralement en quelques minutes.
# Pourquoi faire simple ?
Avec un peu de recul, je me rends compte que cette approche suit
quelques principes simples :
1. **pré-calculer ce qui peut l'être** ;
2. **servir des fichiers plutôt que du calcul** ;
3. **réserver le backend aux cas réellement nécessaires**.
Ces principes permettent souvent d'absorber une charge importante
avec des ressources très modestes.
Pendant plus de dix ans, j'ai par exemple organisé un challenge de
sécurité informatique qui a fini par accueillir environ 300
participants simultanés, avec des machines très simples.
Le secret n'était pas la puissance du matériel, mais la conception du
système. Je vous laisse visionner ma [présentation de cette
infrastructure](https://youtube.com/watch?v=naFxBW5yoUA), avec les
tâtonnements, les erreurs et les contraintes qui l'ont façonné.
# Et les comptes utilisateurs, les paiements ?
Une "connexion" à un compte utilisateur n'a pas nécessairement besoin
d'une validation systématique par un backend (d'ailleurs la notion de
compte utilisateur n'a pas toujours de sens).
Une seule requête d'API peut faire l'authentification (que ce soit
la validation d'un paiement ou d'une adresse email, ...) puis on
stocke cette réponse dans le navigateur pour en faire usage dans
l'interface : maintenant ... ou même plus tard. Comme ça, inutile de
refaire une requête à l'API pour une information que l'on a déjà.
Non seulement cela réduit la charge du serveur, mais cela accroit
aussi la vitesse de chargement pour l'utilisateur qui voit ses données
sans appel réseau, et donc même hors ligne. Tout le monde est gagnant.
# Conclusion
L'infrastructure moderne propose de nombreux outils très puissants.
Mais il est parfois utile de se rappeler que beaucoup de problèmes
peuvent être résolus de manière beaucoup plus simple.
Avant d'ajouter une nouvelle couche technologique, il vaut souvent la
peine de se poser une question très simple :
**est-ce que ce contenu doit vraiment être généré à chaque requête ?**
Dans bien des cas, la réponse est non.