./blog.sh

Zámek, který nečeká

Dvakrát za hodinu na dost velkém webu sáhnou dvě úlohy cronu do téže složky téměř ve stejnou chvíli: naplánované publikování, které sestaví a nasadí příspěvek, jehož čas právě nastal, a obnova postranního panelu, která přepisuje několik týchž výstupních souborů čerstvými čísly. Většina tiků se mine o minuty. Na archivu tak velkém, že sestavení s úplným nasazením trvá déle než interval mezi nimi, se některé neminou.

Nasazení, které prochází strom, zatímco ho jiný běh ještě přepisuje, může vydat stránku zapsanou napůl. Běh, který maže osiřelé soubory, může jako osiřelou smazat stránku, kterou druhý běh o sekundu dřív publikoval. Ani jedno selhání se neohlásí – web je prostě potichu špatně.

Zámek a co odmítá dělat

Mezi těmi dvěma běhy stojí jediný soubor, .blog-sh.lock v kořeni projektu – a rozhoduje se způsobem, který vypadá špatně, dokud neuvidíš alternativu. Běh, který najde zámek obsazený, na něj nečeká.

Číst dál

Co zbývá pokazit

Na tomto webu není /admin. Žádný přihlašovací formulář, na kterém by šlo zkoušet hesla, žádná relační cookie, kterou by šlo ukrást, žádný seznam pluginů, který by bylo nutné porovnávat s CVE z minulého měsíce – ne proto, že by je někdo podle kontrolního seznamu odstranil, ale proto, že nic z toho nikdy nevzniklo.

Architektonické poznámky enginu říkají zbytek bez obalu: model hrozeb je statický web bez vlastního serveru. Nic tu neposlouchá na žádném portu. Cílem nikdy nebylo zabezpečit složitý systém proti všemu, co se v něm může pokazit. Cílem bylo žádný takový systém nepotřebovat.

Seznam toho, co zbývá pokazit, je pak kratší než u běžného blogu – co nesou stránky, co leží v pracovním adresáři, a ta jediná věc, která vstupuje zvenčí.

Jediná věc, která vstupuje zvenčí

Psaní z telefonu znamená, že jedny dveře přece jen přijímají bajty z cizího zařízení: scripts/receive.sh, spuštěný jako vynucený příkaz SSH klíče. Neposlouchá nikde – žádný socket, žádný démon, jen klíč, který smí spustit přesně tento skript a nic jiného.

Číst dál

Jak jsem si na sdíleném hostingu nastavil blog.sh

Pavel přestěhoval WordPressový blog ze sdíleného hostingu na blog.sh, a to přes obyčejné FTP. Postup popisuje krok za krokem: export WXR, import, rclone, zkušební běh, nasazení.

Stojí za přečtení, pokud tvůj web běží na hostingu, který nabízí FTP a nic víc.

#blogsh #wordpress #staticsite

Co se načte poslední, vyhrává

Dva skutečné weby nosí vzhled, který tento engine nikdy nedodával. sh.cynicky.blog je oblečený jako Ghost — úvodní karta přes celou šířku, tečkovaný rámeček, dlaždice místo prostého seznamu. arch-linux.cz je oblečený jako téma pro Hugo, konkrétně Blowfish — kompaktní lišta, blok s profilem, karty rozložené jako úplně jiná domovská stránka. Ani jeden nevytvořil fork enginu. Ani jeden neupravil šablonu. Oba dál přijímají obyčejný git pull.

Jeden stylesheet, načtený jako poslední

site.extra_css v config/site.yml udává cestu nebo seznam cest, které se načtou po vlastních colors.css a site.css enginu. To je celý mechanismus — skin je jeden tvůj soubor, který překresluje, co už na stránce je, a engine do něj nikdy nezapisuje, takže s ním aktualizace nikdy nemůže být v konfliktu.

Jen místní cesty: každá stránka nese style-src 'self' a stylesheet z jiného hostitele by prohlížeč prostě zahodil bez jediné chyby, kterou by kdokoli uviděl — sestavení proto vzdálenou cestu odmítne nahlas, dřív než to ticho nastane.

Číst dál

./blog.sh 1.8

./blog.sh 1.8 je venku — vydání na GitHubu.

Vydání o tom, co se stane, když se něco pokazí. Každá stránka, feed a index se teď zapisuje do dočasného souboru a přejmenuje na místo, takže uložení přerušené plným diskem nebo sestavení zastavené uprostřed zápisu už nezanechá stránku v poloviční délce ani příspěvek o 0 bajtech, u kterého je starý text pryč. Studené sestavení tím zdraží zhruba o pětinu; sestavení z cache ne, takže běžný den publikování stojí přesně tolik co dřív.

Dvojí doručení už neznamená, že se něco stane dvakrát: příspěvek odeslaný z telefonu dvakrát nebo jedna potvrzenka doručená ve dvou kopiích najednou je teď jeden příspěvek a opětovný import exportu vlastního enginu už z 1200 příspěvků nedělá 2400. A adrese se už nevěří jen proto, že jako adresa vypadá — ../ ve slugu, v názvu mediálního souboru nebo v cíli přesměrování zůstane uvnitř webu, lokální nasazení zůstane uvnitř svého adresáře a přesměrování z feedu nemůže poslat stahování na localhost.

Číst dál

Sestavení neví, kam míří

