Z WordPressa na Astro + Cloudflare Workers – jak przebudowałem brylka.net
Przez lata ta strona stała na WordPressie z motywem Astra. Działała, ale płaciłem za to standardową cenę: PHP i baza na każde żądanie, wtyczki do wszystkiego, aktualizacje bezpieczeństwa i wynik w Lighthouse, którego nie chciało się pokazywać. Na początku czerwca 2026 przeniosłem brylka.net na statyczny stack Astro 5 + Cloudflare Workers – zero PHP, zero serwera, treść serwowana z edge’a CDN. W tym wpisie opisuję, jak to zrobiłem i jakimi zasadami się kierowałem.
Strona, którą właśnie czytasz, to efekt tej migracji. Jeśli ciekawi Cię, jak wygląda od środka – zajrzyj w źródło (Ctrl+U) albo do konsoli przeglądarki. Zostawiłem tam parę drobiazgów.
Naczelna zasada: jedyny dozwolony legacy
Przy przepisywaniu strony od zera łatwo ulec pokusie „poprawienia wszystkiego przy okazji”. Postawiłem sobie jedną twardą regułę:
Legacy to wyłącznie istniejąca treść i istniejące adresy URL. Reszta bez kompromisów.
To znaczy: każdy wpis, każda kategoria i każdy plik do pobrania musi zostać pod tym samym adresem co w WordPressie. Cała reszta – motyw, hosting, generowanie HTML, obrazy – idzie do kosza i powstaje na nowo. Dzięki temu nie traciłem pozycji w wyszukiwarce ani linków, które ktoś gdzieś zostawił, a jednocześnie nie wlokłem za sobą żadnego długu technicznego starego CMS-a.
Stack docelowy
Cały frontend to Astro 5 w trybie statycznym (SSG) – generuje czysty HTML w czasie builda, bez runtime’u po stronie klienta. Hosting to Cloudflare Workers w trybie static assets: pliki lądują na edge’u i są serwowane z najbliższej użytkownikowi lokalizacji.
| Warstwa | WordPress (było) | Astro + Cloudflare (jest) |
|---|---|---|
| Generowanie stron | PHP w czasie żądania | Astro SSG (HTML w czasie builda) |
| Hosting | własny baremetal: FreeBSD + nginx + php-fpm | Cloudflare Workers (edge) |
| Baza danych | MySQL na każde żądanie | brak – wszystko statyczne |
| Obrazy | wtyczki, różne formaty | WebP jako statyczne assety |
| Kolorowanie kodu | wtyczka + JavaScript | Shiki (zero JS, w czasie builda) |
| Deploy | FTP / panel | git push → automatyczny build i wdrożenie |
Kolorowanie składni robi Shiki – kompletnie bez JavaScriptu, bo podświetlanie liczone jest podczas builda. Obrazy trzymam jako statyczne pliki WebP w public/img/, a Cloudflare rozprowadza je po swoim CDN-ie. Żadnego R2, żadnego zewnętrznego serwisu obrazków.
Treść to baza, nie scraping
Najważniejsza decyzja: treści nie scrapowałem ze starej strony. Zamiast parsować wyrenderowany HTML (z całym śmieciem motywu), wziąłem zrzut bazy WordPressa jako źródło prawdy i napisałem skrypt, który odbudowuje z niego wpisy.
Pipeline wygląda tak:
dump SQL (mysqldump) ──► parser tabel ──► HTML Gutenberga
└─► Markdown (cheerio + turndown + gfm)
└─► obrazy z uploadów ──► WebP
└─► tagi z taksonomii, opis z Yoast, język kodu z heurystykiZ wp_posts wyciągam treść i metadane, z taksonomii – tagi i kategorie, z pól Yoast – opisy SEO. Bloki Gutenberga zamieniam na Markdown (cheerio do parsowania, turndown + wtyczka GFM do konwersji), a osadzone obrazy przepisuję na statyczne WebP. Efektem jest jeden plik .md na wpis – czytelny, wersjonowany w Gicie, niezależny od jakiegokolwiek CMS-a.
Dlaczego z bazy, a nie z HTML? Wyrenderowana strona to treść plus cały motyw, widżety i znaczniki wtyczek. Baza zawiera samą treść w czystej postaci. Odbudowa ze źródła daje czystszy Markdown i pełną kontrolę nad tym, co trafia do nowej strony.
Przy okazji znormalizowałem typografię – m.in. zamieniłem pauzy (em) na półpauzy (en), zgodnie z polską konwencją. Drobiazg, ale przy kilkudziesięciu wpisach robi różnicę.
URL-e 1:1 i przekierowania
To była najbardziej newralgiczna część. WordPress używał permalinku /%postname% – płaskie adresy bez ogona i bez .html. W Astro odtworzyłem to dokładnie:
// astro.config.mjs
export default defineConfig({
build: { format: 'file' }, // /wpis.html zamiast /wpis/index.html
trailingSlash: 'never', // żadnych ukośników na końcu
});Każdy wpis to plik src/content/posts/<slug>.md, a slug = dokładnie ta sama nazwa, co w starym adresie. Renderuje go jeden catch-all route [...slug].astro. URL /<slug> jest więc identyczny jak w WordPressie – to twardy kontrakt zachowania adresów.
Stare przekierowania też musiały przeżyć. WordPress miał wtyczkę Redirection z listą 301-ek; przeniosłem je do pliku public/_redirects (format Cloudflare), dorzucając przy okazji mapowania archiwów taksonomii i starego feeda:
# stare 301-ki z wtyczki Redirection
/stary-adres /nowy-adres 301
# archiwa tagów WP → kategorie
/tag/* /category/:splat 301
# kanał RSS pod starym adresem
/feed /rss.xml 301Dzięki temu nikt – ani użytkownik, ani robot wyszukiwarki – nie trafia na 404 po zmianie silnika.
Hosting na edge’u
Cloudflare Workers w trybie static assets potrzebuje minimalnej konfiguracji – wrangler.jsonc plus jeden mały worker.js. Apex brylka.net podpiąłem jako Custom Domain Workera, a www przekierowuję na apex regułą w panelu.
Deploy jest najprzyjemniejszą częścią całej zmiany. Nie ma FTP ani wgrywania paczek:
git push origin mainPush na main uruchamia Cloudflare Workers Builds: platforma sama odpala npm run build i wdraża wynik. Cała publikacja sprowadza się do commita. Co istotne, cutover był odwracalny – stary origin WordPressa mógł przez jakiś czas stać jako zapas, na wypadek gdyby coś wymagało powrotu.
Wydajność, SEO i GEO
Statyczny HTML serwowany z edge’a robi to, czego po nim oczekujesz – Lighthouse poszedł w górę na całej linii: Performance ~98, SEO 100, dostępność ~96–100, Best Practices ~100. Bez PHP i bez bazy nie ma czego optymalizować po stronie serwera; strona po prostu jest już gotowa.
Przy okazji zadbałem o sygnały dla wyszukiwarek i modeli językowych:
- schema.org –
Person/ProfilePagena stronie głównej,BlogPostingprzy wpisach,BreadcrumbListw okruszkach,WebApplication/MobileApplicationprzy projektach. - Open Graph – domyślny baner generowany z żywego logo, z poprawnymi wymiarami pod duże karty (WhatsApp, Facebook).
/llms.txt– maszynowo czytelny indeks treści pod modele językowe (GEO), generowany automatycznie z kolekcji wpisów i projektów.- GA4 z Consent Mode v2 – analityka odpala się dopiero po zgodzie z bannera cookie, tylko na produkcji.
Drobne smaczki
Skoro i tak pisałem szablon od zera, zostawiłem w nim dwa mrugnięcia do tych, którzy lubią zaglądać pod podszewkę: ramkę ASCII z logo (czcionka Braille’a) w komentarzu w źródle strony oraz stylowany komunikat w konsoli DevToolsów. Nic, co wpływa na działanie – po prostu wizytówka dla ciekawskich.
Efekt
Z grubego WordPressa z bazą i PHP zrobił się zestaw statycznych plików serwowanych z CDN-a, który publikuję jednym git push. Treść jest wersjonowana w Gicie, adresy się nie zmieniły, a wynik w Lighthouse przestał być powodem do wstydu. Najlepsze jest to, że utrzymanie sprowadza się do edycji plików Markdown – bez panelu, bez aktualizacji wtyczek, bez martwienia się o dziurę w kolejnym pluginie.
Jeśli chcesz zobaczyć, co na tym stacku stoi w praktyce, zajrzyj do portfolio – znajdziesz tam projekty webowe i mobilne, które rozwijam podobnym podejściem.