Saját doménes, szerver nélküli blog építése Hugo + GitHub + Decap CMS + Cloudflare Pages stackkel
Ezt a webhelyet korábban egy saját domainhez kötött, a Google Apps (a mai Google Workspace elődje) részét képező klasszikus Google Sites-szal üzemeltettem. Amikor a Google 2021-ben világszerte lekapcsolta ezt a régi szolgáltatást, a https://www.ixam.net domain hosszú időre parlagon maradt. Úgy döntöttem, itt az ideje újra életet lehelni a címbe. A cél egy olyan szerver nélküli architektúra volt, amelyet nem köt egyetlen, bármikor megszűnő platformhoz sem, és a megvalósítást a ChatGPT-vel közösen vittem végig.
Azt hittem, hogy a ChatGPT mellett ez gyerekjáték lesz, de hamar kiderült, hogy korántsem ennyire egyszerű. Sorra felejtettük el a követelményeket, a hibakeresés körbe-körbe forgott, és végül olyan repókat is át kellett néznem, mint a https://github.com/patrickgrey/website/, hogy tovább tudjunk lépni. Kemény munka volt, de végül közös erővel befejeztük.
Az élmény olyan volt, mintha egy rendkívül tehetséges, ám gyakran félrecsúszó csapattársat terelgetnék vissza a sínre – ami egyben azt is jelenti, hogy az MI immár valóban hasznos társ. Ugyanakkor minél összetettebb lett a feladat, annál könnyebb volt frusztrálódni a hibák miatt.
A tanulságom: ahelyett, hogy egyetlen beszélgetésben próbálnánk minden előzményt a fejében tartani, jobb megállni, saját kezűleg összefoglalni a jelenlegi állapotot, majd tiszta lappal, új utasításokkal indítani egy friss threadet.
Mindezek ellenére ennyi kutatást, próbálkozást és tanulást egyedül biztosan nem tudtam volna végigvinni. A generatív MI elképesztő termelékenységnövelő.
Cél
- A blog a
https://www.example.com/címen fusson - A Decap CMS kezelőfelületét a
https://www.example.com/admin/alatt el lehessen érni, és ott lehessen bejegyzéseket készíteni - A létrehozott cikkek GitHubra kerüljenek, és onnan automatikusan települjenek a Cloudflare-re
- A folyamatos üzemeltetés többletköltsége maradjon nullán (a domain regisztrációs díja eleve adott)
0. Előfeltételek és mappastruktúra
0-1. Előfeltételek
-
A domain (például
example.com) már regisztrált -
Windows vagy macOS egyaránt megfelel (mindkettőhöz mutatok parancspéldákat)
-
A használt szolgáltatások (ingyenes csomagban is elegendők)
- GitHub-fiók
- Cloudflare-fiók (Pages használathoz)
- Git (helyi)
- Hugo (helyi előnézethez és a Cloudflare buildhez)
0-2. Példa repós struktúrára
hugo.toml
content/
blog/
posts/
data/
functions/
api/
auth.js
callback.js
layouts/
_default/
baseof.html
index.html
list.html
single.html
static/
_headers
admin/
config.yml
index.html
css/
main.css
Ez a felépítés az alábbi szerepeket fedi le:
hugo.toml— a teljes oldal konfigurációja (abaseURLértékét cseréld a végleges URL-re)functions/api/*.js— Cloudflare Pages Functions (GitHub OAuth-hoz az/api/authés/api/callbackvégpontok)layouts/_default/*.html— Hugo sablonokstatic/admin/— a Decap CMS felülete és beállításaistatic/css/main.css— kinézetstatic/_headers— opcionális HTTP-fejlécek a Cloudflare Pageshez
A leírásban mindenhol „Cseréld ki” jelzőt teszek oda, ahol környezetspecifikus módosításra van szükség.
1. Előkészületek
1-1. GitHub-fiók létrehozása
- Jelentkezz be a GitHubra a böngészőből, és készíts új fiókot
1-2. Cloudflare-fiók létrehozása
- Böngészőből regisztrálj a Cloudflare-re
1-3. Git és Hugo telepítése
-
Windows (PowerShell)
PS C:\Users\alice> winget install Git.Git PS C:\Users\alice> winget install Hugo.Hugo.Extended -
macOS (Terminal)
mac:~ dev$ brew install git mac:~ dev$ brew install hugo
2. Fő lépések (az első telepítésig)
2-1. A repó előkészítése helyben
-
Hozz létre üres repót a GitHubon
- Menüpont: GitHub > New repository
- Név példa:
my-hugo-blog
-
Klónozd le a gépedre
-
Windows
PS C:\work> git clone https://github.com/<YOUR_GH_USERNAME>/my-hugo-blog.git PS C:\work> cd .\my-hugo-blog -
macOS
mac:~/work dev$ git clone https://github.com/<YOUR_GH_USERNAME>/my-hugo-blog.git mac:~/work dev$ cd my-hugo-blog
-
-
Másold be a fenti mappastruktúrát közvetlenül a repó gyökerébe
„Cseréld ki” ellenőrzőlista (kötelező módosítások)
-
hugo.tomlbaseURL = "https://www.example.com" # ← cseréld a saját éles URL-re (példa: https://www.example.com) languageCode = "ja-jp" title = "Example Blog" publishDir = "public" [permalinks] blog = "/blog/:year/:month/:slug/" -
static/admin/config.ymlbackend: name: github repo: <YOUR_GH_USERNAME>/my-hugo-blog # ← cseréld a saját GitHub repódra branch: master # ← a fő ág neve (main vagy master) base_url: https://www.example.com # ← cseréld a saját éles URL-re auth_endpoint: /api/auth # ← funkció végpontja (fix) media_folder: static/uploads public_folder: /uploads
Megjegyzés: a
functions/api/auth.jsésfunctions/api/callback.jsfájlok környezetfüggetlenek, merturl.origin-t használnak, így közvetlen módosításra nincs szükség.
-
Készítsd el az első commitot, majd pushold
-
Windows
PS C:\work\my-hugo-blog> git add -A PS C:\work\my-hugo-blog> git commit -m "Initial commit: Hugo + DecapCMS + CF Pages" PS C:\work\my-hugo-blog> git push -u origin master -
macOS
mac:~/work/my-hugo-blog dev$ git add -A mac:~/work/my-hugo-blog dev$ git commit -m "Initial commit: Hugo + DecapCMS + CF Pages" mac:~/work/my-hugo-blog dev$ git push -u origin master
-
A következő lépésben felsorolt értékeket a Cloudflare Pages felületén környezeti változókba mentsd el.
2-2. GitHub OAuth App létrehozása (a Decap CMS belépéshez)
-
Menüpont: GitHub > Settings > Developer settings > OAuth Apps > New OAuth App
-
Töltsd ki:
- Application name:
DecapCMS for my-hugo-blog - Homepage URL:
https://www.example.com - Authorization callback URL:
https://www.example.com/api/callback← kulcsfontosságú
- Application name:
-
A létrehozás után jegyezd fel:
- Client ID
- Client Secret (generálj újat és mentsd el)
Ezeket az értékeket a Cloudflare Pages környezeti változóiként fogod használni.
2-3. Cloudflare Pages projekt létrehozása
-
Menüpont: Cloudflare dashboard > Pages > Create a project > Connect to Git
-
Kapcsold össze a GitHubot, és válaszd ki a
my-hugo-blogrepót -
Build beállítások:
-
Framework preset:
None(vagy hagyd, hogy a Cloudflare felismerje) -
Build command:
hugo -
Build output directory:
public -
Környezeti változók:
HUGO_VERSION=0.128.0(példa – legyen összhangban a helyi verzióval)GITHUB_CLIENT_ID= az előző szakaszban rögzített értékGITHUB_CLIENT_SECRET= az előző szakaszban rögzített érték
-
-
Kattints a Save and Deploy gombra, és várd meg az első buildet
- A sikeres futások
*.pages.develőnézeti URL-t adnak
- A sikeres futások
2-4. A www.example.com egyedi domain beállítása
-
Menüpont: Cloudflare > Pages > (projekt) > Custom domains > Set up a custom domain
-
Add meg:
www.example.com -
Ha a domaint nem a Cloudflare kezeli teljesen:
- Másold ki a Cloudflare által mutatott DNS-rekord adatokat (például
CNAME www -> <project>.pages.dev) - Állítsd be ezeket a regisztrátornál a dokumentációjuk szerint
- Másold ki a Cloudflare által mutatott DNS-rekord adatokat (például
-
A DNS frissülése után ellenőrizd, hogy a
https://www.example.com/cím a site-ot szolgálja ki
Tipp: ha a domaint már a Cloudflare kezeli, egy kattintás az összes szükséges DNS-rekordot létrehozza.
2-5. Bejelentkezés a Decap CMS adminfelületre
- Nyisd meg a
https://www.example.com/admin/oldalt - Kattints a Login with GitHub gombra, majd hagyd jóvá az OAuth kérést
- Első alkalommal a GitHub kérni fogja az Authorize jóváhagyást – engedélyezd
Ha a bejelentkezés nem sikerül, ellenőrizd az OAuth callback URL-t, valamint a Cloudflare
GITHUB_CLIENT_IDésGITHUB_CLIENT_SECRETkörnyezeti változóit.
3. Üzemeltetés (tartalomkészítés, szinkron, sablonok)
3-1. Bejegyzés készítése a CMS-ből
- Lépj be a
https://www.example.com/admin/felületre - A bal oldali menüben válaszd a Blog → New blog elemet
- Töltsd ki a
Title,Publish Date,DescriptionésBodymezőket - Kattints a Publish gombra – ez GitHub commitot hoz létre, amit a Cloudflare automatikusan telepít
Az elkészült Markdown fájlok a
content/blog/mappába kerülnek.
3-2. Tartalom lehúzása helyben, ha a CMS-ből publikáltál
-
Windows
PS C:\work\my-hugo-blog> git pull origin master -
macOS
mac:~/work/my-hugo-blog dev$ git pull origin master
Így a helyi repó naprakész marad, és biztonságosan szerkesztheted a sablonokat vagy a CSS-t.
3-3. Dizájn és sablon finomhangolása helyben
-
Indítsd el a helyi fejlesztői szervert
-
Windows
PS C:\work\my-hugo-blog> hugo server -D -
macOS
mac:~/work/my-hugo-blog dev$ hugo server -D -
Nyisd meg a
http://localhost:1313/címet a böngészőben az előnézethez
-
-
Gyakori testreszabási pontok
layouts/_default/baseof.html—<head>tartalom, fejléc, lábléclayouts/_default/index.html— legfrissebb bejegyzések listája a főoldalonlayouts/_default/single.html— cikkoldal sablonjastatic/css/main.css— színek, betűk, margók
-
Commit és push
-
Windows
PS C:\work\my-hugo-blog> git add -A PS C:\work\my-hugo-blog> git commit -m "Update theme/layouts" PS C:\work\my-hugo-blog> git push -
macOS
mac:~/work/my-hugo-blog dev$ git add -A mac:~/work/my-hugo-blog dev$ git commit -m "Update theme/layouts" mac:~/work/my-hugo-blog dev$ git push -
A Cloudflare néhány másodpercen vagy percen belül újra telepít
-
3-4. Ágkezelési tippek
- Ellenőrizd, hogy az alapértelmezett ág (
mainvagymaster) azonos legyen astatic/admin/config.ymlfájlban és a Cloudflare projektben - Ha GitHubon pull requestet nyitsz, a Cloudflare Pages automatikusan létrehoz egy előnézeti környezetet
4. Hasznos kiegészítések (opcionális)
4-1. Példa static/_headers beállításra (adminfelület cache tiltása)
/admin/*
Cache-Control: no-store
4-2. Robots és sitemap
- Készíts
static/robots.txtfájlt a robotok szabályozásához - A
hugo.tomloutputsszekciójába felveheted az RSS-t, sitemapot vagy más kimeneteket
5. Gyakori buktatók és megoldások
- A CMS-bejelentkezés végtelen ciklusba kerül
→ Ellenőrizd, hogy a GitHub OAuth callback URL pontosanhttps://www.example.com/api/callback, és a CloudflareGITHUB_CLIENT_ID/GITHUB_CLIENT_SECRETváltozói helyesek - A főoldal működik, de a cikkoldalak 404-et adnak
→ Győződj meg róla, hogy ahugo.tomlbaseURLértéke megegyezik az éles domainnel. Nézd meg a Cloudflare buildlogjait, hogy apublic/mappa tényleg létrejött-e - Az /admin oldal üres
→ Ellenőrizd, hogy astatic/admin/index.htmláltal hivatkozott Decap CMS-szkripteket nem blokkolja-e böngészőbővítmény vagy CSP; kapcsold ki a kiegészítőket és töltsd újra
6. „Cseréld ki” ellenőrzőlista (összefoglaló)
| Fájl / beállítás | Kulcs | Példaérték / teendő |
|---|---|---|
hugo.toml |
baseURL |
https://www.example.com |
static/admin/config.yml |
repo |
<YOUR_GH_USERNAME>/my-hugo-blog |
static/admin/config.yml |
branch |
Egyezzen a fő ággal (main vagy master) |
static/admin/config.yml |
base_url |
https://www.example.com |
| Cloudflare Pages | HUGO_VERSION |
pl. 0.128.0 |
| Cloudflare Pages | GITHUB_CLIENT_ID |
GitHub OAuth App client ID |
| Cloudflare Pages | GITHUB_CLIENT_SECRET |
GitHub OAuth App client secret |
| GitHub OAuth App | Callback URL | https://www.example.com/api/callback |
| Cloudflare Pages | Egyedi domain | Add hozzá a www.example.com címet |
7. Melléklet: mintafájlok (csak a jelölt részeket cseréld)
7-1. functions/api/auth.js
// Cloudflare Pages Functions (/api/auth)
export async function onRequest(context) {
const { request, env } = context;
const client_id = env.GITHUB_CLIENT_ID;
try {
const url = new URL(request.url);
const redirectUrl = new URL('https://github.com/login/oauth/authorize');
redirectUrl.searchParams.set('client_id', client_id);
redirectUrl.searchParams.set('redirect_uri', `${url.origin}/api/callback`);
redirectUrl.searchParams.set('scope', 'repo user');
redirectUrl.searchParams.set('state', crypto.getRandomValues(new Uint8Array(12)).join(''));
return Response.redirect(redirectUrl.href, 302);
} catch (err) {
return new Response(String(err?.message || err), { status: 500 });
}
}
7-2. functions/api/callback.js
function renderBody(status, content) {
const html = `
<script>
const receiveMessage = (message) => {
window.opener.postMessage(
'authorization:github:${status}:${JSON.stringify(content)}',
message.origin
);
window.removeEventListener("message", receiveMessage, false);
}
window.addEventListener("message", receiveMessage, false);
window.opener.postMessage("authorizing:github", "*");
</script>`;
return new Blob([html]);
}
export async function onRequest(context) {
const { request, env } = context;
const client_id = env.GITHUB_CLIENT_ID;
const client_secret = env.GITHUB_CLIENT_SECRET;
try {
const url = new URL(request.url);
const code = url.searchParams.get('code');
const response = await fetch('https://github.com/login/oauth/access_token', {
method: 'POST',
headers: { 'content-type': 'application/json', 'user-agent': 'cf-pages-oauth', 'accept': 'application/json' },
body: JSON.stringify({ client_id, client_secret, code }),
});
const result = await response.json();
if (result.error) {
return new Response(renderBody('error', result), { headers: { 'content-type': 'text/html;charset=UTF-8' }, status: 401 });
}
const token = result.access_token;
const provider = 'github';
return new Response(renderBody('success', { token, provider }), { headers: { 'content-type': 'text/html;charset=UTF-8' }, status: 200 });
} catch (error) {
return new Response(error.message, { headers: { 'content-type': 'text/html;charset=UTF-8' }, status: 500 });
}
}
7-3. static/admin/config.yml
backend:
name: github
repo: <YOUR_GH_USERNAME>/my-hugo-blog
branch: main
base_url: https://www.example.com
auth_endpoint: /api/auth
media_folder: static/uploads
public_folder: /uploads
collections:
- name: 'blog'
label: 'Blog'
folder: 'content/blog'
create: true
slug: '{{slug}}'
editor:
preview: false
fields:
- { label: 'Title', name: 'title', widget: 'string' }
- { label: 'Publish Date', name: 'date', widget: 'datetime' }
- { label: 'Description', name: 'description', widget: 'string' }
- { label: 'Body', name: 'body', widget: 'markdown' }
9. SEO- és teljesítménytippek
Miután a blog élesben fut, az alábbi lépések javíthatják a keresési láthatóságot és a betöltési sebességet:
-
Sitemap és robots.txt
- Regisztráld a Hugo által generált
public/sitemap.xmlfájlt a Google Search Console-ban - Szabályozd a robotokat a
static/robots.txtszerkesztésével
- Regisztráld a Hugo által generált
-
OGP (Open Graph Protocol) és Twitter-kártyák
- Adj hozzá olyan tageket, mint
<meta property="og:title">vagy<meta property="og:image">alayouts/_default/baseof.htmlfájlban - Így a közösségi megosztások is látványosabbak lesznek
- Adj hozzá olyan tageket, mint
-
Képek WebP-re alakítása
- Használd a
resources/_gen/images/könyvtárat és a Hugo Pipes funkciót az automatikus WebP-konverzióhoz - Gyorsabb oldalbetöltés
- Használd a
-
Kategóriák és tagek hozzáadása
- A
content/blog/alatti front matterben töltsd ki acategorieséstagsmezőket, és jelenítsd meg például címkefelhőként a sablonokban
- A
-
Strukturált adatok használata
- Adj meg JSON-LD formátumú metaadatokat a cikkekhez, hogy nagyobb eséllyel jelenjenek meg rich results találatok
8. Összegzés
- Hozz létre egy GitHub-repót, kapcsold a Cloudflare Pageshez, állítsd be a Decap CMS GitHub OAuthot, és rendeld hozzá az egyedi domaint – ezzel készen vagy
- A szerzők az
/admin/felületen publikálnak → GitHub commit → Cloudflare automatikus deploy - A sablonokat és dizájnt helyben a
hugo serversegítségével finomíthatod, majd Git push-sal viszed élesbe
Ezekkel a lépésekkel már működtethető a Hugo + GitHub + Decap CMS + Cloudflare alapú szerver nélküli blog.
A célt elértem: minimális üzemeltetési költségű alapot kaptam. Ugyanakkor a belső kereső, a kategóriák vagy a címkefelhő még elmarad a nagy blogplatformoktól. A terv az, hogy ezeket is fokozatosan bővítsem – továbbra is ChatGPT-vel közösen dolgozva.