Někdo postaví celý web na notebooku, naimportuje do něj desetiletí starých příspěvků, prohlédne si každou stránku — a nic z toho ještě nikam nedorazilo. V env.sh není řečeno kam a nic dalšího na to nečeká: sestavení proběhne, archiv projde kontrolou, každá stránka se vykreslí na localhost. Sestavení neví, kde má web nakonec skončit, a vědět to nepotřebuje.

Totéž sestavení může začít na notebooku, o rok později se přestěhovat na pronajatý VPS a potom skončit na instanci Cloudronu. Mezi těmito přesuny se v obsahové pipeline nemění nic. Mění se odpověď na jedinou otázku — kam mají soubory jít — a odpovědět na ni může šest věcí.

Co o tom rozhoduje

DEPLOY_BACKEND v env.sh určuje cíl; hodnoty pod ním závisejí na tom, který to je. Všechno za tímto řádkem je u všech šesti stejné. Každý backend si vede vlastní manifest — SHA-256, velikost a čas změny každého souboru, který už nahrál — takže nasazení posílá vždy jen to, co se od minulého změnilo. deploy-web.sh --dry-run tento manifest přečte, aniž by se čehokoli dotkl.

Takhle vypadá výstup, spuštěný právě teď proti vlastnímu backendu tohoto webu:

Číst dál

Jeden řádek barvy

Čtenář změnil jednu barvu okraje v site.css, spustil nové sestavení a čekal, zatímco sestavení vytvořilo, bajt po bajtu, každou stránku, která už existovala. Zeptal se proč. Odpovědí bylo jedno slovo v jednom seznamu a 1.7 ho odstraňuje.

Co si sestavení zapisuje

Od 1.6 si sestavení vede záznam o tom, co vstoupilo do každé stránky, kterou zapsalo – příspěvek, příspěvky kolem něj, štítky, čísla, která stránka počítá. Při dalším sestavení se stránka, jejíž záznam se nezměnil, vůbec nevykresluje. Ne že by se vykreslila a pak shledala shodnou – nevykreslí se. Souhrn na konci říká, kolik stránek zůstalo netknutých; to je první číslo, na které se podívat, když je sestavení pomalé.

Záznam platí jen po dobu, kdy engine, který ho zapsal, je týž engine, a proto visí na otisku toho, z čeho se engine skládá – souborů v templates/, lib/, build/, locales/ a config/, hašovaných podle obsahu, ne podle času změny. Změň cokoli z toho a záznam se zahodí celý, protože cokoli z toho může změnit každou stránku.

Proč barva stála celý archiv

Číst dál

To poslední, co kamera zapíše

Někdo otevře příspěvek s videem a stiskne přehrát. Připojení je v pořádku. Video není velké. Chvíli se nic neděje, a pak se video spustí naráz, jako by čekalo na svolení.

Čekalo na rejstřík.

Proč sedí na konci

MP4 je hrstka boxů položených za sebou. Jeden z nich, mdat, je obraz a zvuk. Jiný, moov, je rejstřík: který snímek leží na kterém bajtu, jak dlouho to celé trvá, jakému kodeku to předat. Přehrávač potřebuje moov dřív, než může ukázat jediný snímek.

Číst dál

Kolo, které nikdo nemusel kreslit

Ukázková konfigurace, kterou tento engine dodává, nese kolo: štítek jménem kolo a pod ním ručně vypsané <svg>. Je tam proto, že tam nebylo co jiného dát. tag_icons bral jméno ikony, kterou engine dodává, nebo vlastní kresbu, a dodával jen osm typů obsahu – text, obrázek, video, odkaz, zvuk, citát, dokument, chat. Štítek o cyklistice mohl nosit znak pro „zvuk", nebo někdo mohl strávit večer nad souřadnicovou mřížkou.

1.7 mezi to vkládá pětapadesát kreseb a každé dává jméno.

Pětapadesát podstatných jmen

Spočítáno v lib/icons.rb: osm typů obsahu, pětapadesát dalších, třiašedesát jmen, o která si štítek může říci. Seskupeno podle toho, o čem blogy bývají.

Číst dál

Adresa, o které příspěvek je

Někdo ti pošle článek. Přečteš ho a máš k němu dvě stě slov – ne recenzi, jen to, čeho sis všiml, a jednu větu o tom proč. Příspěvek je z větší části ta druhá stránka a adresa, o které je, musí někde bydlet.

Až do tohoto vydání zněla poctivá odpověď: v odstavci, jako každý jiný odkaz. Karta, kterou takový příspěvek otevírá, jako blok existovala – importéry ji vyrábějí z Tumblru a z Bluesky – ale nic, co by šlo napsat, ji nevytvořilo. Zapisovač, který příspěvek převádí zpět do markdownu, pro ni neměl syntaxi, takže edit na příspěvku s odkazem nabízel kartu zahodit a add <soubor> ji neuměl vytvořit vůbec. Vlastní příspěvky o vydáních tohoto projektu z toho důvodu po 1.3 přestaly být příspěvky s odkazem. Nástroj se změnil; záměr ne.

Tři řádky v hlavičce

---
tags: release
link: https://example.org/clanek-nekoho-jineho
link_title: Článek někoho jiného
link_description: O čem je, podle jeho vlastní stránky.
---

Dvě věci v něm jsou špatně a jedna stojí za ukradení.
Číst dál