দীর্ঘদিন ধরে https://www.ixam.net ডোমেইনে গুগল সাইটস (Google Apps যুগের) দিয়ে সাইট চালাতাম। অনেক আগেই গুগল সাইটস অকার্যকর হয়ে যাওয়ায় ডোমেইনটা ফাঁকা পড়ে ছিল। অবশেষে আবার কাজে লাগানোর সিদ্ধান্ত নিয়ে রিনিউ করার প্রক্রিয়ায় নামলাম। সার্ভারলেস রাখতে চাই, আর কনটেন্ট যেন গুগল সাইটসের মতো ইচ্ছেমতো বন্ধ হয়ে যাওয়া সেবার ওপর নির্ভর না করে—এই শর্ত নিয়ে ChatGPT-কে সঙ্গী করলাম।

ভেবেছিলাম ChatGPT-ই সবকিছু সহজ করে দেবে। বাস্তবে দেখা গেল, মৌলিক প্রয়োজন বাদ পড়ে যায়, ট্রাবলশুটিং ঘুরপাক খায়—মোটেও সোজা নয়। শেষমেশ গুগল করে পাওয়া https://github.com/patrickgrey/website/ রেপোজিটরির মতো উদাহরণও দেখে, একসঙ্গে সমাধান খুঁজেছি।

যাকে বলে “টেকনিক্যালি দক্ষ, কিন্তু বারবার ভুল ধারণা করা জুনিয়রকে পথ দেখানো”—সে অভিজ্ঞতা। সেই পর্যায়ে পৌঁছে যাওয়ার মত এআই তৈরি হয়েছে, ভাবতেই অবাক লাগে।

তবে জটিলতা বাড়তে থাকলে সেই এআই-ও বেশ বিরক্তিকর ভুল করতে শুরু করে। এটাও একধরনের বাস্তবতা!?

আপাতত দীর্ঘ আলাপ চালিয়ে সব প্রাক-শর্ত বুঝে নেওয়ার বদলে, কথোপকথন জটিল হলেই মানুষ নিজে সংক্ষেপ করে নতুন থ্রেডে নির্দেশনা দিলে সবচেয়ে কার্যকর মনে হয়েছে।

তা সত্ত্বেও, একা করলে গবেষণা, কাজের পরিমাণ, ধৈর্য—কোনোটাই সামলাতে পারতাম না। জেনারেটিভ এআইয়ের উৎপাদনশীলতা সত্যিই বিস্ময়কর।


লক্ষ্য

  • https://www.example.com/-এ ব্লগ প্রদর্শন করা যাবে
  • https://www.example.com/admin/ থেকে DecapCMS-এ লগইন করে নিবন্ধ তৈরি করা যাবে
  • লেখা GitHub-এ কমিট হবে এবং Cloudflare স্বয়ংক্রিয়ভাবে ডিপ্লয় করবে
  • বর্তমানে অতিরিক্ত কোনো রানিং কস্ট নেই (ডোমেইন রেজিস্ট্রেশনের পুরোনো খরচ ছাড়া)

0. পূর্বশর্ত ও ফোল্ডার বিন্যাস

0-1. পূর্বশর্ত

  • ডোমেইন (example.com) ইতোমধ্যে ক্রয় করা আছে

  • OS 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 এর UI ও কনফিগারেশন ফাইল
  • 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. GitHub OAuth App তৈরি করা (DecapCMS লগইনের জন্য)

  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-এর এনভায়রনমেন্ট ভেরিয়েবল হিসেবে সেট করবেন।


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

    • এনভায়রনমেন্ট ভেরিয়েবল:

      • HUGO_VERSION = 0.128.0 (উদাহরণ: লোকাল সংস্করণের সাথে মিল রাখলে সুবিধা)
      • 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. DNS সক্রিয় হলে 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 ভেরিয়েবল (GITHUB_CLIENT_ID/SECRET) আবার যাচাই করুন।


3. অপারেশন গাইড (নিবন্ধ লেখা, লোকাল সিঙ্ক, টেমপ্লেট সম্পাদনা)

