Owner-authored CV rework: technical skills promoted above experience,
'Centres d'intérêt' dropped, markup trimmed 656 -> 424 lines. Header
carries the Loire-Atlantique · Vendée · Morbihan zone and the presence
hierarchy (full remote, hybrid or on-site in the zone, Paris capped at
1-2 days/month).
Adds CV_Bastien_CHANOT_General.{html,pdf} as the general variant kept
alongside the served CV. Not linked from the landing and not in the
Dockerfile COPY whitelist, so it ships in the repo only, not to prod.
Both HTML/PDF pairs verified in sync via weasyprint re-render (text
identical, 2 pages each). New files normalized to mode 644.
bchanot.fr
Personal landing page + CV for Bastien Chanot — developer, systems & backend.
Static single-page site (no framework, no build step). Lives at https://bchanot.fr.
Contents
| File | Purpose |
|---|---|
index.html |
Landing page (inline CSS + JS, single file) |
CV_Bastien_Chanot.html |
CV — web version, linked from landing as "Voir le CV" |
CV_Bastien_Chanot.pdf |
CV — printable, served via "Télécharger PDF" |
CLAUDE.md |
Project rules for the Claude assistant |
.claude/ |
Memory registries, tasks, audits |
Dockerfile |
Container image build — copies static assets into nginx |
docker-compose.yml |
Service def — host port, hardening (read-only, cap_drop), tmpfs |
nginx.conf |
In-container nginx — CSP, gzip, cache rules |
nginx-security-headers.conf |
Shared security-headers snippet, re-included per location (nginx add_header inheritance is all-or-nothing) |
.env.example |
Sample env — PORT for the host bind |
.githooks/ |
Versioned git hooks — pre-commit blocks direct code commits on main/develop (gitflow) |
favicon.*, apple-touch-icon.png |
Favicon set — SVG primary + ICO/PNG + 180×180 apple-touch |
After cloning, wire the versioned hooks once:
git config core.hooksPath .githooks
Local preview
python3 -m http.server 8000 --bind 0.0.0.0
Then open http://localhost:8000/ (same machine) or http://192.168.1.101:8000/
from any device on the LAN.
If the LAN URL is unreachable, the firewall is likely blocking the port:
sudo ufw allow 8000/tcp
Regenerate the CV PDF after editing the HTML
weasyprint CV_Bastien_Chanot.html CV_Bastien_Chanot.pdf
Run this every time CV_Bastien_Chanot.html is modified so the served PDF
stays in sync.
Stack
- HTML5 + CSS3 (inline
<style>in<head>) - Vanilla JS (inline
<script>before</body>) - Google Fonts: JetBrains Mono, Fraunces, DM Sans
weasyprintfor HTML → PDF conversion (CV only)
No bundler. No npm. No runtime dependencies beyond Google Fonts.
Design rules
Strict palette (non-negotiable):
| Hex | Role |
|---|---|
#0d1b12 |
Dark forest — nav, dark sections, footer |
#1b5e3b |
Green primary — section titles, links on light bg |
#2d7a4f |
Green accent — borders, dots, separators |
#6ab98a |
Green light — text on dark bg |
#dff0e7 |
Green tint — pill background |
#f5f3ec |
Parchment — page background |
Plus a documented set of functional neutrals (text inks, rules/tags, two
green-scale intermediates) — the exhaustive list lives in CLAUDE.md.
Typography:
Fraunces— display (names, titles)JetBrains Mono— technical labels, badges, pills, nav, contactDM Sans— body text
Mobile-first, responsive at 768px + 1200px breakpoints. WCAG AA contrast. Focus visible. Semantic HTML.
Deploy
Production currently serves the static files directly from the VPS's native
nginx (which also terminates TLS). The repo additionally maintains a hardened
container path (bchanot-web, nginxinc/nginx-unprivileged:1.30-alpine,
digest-pinned, runs as uid 101 on port 8080) for when a containerized deploy
is preferred: the host port is set via PORT (default 8080) and bound to
127.0.0.1, so all traffic goes through the front proxy.
cp .env.example .env # optional: set PORT
docker compose up -d --build
Dockerfile copies the assets (HTML, PDF, favicons) into the image by an
explicit whitelist — when you add a new top-level asset, add it there too or it
will 404 in production. nginx.conf applies the security headers, gzip and
cache rules. The site is also plain static: index.html, the CV HTML/PDF and
favicon set drop onto any static host (Netlify, Vercel, GitHub Pages, plain
nginx) at the root.
License
Personal site content — © Bastien Chanot.