Migrace z Blogger na Hugo a GitLab Pages

Když jsem před sedmi lety začal psát blog SoftWare Samuraj, nevědel jsem, jestli mi psaní vydrží. Chtěl jsem hlavně rychle začít — abych neztratil motivaci — a nechtěl jsem se vrtat v nějakém PHP, nebo redakčním systému. A tak jsem si založil blog na Blogger.com. A byl jsem s tím docela spokojený.

Nedávno jsem brouzdal po Twitteru a narazil jsem na článek Tomáše Klinera Create a blog within 20 minutes with Hugo, a static page generator written in Go. Musím říct, že celý ten humbuk kolem JAM Stacku a static site generátorů kolem mne prošuměl, jako kdyby nebyl a tak jediný, co mě na článku zaujalo, bylo, že Hugo je napsaný v Golangu. (A pro Golang mám poslední dobou slabost.)

Takže, bohužel — neřeknu vám nic o tom, proč jsou statické generátory super a jak je JAM Stack cool-hustý-parádní. Bylo to jen chvilkové hnutí mysli, nic víc.

Nicméně, věcí, co jsem musel pořešit, bylo docela dost a tak přináším návod a inspiraci, jak na to.

Průzkum

Statické generátory

Jak jsem zmínil, u statických generátorů jsem měl jasno od začátku — Hugo a hotovo. Prostě Golang rules! a matlat se s nějakým Ruby (a.k.a. Jekyll) by měl ani nenapadlo. 😉

Hosting

Hosting už jsem řešil trochu víc:

  1. Pročetl jsem si z Hugo dokumentace stránku Hosting & Deployment.
  2. Zúžil výběr na:
    1. Netlify,
    2. GitHub Pages,
    3. GitLab Pages.
  3. Finálně vybral GitLab Pages, hlavně proto, že mají:
    • all-in-one solution (tj. Git repository + CI/CD + Pages),
    • excelentní CI/CD (o kterém si GitHub jen může nechat zdát),
    • podporu SSL/TLS a custom domains.

Jedinou nevýhodou GitLab Pages je, že nemají integrovanou podporu pro Let’s Encrypt a certifikáty je potřeba měnit ručně. To je nepohodlné, ale pro mne akceptovatelné.

[Update 13. 12. 2019] Od verze 12.1GitLab podporu automatické obnovy Let’s Encrypt certifikátů.[/Update]

Migrace

Hugo projekt

Na začátku jsem si vytvořil prázdný Hugo projekt a na něm odladil šablonu:

$ hugo new site blog               # nový Hugo projekt
$ cd blog
$ hugo new posts/first-article.md  # první, testovací článek
$ hugo server -D                   # lokální statická site (http://localhost:1313)
$

Původně jsem si vybral jedno z Hugo témat, ale pak jsem do něj začal dělat úpravy, takže jsem ho nakonec forknul a do projektu ho přidal jako Git submodule.

GitLab projekt

Jakmile jsem měl novou verzi blogu odladěnou lokálně, publikoval jsem ho do vzdálené Git repozitory (klasický git initgit add remotegit push).

Výhodou GitLabu je, že mají opravdu odladěný CI/CD a tak jediný, co je potřeba, aby pro git push došlo k publikování stránek je následující jednoduchá konfigurace, uložená v souboru .gitlab-ci.yml:

Voilà, a jsme live! Magic! 🎉🎆

Blogger export, Hugo import

Export z Bloggeru je jednoduchý: Blogger → Settings → Other → Back up Content

Výsledkem je obrovské XML, se zálohou všech článků, které lze následně naimportovat do Hugo projektu. Pro import existuje několik utilitek, já jsem si vybral blogimport, který dělá jen to nejnutnější — rozseká články do souborů a přidá Hugo hlavičky — takže záleží, co čekáte od výsledku. V mém případě to pak zahrnovalo ještě nějakou ruční práci na formátování, úpravě hlaviček a adresářové struktuře.

Konfigurace domény

(Re)konfigurace domény je něco, co dělám jen jednou za pár let, takže to může být trochu frustrující a já s tím vždycky lehce bojuji. Konkrétní nastavení se bude lišit vzhledem k vašemu poskytovateli domény. V zásadě to ale znamená poeditova následující DNS záznamy:

  • Přidat A záznam pro doménu 2. řádu.
  • Přidat CNAME záznam pro doménu 3. řádu (třeba www apod.).
  • Přídat TXT záznam(y) pro verifikaci vlastnictví domény.

Pro ladění, jestli je DNS správně nastavený se mi osvědčily příkazy nslookup a dig.

$ dig +nocomments www.sw-samuraj.cz

; <<>> DiG 9.11.3-1ubuntu1.2-Ubuntu <<>> +nocomments www.sw-samuraj.cz
;; global options: +cmd
;www.sw-samuraj.cz.		IN	A
www.sw-samuraj.cz.	681	IN	CNAME	sw-samuraj.gitlab.io.
sw-samuraj.gitlab.io.	81	IN	A	35.185.44.232
;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Tue Nov 13 10:47:49 CET 2018
;; MSG SIZE  rcvd: 96

HTTPS a GitLab custom domény

HTTPS je dneska standard, takže to samozřejmě budeme chtít i pro nové stánky. GitLab poskytuje automatické HTTPS pro domény 3. řádu na gitlab.io, tedy např. sw-samuraj.gitlab.io. Pro custom domény je potřeba každou z nich přidat a nastavit jí TLS certifikát.

Přidání custom domény je triviální, ale důležitá je její verifikace, tedy přidání TXT DNS záznamu.