3-1. CMS থেকে নিবন্ধ তৈরি

  1. https://www.example.com/admin/ খুলুন
  2. বাম ন্যাভ থেকে Blog > New 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. ব্রাঞ্চ ব্যবস্থাপনা টিপস

  • ডিফল্ট ব্রাঞ্চ main নাকি master—এই নামটি DecapCMS এর config.yml ও Cloudflare সেটিং এ একই রাখুন
  • প্রিভিউ দরকার হলে GitHub-এ Pull Request খুললেই Cloudflare Pages Preview পরিবেশ জেনারেট করে

4. অতিরিক্ত সুবিধা (ঐচ্ছিক)

4-1. static/_headers উদাহরণ (অ্যাডমিন প্যানেল ক্যাশ না করা)

/admin/*
  Cache-Control: no-store

4-2. robots ও সাইটম্যাপ (প্রয়োজনে)

  • static/robots.txt দিয়ে ক্রলার নিয়ন্ত্রণ
  • hugo.toml-এ outputs যোগ করে RSS বা সাইটম্যাপ আউটপুট বাড়ানো সম্ভব

5. সাধারণ সমস্যাগুলো ও সমাধান

  • CMS লগইন ঘুরেই চলেছে
    → GitHub OAuth-এর Callback URL https://www.example.com/api/callback কি না এবং Cloudflare ভেরিয়েবল GITHUB_CLIENT_ID/SECRET সঠিক কি না দেখুন
  • হোমপেজ খুলছে কিন্তু নিবন্ধে 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 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 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) ও টুইটার কার্ড

    • layouts/_default/baseof.html-এ <meta property="og:title">, <meta property="og:image"> ইত্যাদি যোগ করুন
    • সোশ্যাল শেয়ারে আকর্ষণীয় প্রদর্শনের জন্য কার্যকর
  3. ছবিকে WebP-তে রূপান্তর

    • resources/_gen/images/ ব্যবহার করে Hugo পাইপলাইনে স্বয়ংক্রিয় WebP তৈরি করুন
    • পেজ লোডিং সময় কমে যাবে
  4. ক্যাটাগরি/ট্যাগ ফিচার বাড়ানো

    • content/blog/-এর ফ্রন্ট ম্যাটারে categoriestags যোগ করে টেমপ্লেটে ট্যাগ ক্লাউড দেখাতে পারেন
  5. স্ট্রাকচার্ড ডেটা

    • JSON-LD ফরম্যাটে নিবন্ধ তথ্য সার্চ ইঞ্জিনকে জানিয়ে রিচ রেজাল্টের সম্ভাবনা তৈরি করুন

8. সারসংক্ষেপ

  • GitHub-এ রেপোজিটরি, Cloudflare Pages-এ সংযোগ, DecapCMS এর GitHub OAuth সেটিং, নিজস্ব ডোমেইন ম্যাপ করলেই বেসিক সেটআপ সম্পন্ন
  • /admin/ থেকে নিবন্ধ তৈরি → GitHub-এ কমিট → Cloudflare স্বয়ংক্রিয় ডিপ্লয়
  • টেমপ্লেট ও ডিজাইন লোকালে hugo server চালিয়ে এডিট করুন, তারপর Git দিয়ে প্রতিফলিত করুন

এভাবে Hugo + GitHub + Decap CMS + Cloudflare ভিত্তিক সার্ভারলেস ব্লগ সহজে তৈরি ও রক্ষণাবেক্ষণ সম্ভব।

এখনো পর্যন্ত স্বল্প খরচে একটি সাইট দাঁড়াল বটে, কিন্তু সাইট সার্চ, ক্যাটাগরি, ট্যাগ ও ট্যাগ ক্লাউড—এসব তুলনা করলে পরিণত ব্লগের মতো সমৃদ্ধ নয়। আপাতত এটা মেনে নিয়েছি; ধীরে ধীরে ChatGPT-কে সঙ্গে নিয়ে সমৃদ্ধ করবো।