Le site est en ligne. Avant d'en parler à qui que ce soit, cette page ajoute les deux fichiers qu'un export statique ne produit pas tout seul — robots.txt et sitemap.xml —, allège les fichiers qui ralentissent les pages, puis vérifie depuis l'extérieur, comme le voient un visiteur ou un robot d'indexation, tout ce que les pages 4 à 7 ont mis en place. Elle se termine par les moteurs de recherche et une courte liste pour le jour de l'annonce.
Avant de commencer
Le site est déployé avec le script de la page 6 et répond sur son domaine. Tout ce qui suit se fait sur ton Mac, depuis le dossier du projet, sauf les modifications HSTS sur le serveur. Prévois deux amis comme testeurs externes pour la fin : un en données mobiles, un sur le Wi-Fi d'un autre opérateur. D'abord, la page d'accueil répond :
$curl -s -o /dev/null -w '%{http_code}' https:///200
Ajouter robots.txt et sitemap.xml
output: "export" n'écrit que ce que l'application déclare. Next.js a deux fichiers de métadonnées pour ça : app/robots.ts et app/sitemap.ts. Au build, chacun devient un fichier ordinaire dans out/.
Règle d'abord le choix d'indexation dans le panneau. Laisse-le désactivé tant que le site contient encore des exemples ou des fonctions qui font semblant de marcher, comme un formulaire de contact qui simule l'envoi : les robots les indexeraient tels quels. Active-le, et redéploie, le jour du lancement.
Dans un terminal sur ton Mac, va dans le dossier du projet, puis copie chaque bloc de fichier ci-dessous et colle-le dans le terminal : chacun écrit son fichier.
$cd import type { MetadataRoute } from "next";export const dynamic = "force-static";const SITE = "https://";export default function robots(): MetadataRoute.Robots { return { rules: { userAgent: "*", allow: "/" }, sitemap: SITE + "/sitemap.xml", };}import type { MetadataRoute } from "next";export const dynamic = "force-static";const SITE = "https://";const ROUTES = [ "/", "/bio/", "/bookmarks/", "/chess/", "/clippings/", "/contact/", "/endeavor/", "/how-i-want-to-live/", "/journey/", "/lately/", "/library/", "/own/", "/pearl/", "/picture/", "/support/", "/thought/", "/travel/", "/writing/",];export default function sitemap(): MetadataRoute.Sitemap { const now = new Date(); return ROUTES.map((path) => ({ url: SITE + path, lastModified: now }));}Déploie avec le script de la page 6, qui construit avant d'envoyer, puis vérifie que les deux fichiers ont bien été générés :
$cd $./scripts/deploy.sh$ls out/robots.txt out/sitemap.xml$curl -s https:///robots.txt | head -1User-Agent: *
Si le build échoue ou si out/robots.txt manque
Un public/robots.txt ou public/sitemap.xml entre en conflit avec celui qui est généré : supprime celui de public/. Une erreur qui cite dynamic ou revalidate sur /robots.txt veut dire que la ligne force-static manque. Un projet organisé en src/app/ prend les deux fichiers à cet endroit.
Alléger les fichiers les plus lourds
Un WAV de 50 Mo sur une page, c'est 50 Mo à télécharger sur un téléphone. Liste tout ce que le site sert au-delà de 5 Mo :
$cd $find out -type f -size +5M -exec ls -lh {} \; | sort -k5 -hL'audio : convertis chaque WAV en Opus, ou en MP3 pour les navigateurs les plus anciens, puis change la référence dans le code.
$brew install ffmpeg$ffmpeg -i public/audio/track.wav -c:a libopus -b:a 128k public/audio/track.opus$ffmpeg -i public/audio/track.wav -c:a libmp3lame -q:a 2 public/audio/track.mp3$grep -rn '\.wav' app components lib 2>/dev/nullLes images : rien sur une page web n'a besoin de plus de 2400 px sur le grand côté.
$cd $cp -R public ../public-before-resize$find public -iname '*.jp*g' -size +1M -exec sips -Z 2400 {} \;$du -sh ../public-before-resize publicVérifier depuis l'extérieur
Redirections et codes de statut
$curl -sI http:/// | grep -iE '^(HTTP|location)'$curl -sI https://www./ | grep -iE '^(HTTP|location)'$curl -s -o /dev/null -w '%{http_code}\n' https:///no-such-page/HTTP/1.1 308 Permanent RedirectLocation: https:///HTTP/2 301location: https:///404$curl -s -o /dev/null -w '%{http_code}' https:///no-such-page/404
TLS
Ouvre le test SSL Labs pour ton domaine. Il prend environ deux minutes. Vise A ; A+ demande un max-age HSTS d'au moins six mois, que l'étape qui suit ces vérifications met en place.
$open "https://www.ssllabs.com/ssltest/analyze.html?d="$curl -sv -o /dev/null https:/// 2>&1 | grep -E 'issuer|expire date'$echo | openssl s_client -connect :443 -servername 2>/dev/null | openssl x509 -noout -issuer | grep -o 'Let.s Encrypt'Let's Encrypt
En-têtes de sécurité
$open "https://securityheaders.com/?q=https:///&followRedirects=on"$curl -sI https:/// | grep -iE '^(strict-transport|x-content-type|x-frame|referrer|permissions|content-security)'Attends-toi à strict-transport-security, x-content-type-options: nosniff, referrer-policy et ce que la page 5 a ajouté d'autre. L'absence de content-security-policy est normale à ce stade : elle coûte une note, pas une sécurité que tu avais déjà.
IPv6 et HTTP/3
$dig +short AAAA $curl -6 -sI https:/// | head -1$curl -sI https:/// | grep -i '^alt-svc'Usurpation d'adresse mail
Si tu as indiqué en page 4 que le domaine n'envoie pas de mail, vérifie que les enregistrements « pas de mail » sont publiés, pour que personne ne puisse envoyer du hameçonnage en ton nom :
$dig +short TXT _dmarc.$dig +short TXT | grep spf1Performance
Dans Chrome, ouvre le site en navigation privée, puis DevTools → Lighthouse → Mobile → Analyze page load. Ou passe par PageSpeed Insights, qui lance le même test depuis les serveurs de Google :
$open "https://pagespeed.web.dev/report?url=https:///"Passer HSTS à un an
La page 5 a démarré l'en-tête HSTS à un jour. Une fois toutes les vérifications ci-dessus au vert, passe-le à un an, sur le serveur :
$ssh vps$sudo sed -i 's/max-age=86400"/max-age=31536000"/' /etc/caddy/Caddyfile$sudo -u caddy caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy$curl -sI https:/// | grep -i '^strict-transport-security'strict-transport-security: max-age=31536000
Moteurs de recherche
Dis à Google et à Bing que le site existe et où se trouve le sitemap.
- Dans Google Search Console, ajoute une propriété de type Domaine avec
. Google affiche un enregistrement TXT qui commence pargoogle-site-verification=. - Dans le Manager Infomaniak, Zone DNS du domaine (comme en page 4), ajoute cet enregistrement TXT sur le domaine lui-même, puis clique sur Valider dans Search Console. Ça peut prendre quelques minutes.
- Dans Search Console → Sitemaps, saisis
sitemap.xmlet envoie. - Dans Bing Webmaster Tools, connecte-toi et choisis l'import depuis Google Search Console : il reprend le site et le sitemap.
$dig +short TXT | grep google-site-verificationAnnoncer
Un dernier coup d'œil avant de publier le lien et de demander à tes testeurs externes d'ouvrir le site sur leur téléphone :
- Favicon :
/favicon.icorépond 200 (commande ci-dessous). Next.js sertapp/favicon.icoouapp/icon.png. - Image d'aperçu des liens : un JPEG de 1200 × 630 en
app/opengraph-image.jpg(Next.js ajoute les balises meta) etmetadataBaseréglé sur https://dans le layout racine, pour que l'URL de l'image soit absolue. Exporte-la depuis les originaux dephotos-26-og/; eux restent hors du site. Colle le lien dans un message à toi-même pour voir l'aperçu. - Page 404 : mise en forme, avec un chemin vers l'accueil.
- Fonctions en attente : le formulaire de contact et la sauvegarde des parties d'échecs n'ont pas encore de backend ; cache-les ou marque-les « bientôt ».
- Surveillance : la sonde de disponibilité de la page 7 est au vert et ses alertes arrivent à
. - Après le lancement : les flux RSS de
/latelynotés dans le TODO du projet peuvent attendre ; un flux ajouté la semaine prochaine marche pareil.
$curl -s -o /dev/null -w '%{http_code}\n' https:///favicon.ico$curl -s https:/// | grep -o '<meta property="og:image"[^>]*>'Terminé
La série est complète : un site Next.js construit sur ton Mac, servi en HTTPS par Caddy depuis ton propre VPS Debian chez OVH, sur un domaine géré chez Infomaniak, déployé de façon atomique, sauvegardé, surveillé et vérifié depuis l'extérieur, avec Google et Bing qui savent où trouver le sitemap. Le script Automatique de cette page sert aussi de test rapide après chaque gros changement.
Une page à venir, pas encore écrite — la page 9 — donnera un backend au formulaire de contact et aux sauvegardes d'échecs sur le même VPS : un petit service Node derrière Caddy, avec SQLite.