<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Waline on Ngoc Thach's Space</title><link>https://pngocthach.github.io/vi/tags/waline/</link><description>Recent content in Waline on Ngoc Thach's Space</description><generator>Hugo -- gohugo.io</generator><language>vi</language><lastBuildDate>Sun, 08 Mar 2026 19:25:00 +0700</lastBuildDate><atom:link href="https://pngocthach.github.io/vi/tags/waline/index.xml" rel="self" type="application/rss+xml"/><item><title>Cách tôi setup blog cá nhân nhanh, đẹp, miễn phí</title><link>https://pngocthach.github.io/vi/p/c%C3%A1ch-t%C3%B4i-setup-blog-c%C3%A1-nh%C3%A2n-nhanh-%C4%91%E1%BA%B9p-mi%E1%BB%85n-ph%C3%AD/</link><pubDate>Sun, 08 Mar 2026 19:25:00 +0700</pubDate><guid>https://pngocthach.github.io/vi/p/c%C3%A1ch-t%C3%B4i-setup-blog-c%C3%A1-nh%C3%A2n-nhanh-%C4%91%E1%BA%B9p-mi%E1%BB%85n-ph%C3%AD/</guid><description>&lt;p&gt;Nếu bạn muốn có một blog cá nhân &lt;strong&gt;nhanh, đẹp, miễn phí hoàn toàn&lt;/strong&gt;, không quảng cáo, load nhanh, và có phần comment với đầy đủ tính năng (emoji, reaction, anonymous&amp;hellip;), thì combo này là lựa chọn tuyệt vời năm 2026:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hugo&lt;/strong&gt; (static site generator siêu nhanh)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theme Stack&lt;/strong&gt; (thiết kế hiện đại, tối giản, dark mode đẹp)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Pages&lt;/strong&gt; (host miễn phí)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Waline&lt;/strong&gt; (comment system open-source, self-host trên Vercel + Neon Postgres, hỗ trợ anonymous, comment hiện ngay)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="yêu-cầu-trước-khi-bắt-đầu"&gt;Yêu cầu trước khi bắt đầu
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Tài khoản GitHub (public repo)&lt;/li&gt;
&lt;li&gt;Tài khoản Vercel (miễn phí, đăng nhập bằng GitHub)&lt;/li&gt;
&lt;li&gt;Tài khoản Neon (miễn phí, serverless Postgres)&lt;/li&gt;
&lt;li&gt;Máy tính có Git + Hugo installed (extended version khuyến nghị)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bước-1-clone-template-hugo-stack-và-setup-site-cơ-bản"&gt;Bước 1: Clone template Hugo Stack và setup site cơ bản
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Truy cập repo starter chính thức:&lt;br&gt;
&lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack-starter" target="_blank" rel="noopener"
 &gt;https://github.com/CaiJimmy/hugo-theme-stack-starter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Use this template&lt;/strong&gt; → &lt;strong&gt;Create a new repository&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặt tên repo:
&lt;ul&gt;
&lt;li&gt;Nếu muốn domain root: &lt;code&gt;username.github.io&lt;/code&gt; (ví dụ: pngocthach.github.io)&lt;/li&gt;
&lt;li&gt;Nếu muốn subpath: bất kỳ tên nào (ví dụ: my-blog) → domain sẽ là &lt;code&gt;username.github.io/my-blog&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clone repo về máy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/username/username.github.io.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; username.github.io
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cài Hugo nếu chưa có:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;brew install hugo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Windows: dùng Scoop/Chocolatey hoặc tải binary extended từ &lt;a class="link" href="https://github.com/gohugoio/hugo/releases" target="_blank" rel="noopener"
 &gt;https://github.com/gohugoio/hugo/releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linux (tùy distro): &lt;code&gt;sudo apt install hugo&lt;/code&gt; (hoặc extended)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kiểm tra: &lt;code&gt;hugo version&lt;/code&gt; (nên ≥ 0.120)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chạy thử local:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mở &lt;a class="link" href="http://localhost:1313" target="_blank" rel="noopener"
 &gt;http://localhost:1313&lt;/a&gt; → thấy trang demo Stack là OK.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy lên GitHub Pages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vào repo Settings → Pages&lt;/li&gt;
