Ce site est lui-même un projet : un site web multilingue et auto-hébergé, construit de zéro en Rust. La production tourne sur un VPS Linux ; le homelab héberge le dépôt Forgejo et le runner CI qui compile et déploie à chaque push sur main.
Rust a été choisi délibérément. Le runtime n'a pas de ramasse-miettes, pas d'allocation mémoire cachée, et démarre en quelques millisecondes. Pour un site de contenu comme celui-ci, cela signifie que le serveur est systématiquement rapide — sous charge ou à froid — et que le binaire est suffisamment petit pour résider confortablement dans un conteneur Podman.
Le framework est Axum, une bibliothèque HTTP ergonomique construite sur le runtime asynchrone de Tokio.
Tout le contenu vit dans des fichiers Markdown bruts, organisés par langue et section. Au démarrage, le serveur lit chaque fichier exactement une fois :
--- en tête de chaque fichier, avant que le contenu ne soit transmis au moteur Markdown.translations.txt par langue (paires clé = valeur) sont parsés en table de correspondance.Les templates HTML sont embarqués directement dans le binaire à la compilation via la macro include_str!() de Rust. Il n'y a pas de moteur de templates — juste une convention {{ PLACEHOLDER }} et des appels à .replace() au moment de la requête. Le résultat est un serveur avec zéro I/O disque par requête.
flowchart TD
classDef visitor fill:#f9f9f9,stroke:#333,stroke-width:2px;
classDef infra fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
classDef runtime fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
classDef source fill:#fff3e0,stroke:#ef6c00,stroke-width:2px;
classDef pipeline fill:#ede7f6,stroke:#4527a0,stroke-width:2px;
classDef cicd fill:#fce4ec,stroke:#880e4f,stroke-width:2px;
Visitor([Navigateur])
subgraph VPS [VPS — Linux]
NGINX["NGINX · terminaison TLS"]
Static["Fichiers statiques · CSS · favicon"]
subgraph Container [Conteneur Podman]
Router["Routeur Axum\n/{lang}/blog · /services · /projects · /cv"]
Handler["Gestionnaire de requête"]
Templates["Templates HTML\ninclude_str! — compilés dans le binaire"]
AppState["Arc<AppState> — cache partagé en lecture seule"]
end
end
subgraph Homelab [Homelab — origine CI/CD]
Forgejo["Forgejo\nGit + CI"]
ForgejoRunner["Forgejo runner"]
end
subgraph Pipeline [Pipeline de démarrage — exécuté une fois au lancement]
MDFiles[("Fichiers Markdown\nresources/en · es · fr")]
FrontMatter["Parser de frontmatter\nauteur · date"]
Cmark["pulldown-cmark\nMarkdown → HTML"]
Prebuilt["HTML pré-construit\nlistes · nav dropdowns · traductions"]
end
Visitor -->|HTTPS| NGINX
NGINX --> Router
Router --> Handler
Handler --> Templates
Handler --> AppState
Templates -->|Réponse HTML| Visitor
Static -->|ServeDir| Visitor
Forgejo -->|push déclenche| ForgejoRunner
ForgejoRunner -->|build + déploiement| VPS
MDFiles --> FrontMatter
FrontMatter --> Cmark
Cmark --> Prebuilt
Prebuilt -->|chargé dans| AppState
class Visitor visitor;
class NGINX infra;
class Router,Handler,Templates,AppState runtime;
class Static source;
class MDFiles,FrontMatter,Cmark,Prebuilt pipeline;
class Forgejo,ForgejoRunner cicd;
Le site sert l'anglais, l'espagnol et le français depuis le même binaire. Le préfixe d'URL (/en/, /es/, /fr/) détermine la langue. Le contenu est organisé en répertoires par langue, et les templates portent des marqueurs {{ T_CLÉ }} résolus au moment du rendu. Les slugs en anglais servent de clé canonique — les autres langues reviennent à la version anglaise si une traduction est absente.
Déployé en conteneur Podman sur un VPS Linux. NGINX termine le TLS et reverse-proxifie le trafic vers le conteneur. Le pipeline de livraison vit sur le homelab : le code source est hébergé sur une instance Forgejo auto-gérée, et un runner Forgejo prend en charge chaque push, compile le binaire et déploie le conteneur mis à jour sur le VPS. Pas de cloud. Pas de service CI managé. Pas de base de données.
Chaque changement passe par un environnement de staging avant d'atteindre la production. Le même runner Forgejo qui gère les déploiements en production gère aussi le staging — un conteneur séparé tournant la même image, accessible en interne pour validation.
Promouvoir en production consiste en un git merge vers main. Le runner détecte le push, compile le binaire de release et redéploie le conteneur de production sur le VPS.
sequenceDiagram
actor Dev as Développeur
participant Repo as Forgejo (homelab)
participant Runner as Forgejo runner
participant Staging as Conteneur staging
participant Prod as VPS — Production
Dev->>Repo: push sur branche staging
Repo->>Runner: déclencher pipeline CI
Runner->>Runner: cargo build --release
Runner->>Staging: déployer conteneur
Runner-->>Dev: staging prêt pour validation
Note over Dev,Staging: valider sur staging
Dev->>Repo: git merge staging → main
Repo->>Runner: déclencher pipeline CI (main)
Runner->>Runner: cargo build --release
Runner->>Prod: déployer conteneur Podman
Runner-->>Dev: production mise à jour
Rust · Axum · pulldown-cmark · tower-http · Forgejo CI · Mermaid.js