A little corner of the internet where Gaspard Witrand hosts the side projects he actually uses: a handful of cycling tools, a living-room quiz engine, a faster window into live bike-race tracking, and the usual toolbox companions — a file drop, dashboards, the works.
Self-hosted uptime monitoring with public status pages and multi-channel alerting. HTTP / TCP / ping checks at 30 s–5 min intervals, consecutive-failure thresholds, automatic incident open/resolve, and 24 h / 7 d / 30 d uptime stats with a response-time sparkline. Webhook (Slack/Discord), per-user SMTP email and Telegram alerts with cooldowns. Public status pages with custom branding, RSS feed, incident updates. Free / Pro / Team plan tiers gated by Stripe billing, with graceful downgrade enforcement and daily S3 database backups.
Upload a GPX route and get back a long, flat elevation-profile strip sized for the handlebar of a bike. Climbs over a gain threshold are highlighted in orange with gradient and elevation labels; waypoints appear as red checkpoints. There's a mirror option for those who print onto transparent film and tape it the other way round.
A self-hosted real-time quiz game in the spirit of Kahoot. Host a round on a big screen, players join from their phones with a 6-digit PIN or QR. True/false or multi-choice questions, per-question images and timers, live leaderboard with confetti and a dramatic podium reveal. Argon2 + JWT + proof-of-work captcha — no third-party auth.
A drop-in replacement for one event page on app.madcap.cc — live bike-race GPS tracking. The original ships a 13 MB bundle and waits 6-9 s on a cold origin XHR. This server caches every 30 s, pre-compresses brotli/gzip, and serves the whole thing in ~0.7 s instead of ~31 s. Same data, one memcpy per request.
Self-hosted browser for Brevets de Randonneurs Mondiaux, pulled from the Audax Club Parisien worldwide calendar. Filter by distance (200 / 300 / 400 / 600 / 1000), country, region and date; plot everything on a clustered Leaflet map; download a GPX for any OpenRunner-hosted route with one click. A hard 24 h floor on upstream fetches keeps ACP's servers happy.
Upload a GPX (or pick one from BRM Maps / Cyclo Copains), choose a start datetime, and get a per-segment forecast along the route — temperature, rain probability, and wind vector projected onto your heading so you see exactly where you'll eat a headwind and where the wind's on your back. A "best departure window" picker resimulates the ride at 30-minute offsets over the next 48 h and shows which start minimises total headwind exposure. Forecasts are cached per (lat, lon, hour) in SQLite, so repeat queries are instant.
Upload a GPX and see every ravito along the route — bakeries, supermarkets, bar-tabacs, water fountains — pulled from OpenStreetMap via the Overpass API. Grouped by ride-km so you can plan stops every 40-60 km instead of bonking at km 210. Opening-hours strings are parsed so you know whether the boulangerie at km 180 will actually be open when you get there. Results cached locally so re-running the same route is instant.
Upload a Strava CSV export and get a full personal dashboard — yearly / monthly / weekly volume, activity streaks, personal bests, fitness-fatigue (CTL / ATL / TSB) curve, power trends, HR zone breakdown, and weather correlation (wind rose, temperature vs. speed). All computed server-side, no Strava API token required. Your data stays on this box.
A full-screen countdown timer aimed at a target date — currently July 25 2026, 14:00 CEST — that flips to an elapsed-time counter once the deadline passes. Friends and supporters can submit encouragement messages (with bib number and runner name) via /send; messages rotate on the main display with cinematic fade-in animations. Built for projecting on a big screen at race events.
A scriptable file-upload service (the excellent open-source root-gg/plik). Drop a file, get a link with a TTL, one-shot download, optional password, optional comments — and a clean CLI companion for piping tarballs from a terminal straight to a shareable URL.
An internal tool built for the Mayo Jaune cycling group: pull a weekly announcement from Discord, strip @everyone and role pings, resolve user mentions to Instagram handles, pick the matching *_{km}.png header image for the ride distance, and post it to Instagram via the Graph API — with a Telegram approval gate so a human sees every post before it goes live. Edits on Discord round-trip back to Instagram too.
Landing page for Mayo Jaune, a Paris cycling group — single-page site plus a /maps viewer that lists the group's rides as GPX traces pulled from Komoot. Static Next.js export, deployed to its own domain. Source lives on GitLab.
Self-hosted shareable money pots — a Leetchi alternative without the 4% commission. Create a pot with a goal, drop in your Lydia / IBAN / PayPal details, share the link. Contributors declare what they've paid; the organiser confirms each entry against the actual transfer. Progress bar, contributor list, deadline auto-close, CSV export — no payment processor, no account for participants.
A self-hosted recipe book — collect, search, and cook from a personal library. Recipes are stored with ingredients, steps, prep / cook times and tags; a cookie-session login keeps the kitchen private. Postgres-backed for honest full-text search, Tera templates for server-rendered pages, Argon2 for the password hash. No third-party API, no tracking, no ads.
Self-hosted live GPS tracker for solo bike rides. Open the tracker on your phone, share the link, and anyone can watch your breadcrumb trail on a Leaflet map in real time via WebSocket push — with speed, distance and elevation. Pings queue offline and flush when signal returns. Sessions auto-expire after 48 h. A self-hosted Strava Beacon with zero cloud dependency.
« Trouve ta prochaine sortie vélo entre copains. » A directory of social bike rides across France — no race timing, no pressure. Filter by region, see the organising clubs, drop rides on a calendar or a map. A small admin backend lets me keep the listings up to date.
No framework, no build step, no client-side JavaScript framework. A single index.html with inline CSS, served by Caddy as a plain file. The whole page is a few kilobytes over the wire.
Each subdomain above is a Caddy reverse_proxy block pointing either to a container on the Docker bridge (172.17.0.1:PORT) or to the host's public IP on a fixed port. Caddy handles TLS everywhere automatically once the DNS is in place.
Palette borrowed from Cyclo Copains: paper, ink, mustard, vermilion, teal. Fonts are Bricolage Grotesque (display), Fraunces (serif italic accents) and Space Mono (labels). A tiny SVG grain layer sits on top at 28% opacity.
The document lives at /srv/extragornax/index.html. Updating it is one scp. No container, no process, no restart — Caddy picks up the new bytes on the next request.
Every tool I wrote on this box is a Rust binary running on top of Axum, shipped as a multi-stage Docker image on top of debian:12-slim. Templates are compiled via Askama; persistence is SQLite or Postgres depending on the workload.
All of the tools on this page — homepage included — live under github.com/extragornax. Poke around, clone, open issues, send a PR if something catches your eye.