&lt;li&gt;Source: Deploy from a branch → Branch: main → Folder: / (root) → Save&lt;/li&gt;
&lt;li&gt;Template đã có GitHub Actions workflow sẵn (&lt;code&gt;.github/workflows/hugo.yml&lt;/code&gt;), chỉ cần push là tự build.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Trang live sau 1-3 phút: &lt;a class="link" href="https://username.github.io" target="_blank" rel="noopener"
 &gt;https://username.github.io&lt;/a&gt; (hoặc /my-blog)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bước-2-setup-waline-comment-backend-vercel--neon-postgres"&gt;Bước 2: Setup Waline comment backend (Vercel + Neon Postgres)
&lt;/h2&gt;&lt;p&gt;Waline là hệ thống comment open-source, nhẹ, hỗ trợ anonymous (comment không cần login), emoji/reaction đẹp.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Deploy Waline trên Vercel (miễn phí):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Truy cập: &lt;a class="link" href="https://waline.js.org/en/guide/deploy/vercel.html" target="_blank" rel="noopener"
 &gt;https://waline.js.org/en/guide/deploy/vercel.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click nút &lt;strong&gt;Deploy&lt;/strong&gt; (màu xanh)&lt;/li&gt;
&lt;li&gt;Đăng nhập Vercel bằng GitHub → Đặt tên project (ví dụ: &lt;code&gt;my-waline-backend&lt;/code&gt;) → Create&lt;/li&gt;
&lt;li&gt;Chờ deploy xong (1-2 phút) → Lấy URL backend: &lt;a class="link" href="https://my-waline-backend.vercel.app" target="_blank" rel="noopener"
 &gt;https://my-waline-backend.vercel.app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tạo database Neon Postgres (free tier):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trong Vercel Dashboard → Tab &lt;strong&gt;Storage&lt;/strong&gt; → &lt;strong&gt;Create Database&lt;/strong&gt; → Chọn &lt;strong&gt;Neon&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Region: &lt;strong&gt;Singapore (aws-ap-southeast-1)&lt;/strong&gt; (latency thấp nhất từ VN)&lt;/li&gt;
&lt;li&gt;Tạo DB → Open in Neon console&lt;/li&gt;
&lt;li&gt;Trong Neon SQL Editor → Paste script init từ:&lt;br&gt;
&lt;a class="link" href="https://github.com/walinejs/waline/blob/main/assets/waline.pgsql" target="_blank" rel="noopener"
 &gt;https://github.com/walinejs/waline/blob/main/assets/waline.pgsql&lt;/a&gt;&lt;br&gt;
→ Run để tạo tables&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kết nối Neon với Vercel:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trong Vercel → Storage → Chọn Neon DB vừa tạo → &lt;strong&gt;Connect&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Tick &lt;strong&gt;tất cả Environments&lt;/strong&gt;: Development, Preview, Production&lt;/li&gt;
&lt;li&gt;Tick &lt;strong&gt;Preview&lt;/strong&gt; cho branching (bỏ Production nếu không cần)&lt;/li&gt;
&lt;li&gt;Custom Prefix: Để &lt;strong&gt;trống&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Connect → Vercel tự inject env vars&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tạo admin account:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Truy cập: &lt;a class="link" href="https://my-waline-backend.vercel.app/ui/register" target="_blank" rel="noopener"
 &gt;https://my-waline-backend.vercel.app/ui/register&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Đăng ký user đầu tiên → thành admin&lt;/li&gt;
