Hugo + GitHub + Decap CMS + Cloudflare Pages स्टैक से कस्टम डोमेन वाला सर्वरलेस ब्लॉग बनाने की प्रक्रिया
यह साइट पहले गूगल ऐप्स के दौर के Google Sites पर कस्टम डोमेन के साथ चलती थी, लेकिन बहुत पहले Google Site सेवा बंद हो गई और मैंने https://www.ixam.net को लंबे समय तक यूँ ही छोड़ दिया। अब मन बनाया कि इसे किसी तरह उपयोग में लाया जाए, इसलिए पुनर्निर्माण शुरू किया। साथ ही यह चाहता था कि ढांचा सर्वरलेस हो और Google Site जैसी अचानक बंद होने वाली सेवा पर निर्भर न रहे, इसलिए Chat GPT के साथ मिलकर किए गए प्रयोग का यह परिणाम है।
सच कहूँ तो मुझे लगा था कि सिर्फ Chat GPT के भरोसे यह काम चुटकी में हो जाएगा, पर ऐसा नहीं हुआ। वह बुनियादी आवश्यकताएँ छोड़ देता था, ट्रबलशूटिंग में चक्कर काटता रहता था, और अंततः मुझे खुद ढूँढे गए GitHub रिपॉज़िटरी “https://github.com/patrickgrey/website/” जैसी सामग्री को देखकर ही किसी तरह साथ मिलकर पूरा करना पड़ा।
एहसास कुछ ऐसा था जैसे कोई तकनीकी रूप से सक्षम लेकिन लगातार गलत समझने वाला अधीनस्थ हो, जिसे पटरी पर लाते हुए काम पूरा कराना पड़े। एक तरह से देखें तो AI इस स्तर तक पहुँच गया है, यह भी कम आश्चर्यजनक नहीं है।
लेकिन सामग्री जितनी पेचीदा होती जाती है, उतना ही वह झुंझलाहट पैदा करने वाली मूर्खता दिखाने लगता है।
शायद यह भी किसी मायने में वास्तविक ही है?
अभी तक के अनुभव में, लम्बी बातचीत खींचकर उसे सब कुछ समझा देने की कोशिश करने से बेहतर है कि बातचीत जटिल होते ही मनुष्य एक बार सब व्यवस्थित करे और फिर बिल्कुल नई थ्रेड में निर्देश दे, तभी यह ठीक से काम में आता है।
फिर भी, अगर मैं अकेले होता तो शोध, काम का बोझ और धैर्य—किसी भी दृष्टि से यह पूरा नहीं कर पाता, इसलिए जनरेटिव AI की उत्पादकता सचमुच जबरदस्त है।
लक्ष्य
https://www.example.com/
पर ब्लॉग दिखा सकेंhttps://www.example.com/admin/
से DecapCMS में लॉगिन करके लेख बना सकें- बनाए गए लेख GitHub में कमिट हों और Cloudflare पर स्वतः डिप्लॉय हो जाएँ
- और फिलहाल अतिरिक्त रनिंग लागत 0 है (डोमेन पंजीकरण शुल्क तो पहले से ही लगता है)
0. पूर्वनिर्धारण और फ़ोल्डर संरचना
0-1. पूर्वनिर्धारण
-
माना गया है कि डोमेन (
example.com
) पहले से प्राप्त है -
ऑपरेटिंग सिस्टम Windows या macOS कुछ भी हो सकता है (दोनों के कमांड उदाहरण दिए जाएँगे)
-
उपयोग होने वाली सेवाएँ (मुफ़्त स्तर पर्याप्त है)
- GitHub खाता
- Cloudflare खाता (Pages का उपयोग)
- Git (लोकल)
- Hugo (लोकल प्रीव्यू के लिए, Cloudflare बिल्ड में भी इस्तेमाल)
0-2. रिपॉज़िटरी की मुख्य संरचना (उदाहरण)
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
इस संरचना का उद्देश्य नीचे है:
hugo.toml
… साइट की समूची सेटिंग ( baseURL को प्रोडक्शन URL से बदलना ज़रूरी है )functions/api/*.js
… Cloudflare Pages Functions (GitHub OAuth के/api/auth
और/api/callback
के लिए)layouts/_default/*.html
… Hugo टेम्पलेटstatic/admin/
… DecapCMS का इंटरफ़ेस और सेटिंगstatic/css/main.css
… दृश्य शैली (CSS)static/_headers
… Cloudflare Pages के HTTP हेडर सेटिंग (वैकल्पिक)
※ इस मार्गदर्शिका में जहाँ भी पर्यावरण के अनुसार मान बदलने की ज़रूरत हो, वहाँ “प्रतिस्थापन जाँच” के रूप में स्पष्ट बताया गया है।
1. प्रारम्भिक तैयारी
1-1. GitHub खाता बनाना
- ब्राउज़र में GitHub खोलें और साइन अप करें
1-2. Cloudflare खाता बनाना
- ब्राउज़र में Cloudflare खोलें और साइन अप करें
1-3. Git और Hugo इंस्टॉल करना
-
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. मुख्य प्रक्रिया (डिप्लॉय तक)
2-1. लोकल में रिपॉज़िटरी तैयार करना
-
GitHub पर खाली रिपॉज़िटरी बनाएँ
- स्क्रीन: GitHub > New repository
- नाम उदाहरण:
my-hugo-blog
-
उसे लोकल में क्लोन करें
-
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
-
-
ऊपर बताए गए फ़ोल्डर और फ़ाइलों का पूरा सेट रिपॉज़िटरी के रूट में रखें
प्रतिस्थापन जाँच (यहाँ ज़रूर बदलाव करें)
-
hugo.toml
baseURL = "https://www.example.com" # ← इसे प्रोडक्शन URL से बदलें (उदा.: 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 # ← इसे आपके GitHub रिपॉज़िटरी से बदलें branch: master # ← रिपॉज़िटरी की डिफ़ॉल्ट शाखा का नाम (main या master) base_url: https://www.example.com # ← इसे प्रोडक्शन URL से बदलें auth_endpoint: /api/auth # ← Functions का एंडपॉइंट (निश्चित) media_folder: static/uploads public_folder: /uploads
संदर्भ:
functions/api/auth.js
औरfunctions/api/callback.js
वैसे ही रहने दें (वेurl.origin
का उपयोग करते हैं, इसलिए पर्यावरण पर आधारित स्थिर मान लिखने की आवश्यकता नहीं है)।
-
पहली कमिट और पुश
-
Windows
PS C:\work\my-hugo-blog> git add -A PS C:\work\my-hugo-blog> git commit -m "Initial commit: Hugo + [DecapCMS](https://decapcms.org/) + 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](https://decapcms.org/) + CF Pages" mac:~/work/my-hugo-blog dev$ git push -u origin master
-
2-2. DecapCMS लॉगिन के लिए GitHub OAuth ऐप बनाना
-
स्क्रीन: GitHub > Settings > Developer settings > OAuth Apps > New OAuth App
-
इनपुट:
- Application name:
[DecapCMS](https://decapcms.org/) for my-hugo-blog
- Homepage URL:
https://www.example.com
- Authorization callback URL:
https://www.example.com/api/callback
← अत्यंत महत्वपूर्ण
- Application name:
-
बनाने के बाद यह जानकारी दिखाई देगी:
- Client ID
- Client Secret (नई वैल्यू जेनरेट करके सुरक्षित रखें)
इन मानों को Cloudflare Pages की environment variables में सेट करें।
2-3. Cloudflare Pages प्रोजेक्ट बनाना
-
स्क्रीन: Cloudflare डैशबोर्ड > Pages > Create a project > Connect to Git
-
GitHub से कनेक्ट करें और
my-hugo-blog
रिपॉज़िटरी चुनें -
बिल्ड सेटिंग:
-
Framework preset:
None
(या Cloudflare स्वतः पहचाने) -
Build command:
hugo
-
Build output directory:
public
-
environment variables:
HUGO_VERSION
=0.128.0
(उदाहरण; लोकल Hugo के संस्करण से मिलाना बेहतर)GITHUB_CLIENT_ID
= (पिछले चरण में प्राप्त मान)GITHUB_CLIENT_SECRET
= (पिछले चरण में प्राप्त मान)
-
-
Save and Deploy पर क्लिक करें और पहली डिप्लॉयमेंट का इंतज़ार करें
- सफलता पर
*.pages.dev
वाला प्रीव्यू URL मिलता है
- सफलता पर
2-4. कस्टम डोमेन www.example.com
जोड़ना
-
स्क्रीन: Cloudflare > Pages > (संबंधित प्रोजेक्ट) > Custom domains > Set up a custom domain
-
www.example.com
दर्ज करके जोड़ें -
अगर डोमेन Cloudflare पर ट्रांसफ़र नहीं किया गया है:
- Cloudflare में दिख रहे DNS रिकॉर्ड विवरण नोट करें (उदा.:
CNAME www -> <project>.pages.dev
) - जिस रजिस्ट्रार के पास डोमेन है, उसकी प्रबंधन स्क्रीन पर उसी के अनुरूप रिकॉर्ड सेट करें (प्रत्येक रजिस्ट्रार की प्रक्रिया अलग होगी)
- Cloudflare में दिख रहे DNS रिकॉर्ड विवरण नोट करें (उदा.:
-
बदलाव लागू होने के बाद सुनिश्चित करें कि
https://www.example.com/
पर साइट खुल रही है
सुझाव: यदि डोमेन पहले से Cloudflare में है, तो एक बटन से आवश्यक DNS सेटिंग अपने आप जुड़ जाती है।
2-5. DecapCMS प्रबंधन इंटरफ़ेस में लॉगिन करना
- ब्राउज़र में
https://www.example.com/admin/
खोलें - “Login with GitHub” जैसे बटन से GitHub OAuth को अनुमति दें
- पहली बार GitHub “क्या आप इस ऐप को अनुमति देना चाहते हैं?” पूछेगा, वहाँ Authorize दबाएँ
यदि लॉगिन विफल होता है तो OAuth callback URL और Cloudflare की environment variables (
GITHUB_CLIENT_ID/SECRET
) को फिर से जाँचें।
3. संचालन चरण (लेखन, लोकल सिंक, टेम्पलेट संपादन)
3-1. CMS से लेख बनाना
- स्क्रीन:
https://www.example.com/admin/
- बाएँ नेविगेशन: Blog → New blog पर क्लिक करें
- भरें:
Title
,Publish Date
,Description
,Body
- Publish दबाते ही GitHub में कमिट → Cloudflare पर स्वतः डिप्लॉय
तैयार हुआ Markdown
content/blog/
में सहेजा जाता है।
3-2. CMS से पोस्ट करने के बाद लोकल रिपॉज़िटरी को नवीनतम स्थिति में लाना
-
Windows
PS C:\work\my-hugo-blog> git pull origin master
-
macOS
mac:~/work/my-hugo-blog dev$ git pull origin master
इससे नवीनतम लेख लोकल में आ जाते हैं और आप टेम्पलेट या CSS सुरक्षित रूप से संपादित कर सकते हैं।
3-3. लोकल में डिज़ाइन और टेम्पलेट समायोजित करना
-
लोकल डेवलपमेंट सर्वर शुरू करें
-
Windows
PS C:\work\my-hugo-blog> hugo server -D
-
macOS
mac:~/work/my-hugo-blog dev$ hugo server -D
-
ब्राउज़र में
http://localhost:1313/
खोलकर परिणाम देखें
-
-
संभावित बदलाव (उदाहरण)
layouts/_default/baseof.html
…<head>
, हेडर/फ़ूटरlayouts/_default/index.html
… शीर्ष पृष्ठ की “नवीनतम लेख” सूचीlayouts/_default/single.html
… लेख पृष्ठ का मुख्य भागstatic/css/main.css
… रंग, फ़ॉन्ट, मार्जिन आदि
-
बदलाव कमिट और पुश करें
-
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
-
कुछ सेकंड से लेकर कुछ मिनटों में Cloudflare स्वयं डिप्लॉय कर देता है
-
3-4. ब्रांच संचालन के लिए छोटा सुझाव
- डिफ़ॉल्ट ब्रांच का नाम DecapCMS की
config.yml
फ़ाइल और Cloudflare सेटिंग दोनों में समान रखें (main
याmaster
) - यदि पूर्वावलोकन चाहिए तो GitHub में Pull Request बनाएं, Cloudflare Pages स्वयं preview environment तैयार करता है
4. उपयोगी अतिरिक्त जानकारी (वैकल्पिक)
4-1. static/_headers
का उदाहरण (प्रबंधन इंटरफ़ेस को कैश न करें)
/admin/*
Cache-Control: no-store
4-2. robots और साइटमैप (आवश्यकतानुसार)
static/robots.txt
तैयार करें ताकि क्रॉलर व्यवहार नियंत्रित किया जा सकेhugo.toml
मेंoutputs
जोड़कर RSS और sitemap के आउटपुट को विस्तारित किया जा सकता है
5. सामान्य अड़चनें और समाधान
- CMS लॉगिन केवल घूमता रहता है\
→ देखें कि GitHub OAuth का Callback URL
https://www.example.com/api/callback
है या नहीं, और Cloudflare मेंGITHUB_CLIENT_ID/SECRET
environment variables सही हैं या नहीं - होमपेज खुलता है लेकिन लेख पेज 404 देता है\
→
hugo.toml
काbaseURL
वास्तविक डोमेन से मेल खाता है या नहीं, और Cloudflare के बिल्ड लॉग मेंpublic/
बन रहा है या नहीं - /admin पूरी तरह सफेद दिखता है\
→ देखें कि
static/admin/index.html
में DecapCMS लोड करने वाला CDN कहीं ब्लॉक तो नहीं हो रहा; ब्राउज़र एक्सटेंशन बंद करके पुनः लोड करें
6. प्रतिस्थापन / सेटिंग जाँच बिंदुओं का सारांश
फ़ाइल/सेटिंग | कुंजी | बदलने या सेट करने की सामग्री (उदाहरण) |
---|---|---|
hugo.toml |
baseURL |
https://www.example.com |
static/admin/config.yml |
repo |
<YOUR_GH_USERNAME>/my-hugo-blog |
static/admin/config.yml |
branch |
वास्तविकता के अनुसार main या master चुनें |
static/admin/config.yml |
base_url |
https://www.example.com |
Cloudflare Pages | HUGO_VERSION |
उदाहरण: 0.128.0 |
Cloudflare Pages | GITHUB_CLIENT_ID |
GitHub OAuth ऐप का Client ID |
Cloudflare Pages | GITHUB_CLIENT_SECRET |
GitHub OAuth ऐप का Client Secret |
GitHub OAuth App | Callback URL | https://www.example.com/api/callback |
Cloudflare Pages | Custom domain | www.example.com को जोड़ें |
7. परिशिष्ट: फ़ाइल नमूने (आवश्यक भाग बदलें और उपयोग करें)
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 और परफॉर्मेंस अनुकूलन के बिंदु
ब्लॉग तैयार होने के बाद नीचे दिए गए उपाय खोज रैंकिंग और लोडिंग गति को और बेहतर करते हैं।
-
साइटमैप और robots.txt सेट करें
- Hugo द्वारा स्वतः बने
public/sitemap.xml
को Google Search Console में पंजीकृत करें static/robots.txt
में क्रॉलर नियंत्रण जोड़ें
- Hugo द्वारा स्वतः बने
-
OGP (Open Graph Protocol) और Twitter कार्ड सेट करें
layouts/_default/baseof.html
में<meta property="og:title">
,<meta property="og:image">
आदि जोड़ें- सोशल शेयरिंग के समय पेज अधिक आकर्षक दिखेगा
-
छवियों को WebP में बदलें
resources/_gen/images/
का उपयोग करके Hugo पाइपलाइन से स्वतः WebP रूपांतरण कराएँ- पेज लोडिंग स्पीड बेहतर होती है
-
श्रेणी और टैग सुविधाएँ बढ़ाएँ
content/blog/
के फ्रंट मैटर मेंcategories
औरtags
जोड़ें तथा टेम्पलेट में टैग क्लाउड दिखाएँ
-
संरचित डेटा लागू करें
- JSON-LD प्रारूप में लेख की जानकारी खोज इंजनों को दें ताकि रिच रिज़ल्ट का अवसर बढ़े
8. निष्कर्ष
- GitHub में रिपॉज़िटरी बनाकर, Cloudflare Pages से जोड़कर, DecapCMS के लिए GitHub OAuth सेट करके और कस्टम डोमेन बाँधकर सेटअप पूरा हो जाता है
- लेख
/admin/
से बनाएँ → GitHub में कमिट → Cloudflare स्वतः डिप्लॉय करता है - टेम्पलेट और डिज़ाइन को लोकल में
hugo server
चलाकर संपादित करें और Git से लागू करें
इतना करने पर Hugo + GitHub + Decap CMS + Cloudflare वाला सर्वरलेस ब्लॉग वातावरण संचालित किया जा सकता है।
अभी इतने पर कम लागत वाला साइट सेटअप तैयार हो गया है, लेकिन साइट सर्च, श्रेणी, टैग और टैग क्लाउड जैसी सुविधाएँ मौजूदा ब्लॉग्स की तुलना में अभी भी कम हैं। फिलहाल इसे इसी रूप में चलाना होगा, और आगे ChatGPT के साथ मिलकर धीरे-धीरे विस्तार करना चाहूँगा।