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/callback
vé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.toml
baseURL = "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.yml
backend: 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.js
fá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-blog
repó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.dev
elő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_SECRET
kö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
ésBody
mező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 (
main
vagymaster
) azonos legyen astatic/admin/config.yml
fá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.txt
fájlt a robotok szabályozásához - A
hugo.toml
outputs
szekció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_SECRET
változói helyesek - A főoldal működik, de a cikkoldalak 404-et adnak
→ Győződj meg róla, hogy ahugo.toml
baseURL
é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.xml
fájlt a Google Search Console-ban - Szabályozd a robotokat a
static/robots.txt
szerkeszté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.html
fá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
éstags
mező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 server
segí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.