यह साइट पहले गूगल ऐप्स के दौर के 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 कुछ भी हो सकता है (दोनों के कमांड उदाहरण दिए जाएँगे)

  • उपयोग होने वाली सेवाएँ (मुफ़्त स्तर पर्याप्त है)

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. लोकल में रिपॉज़िटरी तैयार करना

  1. GitHub पर खाली रिपॉज़िटरी बनाएँ

    • स्क्रीन: GitHub > New repository
    • नाम उदाहरण: my-hugo-blog
  2. उसे लोकल में क्लोन करें

    • 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
      
  3. ऊपर बताए गए फ़ोल्डर और फ़ाइलों का पूरा सेट रिपॉज़िटरी के रूट में रखें

प्रतिस्थापन जाँच (यहाँ ज़रूर बदलाव करें)

  • 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 का उपयोग करते हैं, इसलिए पर्यावरण पर आधारित स्थिर मान लिखने की आवश्यकता नहीं है)।

  1. पहली कमिट और पुश

    • 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 ऐप बनाना

  1. स्क्रीन: GitHub > Settings > Developer settings > OAuth Apps > New OAuth App

  2. इनपुट:

    • 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अत्यंत महत्वपूर्ण
  3. बनाने के बाद यह जानकारी दिखाई देगी:

    • Client ID
    • Client Secret (नई वैल्यू जेनरेट करके सुरक्षित रखें)

इन मानों को Cloudflare Pages की environment variables में सेट करें।


2-3. Cloudflare Pages प्रोजेक्ट बनाना

  1. स्क्रीन: Cloudflare डैशबोर्ड > Pages > Create a project > Connect to Git

  2. GitHub से कनेक्ट करें और my-hugo-blog रिपॉज़िटरी चुनें

  3. बिल्ड सेटिंग:

    • 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 = (पिछले चरण में प्राप्त मान)
  4. Save and Deploy पर क्लिक करें और पहली डिप्लॉयमेंट का इंतज़ार करें

    • सफलता पर *.pages.dev वाला प्रीव्यू URL मिलता है

2-4. कस्टम डोमेन www.example.com जोड़ना

  1. स्क्रीन: Cloudflare > Pages > (संबंधित प्रोजेक्ट) > Custom domains > Set up a custom domain

  2. www.example.com दर्ज करके जोड़ें

  3. अगर डोमेन Cloudflare पर ट्रांसफ़र नहीं किया गया है:

    • Cloudflare में दिख रहे DNS रिकॉर्ड विवरण नोट करें (उदा.: CNAME www -> <project>.pages.dev)
    • जिस रजिस्ट्रार के पास डोमेन है, उसकी प्रबंधन स्क्रीन पर उसी के अनुरूप रिकॉर्ड सेट करें (प्रत्येक रजिस्ट्रार की प्रक्रिया अलग होगी)
  4. बदलाव लागू होने के बाद सुनिश्चित करें कि https://www.example.com/ पर साइट खुल रही है

सुझाव: यदि डोमेन पहले से Cloudflare में है, तो एक बटन से आवश्यक DNS सेटिंग अपने आप जुड़ जाती है।


2-5. DecapCMS प्रबंधन इंटरफ़ेस में लॉगिन करना

  1. ब्राउज़र में https://www.example.com/admin/ खोलें
  2. “Login with GitHub” जैसे बटन से GitHub OAuth को अनुमति दें
  3. पहली बार GitHub “क्या आप इस ऐप को अनुमति देना चाहते हैं?” पूछेगा, वहाँ Authorize दबाएँ

यदि लॉगिन विफल होता है तो OAuth callback URL और Cloudflare की environment variables (GITHUB_CLIENT_ID/SECRET) को फिर से जाँचें।


3. संचालन चरण (लेखन, लोकल सिंक, टेम्पलेट संपादन)

3-1. CMS से लेख बनाना

  1. स्क्रीन: https://www.example.com/admin/
  2. बाएँ नेविगेशन: BlogNew blog पर क्लिक करें
  3. भरें: Title, Publish Date, Description, Body
  4. 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. लोकल में डिज़ाइन और टेम्पलेट समायोजित करना

  1. लोकल डेवलपमेंट सर्वर शुरू करें

    • Windows

      PS C:\work\my-hugo-blog> hugo server -D
      
    • macOS

      mac:~/work/my-hugo-blog dev$ hugo server -D
      
    • ब्राउज़र में http://localhost:1313/ खोलकर परिणाम देखें

  2. संभावित बदलाव (उदाहरण)

    • layouts/_default/baseof.html<head>, हेडर/फ़ूटर
    • layouts/_default/index.html … शीर्ष पृष्ठ की “नवीनतम लेख” सूची
    • layouts/_default/single.html … लेख पृष्ठ का मुख्य भाग
    • static/css/main.css … रंग, फ़ॉन्ट, मार्जिन आदि
  3. बदलाव कमिट और पुश करें

    • 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 और परफॉर्मेंस अनुकूलन के बिंदु

ब्लॉग तैयार होने के बाद नीचे दिए गए उपाय खोज रैंकिंग और लोडिंग गति को और बेहतर करते हैं।

  1. साइटमैप और robots.txt सेट करें

    • Hugo द्वारा स्वतः बने public/sitemap.xml को Google Search Console में पंजीकृत करें
    • static/robots.txt में क्रॉलर नियंत्रण जोड़ें
  2. OGP (Open Graph Protocol) और Twitter कार्ड सेट करें

    • layouts/_default/baseof.html में <meta property="og:title">, <meta property="og:image"> आदि जोड़ें
    • सोशल शेयरिंग के समय पेज अधिक आकर्षक दिखेगा
  3. छवियों को WebP में बदलें

    • resources/_gen/images/ का उपयोग करके Hugo पाइपलाइन से स्वतः WebP रूपांतरण कराएँ
    • पेज लोडिंग स्पीड बेहतर होती है
  4. श्रेणी और टैग सुविधाएँ बढ़ाएँ

    • content/blog/ के फ्रंट मैटर में categories और tags जोड़ें तथा टेम्पलेट में टैग क्लाउड दिखाएँ
  5. संरचित डेटा लागू करें

    • JSON-LD प्रारूप में लेख की जानकारी खोज इंजनों को दें ताकि रिच रिज़ल्ट का अवसर बढ़े

8. निष्कर्ष

  • GitHub में रिपॉज़िटरी बनाकर, Cloudflare Pages से जोड़कर, DecapCMS के लिए GitHub OAuth सेट करके और कस्टम डोमेन बाँधकर सेटअप पूरा हो जाता है
  • लेख /admin/ से बनाएँ → GitHub में कमिट → Cloudflare स्वतः डिप्लॉय करता है
  • टेम्पलेट और डिज़ाइन को लोकल में hugo server चलाकर संपादित करें और Git से लागू करें

इतना करने पर Hugo + GitHub + Decap CMS + Cloudflare वाला सर्वरलेस ब्लॉग वातावरण संचालित किया जा सकता है।

अभी इतने पर कम लागत वाला साइट सेटअप तैयार हो गया है, लेकिन साइट सर्च, श्रेणी, टैग और टैग क्लाउड जैसी सुविधाएँ मौजूदा ब्लॉग्स की तुलना में अभी भी कम हैं। फिलहाल इसे इसी रूप में चलाना होगा, और आगे ChatGPT के साथ मिलकर धीरे-धीरे विस्तार करना चाहूँगा।