Po přidání TLS certifikátu (viz dále) je HTTPS funkční.

Výsledek by měl v GitLab konzoli vypadat takto:

Let’s Encrypt!

[Update 13. 12. 2019] Od verze 12.1GitLab podporu automatické obnovy Let’s Encrypt certifikátů, takže tuto část již není potřeba řešit.[/Update]

Let’s Encrypt je sympatická certifikační autorita (CA), která zdarma vydává TLS certifikáty. Výhodou je, že pokud to váš poskytovatel podporuje, je vydávání a obnova certifikátů automatická. Bohužel, v případě GitLab Pages automatika (zatím) nefunguje a je potřeba certifikáty měnit ručně. To je sice trošku nepříjemné, ale zase na druhou stranu žádná velká věda — platnost Let’s Encrypt certifikátů je 3 měsíce, takže mám v kalendáři připomínku (podobně jako pro Lítačku) a získat a nainstalovat nový certifikát je otázka 10 minut.

Pro vydání certifikátu slouží utilita Certbot a v našem případě využijeme její manual plugin. Následujícím příkazem si zažádám o dva nové/obnovené certifikáty pro dvě domény sw-samuraj.cz a www.sw-samuraj.cz:

sudo certbot certonly --manual -d sw-samuraj.cz -d www.sw-samuraj.cz

Let’s Encrypt následně vygeneruje challenge, abychom potvrdili vlastnictví domény:

Create a file containing just this data:

jwPa1N7aT-C3Qtm5FI5ZcYxsylxJZqeq3zfdmXTFrmk.oxjh1Mqila9LFc6d965eCQTwh3h82chnQed8WtgKsN4

And make it available on your web server at this URL:

http://sw-samuraj.cz/.well-known/acme-challenge/jwPa1N7aT-C3Qtm5FI5ZcYxsylxJZqeq3zfdmXTFrmk

U Hugem generovaných stránek to může být trochu výzva (anglicky challenge 😈) takovou challenge zprostředkovat. Mě se osvědčilo přidat do adresáře static/.well-known/acme-challenge/ soubor s daným názvem a obsahem a následně ho publikovat. (Pokud to není jasný, tady je ukázka.)

Jakmile úspěšně potvrdíme challenge, najdeme nově vydané certifikáty v adresáři /etc/letsencrypt/live/<název-domény> a speciálně pro GitLab Pages nás bude zajímat obsah souborů fullchain.pem a privkey.pem, které nakopírujeme do příslušného formuláře v konfiguraci GitLab Pages (viz výše, obrázek v sekci HTTPS a GitLab custom domény).

Přesměrování

Blogger a Hugo generují z článků sice dost podobné, ale přeci jenom rozdílné URL. Sice se dá Hugo instruovat, aby používal tzv. ugly URL, které věšinou Blogger URL odpovídají, ale já jsem chtěl pretty URL. Pro tyto případy má Hugo aliasy — mechanizmus pro přesměrování URL.

Do hlavičky Hugo markdownu se přidá klíč aliases který může obsahovat seznam původních, přesměrovávaných URL:

aliases = [
    "/2018/01/spring-security-saml-adfs-implementace.html"
]

[Update 10. 12. 2018] Jak mě na Twitteru upozornil BanterCZ, zapomněl jsem přesměrovat RSS kanál. Tedy přesměrovat “Bloggerovské” /feeds/posts/default na “Hugovské” /index.xml.

Tady mě Hugo a GitLab Pages trochu zklamali — jednoduché přesměrování nejde. Po nahlédnutí do dokumentace (Redirects in GitLab Pages) jsem to tedy nabouchal “na hulváta”:

Do souboru content/feeds/posts/default/index.html jsem přidal klasický HTTP Meta refresh tag:

[/Update]

Refaktoring

Výše zmiňovaný blogimport funguje hodně jednoduše — vlastně jen vyextrahuje HTML <body> daného článku a přidá k němu Hugo hlavičku. Což by mohlo i stačit, ale já mám rád věci jaksi čistší. Takže jsem pak články ještě ručně čistil — převádím postupně HTML do Markdownu. Tady záleží, jak moc je člověk perfekcionista (zlí jazykové o mně tvrdí, že to já jsem 🙉).

Čistil jsem ve Vimu a vytunil jsem si na to pár pěkných regulárních výrazů. Jen taková malá ochutnávka:

" převedení nadpisů
%s/<h2.\{-}>\(.\{-}\)<\/h2>/## \1\r\r/cg
" převedení odkazů
%s/<a href="https\?:\(.\{-}\)">\(.\{-}\)<\/a>/[\2](\1)/cg
" převedení monospace textu
%s/<span.\{-}monospace.\{-}>\(.\{-}\)<\/span>/`\1`/cg
" převedení tučného textu a kurzívy
%s/<b>\(.\{-}\)<\/b>/**\1**/cg
%s/<i>\(.\{-}\)<\/i>/_\1_/cg
" převedení Gist JavaScriptu na Hugo Shortcode
%s/<script .\{-}\(sw-samuraj\)\/\(.\{-}\)\.js">//cg

Finální pocity

I když jsem migraci blogu udělal jen z pouhého rozmaru, jsem nakonec dost spokojený. Jednak jsem se něco nového naučil, jednak jsem blog trochu redesignoval, jednak mám věci víc pod kontrolou. Navíc jsem unikl ze spárů zlého Googlu (Pamatujete Don’t be evil? 😈). Prostě samé benefity a sociální jistoty. Teď už jen zbývá psát a psát.

Související externí odkazy