&lt;li&gt;Login tại &lt;code&gt;/ui&lt;/code&gt; để quản lý comment sau này (nếu cần review spam)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bước-3-tích-hợp-waline-vào-hugo-stack"&gt;Bước 3: Tích hợp Waline vào Hugo Stack
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Chỉnh file config (&lt;code&gt;config/_default/params.toml&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;waline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;serverURL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://waline-backend-iota.vercel.app&amp;#34;&lt;/span&gt; &lt;span class="c"&gt;# Thay bằng URL Vercel của bạn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;vi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;reaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://unpkg.com/@waline/emojis@1.0.1/tw-emoji&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://unpkg.com/@waline/emojis@1.0.1/weibo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Override để comment hiển thị full URL (dễ quản lý trong admin)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Quá trình deploy bạn có thể gặp tình trạng comment lưu trên Vercel chỉ nhận dạng bằng đường dẫn path relative &lt;code&gt;\p\bai-viet&lt;/code&gt; thay vì &lt;code&gt;https:\\domain\p\bai-viet&lt;/code&gt;. Khiến cực khó phân biệt bài viết.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Để xử lý việc này, hãy tạo file: &lt;code&gt;layouts/partials/comments/provider/waline.html&lt;/code&gt; đè lên file của theme.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nội dung file:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;//unpkg.com/@waline/client@v2/dist/waline.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;//unpkg.com/@waline/client@v2/dist/waline.css&amp;#39;&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;waline&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;waline-container&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;waline-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;shadow&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;--waline-font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;waline-container&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;wl-count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;text&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kc"&gt;color&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- $permalink := .Permalink -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- with .Site.Params.comments.waline -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- $config := dict &amp;#34;el&amp;#34; &amp;#34;#waline&amp;#34; &amp;#34;dark&amp;#34; `html[data-scheme=&amp;#34;dark&amp;#34;]` &amp;#34;path&amp;#34; $permalink -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- $replaceKeys := dict &amp;#34;serverurl&amp;#34; &amp;#34;serverURL&amp;#34; &amp;#34;requiredmeta&amp;#34; &amp;#34;requiredMeta&amp;#34; &amp;#34;wordlimit&amp;#34; &amp;#34;wordLimit&amp;#34; &amp;#34;pagesize&amp;#34; &amp;#34;pageSize&amp;#34; &amp;#34;imageuploader&amp;#34; &amp;#34;imageUploader&amp;#34; &amp;#34;texrenderer&amp;#34; &amp;#34;texRenderer&amp;#34; &amp;#34;turnstilekey&amp;#34; &amp;#34;turnstileKey&amp;#34; -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- range $key, $val := . -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {{- if ne $val nil -}} 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {{- $replaceKey := index $replaceKeys $key -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {{- $k := default $key $replaceKey -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {{- $config = merge $config (dict $k $val) -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {{- end -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- end -}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;waline-config&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;jsonify&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;safeJS&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;/// Waline client configuration see: https://waline.js.org/en/reference/client.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;walineConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;waline-config&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Waline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walineConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{{- end -}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.Permalink&lt;/code&gt; sẽ tự động lấy full URL (bao gồm domain), giúp admin Waline hiển thị comment dưới dạng &lt;code&gt;https://yourblog.com/p/bai-viet/&lt;/code&gt; thay vì path tương đối → cực kì dễ nhận biết blog nào.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bước-4-cách-viết-bài-mới-và-cập-nhật-blog"&gt;Bước 4: Cách viết bài mới và cập nhật blog
&lt;/h2&gt;&lt;p&gt;Sau khi đã setup xong &amp;ldquo;bộ khung&amp;rdquo;, việc viết bài hằng ngày sẽ cực kỳ đơn giản:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo bài viết mới&lt;/strong&gt;: Bạn sử dụng terminal và chạy lệnh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new content post/ten-bai-viet-cua-ban/index.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lệnh này sẽ tạo ra một thư mục mới trong &lt;code&gt;content/post/&lt;/code&gt; kèm theo file &lt;code&gt;index.md&lt;/code&gt;. Đây là nơi bạn sẽ viết nội dung bài viết.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Soạn thảo nội dung&lt;/strong&gt;: Mở file &lt;code&gt;index.md&lt;/code&gt; vừa tạo. Bạn sẽ thấy phần đầu (nằm giữa cặp &lt;code&gt;+++&lt;/code&gt;) gọi là &lt;strong&gt;Front Matter&lt;/strong&gt;—nơi chứa thông tin meta như tiêu đề, ngày tháng, mô tả, ảnh bìa&amp;hellip; Phía dưới đó là nơi bạn viết nội dung bằng cú pháp Markdown quen thuộc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kiểm tra cục bộ&lt;/strong&gt;: Chạy &lt;code&gt;hugo server&lt;/code&gt; để xem bài viết hiển thị như thế nào trên máy tính mình trước.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đăng bài (Cực kỳ quan trọng)&lt;/strong&gt;: Khi đã ưng ý, bạn chỉ cần thực hiện 3 lệnh Git cơ bản:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;Thêm bài viết mới: Tên bài viết&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ngay sau khi push, GitHub Actions sẽ tự động làm mọi việc còn lại. Sau khoảng 1 phút, bài viết mới của bạn sẽ xuất hiện &amp;ldquo;chễm chệ&amp;rdquo; trên blog live!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="kết-luận"&gt;Kết luận
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Tổng chi phí: &lt;strong&gt;0 đồng&lt;/strong&gt; (tận dụng free tier của GitHub Pages, Vercel và Neon là quá đủ dùng cho blog cá nhân).&lt;/li&gt;
&lt;li&gt;Ưu điểm: Hệ thống bình luận đầy đủ tính năng, hỗ trợ ẩn danh (anonymous), hiển thị ngay lập tức cùng với emoji và reaction dễ thương.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tự động hóa&lt;/strong&gt;: Sau khi setup xong, công việc duy nhất của bạn là tập trung viết bài bằng Markdown và push code lên GitHub. GitHub Actions sẽ lo liệu phần còn lại (build và deploy) để bài viết của bạn xuất hiện trên blog ngay lập tức.&lt;/li&gt;
&lt;li&gt;Nhược điểm: Nếu traffic tăng cao đột biến, có thể cần nâng cấp Neon/Vercel (nhưng rất hiếm gặp với blog cá nhân).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vậy là chỉ với vài bước đơn giản và không tốn bất kỳ chi phí nào, bạn đã có cho mình một trang blog xịn sò để thỏa sức viết lách rồi. Giờ chỉ còn việc sắp xếp thời gian để ra bài viết thôi. Cảm ơn đã đọc và hẹn gặp lại ở các bài viết sau! Nếu gặp phải lỗi hoặc cần hỗ trợ gì, bạn cứ để lại comment bên dưới nhé!&lt;/p&gt;
&lt;h2 id="tài-liệu-tham-khảo"&gt;Tài liệu tham khảo
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hugo Theme Stack Starter Template&lt;/strong&gt; (repo chính thức để clone và bắt đầu nhanh):&lt;br&gt;
&lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack-starter" target="_blank" rel="noopener"
 &gt;https://github.com/CaiJimmy/hugo-theme-stack-starter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hugo Theme Stack Official Documentation&lt;/strong&gt; (config comments, Waline, và tùy chỉnh chung):&lt;br&gt;
&lt;a class="link" href="https://stack.jimmycai.com/" target="_blank" rel="noopener"
 &gt;https://stack.jimmycai.com/&lt;/a&gt;&lt;br&gt;
Phần Comments: &lt;a class="link" href="https://stack.jimmycai.com/config/comments" target="_blank" rel="noopener"
 &gt;https://stack.jimmycai.com/config/comments&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hugo Official Guide: Host and Deploy on GitHub Pages&lt;/strong&gt; (deploy với GitHub Actions):&lt;br&gt;
&lt;a class="link" href="https://gohugo.io/host-and-deploy/host-on-github-pages/" target="_blank" rel="noopener"
 &gt;https://gohugo.io/host-and-deploy/host-on-github-pages/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Waline Official Documentation&lt;/strong&gt; (deploy trên Vercel, config client, ecosystem):&lt;br&gt;
&lt;a class="link" href="https://waline.js.org/en/" target="_blank" rel="noopener"
 &gt;https://waline.js.org/en/&lt;/a&gt;&lt;br&gt;
Deploy Vercel: &lt;a class="link" href="https://waline.js.org/en/guide/deploy/vercel.html" target="_blank" rel="noopener"
 &gt;https://waline.js.org/en/guide/deploy/vercel.html&lt;/a&gt;&lt;br&gt;
Client config (path, lang, reaction): &lt;a class="link" href="https://waline.js.org/en/reference/client/props.html" target="_blank" rel="noopener"
 &gt;https://waline.js.org/en/reference/client/props.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Neon Docs: Integrate with Vercel&lt;/strong&gt; (kết nối Neon Postgres với Vercel, env vars, branching):&lt;br&gt;
&lt;a class="link" href="https://neon.com/docs/guides/vercel-overview" target="_blank" rel="noopener"
 &gt;https://neon.com/docs/guides/vercel-overview&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Source code của chính blog này&lt;/strong&gt; (để bạn tham khảo thực tế):&lt;br&gt;
&lt;a class="link" href="https://github.com/pngocthach/pngocthach.github.io" target="_blank" rel="noopener"
 &gt;https://github.com/pngocthach/pngocthach.github.io&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item></channel></rss>